Making Your App Ready for Translations

Ex Libris Developer Network Ex Libris Cloud Apps Tutorials Making Your App Ready for Translations

Alma has an international audience and has been translated into many languages. Cloud Apps also support working in multiple languages. When a user opens your Cloud App, Alma will pass through the language of the user’s session and set the language of your app.

While you might not speak multiple languages yourself, you can prepare your application to be translated by using the framework included in the Cloud App CLI. You can then leverage the community for help providing translations for additional languages.

Cloud Apps use the ngx-translate framework to support translations. There are many good reference sites and blog posts  which discuss the features of this framework. The basic concept is that all strings which must be translated are separated into a JSON file per language. The app’s html and ts files reference the string keys and display the text provided in the JSON files. If a translation is not available in the user’s language, the English file is used by default.

In this tutorial we’ll show how to extract the strings your app displays. We’ll review several alternatives for accessing translated strings. First, follow the instructions in the “Adding additional routes” tutorial to add a new component and route called “translate”.

In translate.component.html, we show several examples of specifying translations.

Translation directive with the key as content:

<p translate>Translate.SelectDesc</p>

Translation pipe:

<button mat-stroked-button type="button" (click)="hi()">{{ 'Translate.Button' | translate }}</button>

Translation directive with parameters:

<p translate [translateParams]="{ date: today }">Translate.Intro</p>

Looping through an array of values:

<mat-option *ngFor="let policy of policies" [value]="policy.code">
  {{ policy.desc | translate }}
</mat-option>

In translate.component.ts, we show a few examples of using the TranslateService, which we inject via the constructor. To get the translated page title, we use the get method which returns an observable (since the translations may not be available immediately when the page is loaded).

translate.component.tsView on Github

In our hi method, we use the instant method of the translate service to retrieve the prompt string, and pass in the user name as a parameter which is referenced in the en.json file:

translate.component.tsView on Github
{ 
  "Prompt": "Hello {{name}}"
}

Extracting Strings

In order to create our translation string files, we use the Cloud App CLI (which wraps the ngx-translate-extract tool). First, we create a file called en.json in the cloudapp/src/i18n folder and initialize it with an empty JSON object: { }. Then we run the extract-labels command:

$ eca extract-labels

This will scan all of the html and ts files for any references to translated strings and merge the results into the files(s). This can be run at any time to keep the string files in synch with the code.

For cases where the string is not used with the translate service (i.e. get/instant) or in a pipe/directive in the html file, we can use a marker to indicate that the string should be extracted. In our example, we populate an array with several code/description pairs. For the description, we use a translation code. We mark it using a “marker” that indicates to the extract tool that the string should be translated. In our case, the marker is a _( ), as seen in the “policies” definition above.

Using other parsers

Often we need to provide alternative strings for plural or other cases (such as gender). Angular templates use the ICU syntax to provide plural alternatives. You can use the same ICU syntax with the translation engine used in Cloud Apps, but it requires some changes to your app. This example will use this template parser, but the same strategy can be used for other parsers or compilers supported by ngx-translate.

Start by installing the parser with $ npm i ngx-translate-parser-plural-select --save. In your app.module.ts, define your own module using the LazyTranslateLoader provided by the Cloud App SDK and include it in your imports.

import { TranslateModule, TranslateLoader, TranslateParser } from '@ngx-translate/core';
import { TranslateICUParser } from 'ngx-translate-parser-plural-select';
import { LazyTranslateLoader } from '@exlibris/exl-cloudapp-angular-lib';

export function getTranslateModuleWithICU() {
  return TranslateModule.forRoot({
    loader: {
      provide: TranslateLoader,
      useClass: (LazyTranslateLoader)
    },
    parser: {
      provide: TranslateParser,
      useClass: TranslateICUParser
    }
  });
}
imports: [
   ...
   FormsModule,
   ReactiveFormsModule,
   getTranslateModuleWithICU(),
   ...
],

Then you can use the ICU syntax in your translation files such as this:

{
  "Success": "{num} {num, plural, =1{record was} other{records were}} updated successfully."
}

 

Switching Languages

Your Cloud App will default to the Alma interface language of the currently logged-in user. If your app contains a translation file for that language, the appropriate strings will be displayed (falling back to English). You can also provide a method in your user interface to switch languages. Doing so is as simple as calling the use method of the Translate Service. In the tutorial, we provide a way to switch between English and Spanish. (Note that the Spanish translations are machine-generated. We’re happy to take a pull request to fix the translations in this file.)

 

Text Direction

Languages like Arabic and Hebrew are read from right to left. HTML supports text direction with a dir attribute. Using dir="rtl" changes the layout of all of the content within the node, including layout via styles.

In our example, we’ve added an option to display text in Hebrew. In the init function, we subscribe to the onLangChange method of the translate service. When the language is changed, we check the new language and set a direction property accordingly.

translate.component.tsView on Github

While we do this in our translate component, you might choose to implement this in your app component to apply it to you entire application.