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:

Bundle with language files
├── 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:

nls/de/bundle.js
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.

Access using the injected i18n property
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.

Access using the i18n property in provided by the constructor
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:

Language strings used for bundle properties
{
  ...
  "description": "${myBundleDescription}",
  ...
}

But you can also pass single strings or sub-sections of a bundle’s language strings into components:

Passing language strings to a component
{
  ...
  "components": [
    {
      "name": "FooWindowFactory",
      "properties": {
          "windowMessages": "${foo.window}"
      }
    }
  ],
  ...
}

Disabling internationalization

To disable i18n support, set an empty array in the manifest.json file:

Disable i18n in manifest.json file
{
  ...
  "i18n" : [], // disables i18n support for this bundle
  ...
}

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() ?? {};
    }
}