ngx-translate and ngx-translate-extract – Internationalization Made Easy

It’s a bit surprising that there so many libraries offering internationalization for Angular applications. It’s surprising because there the Angular cookbook describes a well-thought approach to internationalization. Unfortunately, ng-xi18n was broken last time I checked, so let’s explore another library today. ngx-translate is a simple but useful library for supporting multiple languages. And ngx-translate-extract makes working with ngx-translate even easier by extracting texts to be translated automatically.

What’s the difference between ng-xi18n and ngx-translate?

Talking of ng-xi18n: there’s a big difference to ngx-translate. ng-xi18n has been developed with professional translators in mind. In particular, this library uses the well-known XLIFF standard. Developers probably tend to think this standard is clumsy. It’s XML, and it’s sort of bloated. ngx-translate, in contrast, uses slime Json file to map one language to another. The backside being it supports fewer use-cases than XLIFF.

Getting started

Before beginning the walk-through, I should mention I’ve used ngx-translate with a demo project of mine. So if you’re stuck with the walk-through, you can checkout my project and see how things are meant to work.

You have to add two dependencies to your package.json. I also recommend to add ngx-translate-extract because it makes your life easier, but strictly speaking, you don’t need it.

npm install @ngx-translate/core --save
npm install @ngx-translate/http-loader --save
npm install @biesbjerg/ngx-translate-extract --save-dev

The next step is to define the translation module in the central AppModule:

export function createTranslateLoader(http: Http) {
  return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}
@NgModule({
  declarations: [ ... ],
  imports: [ ...,
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: createTranslateLoader,
        deps: [Http]
      }
    })
  ],
  providers: [...],
  bootstrap: [AppComponent]
})

This approach only supports a central translation file for the entire application. We’ll cover multiple modules in a minute.

We activate the translation service in the AppComponent like so:

export class AppComponent {

  constructor(translate: TranslateService){
    translate.setDefaultLang('en');
    translate.use("es");
  }
}

In this example, I’ve set the language to Spanish. In general, you’ll probably want to use the browser default. The default language setting defines which language to use if a translation is missing.

Now we’re ready to use the translation service in the HTML templates:

{{'Registration form' | translate}}
<input mdInput placeholder="{{'First name:' | translate}}">

As you can see, the texts are simply translated by using a pipe. The only drawback is that the special keys make typing a bit cumbersome. The nice thing is that you can use the plain English (or whichever language you’re using) text as a key. Strictly speaking, the Json format doesn’t support keys with spaces and special characters, but ngx-translate is flexible enough to parse those Json files nonetheless.

Extracting the translation table

Now you can extract the key using ngx-translate-extract. This npm script finds every translation pipe and generates a key in the Json file containing the translation table. The script has a lot of parameters, so it’s a good idea to add a script to the package.json:

   "extract": "ngx-translate-extract --input ./src/app/ --output ./src/assets/i18n/{en,es,de}.json --clean --sort --format namespaced-json"

After running npm run extract you’ll find three json files in the assets folder. Edit these files, run your application and you’re done.

Parameters and texts in the TypeScript code

It’s pretty straight-forward to add parameters to a translation and to use it in the TypeScript code, so suffice it to quote the example from the documentation:

{
    "hello parameter": "hello {{value}}"
}
translate.get('hello parameter', {value: 'world'}).subscribe((res: string) => {
    console.log(res);
    //=> 'hello world'
});

Multiple modules

ngx-extracts also supports multiple modules with lazy loading. In this case, you need to create a Json file for each module:

   "i18n_1": "ngx-translate-extract --input ./src/app/registration --output ./src/assets/i18n/registration/{en,es,de}.json --clean --sort --format namespaced-json",
    "i18n_2": "ngx-translate-extract --input ./src/app/highscore --output ./src/assets/i18n/highscore/{en,es,de}.json --clean --sort --format namespaced-json",
    "extract": "npm run i18n_1 && npm run i18n_2"

We’ve define two extraction scripts, one for each module. The command npm run extract starts both extractions scripts.

The declaration of the translation service in the child module is a bit different from the definition in the root module:

export function createTranslateLoader(http: Http) {
  return new TranslateHttpLoader(http, './assets/i18n/registration/', '.json');
}

@NgModule({
  imports: [
    ...,
    TranslateModule.forChild({
      loader: {provide: TranslateLoader, useFactory: createTranslateLoader,  deps: [Http]},
      isolate: true
    })
  ],
  declarations: [
    ...
  ]
})

The documentation of the project explains it a bit more complicated because it also mentions the advanced options. For starters, the down-stripped version above will do the trick just as well.

Missing features

Like said before, ngx-translate supports the most important use cases, but it doesn’t strive for completeness. It doesn’t support plural and singulars. It doesn’t add fields for indicating the meaning and the intent of the text snippet. Plus, translation agencies usually don’t work with Json files. This won’t be a problem in most cases, but it might make the translation more costly and error-prone in large-scale applications.

By the way, there’s little to none risk that you run into problems using ngx-translate. At the time of writing, it’s a very small library. So even if you end up missing an important feature, you can easily fork the library and implement it yourself.

Kudos

At this point, I’d like to thank my co-worker Jessica Mäser. She gave me the idea to investigate about ngx-translate and to write this article. Thanks, Jessica!

Wrapping it up

While I’d love to see ng-xi18n to be fixed, ngx-translate is a good library we can use in the meantime. Or even continue using it after ng-xi18n has been fixed. It’s a simple but robust approach. Maybe it’s a bit slower than the “official” approach of the Angular team because ngx-translate doesn’t integrate as deep with the AOT compiler than ng-xi18n does. However, I believe in most cases the translation is fast enough.

Dig deeper

The core library (scroll down for the documention)
a demo project of mine

Leave a Reply

Your email address will not be published.