Localization

Enterprise organizations operating in multiple regions or countries often must adapt to local cultures and preferences, while also maintaining a unified brand and user experience.

Internationalization and localization are critical for enterprises to reach a global audience, letting them to adjust their digital offering to meet local preferences and cultural norms. However, this process can be complex and time-consuming, requiring significant effort and resources to implement effectively. Systems must:

  • Handle content for multiple languages and cultures
  • Adjust content to regional market needs
  • Translate content from one language to another.

The approach to content governance and operations can also affect how this content must be managed. Centralized teams may need to manage content across multiple regions to ensure consistency in branding and messaging. Distributed teams may need to manage content within a specific region, tailoring it to the local market. The operational model may also differ with how much autonomy a team has to create and maintain their own content and technology.

Uniform enables building internationalized projects, supporting both localization (serving different content to a locale, such as a regional promotion) and translation (serving the same content but in a different language). This is great for:

  • Regional teams who have autonomy to create experiences but want to gain efficiency through a shared design system and shared content.
  • A single, multi-lingual team working on the same experience but for different markets, or who needs to translate content into multiple languages.
  • Any team looking to customize content or structures to account for regional differences.

Locales, as defined by system architects, are at the center of Uniform internationalization. A locale is an object containing a display name (like "English US"), a locale code (such as en-us), and a Boolean for if it's the default project locale. It can be any string value up to 32 characters. Uniform recommends using standard ISO language and region codes, such as en-GB, de-AT, or es-ES, because this enables easy interoperability with other systems and browser locale preferences.

Parameters and fields can be configured so the value can be translated to different languages as configured by locales. A check box can be added to indicate the parameter or field is "Localizable."

info

Blocks can't be localized. Content within a block can, however, be localized.

System architects can control which objects can be localized as they're defined in Mesh integrations. They can set localization to be:

  • On by default
  • Off by default
  • Forced on
  • Forced off

See example code for how to configure localization for projects.

To create a locale in Uniform:

  1. Open your project.

  2. Navigate to the Settings > Canvas Settings.

  3. Click New Locale.

    add-locale
    Add a new local from the Uniform Canvas Settings page.
  4. Enter the following data:

    FieldDescriptionIs required?
    Display NameThis is used to help editors choose between locales.Required
    Locale CodeThis is the code that will be stored with content and used for API requests. Uniform recommends ISO 638-1 codes. This can't be changed after creation.Required
    DefaultChoose if the locale is default. The default locale is automatically enabled for compositions once a locale is defined and is the default loaded when editing. API calls don't default to use this locale, they default to fetching all locales.

One common internationalization use case is to translate content data (parameters or fields) into different locales. Once you have defined locales in Uniform, you can configure components or content types to contain translated content.

To configure a property for localization:

  1. Edit a component in the Component library.
  2. Add or edit a parameter on the component.
  3. Check off the "Localizable" option.
  4. Save the component definition.
  5. The parameter can now have a locale-specific value.

info

Certain parameter types, such a blocks, may not support localized values, in which case the localizable checkbox won't appear.

info

It's possible to change a parameter from localizable to not-localizable and back after there are instances of the parameter with content in them.

When changing to localizable, all locales will receive any previous parameter value.

When changing from localizable, the existing locale-specific behaviour will continue to occur until one edits the composition containing the parameter value. The editor will then convert the localized value into a non-locale-specific value automatically.

When accessing localized parameters and all locales' data are present, this is how it's stored. This has a TypeScript type (import type { ComponentParameter } from '@uniformdev/canvas').

{ "parameters": { "notLocalized": { "type": "text", "value": "This is a regular parameter value which does not support localization, or has been run through a localize() function" }, "localized": { "type": "text", "locales": { "en-US": "This is a localized parameter with a value in the `en-US` locale", "de-DE": "Dies ist ein lokalisierter Parameter mit einem Wert im Gebietsschema „de-DE“", } } } }

If the above example was run through a localize routine to en-US (either by passing locale=en-US to the composition API, or using the localize() function - see the guide), it would end up like so:

{ "parameters": { "notLocalized": { "type": "text", "value": "This is a regular parameter value which does not support localization, or has been run through a localize() function" }, "localized": { "type": "text", // note that the de-DE value was tossed, and the en-US value is now in the `value` after localization "value": "This is a localized parameter with a value in the `en-US` locale" } } }

When editing a composition and locales are defined for your project, you will see a locale selector in the upper right corner. When you edit a localizable parameter, the value being edited is always the selected locale's value. Changing the current locale will change the preview and parameters panes to show that locale's values instead. You can tell if you are editing a localizable parameter because a localizable parameter has a globe icon on it which shows the current locale code when you hover your mouse over it.

localized-parameter
A localized parameter is indicated with a globe icon

Non-localizable parameters can always be edited no matter what locale is selected, and they don't display the globe icon.

Compositions are required to enable locales before the use them, because sometimes content isn't available for all locales. For example the project might define en, de, and ko as locales, but a specific composition might only have data in en and ko (either because the data isn't relevant to de, or it might be out for translation). New compositions automatically enable the default locale, if there is a default locale. Additional locales can be enabled by clicking edit in the locale selector or

In Uniform all composition structure data is shared across every locale by default. This makes maintaining consistency of appearance easy, but sometimes it's necessary to alter the structure of the content for each locale in addition to translating values. For example a promotion might only be active in Romania, so we don't want to show it to German visitors. To accomplish this, Uniform provides the Localization component. The Localization component can be placed into a slot and contain child components that can be tagged to appear only in a specific locale.

A localization component is like any other component, so if you have slots that have specifically allowed components in them, you must enable the Localization component to be used in the slot you want to localize.

tip

If you are using a slot that allows any component, you can skip this and go straight to "Localize components"

  1. In Uniform, edit a component with the slot to which you want to add localized components.
  2. Navigate to the slot.
  3. In the section Allowed Components, select the component Localization.
component-selected
The hero component can be localized in the slot.

About this step

You must have other components selected on the slot. Those will be the component types that can be localized in this slot.

  1. Click OK.
  2. Save the component.
  1. In Uniform, insert a component into a slot you have enabled localization for, or you can use an existing component.

  2. Click the component.

  3. Click the Localize This button.

    About this step

    A new component Localization is added to the slot, and the component is moved into that component. In this way localization works the same as personalization and testing.

  4. Select the original component.

  5. A new parameter Locale is available on the component. This parameter is a dropdown of the locales you defined in your project. Select the locale for the component.

    locale-assigned
    The localized component within the structure panel of Canvas.

    About this step

    The locale assigned to the component will appear in the box that represents the component in the composition.

  6. Save the composition.

  7. Add more components under the component Localization and assign a locale to each component you add. Each component will represent the locale you assigned.

    localized-components
    Localized components within the localization structure.

The following is an example of the JSON object that represents a slot with components localized for two locales (such as en-US and da-DK):

{ "parameters": {}, "type": "$localization", "slots": { "localized": [ { "type": "event", "parameters": { "name": { "type": "text", "value": "Sankt Hans Aften" }, "locale": { "type": "localeSelect", "value": "da-DK" } } }, { "type": "event", "parameters": { "name": { "type": "text", "value": "Summer Solstice" }, "locale": { "type": "localeSelect", "value": "en-US" } } } ] } }

Uniform supports three different strategies for resolving locale values, in increasing order by complexity and capability:

  • Use a path segment from the project map as a locale value.
  • Pass a locale to the Uniform API.
  • Fetch all locales from the Uniform API and apply the localization yourself in your frontend application.

Regardless of the approach selected, the end result is the same: A locale will resolve to show the content for the current active locale and remove other locale data. This allows the frontend to act as if no localization took place and enables direct access to the localized values. If Uniform can't resolve the requested locale then it will return "not found".

Often, a front-end application will want to use an internationalization library such as next-intl for Next.js to manage the user's selected locale, or negotiate the initial locale with a browser's Accept-Language headers, among other tasks. Uniform's SDK is designed to complement any of these existing localization and static-translation management strategies. Uniform doesn't provide any frontend-side state management for localization of its own.

In this model a special node is added to the project map that dynamically represents the locale. This is appropriate when your project is using URLs and the locale code should be part of the URL such as /en-GB/about-us. This has some significant advantages, as the source of the locale will be plain for authors and the frontend application will work automatically. When using the project map as a locale source, link parameters will be able to pass the current locale as a dynamic input, allowing simple maintenance of links without needing to define the target in every locale.

The locale node is added directly under the home node of the project map so that its route path becomes /<locale>. However this isn't required and you may define locale nodes at any level in the project map. To add a locale node, add a project map node and choose "Locale" as the node type.

add-locale-node
Adding a Locale node to a project map

If you have existing project map nodes, you may need to move them under your locale node after doing this, noting that it could change your URL structure, and might require some redirects.

locale-node
Using a Locale node as the first path segment of a project map

You can pass a locale parameter to all Uniform APIs that return routes, compositions, or entries. This parameter is also reflected in Uniform-provided API client classes and framework specific SDKs (if the option is missing, you may need to upgrade your SDK packages).

The locale parameter is allowed to be one of:

  • A single locale code, such as en
  • A comma-separated list of locale codes, such as en, en-US, de-DE to enable language fallback
  • A list of locale codes in the format of the HTTP Accept-Language header, such as en;q=0.8,en-US;q=0.9

When the locale parameter is passed:

  • List responses will include only compositions which have either:

    • Enabled one or more of the locale(s) provided by the locale parameter
    • Not enabled any locales (this is to make it easier to migrate to locales).

    Note that once a default locale has been added to a project, any composition that's edited will be set to enabled for the default locale and no longer match this criteria.

  • All responses will "localize" the composition data, to:

    • Determine the target locale: This is the first locale in the locale parameter which has been enabled for the composition. For example, if the locale parameter is en,de and the composition has enabled ['zh', 'de'], then de will be selected.
    • All locale data which isn't for the target locale is removed from the composition: This includes both localization components (replaced by their selected locale component, if any) and locale-specific parameter data (the target locale value is copied into the value property as if it weren't localized).

tip

You can still pass an explicit locale if you are using a project-map based locale resolution. The explicit locale will override the value resolved from the project map. This can be useful to configure locale fallback chains, because you can explicitly pass more than one locale.

If the locale parameter isn't passed when fetching composition data, Uniform returns all the locales' data at the same time. This is a good option when you need to perform advanced, locale-selection logic of your own, or if you intend to cache composition data and don't want to vary the cache by locale.

When all locales are in a composition, Uniform provides a function that can be used to apply the same localization logic that the APIs use on demand:

import { localize, type RootComponentInstance } from '@uniformdev/canvas' // todo: determine your visitor's current locale from however you manage that state // for simplicity we will hardcode one here, but one should use a library for this const currentLocale = 'uk-UA' const myCompositionApiResult: RootComponentInstance = { // the composition data fetched or cached from the Uniform API that has all locales in it // (required properties omitted for brevity) } // NOTE: localize() will mutate the `myCompositionApiResult` object. // If you prefer immutability, it can be wrapped in an immer `produce` function. localize({ nodes: myCompositionApiResult, locale: currentLocale }) // myCompositionApiResult is now localized for `uk-UA` locale

About this step

Just like enhancers, localization changes the data available in the composition. It removes all the components that don't match the locale specified in the localize() function call.

About this step

This section describes how to build a localized Next.js application using the Pages Router.

Localized routing using the App Router is specific to the implementation and will require some custom development.

To enable localized routing in Next.js we recommend to follow the sub-path routing strategy:

Step 1: Configure locales in next.config.js to activate localization mode in Next.js. These should match the locales codes that are defined in your Uniform project.

next.config.js

const nextConfig = { // other Next.js config ... // declare locales i18n: { locales: ['en-US', 'de-DE'], defaultLocale: 'en-US', } }; module.exports = nextConfig;

Step 2: Update the dynamic route file (e.g. /pages/[[...slug]].tsx) to pass the active locale to Uniform's Route API.

If you use the project map to resolve locales and your routes start with the locale identifier (e.g. /en-US/) then you can pass the prependLocale helper function from the @uniformdev/canvas-next NPM package to the modifyPath function.

/pages/[[...slug]].tsx

import PageComposition from "@/components/PageComposition"; import { prependLocale, withUniformGetServerSideProps, } from "@uniformdev/canvas-next/route"; export const getServerSideProps = withUniformGetServerSideProps({ // prepend the active locale to the current path for fetching the composition // by default Next.js does not include the locale in the path modifyPath: prependLocale, }); export default PageComposition;

tip

The source code for a simple localization example using Next.js Pages Router be found in our Examples Github repository