Skip to main content

Localization

Localization is intended to be used in the situation where there are specific components or data items you would like to show a particular locale. You are free to define locales with any name and they do not have to align with language codes.

As an example, a project could have EMEA and Americas configured as locales. It would then be possible to associate one component with EMEA and another with Americas using the localization component inside of a slot. When the page is rendered, only the component that matches the locale would be shown.

Setting up locales

Before you can make use of localization, you must define some locales:

  • Navigate to the Settings tab
  • Using the sidebar, navigate to Canvas Settings
  • Use the Add Locale form to define locales you would like to target.

Enabling localization on components

Like personalization and test components, you can control where it's allowed to be used. To do this, you must enable the Localization component in slots where you would like to allow localization.

  • Navigate to the Canvas tab
  • Using the sidebar, navigate to the Component Library
  • Open the component where you would like to utilize localization
  • In the Slots tab, find the slot where you want to put localized contents
  • Enable the Localization component by clicking it.
  • Click Save and Close

Repeat this process for any additional components you would like to use localization with.

Localizing content

  • Navigate to the Canvas tab
  • Open a Composition that has had localization enabled on it's definition
  • Click the plus sign to insert a component on the slot where localization is enabled on
  • Insert the Localization component.
  • Drag or insert components into the slot provided by this component.
  • Click a component inside of the Localization component and use the Locale parameter dropdown to associate a locale with this component.
  • Save (and publish, if desired) your changes.

Evaluating localization in code

The localization component contains data for every single locale that could appear in this spot but you only want to render the locale which is currently in context, to do this, you need to do the following:

All of the changes described below will involve changing the files you are currently using the retrieve and enhance compositions already.

First, start by importing the localize function. Note: If you're already importing the enhance function, this can just be added to the same import.

import { localize } from '@uniformdev/canvas';

Then find the call to getCompositionBySlug and add a call to localize after it but before the enhance function call. localize will mutate the composition and remove the wrapper $localization component and replace it with only the variant that matches the specified locale.

localize({
composition,
locale: 'EN'
});

In the example above, it is using a hardcoded locale. In reality, this should be sourced from wherever you are indicating what the current locale is active, which is most commonly part of the URL.

After these components are removed, enhance will run and only process the remaining locale component, not even knowing anything about the other possible locales.

Localization with fallback

Besides the mode of localize which just accepts a string value for locale, which is great if an entire page has been wrapped in a localization component but if you are mixing and matching, you need to be able to fallback when needed.

localize can also be a function that allows you to program the fallback logic to fit your needs. For example:

localize({
composition,
locale: ({ locales }) => {
// check if this component has a danish locale
if (locales['Denmark']) {
return 'Denmark';
}

// otherwise fallback to english
return 'Global';
}
});

Localization format

If you look at the JSON of a composition before enhancement, you'll see a $localization system component that looks like the following:

{
"type": "$localization",
"slots": {
"localized": [
{
"type": "hero",
"parameters": {
"text": {
"type": "text",
"value": "Spanish Title Here"
},
"locale": {
"type": "localeSelect",
"value": "ES"
}
}
},
{
"type": "hero",
"parameters": {
"text": {
"type": "text",
"value": "English Title Here"
},
"locale": {
"type": "localeSelect",
"value": "EN"
}
}
}
]
},
"parameters": {}
}

The goal of this component is to disappear and leave you with the variant that matches whatever locale is determined for this component. So after running this component through the localize function, assuming your locale was ES, it would leave behind:

{
"type": "hero",
"parameters": {
"text": {
"type": "text",
"value": "Spanish Title Here"
},
"locale": {
"type": "localeSelect",
"value": "ES"
}
}
}

Localization with Next.js

Let's do a non-theoretical example of setting up localization to work with Next.js localization. Let's start by following the Sub-path Routing section on the Next.js documentation. This will have you modify your next.config.js and add in some defined locales.

After these locales are in place, we can use the locale field that getStaticProps gives us and just pass this directly into the localize function.

export async function getStaticProps(context: GetStaticPropsContext) {
const slug = context?.params?.slug ?? '';

const slugString = Array.isArray(slug) ? slug.join('/') : slug;

const { preview, locale } = context;

// fetch the layout from the Canvas enhancer proxy
const { composition } = await canvasClient.getCompositionBySlug({
slug: `/${slugString}`,
state: preview ? CANVAS_DRAFT_STATE : CANVAS_PUBLISHED_STATE,
});

localize({
composition,
locale: locale || 'EN'
});

await enhance({ composition, enhancers, context });

return {
props: {
composition
},
};
}

This example passes locale in with a fallback to EN if it happens to not be defined in the context. Handle this situation to fit your needs.

Localization inside enhancers

As mentioned before, this functionality is geared towards showing specific components for locales which you define. If you are linking entries with integration parameters, these will not be resolved per the locale you specify. It is currently expected that you will have discrete entries for each locale.

Nothing is preventing from augmenting enhancer logic to make this possible. For example, with Contentful you can define locales and have fields per locale on the same entry.

This is an example of how to accomplish this.

import { CANVAS_LOCALE_TAG_PARAM } from '@uniformdev/canvas';

/* ... */

createContentfulEnhancer({
client: new ContentfulClientList({ client, previewClient }),
useBatching: true,
createQuery: ({ defaultQuery, context, component }) => {
const locale = component?.parameters?.[CANVAS_LOCALE_TAG_PARAM].value as string | undefined;

const queryOptions = {
...defaultQuery,
select: 'fields',
include: 2
};

if (locale) {
queryOptions.locale = locale;
}

return queryOptions;
},
});

This example would pull the locale off of the component parameter and request this version from Contentful.