« return to the manuals

Preliminary readings:

Internationalizing a Widget

In LaxarJS, internationalization (i18n) of widgets is optional. Read on if you are interested in writing widgets that support multiple languages, and even switching languages without reloading the page.

Locales and Language Tags: I18n in LaxarJS

LaxarJS distinguishes locales and language tags for internationalization. Each locale has a constant name like "default" or "customer" and a RFC-5646 language tag like "en-US", which can change over time. The locale corresponds to the audience for which a language tag should be valid. If you have only one audience (regular users), using only default should be fine. The language tag of a given locale can be modified through activities or widgets when the application is running. To change the language tag of a locale an activity has to publish the changeLocaleRequest.{locale} event.

Example: To change the language tag of the locale myLocale to de-DE, the following event has to be published:

$scope.eventBus.publish( 'changeLocaleRequest.myLocale.',
    {
        locale: 'myLocale',
        languageTag: 'de-DE'
    }
);

If a widget is interested in changes to myLocale, it would subscribe to the corresponding didChangeLocale-event, which is published by the LaxarJS flow-controller:

$scope.eventBus.subscribe( 'didChangeLocale.myLocale.', function( event ) {
   ax.log.info( 'I have received tag [0] for locale [1]', event.languageTag, event.locale );
} );

Widgets can use the language tags that they receive over the event bus to localize internationalized values. Internationalized values are JSON-Objects which contain an entry for each supported language tag. By convention, variables and properties that contain internationalized values are prefixed with i18n:

"i18nHtmlText": {
    "en-US": "Upload file",
    "de-DE": "Datei hochladen"
}

LaxarJS provides some tools which help to deal with i18n. They are based on the events shown above, and demonstrated in the following section.

Writing an I18n-Capable Widget

To be able to localize internationalized values in templates, widgets can use the i18n-directives which are provided by Laxar-UiKit. This is accomplished by adding the i18n control to the top-level entry controls in the widget.json. If missing, this entry must be created:

"controls": [
    "laxar_uikit/controls/i18n"
]

Next, we have to add a feature i18n. It allows page authors to configure the name of the locale (e.g. "customer") to be used by this widget. The actual language tag associated with that locale (for example en-GB) is then used to localize internationalized values.

"i18n": {
   "description": "Which locale to use for displaying this widget.",
   "type": "object",
   "properties": {
      "locale": {
         "type": "string",
         "description": "The topic under which to expect the locale for this widget.",
         "default": "default"
      }
   }
}

If not already done, we import the Laxar-Patterns library into the widget controller (my_widget.js). The i18n-handler offered by Laxar-Patterns subscribes the widget to the right didChangeLocale-events for us, by using the feature configuration that we added in the previous step:

define( [   
   'laxar-patterns'
], function( patterns ) {
   patterns.i18n.handlerFor( $scope ).scopeLocaleFromFeature( 'i18n' );
   ...
}

Any updates to the i18n-locale received over the event bus will now be saved under $scope.i18n, along with their tags. More locales may be registered for other features (if a single widget wants to use more than one language at the same time), resulting ins something like:

$scope.i18n = {      
   locale: 'default',
   tags: {
      'default': 'en-US',
      'customer': 'de-DE',
      'support': 'en-GB'
   }
}

In the HTML template we can now use the angular filter axLocalize to convert an i18nHtmlText to a string:

<p data-ng-bind-html="model.i18nHtmlText | axLocalize:i18n"></p>

The filter expects an object for internationalization or a string if the value is not internationalized. It uses $scope.i18n.locale (passed as an argument to the filter) to select the correct language tag. Every property of the object should have a language tag as key and the translated text or html as value.

"i18nHtmlText": {
    "en-US": "Upload file <em>now</em>",
    "de-DE": "Datei <em>jetzt</em> hochladen"
}

Localizing Values in the Controller

In some cases it is more appropriate to create the localized string inside the controller of the widget. This is the case if the localization has to be retrieved from the server first.

<p data-ng-bind-html="model.htmlVeryLongDocument"></p>

To achieve this, we obtain a localize function when we subscribe the widget to the didChangeLocale event. Like the axLocalize-directive, this function automatically uses the current language tag:

var localize = patterns.i18n.handlerFor( $scope ).scopeLocaleFromFeature( 'i18n', {
    onChange: updateLocalization
} ).localizer();

Now, we can transform any object with language tag properties to a string using the localize function:

function updateLocalization() {
   var documentUrl = localize( $scope.features.i18nDocumentUrl );
   $http.get( documentUrl ).then( function( response ) {
      $scope.model.htmlVeryLongDocument = response.data;
   } );
}