Skip to main content

i18n

Internationalization is a key feature in Assemble, where we handle two main concepts:

  • Dictionary translations for each possible language.
  • App Directionality (ltr and rtl).

The i18n is in charge of this feature, but we also have some extra info and utilities that are worth mentioning.

Architecture

Besides the Control setup for the dictionary as explained in the i18n Service documentation Assemble handle the i18n in the following order:

  1. Initialize the i18n/localization based on the segment and selected language at application startup
  2. Store the status (while loading and once loaded), including the locales and directionality value within a React Context
  3. Defines a global utility to get the locales from the i18n Service to be used inside the Context but also in the DTOs inside the appInitialization
  4. Defined a global utility to do interpolation of any string using the {{key}} interpolation string

Dictionary Key usage inside Components

Server Components/DTO/Utils

import { getI18n } from '@/utils/boot/appInitialization';
const i18n = await getI18n();
const loginKey = i18n.login;

Client Components

Alternative 1: single key

import { useContext } from 'react';
import { I18nContext } from '@/context/i18nContext';

const i18nContext = useContext(I18nContext);

return <div>{i18nContext.locales.watchNow}</div>;

Alternative 2: single key

import { useContext } from 'react';
import { I18nContext } from '@/context/i18nContext';

const i18nContext = useContext(I18nContext);
const { getLocale } = i18nContext;
const watchNowText = useMemo(() => getLocale('watchNow'), [getLocale]);

return <div>{watchNowText}</div>;

Alternative 3: multiple keys

import { useContext } from 'react';
import { I18nContext } from '@/context/i18nContext';

const i18nContext = useContext(I18nContext);
const { getLocales } = i18nContext;

const [key1, key2, key3, key4, key5, key6] = useMemo(
() => getLocales(['key1', 'key2', 'key3', 'key4', 'key5', 'key6']),
[getLocales],
);

return <div>{key2}</div>;

Alternative 4: multiple keys as an object

import { useContext } from 'react';
import { I18nContext } from '@/context/i18nContext';

const i18nContext = useContext(I18nContext);
const { getLocalesObj } = i18nContext;

const { key1, key2, key3, key4, key5, key6 } = useMemo(
() => getLocalesObj(['key1', 'key2', 'key3', 'key4', 'key5', 'key6']),
[getLocales],
);

return <div>{key2}</div>;

Alternative 5: useLocalize hook

Hook is abstracting some of the boilerplate code, and provides simple way to access and memoize any translations -

import { useLocalize } from '@/hooks/useLocalize';

Use an array or multiple arguments to construct an object with the translation keys -

const translations = useLocalize(['key1', ['key2', { key: 'value' }]]);

return <div>{translations.key2}</div>;
const { key1, key2 } = useLocalize('key1', ['key2', { key: 'value' }]);

return <div>{key2}</div>;

Using an object with custom names for the translations will return an object with the custom names as keys -

const translations = useLocalize({
title: 'key1',
description: ['key2', { key: 'value' }],
});

return <div>{translations.description}</div>;
const { title, description } = useLocalize({
title: 'key1',
description: ['key2', { key: 'value' }],
});

return <div>{description}</div>;

Interpolation

Interpolation works by passing a context of the items that contains the template within it.

eg. Given the string S{{season}}E{{episode}}: {{title}} and the data model

{
// […]
id: "uuid",
season: 3,
episode: 5,
title: "Episode Title",
}

The result would be S3E5: Episode Title.

String interpolation is available through any of the functions exposed. This is done by passing a tuple instead of a string, where the first element is the key and the second element is the context to be used.

import { useContext } from 'react';
import { I18nContext } from '@/context/i18nContext';

const i18nContext = useContext(I18nContext);
const { getLocale, getLocales, getLocalesObj } = i18nContext;

const movie = {
season: 3,
episode: 5,
title: 'Episode title',
};

// Given key2: 'S{{season}}E{{episode}}: {{title}}'

// returns 'S3E5: Episode Title'
const key2 = useMemo(() => getLocale(['key2', movie]), [getLocales]);

// returns 'S3E5: Episode Title'
const [key1, key2] = useMemo(
() => getLocales(['key1', ['key2', movie]]),
[getLocales],
);

// returns 'S3E5: Episode Title'
const { key1, key2 } = useMemo(
() => getLocalesObj(['key1', ['key2', movie]]),
[getLocales],
);

The function that handles interpolation for all of the above, transform, is also available and can be used directly

import { useContext } from 'react';
import { I18nContext } from '@/context/i18nContext';

const i18nContext = useContext(I18nContext);
const { transform } = i18nContext;

const movie = {
season: 3,
episode: 5,
title: 'Episode title',
};

// Given key2: 'S{{season}}E{{episode}}: {{title}}'

// returns 'S3E5: Episode Title'
const title = transform('key_2', movie);

transform’s first argument should be a dictionary key, and will attempt to retrieve it based on the current set of locales. If the key is not found on the current dictionary set, it then assumes that the string is the value to be interpolated. This allows transform to work directly with the template value.

import { useContext } from 'react';
import { I18nContext } from '@/context/i18nContext';

const i18nContext = useContext(I18nContext);
const { useLocale transform } = i18nContext;

const movie = {
season: 3,
episode: 5,
title: 'Episode title',
};

// returns 'S{{season}}E{{episode}}: {{title}}'
const key2 = useMemo(
() => getLocale('key2'),
[getLocales],
);

// returns 'S3E5: Episode Title'
const title = transform(key2, movie);

Dictionary Keys

In order to handle the existing dictionary keys for the data fetch, inside appInitialization there's a method called getI18n which will return all the existing keys based on a defined dictionary inside src/utils/boot/dictionary.ts.

That list is used for both initialization and data type validation, if you need to use any extra keys, you need to add to that list before using it.