Skip to content

guide internationalization

devonfw-core edited this page Jan 5, 2022 · 8 revisions

Internationalization

Nowadays, a common scenario in front-end applications is to have the ability to translate labels and locate numbers, dates, currency and so on when the user clicks over a language selector or similar. devon4ng and specifically Angular has a default mechanism in order to fill the gap of such features, and besides there are some wide used libraries that make even easier to translate applications.

devon4ng i18n approach

The official approach could be a bit complicated, therefore the recommended one is to use the recommended library Transloco from https://github.com/ngneat/transloco/.

Install and configure Transloco

In order to include this library in your devon4ng Angular >= 7.2 project you will need to execute in a terminal:

$ ng add @ngneat/transloco

As part of the installation process you’ll be presented with questions; Once you answer them, everything you need will automatically be created for you.

  • First, Transloco creates boilerplate files for the requested translations.

  • Next, it will create a new file, transloco-root.module.ts which exposes an Angular’s module with a default configuration, and inject it into the AppModule.

import { HttpClient } from '@angular/common/http';
import {
  TRANSLOCO_LOADER,
  Translation,
  TranslocoLoader,
  TRANSLOCO_CONFIG,
  translocoConfig,
  TranslocoModule
} from '@ngneat/transloco';
import { Injectable, NgModule } from '@angular/core';
import { environment } from '../environments/environment';

@Injectable({ providedIn: 'root' })
export class TranslocoHttpLoader implements TranslocoLoader {
  constructor(private http: HttpClient) {}

  getTranslation(lang: string) {
    return this.http.get<Translation>(`/assets/i18n/${lang}.json`);
  }
}

@NgModule({
  exports: [ TranslocoModule ],
  providers: [
    {
      provide: TRANSLOCO_CONFIG,
      useValue: translocoConfig({
        availableLangs: ['en', 'es'],
        defaultLang: 'en',
        // Remove this option if your application doesn't support changing language in runtime.
        reRenderOnLangChange: true,
        prodMode: environment.production,
      })
    },
    { provide: TRANSLOCO_LOADER, useClass: TranslocoHttpLoader }
  ]
})
export class TranslocoRootModule {}
ℹ️
As you might have noticed it also set an HttpLoader into the module’s providers. The HttpLoader is a class that implements the TranslocoLoader interface. It’s responsible for instructing Transloco how to load the translation files. It uses Angular HTTP client to fetch the files, based on the given path.

Usage

In order to translate any label in any HTML template you will need to use the transloco pipe available:

{{ 'HELLO' | transloco }}

An optional parameter from the component TypeScript class could be included as follows:

{{ 'HELLO' | transloco: { value: dynamic } }}

It is possible to use with inputs:

<span [attr.alt]="'hello' | transloco">Attribute</span>
<span [title]="'hello' | transloco">Property</span>

In order to change the language used you will need to create a button or selector that calls the this.translocoService.use(language: string) method from TranslocoService. For example:

export class AppComponent {
  constructor(private translocoService: TranslocoService) {}

  changeLanguage(lang) {
      this.translocoService.setActiveLang(lang);
  }
}

The translations will be included in the en.json, es.json, de.json, etc. files inside the /assets/i18n folder. For example en.json would be (using the previous parameter):

{
    "HELLO": "hello"
}

Or with an optional parameter:

{
    "HELLO": "hello {{value}}"
}

Transloco understands nested JSON objects. This means that you can have a translation that looks like this:

{
    "HOME": {
        "HELLO": "hello {{value}}"
    }
}

In order to access access the value, use the dot notation, in this case HOME.HELLO.

Using the service, pipe or directive

Structural Directive

Using a structural directive is the recommended approach. It’s DRY and efficient, as it creates one subscription per template:

<ng-container *transloco="let t">
  <p>{{ t('title') }}</p>

  <comp [title]="t('title')"></comp>
</ng-container>

Note that the t function is memoized. It means that given the same key it will return the result directly from the cache.

We can pass a params object as the second parameter:

<ng-container *transloco="let t">
  <p>{{ t('name', { name: 'Transloco' }) }}</p>
</ng-container>

We can instruct the directive to use a different language in our template:

<ng-container *transloco="let t; lang: 'es'">
  <p>{{ t('title') }}</p>
</ng-container>

Pipe

The use of pipes can be possible too:

template:

<div>{{ 'HELLO' | transloco:param }}</div>

component:

param = {value: 'world'};

Attribute Directive

The last option available with transloco is the attribute directive:

<div transloco="HELLO" [translocoParams]="{ value: 'world' }"></div>

Service

If you need to access translations in any component or service you can do it injecting the TranslocoService into them:

// Sync translation
translocoService.translate('HELLO', {value: 'world'});

// Async translation
translocoService.selectTranslate('HELLO', { value: 'world' }).subscribe(res => {
    console.log(res);
    //=> 'hello world'
});
You can find a complete example at https://github.com/devonfw/devon4ng-application-template.

Please, visit https://github.com/ngneat/transloco/ for more info.

Clone this wiki locally