---
title: Localization API
description: >-
  The Localization API lets you translate strings, format numbers and dates, and
  read the buyer's language, country, and currency context. Use this API to
  build extensions that adapt their content and behavior to the customer's
  locale, including support for pluralization and dynamic values in
  translations.
api_version: 2027-01
source_url:
  html: >-
    https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/target-apis/platform-apis/localization-api
  md: >-
    https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/target-apis/platform-apis/localization-api.md
api_name: customer-account-ui-extensions
---

# Localization API

The Localization API lets you translate strings, format numbers and dates, and read the buyer's language, country, and currency context. Use this API to build extensions that adapt their content and behavior to the customer's locale, including support for pluralization and dynamic values in translations.

Translation keys must be defined in static JSON locale files bundled with the extension. Dynamic runtime translation loading isn't supported.

### Use cases

* **Display translated content**: Render UI strings in the customer's preferred language using translation keys defined in locale JSON files.
* **Format numbers and currency**: Use `shopify.i18n.formatNumber()` to display numbers, prices, and quantities in the customer's locale format.
* **Show country-specific messaging**: Read the customer's country from `shopify.localization.country` to conditionally display region-specific notices, shipping information, or promotions.
* **Handle pluralization**: Use the `count` option in `shopify.i18n.translate()` to automatically select the correct plural form based on the customer's locale rules.

### Support Targets (24)

### Supported targets

* [customer-account.​footer.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/footer#footer-render-after-)
* [customer-account.​order-index.​announcement.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/order-actions#order-index-announcement-)
* [customer-account.​order-index.​block.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/order-actions#order-index-block-)
* [customer-account.​order-status.​announcement.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/order-status#order-status-announcement-)
* [customer-account.​order-status.​block.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/order-status#order-status-block-)
* [customer-account.​order-status.​cart-line-item.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/order-status#cart-line-item-render-after-)
* [customer-account.​order-status.​cart-line-list.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/order-status#cart-line-list-render-after-)
* [customer-account.​order-status.​customer-information.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/order-status#customer-information-render-after-)
* [customer-account.​order-status.​fulfillment-details.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/fulfillment-status#fulfillment-status-targets)
* [customer-account.​order-status.​payment-details.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/payments-and-returns#payments-and-returns-targets)
* [customer-account.​order-status.​return-details.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/payments-and-returns#return-details-render-after-)
* [customer-account.​order-status.​unfulfilled-items.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/fulfillment-status#unfulfilled-items-render-after-)
* [customer-account.​order.​action.​menu-item.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/order-actions#order-action-menu-item-)
* [customer-account.​order.​action.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/order-actions#order-action-)
* [customer-account.​order.​page.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/full-page#order-specific-full-page-)
* [customer-account.​page.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/full-page#customer-account-full-page-)
* [customer-account.​profile.​addresses.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/profile-page-default#profile-page-default-targets-)
* [customer-account.​profile.​announcement.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/profile-page-default#profile-announcement-)
* [customer-account.​profile.​block.​render](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/profile-page-default#profile-block-)
* [customer-account.​profile.​company-details.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/profile-page-b2b#profile-page-b2b-targets-)
* [customer-account.​profile.​company-location-addresses.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/profile-page-b2b#company-location-addresses-render-after-)
* [customer-account.​profile.​company-location-payment.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/profile-page-b2b#company-location-payment-render-after-)
* [customer-account.​profile.​company-location-staff.​render-after](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc/targets/profile-page-b2b#company-location-staff-render-after-)
* customer-account.​profile.​payment.​render-after

### Properties

The [`shopify` global object](https://shopify.dev/docs/api/customer-account-ui-extensions/2027-01-rc#target-apis-define-what-your-extension-does) provides localization and translation utilities for customer account extensions. Access the following properties on `shopify` to translate strings, format values, and read the buyer's language and country context.

* **i18n**

  **I18n**

  **required**

  Utilities for translating strings, formatting currencies, numbers, and dates according to the buyer's locale. Use this alongside `localization` to build fully localized extensions.

* **localization**

  **Localization**

  **required**

  The buyer's language, country, and locale context. Use this to adapt your extension to the buyer's region and display localized content.

### I18n

Utilities for translating strings, formatting currencies, numbers, and dates according to the buyer's locale. Use the I18n API alongside the Localization API to build fully localized extensions.

* formatCurrency

  Returns a localized currency value. This function behaves like the standard \`Intl.NumberFormat()\` with a style of \`currency\` applied. It uses the buyer's locale by default.

  ```ts
  (number: number | bigint, options?: { inExtensionLocale?: boolean; } & NumberFormatOptions) => string
  ```

* formatDate

  Returns a localized date value. Behaves like the standard \`Intl.DateTimeFormat()\` and uses the buyer's locale by default. Learn more about \[\`Intl.DateTimeFormat\`]\(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global\_Objects/Intl/DateTimeFormat) and its \[formatting options]\(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global\_Objects/Intl/DateTimeFormat#using\_options).

  ```ts
  (date: Date, options?: { inExtensionLocale?: boolean; } & DateTimeFormatOptions) => string
  ```

* formatNumber

  Returns a localized number. This function behaves like the standard \`Intl.NumberFormat()\` with a style of \`decimal\` applied. It uses the buyer's locale by default.

  ```ts
  (number: number | bigint, options?: { inExtensionLocale?: boolean; } & NumberFormatOptions) => string
  ```

* translate

  Returns translated content in the buyer's locale, as supported by the extension. - \`options.count\` is a special numeric value used in pluralization. - The other option keys and values are treated as replacements for interpolation. - If the replacements are all primitives, then \`translate()\` returns a single string. - If replacements contain UI components, then \`translate()\` returns an array of elements.

  ```ts
  I18nTranslate
  ```

### I18nTranslate

Translates a key from your extension's locale files into a localized string. Supports interpolation with placeholder replacements and pluralization via a \`count\` option.



### Localization

The buyer's language, country, and locale context in customer accounts. Properties on this interface are subscribable and update automatically when the buyer changes their country.

* country

  The buyer's country in customer accounts. Updates automatically if the buyer changes their country. The value is \`undefined\` if the country is unknown.

  ```ts
  SubscribableSignalLike<Country | undefined>
  ```

* extensionLanguage

  The buyer's language, as supported by the extension. If the buyer's actual language isn't supported, this falls back to the closest match or the extension's default locale (the one matching your \`.default.json\` file). For example, if the buyer's language is \`'fr-CA'\` but your extension only supports \`'fr'\`, then \`isoCode\` is \`'fr'\`. If your extension doesn't provide French translations at all, this returns the default locale.

  ```ts
  SubscribableSignalLike<Language>
  ```

* language

  The language the buyer sees in the customer account hub.

  ```ts
  SubscribableSignalLike<Language>
  ```

### SubscribableSignalLike

Represents a reactive signal interface that provides both immediate value access and subscription-based updates. Enables real-time synchronization with changing data through the observer pattern. This interface extends \`ReadonlySignalLike\` with deprecated fields that are still supported for backwards compatibility.

* current

  The current value of the signal. Equivalent to \`.value\`, accessing this property subscribes to changes when used in a reactive context.

  ```ts
  T
  ```

* destroy

  Cleans up the subscription and releases any resources held by this signal. After calling \`destroy()\`, the signal stops receiving updates from the main thread.

  ```ts
  () => Promise<void>
  ```

* subscribe

  Subscribes to value changes and calls the provided function whenever the value updates. Returns an unsubscribe function to clean up the subscription. Use to automatically react to changes in the signal's value.

  ```ts
  (fn: (value: T) => void) => () => void
  ```

* value

  The current value of the signal. This property provides immediate access to the current value without requiring subscription setup. Use for one-time value checks or initial setup.

  ```ts
  T
  ```

### Country

A buyer's country, identified by its ISO country code.

* isoCode

  The two-letter country code in \[ISO 3166-1 alpha-2]\(https://en.wikipedia.org/wiki/ISO\_3166-1\_alpha-2) format.

  ```ts
  CountryCode
  ```

### CountryCode

```ts
'AC' | 'AD' | 'AE' | 'AF' | 'AG' | 'AI' | 'AL' | 'AM' | 'AN' | 'AO' | 'AR' | 'AT' | 'AU' | 'AW' | 'AX' | 'AZ' | 'BA' | 'BB' | 'BD' | 'BE' | 'BF' | 'BG' | 'BH' | 'BI' | 'BJ' | 'BL' | 'BM' | 'BN' | 'BO' | 'BQ' | 'BR' | 'BS' | 'BT' | 'BV' | 'BW' | 'BY' | 'BZ' | 'CA' | 'CC' | 'CD' | 'CF' | 'CG' | 'CH' | 'CI' | 'CK' | 'CL' | 'CM' | 'CN' | 'CO' | 'CR' | 'CU' | 'CV' | 'CW' | 'CX' | 'CY' | 'CZ' | 'DE' | 'DJ' | 'DK' | 'DM' | 'DO' | 'DZ' | 'EC' | 'EE' | 'EG' | 'EH' | 'ER' | 'ES' | 'ET' | 'FI' | 'FJ' | 'FK' | 'FO' | 'FR' | 'GA' | 'GB' | 'GD' | 'GE' | 'GF' | 'GG' | 'GH' | 'GI' | 'GL' | 'GM' | 'GN' | 'GP' | 'GQ' | 'GR' | 'GS' | 'GT' | 'GW' | 'GY' | 'HK' | 'HM' | 'HN' | 'HR' | 'HT' | 'HU' | 'ID' | 'IE' | 'IL' | 'IM' | 'IN' | 'IO' | 'IQ' | 'IR' | 'IS' | 'IT' | 'JE' | 'JM' | 'JO' | 'JP' | 'KE' | 'KG' | 'KH' | 'KI' | 'KM' | 'KN' | 'KP' | 'KR' | 'KW' | 'KY' | 'KZ' | 'LA' | 'LB' | 'LC' | 'LI' | 'LK' | 'LR' | 'LS' | 'LT' | 'LU' | 'LV' | 'LY' | 'MA' | 'MC' | 'MD' | 'ME' | 'MF' | 'MG' | 'MK' | 'ML' | 'MM' | 'MN' | 'MO' | 'MQ' | 'MR' | 'MS' | 'MT' | 'MU' | 'MV' | 'MW' | 'MX' | 'MY' | 'MZ' | 'NA' | 'NC' | 'NE' | 'NF' | 'NG' | 'NI' | 'NL' | 'NO' | 'NP' | 'NR' | 'NU' | 'NZ' | 'OM' | 'PA' | 'PE' | 'PF' | 'PG' | 'PH' | 'PK' | 'PL' | 'PM' | 'PN' | 'PS' | 'PT' | 'PY' | 'QA' | 'RE' | 'RO' | 'RS' | 'RU' | 'RW' | 'SA' | 'SB' | 'SC' | 'SD' | 'SE' | 'SG' | 'SH' | 'SI' | 'SJ' | 'SK' | 'SL' | 'SM' | 'SN' | 'SO' | 'SR' | 'SS' | 'ST' | 'SV' | 'SX' | 'SY' | 'SZ' | 'TA' | 'TC' | 'TD' | 'TF' | 'TG' | 'TH' | 'TJ' | 'TK' | 'TL' | 'TM' | 'TN' | 'TO' | 'TR' | 'TT' | 'TV' | 'TW' | 'TZ' | 'UA' | 'UG' | 'UM' | 'US' | 'UY' | 'UZ' | 'VA' | 'VC' | 'VE' | 'VG' | 'VN' | 'VU' | 'WF' | 'WS' | 'XK' | 'YE' | 'YT' | 'ZA' | 'ZM' | 'ZW' | 'ZZ'
```

### Language

A language identifier following the \[BCP-47 standard]\(https://en.wikipedia.org/wiki/IETF\_language\_tag).

* isoCode

  The \[BCP-47]\(https://en.wikipedia.org/wiki/IETF\_language\_tag) language tag that identifies the language. This is a standardized code that may include a base language and an optional region subtag separated by a dash. For example, \`'en'\` represents English and \`'en-US'\` represents English as used in the United States. The region subtag follows the \[ISO 3166-1 alpha-2]\(https://en.wikipedia.org/wiki/ISO\_3166-1\_alpha-2) standard.

  ```ts
  string
  ```

### Examples

* #### Translate a static string

  ##### Description

  Render a translated string from a locale file using \`shopify.i18n.translate()\`. This example displays a welcome message that automatically adapts to the customer's language.

  ##### jsx

  ```tsx
  /* See the locales/en.default.json tab for the translation keys and values for this example */
  import '@shopify/ui-extensions/preact';
  import {render} from 'preact';

  export default async () => {
    render(<Extension />, document.body);
  };

  function Extension() {
    return (
      <s-text>
        {shopify.i18n.translate('welcomeMessage')}
      </s-text>
    );
  }
  ```

  ##### locales/en.default.json

  ```json
  {
    "welcomeMessage": "Welcome to our store!"
  }
  ```

* #### Display country-specific content

  ##### Description

  Read the customer's country to conditionally render region-specific messaging. This example checks whether the customer is in Canada and displays a shipping delay warning if so.

  ##### jsx

  ```tsx
  /* See the locales/en.default.json tab for the translation keys and values for this example */
  import '@shopify/ui-extensions/preact';
  import {render} from 'preact';

  export default async () => {
    render(<Extension />, document.body);
  };

  function Extension() {
    const countryCode =
      shopify.localization?.country?.value?.isoCode;

    if (countryCode === 'CA') {
      return (
        <s-banner status="warning">
          {shopify.i18n.translate(
            'canadaPostWarningMessage',
          )}
        </s-banner>
      );
    }
  }
  ```

  ##### locales/en.default.json

  ```json
  {
    "canadaPostWarningMessage": "Canada Post has issued a red delivery service alert for Ontario due to a severe snowstorm, suspending package delivery and collection for the week."
  }
  ```

* #### Translate a string with pluralization

  ##### Description

  Use the \`count\` option to render the correct plural form for the customer's locale. This example translates a loyalty points message that differs between singular and plural based on the point count.

  ##### jsx

  ```tsx
  /* See the locales/en.default.json tab for the translation keys and values for this example */
  import '@shopify/ui-extensions/preact';
  import {render} from 'preact';

  export default async () => {
    render(<Extension />, document.body);
  };

  function Extension() {
    const points = 10000;
    const formattedPoints =
      shopify.i18n.formatNumber(points);

    // Translate the loyalty points message, using pluralization to differentiate messages
    const loyaltyPointsMsg = shopify.i18n.translate(
      'loyaltyPoints',
      {
        count: points,
        formattedPoints,
      },
    );

    return <s-banner>{loyaltyPointsMsg}</s-banner>;
  }
  ```

  ##### locales/en.default.json

  ```json
  {
    "loyaltyPoints": {
      "one": "You have {{formattedPoints}} loyalty point",
      "other": "You have {{formattedPoints}} loyalty points"
    }
  }
  ```

***

## Best practices

* **Define a default locale file**: Always include a `locales/en.default.json` file as the fallback. This ensures your extension displays meaningful content even when a translation for the customer's language isn't available.
* **Use dynamic values instead of string concatenation**: Pass variables through the `translate()` options object (for example, `{{formattedPoints}}`) rather than concatenating translated fragments. This keeps translations flexible across languages with different word orders.
* **Format numbers with `shopify.i18n.formatNumber()`**: Don't manually format numbers with `toLocaleString()`. The built-in formatter respects the store's locale configuration and produces consistent results.
* **Guard against missing localization data**: Check that `shopify.localization.country` and other localization properties are defined before using them. These values load asynchronously and may be `undefined` on the initial render.

***

## Limitations

* The `translate()` method only supports the pluralization categories defined by the Unicode CLDR for the active locale (for example, `one`, `other`, `few`, `many`). Custom plural categories aren't supported.
* Country and language values reflect the customer's current session context. They can't be overridden programmatically by the extension.

***
