Skip to main content

Multilingual Themes

The Multilingual feature in the Fynd Commerce platform enables sellers to offer their storefronts in multiple languages, enhancing accessibility for customers across diverse regions. Customers can easily switch languages through a click on the storefront and updating all text content to the selected language. This feature is implemented by enabling partners to configure translation keys within the theme code, ensuring that the storefront static content is rendered based on the customer’s language preference.

Multilingua Example

Theme Directory Structure

theme
├── locales
│ │
│ ├── en.json
│ ├── en.schema.json
│ ├── hi.json
│ ├── hi.schema.json
│ ...

├── config
│ │
│ ├── settings_data.json
│ └── settings_schema.json
...

Locales Directory

The locales (locales) directory contains the files for a theme, which are used to provide translated content. Locale files enable developers to translate storefront content and theme editor settings into multiple languages for sellers and customers, utilizing a set of translated text strings available in various languages, including English, Spanish, and Italian. You can leverage locale files to translate any content displayed in your storefront.

There are two types of locale files:

Sr. No.TypeDescription
1.Storefront FilesJSON files that contain a set of translations for text strings used throughout the storefront. They host translation strings for content displayed on the storefront throughout the theme (e.g., en.json file).
2.Schema FileJSON files that contain a set of translations for text strings used throughout the theme editor (en.schema.json file).

Nomenclature of Locale Files

A locale file name is composed of a base language. It must follow the IETF language tag nomenclature standards, which designate the first lowercase letter to represent the language code (such as 'en' for English and 'hi' for Hindi).

LanguageStorefrontSchema
Englishen.jsonen.schema.json
Hindihi.jsonhi.schema.json
Arabicar.jsonar.schema.json

Translation of storefront content is achieved through the en.json file and translation of theme editor content is achieved through the en.schema.json file. Instead of hardcoding text, partners map user-facing messages, ensuring that storefronts automatically render text based on the customer’s selected language.

Translation Key Structure in Locale Files

The translation keys in Locale files need to follow a structured naming convention to maintain consistency across multiple languages, as follows:

{
"resource": { //Category: The top-level namespace that categorizes the type of content
"auth": { //Group: A sub-division under the category that narrows down the context
"account_locked_message": "Your Account is locked" //Description: The actual key representing the specific message to be translated
}
}
}

Define Translation Keys

Each locale file (such as English or Hindi) has its own JSON file inside the Locales directory, mapping keys to their corresponding translations. Each message displayed on the storefront is associated with a translation key.
For example:

  • In locale/en.json file:

    "please_login_first": "Please Login first."
  • In locale/hi.json file:

    "please_login_first": "कृपया पहले लॉग इन करें।"

In the above examples, "please_login_first" is mapped to two languages: English and Hindi.

Config Directory

The Config directory defines the theme settings area of the theme editor.

There are two types of Config files:

Sr. No.TypeDescription
1.settings_data.jsonContains the saved values from the settings in settings_schema.json file.
2.settings_schema.jsonControls the organization and content of the theme settings area of the theme editor.

Example

In the below given example code, Schema translations are accessed with code in the following format:

  • To use the typography attribute, settings_schema.common.typography is used in en.schema.json and hi.schema.json files.
  • To use the font_header attribute, settings_schema.typography.font_header is used in en.schema.json and hi.schema.json files.
  • A t-filter (t:) translates text based on the customer’s selected language. The filter takes a translation key defined in the theme code and converts it into the appropriate localized text.
  "props": [
{
"type": "font",
"id": "font_header",
"category": "t:resource.settings_schema.common.typography",
"default": false,
"label": "t:resource.settings_schema.typography.font_header"
},
]
  • In en.schema.json file:

    "settings_schema": {
    "common": {
    "typography": "Typography",
    },
    }
    "typography": {
    "font_header": "Font Header",
    },
  • In hi.schema.json

    "settings_schema": {
    "common": {
    "typography": "टाइपोग्राफी",
    },
    }
    "typography": {
    "font_header": "फ़ॉन्ट हेडर",
    },

Steps to Translate Static Label

In the example code shown below, multilingual support is implemented in the storefront theme using translation keys defined in the schema files.

When a customer is not logged in and attempts to add a product to their wishlist, a message prompts them to log in. Instead of hardcoding this message, the code uses the t() function to fetch the corresponding translation from the schema file based on the customer’s selected language.

The key resource.auth.login.please_login_first is mapped to different values in locale files such as en.json or hi.json file, ensuring that the message shown in the storefront appears in the appropriate language.

For example, in useProductDescription.jsx:

function addToWishList(event) {
if (event) event.stopPropagation();
if (!LoggedIn) {
showSnackbar(t("resource.auth.login.please_login_first"));
navigate("/auth/login");
return;
}
// wishlist addition logic
}
  • If the customer has selected Hindi, the storefront displays “कृपया पहले लॉग इन करें।”
  • If the customer has selected English, the storefront displays “Please Login first.”
  • Switching languages from the storefront’s dropdown immediately triggers translations

Steps to Translate Dynamic Label

This section explains how to handle translations for dynamic labels that are generated at runtime, such as notifications, alerts, or responses from backend APIs. These Dynamic labels need to be translated based on the customer's selected language.The guideline below demonstrates how to structure your locale files and use the translateDynamicLabel utility function to provide multilingual support for dynamic content in your theme.

In the below given example, the dynamic message appears after adding a product to the cart: English
Hindi

Follow the steps below to implement multilingual support for dynamic content in your theme:

1. Add Dynamic Label Keys to Locale Files

For each dynamic message, add a corresponding key under the dynamic_label object in your [locale].json file. This ensures all dynamic messages are centrally managed and easily translatable.

{
"resource": {
"dynamic_label": {
"product_has_been_added_to_cart": "Product has been added to cart"
}
}
}
caution

Ensure that the dynamic label key matches the exact message string. For instance, for the message "Product has been added to cart", the dynamic label key should be product_has_been_added_to_cart.

2. Import and use the following Utility Function

export function translateDynamicLabel(input, t) {
const safeInput = input
.toLowerCase()
.replace(/\//g, "_") // replace slashes with underscores
.replace(/[^a-z0-9_\s]/g, "") // remove special characters except underscores and spaces
.trim()
.replace(/\s+/g, "_"); // replace spaces with underscores

const translationKey = `resource.dynamic_label.${safeInput}`;
const translated = t(translationKey);

return translated.split(".").pop() === safeInput ? input : translated;
}

This function sanitizes the input string, such as empty or non-string inputs, and provides fallback options for missing translations.

3. Handling Backend-Generated Messages

When your backend sends a dynamic message, such as a notification or alert, you can display it in the user's selected language using the translateDynamicLabel utility. For example, suppose your backend responds with the following message after a product is added to the cart:

If backend responds with: res.data.cartMsg = "Product has been added to cart"

<div>{translateDynamicLabel(res.data.cartMsg, t)}</div>

This auto-generates the key resource.dynamic_label.product_has_been_added_to_cart and returns the translated label (if present).

How It Works

The translateDynamicLabel utility:

  1. Sanitizes the input string:
    1. Converts to lowercase.
    2. Removes special characters (except underscores).
    3. Replaces spaces and slashes with underscores.
      Example: "Product has been added to cart" will be changed to product_has_been_added_to_cart.
  2. Constructs a translation key in the format: resource.dynamic_label.product_has_been_added_to_cart.
  3. Looks up the key using the t() translation function.
  4. If a translation is not found, it returns the original input.

Preview Multilingual Theme

Once you have set up your locales and config directory, you can upload your theme with multilingual support. See Sync Theme Changes for step-by-step instructions.

caution

If you make any changes to the files in the locales directory, ensure you sync your theme. Otherwise, the changes will not appear locally.

Best Practices

To ensure an effective multilingual experience, follow the best practices mentioned below:

  1. Use useGlobalTranslation from fdk-core/utils for consistent static content translation.

    import { useGlobalTranslation } from "fdk-core/utils";
    const { t } = useGlobalTranslation("translation");
  2. Always replace static text with translation keys using the t method.

    <div>Something went wrong</div> // Avoid hardcoded text
    <div>{t("resource.common.error_message")}</div> // Use translation key
  3. Format currencies using currencyFormat with dynamic locale values.

    currencyFormat(
    product?.sizes?.price?.effective?.min,
    product?.sizes?.price?.effective?.currency_symbol,
    formatLocale(locale, countryCode, true)
    );
  4. Use useNavigate from fdk-core/utils instead of react-router-dom for navigation. This ensures standardized routing behavior across locale.

  5. Ensure date/time formatting uses the selected locale with toLocaleString.

    toLocaleString(formatLocale(locale, countryCode), options);
  6. Use only the action prop in FDKLink for navigation. For example, FDKLink internally handle URL conversion.

    <FDKLink action={action} />
  7. Handle redirections with correct locale context in manual redirects.

    const finalUrl = `${window.location.origin}${locale && locale !== "en" ? `/${locale}` : ""}/cart/order-status/?${params.toString()}`;
    window.location.href = finalUrl;
  8. Use locale information when converting UTC dates to local dates.

    convertUTCDateToLocalDate(
    dateString,
    options,
    formatLocale(locale, countryCode)
    );

Best Practices for Building Right-to-Left Compatible Themes

  1. Always test for both LTR and RTL directions when adding styles.

    • To simulate RTL mode, set the dir attribute to rtl on the <html> tag during testing.
  2. Use direction-aware CSS properties instead of physical direction properties:

    • Padding: padding-inline-start, padding-inline-end
    • Margin: margin-inline-start, margin-inline-end
    • Position: inset-inline-start, inset-inline-end
    • Border: border-inline-start, border-inline-end, border-start-start-radius, border-start-end-radius, border-end-start-radius, border-end-end-radius
  3. Use logical (direction-friendly) CSS values:

    • Text alignment: text-align: start, text-align: end
    • Float: float: inline-start, float: inline-end
  4. Handle transforms carefully: When using transform properties like rotate or translateX, apply direction-specific variants if needed for RTL layouts.

  5. Style pseudo-elements (::before and ::after) appropriately for both LTR and RTL modes to avoid visual inconsistencies.

Common Mistakes

When implementing multilingual support, avoid the following common mistakes:

  1. Do not use both to and action props in FDKLink. to will be prioritized if both are provided, causing unexpected behavior.

  2. Do not manually convert actions using convertActionToUrl.

    // Avoid manual conversion
    action={convertActionToUrl(action)}
    to={convertActionToUrl(action)}

    // Correct usage
    action={action}
  3. Do not use object-style paths directly with navigate. Always manage locale-aware navigation through helper methods or hooks.

  4. Do not hardcode locale or omit locale in redirects. Always append the correct locale dynamically when constructing URLs.

Common Mistakes while Building Right-to-Left Compatible Themes

  1. Do not use left or right CSS properties directly:

    • Avoid properties like margin-left, padding-right, or left: 10px.
    • Use logical properties (start, end) instead to maintain RTL compatibility.
  2. Do not hardcode directional icons: Avoid static icons like . Instead, rotate icons dynamically using transform: rotateY(180deg) when in RTL.

  3. Do not rely on text-align: left or text-align: right: Use text-align: start or text-align: end to enable automatic direction switching.

  4. Do not skip RTL testing: Many RTL-specific bugs only surface during proper dir="rtl" testing on <html> or <body>.

  5. Do not blindly use directional utility classes like .ml-4 or .pl-2: In utility-first frameworks (e.g., TailwindCSS), prefer logical utilities like .ps-4 (padding-start) or .pe-2 (padding-end).

  6. Do not apply transforms assuming a fixed direction: Adjust transforms like translateX(100%) or rotate(15deg) according to the active direction context.

  7. Do not use static images, backgrounds, or SVGs with baked-in directionality: Prefer CSS-based or dynamically mirrored SVG assets (scaleX(-1)) to adapt to direction changes.

  8. Do not ignore text alignment inside form inputs: Input text should align based on the language’s direction using text-align: start.

  9. Do not use physical-direction shorthand properties: Avoid shorthand like padding: 10px 20px 30px 40px; which assumes a fixed top-right-bottom-left sequence and does not adapt in RTL.


Was this section helpful?