How to support multiple languages
You can enable bundles to provide language-specific strings, so a user of an app gets messages according to their browser locale or language selection. This process of internationalization (i18n) requires you to define the strings in all languages, which you want to support, inside the bundle.
This guide demonstrates how to add support for multiple languages and how to use language-specific strings in your code.
Checklist
To follow this guide, you need:
-
An arbitrary bundle you like to add language-specific strings to.
-
The bundle manifest must set the property
"i18n": ["bundle"]
. This is the default, see manifest reference documentation.
Step 1: Add language files
Language-specific strings are stored in language files in the nls/
folder, one for each language you want to support.
To set up language files for two languages, create the following file tree in your bundle:
├── manifest.json
└── nls/
├── bundle.js (1)
└── <language_id>/ (2)
└── bundle.js (3)
1 | The default language file that is used when there is no matching language file for the currently selected language. Usually this file hosts English strings. |
2 | A folder containing the language file for the language specified by <language_id> .
<language_id> corresponds to a language ID as specified by RFC 3066 , e.g de or fr . |
3 | A language file containing the strings used for the language specified by its folder name |
Step 2: Add default language strings
The default language file must export an object having a root
property that maps keys to language strings.
Add the default messages to nls/bunde.js
like this:
export default {
root: { (1)
myBundleDescription: "Takes a foo and generates a baz", (2)
foo: {
window: {
title: "Add a foo" (3)
}
statusSuccess: "Baz is ready!"
}
},
"de": true (4)
};
1 | The mandatory root property. |
2 | A message that can be referenced using the key myBundleDescription . |
3 | A message that can be referenced using the compound key foo.window.title . |
4 | This property is a necessary indicator required for each additional language you are supporting.
The key corresponds to the respective <language_id> . |
Step 3: Add additional languages strings
Similar to the default language file, other language files must export an object with the same keys but omitting the intermediary "root"
property.
(Also, don’t add any indicators for additional languages)
Add the language strings to nls/<language_id>/bundle.json
like this:
export default {
myBundleDescription: "Nimmt ein foo und macht ein baz daraus",
foo: {
window: {
title: "Foo hinzufügen"
}
statusSuccess: "Baz fertiggestellt!"
}
};
Step 3: Access language strings in your code
Accessing language strings in a component
To access language strings in a component of your bundle, you need to access the _i18n
property that is automatically injected into it.
export default class {
// A service method
createFooWindow() {
let windowTitle = this._i18n.get().foo.window.title;
// "Takes a foo and generates a baz"
// or "Nimmt ein foo und macht ein baz daraus", depending on the locale set by the runtime.
...
}
}
The language strings are also provided by the constructor argument’s _i18n
property if the component configuration property "propertiesConstructor": true
is set.
export default class {
// A service method
constructor(opts) {
this.fooMessages = opts._i18n.get().foo;
console.debug(fooMessages.window.title);
// "Takes a foo and generates a baz"
// or "Nimmt ein foo und macht ein baz daraus", depending on the locale set by the runtime.
...
}
}
Accessing language strings in the bundle manifest
You may also use ${messageKey}
expressions to access language strings directly inside the bundle manifest.
This allows you to internationalize bundle properties like title or description like this:
{
...
"description": "${myBundleDescription}",
...
}
But you can also pass single strings or sub-sections of a bundle’s language strings into components:
{
...
"components": [
{
"name": "FooWindowFactory",
"properties": {
"windowMessages": "${foo.window}"
}
}
],
...
}
Usage patterns
Declaring the _i18n property with TypeScript
When implementing a module in TypeScript, to communicate the origin and type of the _i18n
property, you are recommended to declare it as an InjectedReference as demonstrated here:
export class MapWidgetFactory implements MapWidgetFactoryInterface {
private _i18n: InjectedReference<any>;
createWidget(options: any): MapWidgetInterface {
const i18n = this._i18n?.get() ?? {};
}
}