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."

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
    TagsSelect existing tags or create new tags to help organize locales for bulk operations. Tags can be used to add secondary grouping of locales by region, language, internal ownership or other criteria.
    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.
add-locale-modal
Modal dialog to create a new locale

Often a specific market or region has multiple locales that belong together. For example, Canada has en-CA and fr-CA. You can create locale groups to bundle multiple locales to represent a market, country, region or even internal team structures that are responsible for a set of locales. This is useful for:

  • Better overview of locales as groups make it easier to scan and find market specific locales or search for them
  • Support for bulk operations based on locale groups

To group locales:

  1. In the Canvas Settings under Locales, click Add locale group from the contextual menu on the Add locale button.
    add-locale-group
    Add a new locale group from the Uniform Canvas Settings page.
  2. Give the group a name in the Add Group dialog.
  3. A new group is added to the list of locales. Use the menu or drag and drop to move the new locale group to the desired position in the list.
  4. You can now drag and drop locales or use the menu to move locales into the group and set their order.
  5. Click Save locales to save the changes.

Locale groups will be displayed in all locale selectors in the Uniform UI, making it easier to find and select the right locale. If you have more than 5 locales then you can also search for locales by typing in the search box of the locale selector.

locale-selector-grouped
Locale selector with groups and search box

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. Select the default localization behavior:
    • Localized: One value can be set per locale
    • Not localized: Singe value is used across all locales
Setting a parameter or field to be localizable
Setting a parameter or field to be localizable
  1. Save the component definition.
  2. 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 behavior will continue to occur until one edits the composition containing the parameter value. The editor will then convert the localized value into a non-localized 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": "Das ist ein übersetzter Parameter mit einem Wert für „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" } } }

Manage locales for a composition or entry#

For each composition or entry you can decide if it should be available in a specific locale by enabling it. This is done in the composition or entry editor via the Manage locales side rail panel.

All localizable parameters of a composition and its child components or all fields of an entry will have a locale-specific value for each enabled locale. The structure of a composition, meaning the components that are placed in slots, is shared across all enabled locales. If you want to have different structures for different locales, you can use Component visibility controls to manage which components are visible for each locale.

manage-locales
Enable locales for a composition or entry

info

Blocks can't be localized. Fields within a block can be localized.

Enable locales for a composition or entry#

To enable locales for a composition or entry:

  1. Open a composition or entry in the Canvas editor.
  2. Click Manage locales in the left side rail of the editor or via the same menu option the locale selector.
manage-locales-selector
Access the 'Manage locales' panel from the locale selector
  1. Click the Enable locales button to open the "Enable locales" dialog.
  2. In the dropdown select one or more locales you want to enable for the composition or entry. You can also search for locales by typing in the dropdown or click on locale groups or tags for bulk selection. Note that only locales are shown that are not already enabled.
enable-locales
Enable locales for a composition or entry
  1. Select the Copy content and visibility checkbox and select a source locale if you want to copy the content and visibility settings from another locale. This is useful when you want to start translating from another locale or don't want to start from scratch for each locale.
  2. Review the copy actions and click Ok to enable the locales.
  3. The newly enabled locales are now listed in the Manage locales panel and in the locales selector in the Canvas editor. By clicking on a locale you can activate it for editing.

Delete locales from a composition or entry#

You can delete locales from a composition or entry by clicking Delete option in the menu next to the local in the Manage locales panel of the Canvas editor.

note

Deleting a locale on a published composition or entry will only affect the draft version. To unpublish the locale you need to re-publish the composition or entry.

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.

localizable-parameter
A localizable property is indicated with a globe icon

Clicking on the globe icon will open the "Locale values" drawer where you see the all enabled locale-specific values for the property. You can also access the drawer by selecting the "Manage locale values..." option from the menu of the parameter or field in the property panel.

From the drawer you can:

  • See and edit any enabled locale-specific value for the property
  • Copy values between locales
  • Enable or disable locale-specific values for the current parameter or field. This can be useful if you want to avoid managing multiple values across locales such as when you use a dynamic token or have no localization or translation needs for that property. In reverse, you can opt in to having locale-specific values for a property that has locale-specific values disabled by default.
  • Access the conditional values settings for a specific locale
Manage locale-specific values for a parameter or field
Manage locale-specific values for a parameter or field

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

Often it is useful to copy content between locales to save time or to reuse translations (for example you could have multiple locales that are the same language but different regions).

Copying content between locales can be done in different levels of granularity:

  • whole composition or entry
  • single component of composition
  • single parameter or field

Copy values between locales of a composition or entry#

  1. Open a composition or entry in the Canvas editor.
  2. Click Manage locales in the left side rail of the editor or click the menu of the composition in the structure or property panel.
  3. Select the Copy values to locales option.
  4. In the dialog select the "Target locales" you want to copy the content to. You can also search for locales by typing in the dropdown or click on locale groups or tags for bulk selection. Only enabled locales are shown as possible targets.
  5. Check the Include all descendant components checkbox if you want to copy the localized parameters of all child components.
  6. Review the copy actions and click Ok to copy the content to the selected locales.
copy-values-to-locales
Copy content between locales of a composition or entry

note

This action will override all localized values in the target locales with the values of the source locale. If you only want to copy a single component or parameter or field, should use the appropriate copy action on that level.

Follow the same steps as for copying from a composition or entry, but initiate the copy action from the component using the menu of the component in the structure or property panel or in the component highlighter.

component-copy-values-to-locales
Copy content between locales for a component

Follow the same steps as for copying from a composition or entry, but initiate the copy action from the localized parameter or field using the menu in the property panel or in the component highlighter.

parameter-copy-values-to-locales
Copy content between locales for a parameter or field

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.

Structural localization can be achieved through various methods, depending on the extent of structural differences required and the level of independence desired for each locale:

Component visibility control

Target one or more locales to show or hide components.

Editions

For fully independent content structures and content workflows for a set of locales.

Localization component - Legacy feature

For simple structural changes targeting a single locale per component

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

Source code for a simple localization example using Next.js is available. We offer versions for page router and app router.