Skip to main content

Localization

Localization shows an application's text in the player's language. Translations live in localization files, JSON assets that hold a message for each key in one or more locales. Text elements and scripts ask for a key, and the application's I18n object, app.i18n, returns the message for the current locale.

Text Localization

Localization Files​

A localization file looks like this:

{
"header": {
"version": 1
},
"data": [
{
"info": {
"locale": "en-US"
},
"messages": {
"title": "Treasure Hunt",
"coins": ["You have {number} coin", "You have {number} coins"]
}
}
]
}
  • header.version must be 1. A file without it is rejected, with an error in the console.
  • data holds an entry for each locale, so a file can hold one language or several.
  • A message is a string, or, for text that depends on a number, an array with one string for each plural form of the language.

In the Editor, CREATE NEW ASSET in the LOCALIZATION section of the Settings panel creates a file in this format.

Plural Forms​

Languages have different numbers of plural forms, and a plural message lists them in the order of the Unicode plural categories that the language uses: zero, one, two, few, many, other. The engine knows the forms of these languages:

FormsLanguages
One: otherChinese, Indonesian, Japanese, Korean, Thai, Vietnamese
Two: one, otherDanish, English, Finnish, German, Greek, Italian, Norwegian, Spanish, Swedish, Turkish and Urdu, where "one" is 1. French, Hindi, Persian and Portuguese, where "one" is 0 or 1
Four: one, few, many, otherPolish, Russian, Ukrainian
Six: zero, one, two, few, many, otherArabic

Any other language uses the English rules.

Loading the Files​

app.i18n reads a localization file once it has loaded, but it does not load it:

const english = new pc.Asset('en-US', 'json', { url: 'localization/en-US.json' });
const french = new pc.Asset('fr-FR', 'json', { url: 'localization/fr-FR.json' });
app.assets.add(english);
app.assets.add(french);

app.i18n.assets = [english, french];
app.assets.load(english);
app.assets.load(french);

Register pc.JsonHandler when you create the application. To use data you already have, pass it to app.i18n.addData() instead.

Choosing the Locale​

The locale is app.i18n.locale, en-US by default. Nothing sets it from the browser, so an application starts in en-US until you choose a locale, including an application published from the Editor. Set it from the player's choice, or from the browser's language:

app.i18n.locale = navigator.language;

A locale doesn't need its own data. When there is none for fr-CA, for example, app.i18n uses fr-FR, or another French locale, and falls back to en-US when it has no French at all. app.i18n.findAvailableLocale('fr-CA') returns the locale it would use for fr-CA.

Changing the locale updates every localized text element. To update anything else, such as HTML, listen for the change event:

app.i18n.on('change', (locale, previous) => {
document.documentElement.lang = locale;
});

In the Editor, the Locale field in the EDITOR section of the Settings panel previews a locale in the viewport and in launched applications. It doesn't affect published applications.

Localized Text Elements​

A text element with a key shows the message for that key in the current locale, and changes with the locale. A key without a message shows the key itself.

const heading = new pc.Entity('heading');
heading.addComponent('element', {
type: pc.ELEMENTTYPE_TEXT,
fontAsset: font.id,
key: 'title',
anchor: [0.5, 1, 0.5, 1],
pivot: [0.5, 1]
});
screen.addChild(heading);

Setting text removes the key, and setting key replaces the text.

A text element with the key of a plural message shows its first form, with {number} left in. Set the text of such elements from a script instead.

Strings in Scripts​

getText returns the message for a key in the current locale, or the key itself when there is no message. getPluralText picks the plural form for a number, but leaves {number} in the text for you to replace:

const title = app.i18n.getText('title');

const count = 3;
const coins = app.i18n.getPluralText('coins', count).replace('{number}', count);
// "You have 3 coins"

Both take a locale as an optional last argument.

Localized Fonts​

A font asset can name a different font asset to use for a locale, for languages that need characters the font doesn't have. When the locale changes, localized text elements switch to that locale's font, and load it if needed. Text elements without a key keep their font.

  • Editor: select the font asset, click Add Locale in the LOCALIZATION section of the inspector, and choose the font for the locale.
  • Engine, React and Web Components: call addLocalizedAssetId on the font asset:
latinFont.addLocalizedAssetId('ja-JP', japaneseFont.id);

A text element's text is not drawn while its font for the new locale is loading.

Formatting Numbers and Dates​

Numbers, prices and dates are written differently in each locale. Format them with the browser's Intl objects and the current locale:

const price = new Intl.NumberFormat(app.i18n.locale, { style: 'currency', currency: 'EUR' }).format(4.5);
const today = new Intl.DateTimeFormat(app.i18n.locale, { dateStyle: 'long' }).format(new Date());

Language Notes​

Chinese, Japanese and Korean​

Text elements wrap Chinese, Japanese and Korean text between characters, without spaces, and keep closing punctuation and small kana on the line before. Their character sets are large, so see Choosing Characters and give them localized fonts.

Thai​

Thai doesn't put spaces between words, and a text element only wraps at spaces, tabs, hyphens and zero-width spaces. Ask translators to put a zero-width space (U+200B) between the words of Thai text, so that it can wrap.

Right-to-Left Languages​

A text element lays out characters from left to right. Arabic, Hebrew and other right-to-left languages need their characters reordered first, and Arabic also needs the joined forms of its letters. The Right to Left Language Support tutorial provides scripts that do this for text elements.

See Also​

  • Text Elements - Drawing, wrapping and fitting text
  • Fonts - Creating font assets and choosing their characters
  • I18n - API reference for app.i18n