Localize a customer account UI extension
In this tutorial, you'll use JavaScript API functions to localize an extension that displays a customer's loyalty point balance on the Profile page. You'll localize the extension text, the number format of the loyalty points balance, and the monetary value of the points. You'll also provide translations for singular and plural values. You can use what you learn here to localize other extensions.
Anchor to What you'll learnWhat you'll learn
In this tutorial, you'll learn how to do the following tasks:
-
Create a customer account UI extension that renders in the Profile page with some basic localization.
-
Run the extension locally and test it on a development store.
-
Define translation data and localize the following elements:
- Numbers using a
formatNumber
function similar to theIntl
object - Currency using a
formatCurrency
Intl
object - Singular and plural values
- Numbers using a
-
Deploy your extension code to Shopify.
Anchor to RequirementsRequirements
-
You've created a Partner account.
-
You've created a new development store with the following:
-
You're familiar with how localization works for customer account UI extensions.
-
You've added and published a second language to your development store.
-
You've activated the language in your development store's primary market.
Anchor to Sample codeSample code
You can copy and paste the following code into your index
file and add a few example values to get the extension to render in the browser.
The rest of the tutorial walks through this sample code step-by-step.
import React from "react";
import {
reactExtension,
Text,
Banner,
useApi,
useTranslate,
} from "@shopify/ui-extensions-react/customer-account";
/* This example assumes that you have the following contents in your `locales/en.default.json` file. You'll add this later in the tutorial:
{
"loyaltyPoints": {
"one": "You have {{formattedPoints}} loyalty point",
"other": "You have {{formattedPoints}} loyalty points"
},
"balanceRemaining": "Your balance is {{formattedBalance}}"
}
*/
// Set the entry point for the extension
export default reactExtension("customer-account.profile.block.render", () => <App />);
function App() {
// Use i18n provided by the extension API
const { i18n } = useApi();
// Use the translate function
const translate = useTranslate();
const balance = 9.99;
// Localize the currency based on the current locale
const formattedBalance = i18n.formatCurrency(balance);
// Translate the balance remaining message
const balanceRemainingMsg = translate("balanceRemaining", {
// Provide a property/value that can be used in the translated message
formattedBalance,
});
const points = 10000;
// Localize the number based on the current locale
const formattedPoints = i18n.formatNumber(points);
// Translate the loyalty points message, using pluralization to differentiate messages
const loyaltyPointsMsg = translate("loyaltyPoints", {
// Specify a count property so that the correct pluralization key (in this example, "many", "one" or "other") will be resolved
count: points,
// Provide a property/value that can be used in the translated message
formattedPoints,
});
// Render the components
return (
<Banner title={loyaltyPointsMsg}>
<Text>{balanceRemainingMsg}</Text>
</Banner>
);
}
import { extension, Banner, Text } from "@shopify/ui-extensions/customer-account";
/* This example assumes that you have the following contents in your `locales/en.default.json` file. You'll add this later in the tutorial:
{
"loyaltyPoints": {
"one": "You have {{formattedPoints}} loyalty point",
"other": "You have {{formattedPoints}} loyalty points"
},
"balanceRemaining": "Your balance is {{formattedBalance}}"
}
*/
// Set the entry point for the extension
export default extension("customer-account.profile.block.render", (root, { i18n }) => {
// Use i18n provided by the extension API
const balance = 9.99;
// Localize the currency based on the current locale
const formattedBalance = i18n.formatCurrency(balance);
// Translate the balance remaining message
const balanceRemainingMsg = i18n.translate("balanceRemaining", {
// Provide a property/value that can be used in the translated message
formattedBalance,
});
const points = 10000;
// Localize the number based on the current locale
const formattedPoints = i18n.formatNumber(points);
// Translate the loyalty points message, using pluralization to differentiate messages
const loyaltyPointsMsg = i18n.translate("loyaltyPoints", {
// Specify a count property so that the correct pluralization key (in this example, "many", "one" or "other") will be resolved
count: points,
// Provide a property/value that can be used in the translated message
formattedPoints,
});
// Render the components
const app = root.createComponent(Banner, { title: loyaltyPointsMsg });
app.appendChild(root.createComponent(Text, {}, balanceRemainingMsg));
root.appendChild(app);
});
api_version = "unstable"
[[extensions]]
name = "customer-account-loyalty-points"
description = "A customer account loyalty points extension"
handle = "customer-account-loyalty-points"
type = "ui_extension"
[[extensions.targeting]]
target = "customer-account.profile.block.render"
module = "./src/LoyaltyPoints.jsx" # React OR "./src/LoyaltyPoints.js" for JavaScript
Anchor to Step 1: Create a customer account UI extensionStep 1: Create a customer account UI extension
If you already have a customer account UI extension that you want to localize, then you can skip ahead.
To create a customer account UI extension, you can use Shopify CLI, which generates starter code for building your extension and automates common development tasks.
-
Navigate to your app directory:
Terminal
cd <directory> -
Run the following command to create a new customer account UI extension:
Terminal
shopify app generate extension --template customer_account_ui --name customer-account-ui-extension -
Select a language for your extension. You can choose from TypeScript, JavaScript, TypeScript React, or JavaScript React.
TipTypeScript or JavaScript is suitable for smaller projects that require a more straightforward API. TypeScript React or JavaScript React is suitable when you want an easy model for mapping state updates to UI updates. With JavaScript or TypeScript, you need to map state updates yourself. This process is similar to writing an application targeting the DOM, versus using
react-dom
.You should now have a new extension directory in your app's directory. The extension directory includes the extension script at
src/index.{file-extension}
. The following is an example directory structure:Customer account UI extension file structure
└── my-app└── extensions└── my-customer-account-ui-extension├── src│ └── CustomerAccount.jsx OR CustomerAccount.js // The index page of the customer account UI extension├── locales│ ├── en.default.json // The default locale for the customer account UI extension│ └── fr.json // The locale file for non-regional French translations├── shopify.extension.toml // The config file for the customer account UI extension└── package.json
-
Start your development server to build and preview your app:
Terminal
shopify app devTo learn about the processes that are executed when you run
dev
, refer to the Shopify CLI command reference. -
Press
p
to open the developer console. In the developer console page, click on the preview link for your extension.
Anchor to Step 2: Define translationsStep 2: Define translations
To define translations, you'll adjust the [locale].json
files in the extensions/<name-of-customer-account-ui-extension>/locales
folder within your app.
In this tutorial, you'll keep French (fr
, non-regional) as an available locale. However, you can also create translations for additional locales.
Anchor to Set the default localeSet the default locale
Your default locale specifies which locale Shopify should use when no other appropriate locale can be matched. In this example, English (en
) is already the default locale. However, you can set any locale to be your default locale.
To change your default locale, go to the locales
folder and change the [locale].json
filename to [locale].default.json
.
Anchor to Add translation stringsAdd translation strings
In this step, you'll add translations for different plural forms. You'll set translations for the many
, one
and other
plural rules needed for French (fr
), but you can specify any pluralization key that Intl.PluralRules.select()
supports and that's appropriate for the locale.
In subsequent steps, you'll define balance
and points
using a placeholder.
- In
en.default.json
, add the following code:
locales/en.default.json
- In the
fr.json
file, add the translated content:
locales/fr.json
Anchor to Step 3: Localize the currencyStep 3: Localize the currency
Now that you've defined translations, you'll learn how to localize currency.
You'll add the formatCurrency
function provided by i18n
. The function wraps the standard Intl
object.
...
function App() {
// Use i18n provided by the extension API
const { i18n } = useApi();
// Use the translate function
const translate = useTranslate();
const balance = 9.99;
// Localize the currency based on the current locale
const formattedBalance = i18n.formatCurrency(balance);
...
}
...
export default extension("customer-account.profile.block.render", (root, { i18n }) => {
// Use i18n provided by the extension API
const balance = 9.99;
// Localize the currency based on the current locale
const formattedBalance = i18n.formatCurrency(balance);
...
});
Depending on the current locale, 9.99
will now resolve to the following localized currency formats:
-
en
:$9.99
-
fr
:9,99
Anchor to Step 4: Localize numbersStep 4: Localize numbers
In this step, you'll learn how to resolve localized numbers.
You'll localize number formatting using the formatNumber
function provided by i18n
. The function wraps the standard Intl
object.
...
function App() {
...
const points = 10000;
// Localize the number based on the current locale
const formattedPoints = i18n.formatNumber(points);
...
}
...
export default extension("customer-account.profile.block.render", (root, { i18n }) => {
...
const points = 10000;
// Localize the number based on the current locale
const formattedPoints = i18n.formatNumber(points);
...
});
Depending on the current locale, 10000
will resolve to one of the following localized number formats:
-
en
:10,000
-
fr
:10 000
Anchor to Step 5: Translate the balance remaining messageStep 5: Translate the balance remaining message
In this step, you'll learn how to translate the balance remaining message using a placeholder.
You'll use a placeholder for formattedBalance
. You'll also call the translate
function, which sends the formattedBalance
variable so that it can be used in the translation string.
When using React, and UI components as placeholders, you should use the provided useTranslate
hook. This will make sure the required unique key is added to each UI component in the returned array.
...
function App() {
...
// Use the translate function
const translate = useTranslate();
const balance = 9.99;
// Localize the currency based on the current locale
const formattedBalance = i18n.formatCurrency(balance);
// Translate the balance remaining message
const balanceRemainingMsg = translate("balanceRemaining", {
// Provide a property/value that can be used in the translated message
formattedBalance,
});
...
}
...
export default extension("customer-account.profile.block.render", (root, { i18n }) => {
const balance = 9.99;
// Localize the currency based on the current locale
const formattedBalance = i18n.formatCurrency(balance);
// Translate the balance remaining message
const balanceRemainingMsg = i18n.translate("balanceRemaining", {
// Provide a property/value that can be used in the translated message
formattedBalance,
});
...
});
Anchor to Step 6: Translate the loyalty points message with plural valuesStep 6: Translate the loyalty points message with plural values
In this step, you'll learn how to translate the loyaltyPoints
message, which supports pluralization.
You'll use the translate
function to pass in the count
of how many points are available. You'll use formattedPoints
to render the points in the current locale.
When working with translation keys with pluralization, you must provide the count
property. This allows the translate
function to determine which pluralization to use, according to Intl Pluralization Rules.
...
function App() {
...
// Use the translate function
const translate = useTranslate();
...
const points = 10000;
// Localize the number based on the current locale
const formattedPoints = i18n.formatNumber(points);
// Translate the loyalty points message, using pluralization to differentiate messages
const loyaltyPointsMsg = translate("loyaltyPoints", {
// Specify a count property so that the correct pluralization key (in this example, "many", "one" or "other") will be resolved
count: points,
// Provide a property/value that can be used in the translated message
formattedPoints,
});
...
}
...
export default extension("customer-account.profile.block.render", (root, { i18n }) => {
...
const points = 10000;
// Localize the number based on the current locale
const formattedPoints = i18n.formatNumber(points);
// Translate the loyalty points message, using pluralization to differentiate messages
const loyaltyPointsMsg = i18n.translate("loyaltyPoints", {
// Specify a count property so that the correct pluralization key (in this example, "many", "one" or "other") will be resolved
count: points,
// Provide a property/value that can be used in the translated message
formattedPoints,
});
...
});
The customer account UI extension should now render localized content for en
and fr
:
To test the extension, preview the language from your development store admin.
Anchor to Step 7: Deploy the UI extensionStep 7: Deploy the UI extension
When you're ready to release your changes to users, you can create and release an app version. An app version is a snapshot of your app configuration and all extensions.
-
Navigate to your app directory.
-
Run the following command.
Optionally, you can provide a name or message for the version using the
--version
and--message
flags.Terminal
shopify app deploy
Releasing an app version replaces the current active version that's served to stores that have your app installed. It might take several minutes for app users to be upgraded to the new version.
If you want to create a version, but avoid releasing it to users, then run the deploy
command with a --no-release
flag.
You can release the unreleased app version using Shopify CLI's release
command, or through the Partner Dashboard.