Internationalizing a Dojo application

    • locale: string
      • The primary locale supported by the application. That is, the default language that will be used if an override locale is not specified.
    • supportedLocales: string[]
      • A list of additional locales that the application supports. These locales need to be activated to override the default locale, either implicitly through an application user’s language setting when running client-side, the process’ or host’s language setting when running server-side, or explicitly within the application itself.

    For example, with the following configuration, an application specifies that its default locale is English (en), and that it supports Spanish (es) and French (fr) as additional locale choices:

    Creating i18n-aware widgets

    Individual widgets can be internationalized by using the i18n middleware from @dojo/framework/core/middleware/i18n. Using the middleware adds some optional i18n-related properties to the widget property interface. The API for the i18n middleware includes a method, localize(bundle) to get the localized nls values given a message bundle and two methods that can be used to get and set the application’s locale details.

    • locale?: string
      • The locale for the widget.If not specified, then the root application locale or is assumed.If specified, the widget’s DOM node will have a lang property set to the locale.
    • rtl?: boolean
      • An optional flag indicating the widget’s text direction. If true, then the underlying DOM node’s dir property is set to "rtl". If it is false, then the dir property is set to "ltr". Otherwise, the property is not set.
    • i18nBundle?: Bundle<Messages> | Map<Bundle<Messages>, Bundle<Messages>>
      • An optional override for the default language bundle passed to the localizeBundle method. If the override contains a messages object, then it will completely replace the underlying default language bundle that the widget may be using. If the override only contains a locales object, a new bundle will be created with the additional locale loaders specified in the override.

    Widgets can pass in their into the localize method to have the bundle localized appropriately given the widget’s locale property.

    If the bundle supports the widget’s current locale, but those locale-specific messages have not yet been loaded, then a bundle of blank message values is returned. Alternatively, the localize method accepts a second boolean argument, which, when true, causes the default messages to be returned instead of the blank bundle. The widget will be invalidated once the locale-specific messages have been loaded, triggering a re-render with the localized message content.

    The object returned by localize contains the following properties and methods:

    • messages
      • An object containing the localized message key-value pairs. If the messages have not yet loaded, then messages will be either a blank bundle or the default messages, depending upon how localize was called.
    • isPlaceholder
      • A boolean property indicating whether the returned messages are the actual locale-specific messages (false) or just the placeholders used while waiting for the localized messages to finish loading (true). This is useful to prevent the widget from rendering at all if localized messages have not yet loaded.
    • format(key: string, replacements: { [key: string]: string })
      • A method that accepts a message key as its first argument and an object of replacement values as its second. For example, if the bundle contains greeting: 'Hello, {name}!', then calling format('greeting', { name: 'World' }) would return 'Hello, World!'.

    An example of using all features returned by localize:

    nls/en/MyI18nWidget.ts

    1. messages: {
    2. hello: 'Welcome to the shop',
    3. purchaseItems: 'Please confirm your purchase',
    4. itemCount: 'Purchase {count} items'
    5. }
    6. };

    Note that with this pattern it is possible for a widget to obtain its messages from multiple bundles. When favoring simplicity, however, it is recommend that widgets are limited to a single bundle wherever possible.

    Individual class-based widgets can be internationalized by adding the I18nMixin mixin from @dojo/framework/core/mixins/I18n. This mixin adds the same optional i18n-related widget properties as the i18n middleware, and provides a localizeBundle method which is used to localize an imported message bundle to the widget’s current locale.

    localizeBundle() method

    Widgets can pass in their into the localizeBundle method to have the bundle localized appropriately given the widget’s locale property.

    If the bundle supports the widget’s current locale, but those locale-specific messages have not yet been loaded, then a bundle of blank message values is returned. Alternatively, the localizeBundle method accepts a second boolean argument, which, when true, causes the default messages to be returned instead of the blank bundle. The widget will be invalidated once the locale-specific messages have been loaded, triggering a re-render with the localized message content.

    The object returned by localizeBundle contains the following properties and methods:

    • messages
      • An object containing the localized message key-value pairs. If the messages have not yet loaded, then messages will be either a blank bundle or the default messages, depending upon how localizeBundle was called.
    • isPlaceholder
      • A boolean property indicating whether the returned messages are the actual locale-specific messages (false) or just the placeholders used while waiting for the localized messages to finish loading (true). This is useful to prevent the widget from rendering at all if localized messages have not yet loaded.
    • format(key: string, replacements: { [key: string]: string })
      • A method that accepts a message key as its first argument and an object of replacement values as its second. For example, if the bundle contains greeting: 'Hello, {name}!', then calling format('greeting', { name: 'World' }) would return 'Hello, World!'.

    An example of using all features returned by localizeBundle:

    nls/en/MyI18nWidget.ts

    1. export default {
    2. messages: {
    3. hello: 'Welcome to the shop',
    4. purchaseItems: 'Please confirm your purchase',
    5. itemCount: 'Purchase {count} items'
    6. }
    7. };

    This mechanism is enabled through registerI18nInjector, a convenience method provided by @dojo/framework/core/mixins/I18n. Calling this method will register the i18n injector within a specific registry instance. Typically this is done at application bootstrap, where the i18n injector is registered against the global registry passed to the renderer.mount() method.

    main.ts

    1. import renderer from '@dojo/framework/core/vdom';
    2. import { w } from '@dojo/framework/core/vdom';
    3. import Registry from '@dojo/framework/core/Registry';
    4. import { registerI18nInjector } from '@dojo/framework/core/mixins/I18n';
    5. import App from './App';
    6. const registry = new Registry();
    7. const r = renderer(() => w(App, {}));

    Changing locales

    The i18n middleware can be used to change the application’s locale. Calling i18n.set({ locale: string, rtl: boolean }); will propagate the new locale to all widgets that are using the i18n middleware, as well as any using I18nMixin (assuming has previously been setup in the application).

    The following example shows an i18n-aware widget that renders two buttons that allow switching the application locale between English and French.

    Widgets that use either the i18n middleware or I18nMixin can have their i18n widget properties overridden when instantiated by a parent. This can be useful when rendering several widgets with different locales in a single application (that is, using multiple locales within one application), as well as to override the set of messages a third-party widget may be using and align them within the context of your application.

    Each i18n-aware widget can have its own independent locale by providing a locale widget property. If no locale property is set, then the is assumed.

    The widget’s default bundle can also be replaced by passing an i18nBundle widget property. Dojo recommends against using multiple bundles in the same widget, but there may be times when an application needs to consume a third-party widget that does make use of more than one bundle. As such, i18nBundle can also be a Map of default bundles to override bundles.

    An example of overriding bundles within child widgets:

    1. import { Bundle } from '@dojo/framework/i18n/i18n';
    2. // A complete bundle to replace WidgetA's message bundle
    3. import overrideBundleForWidgetA from './nls/widgetA';
    4. // Bundles for WidgetB
    5. import widgetB1 from 'third-party/nls/widgetB1';
    6. import overrideBundleForWidgetB from './nls/widgetB';
    7. // WidgetB uses multiple bundles, but only `thirdy-party/nls/widgetB1` needs to be overridden
    8. const overrideMapForWidgetB = new Map<Bundle<any>, Bundle<any>>();
    9. map.set(widgetB1, overrideBundleForWidgetB);
    10. export class MyWidget extends WidgetBase {
    11. protected render() {
    12. return [
    13. w(WidgetA, {
    14. i18nBundle: overrideBundleForWidgetA
    15. }),
    16. w(WidgetB, {
    17. i18nBundle: overrideMapForWidgetB
    18. })
    19. ];
    20. }

    Default locale