Contribute to help us improve!

Are there edge cases or problems that we didn't consider? Is there a technical pitfall that we should add? Did we miss a comma in a sentence?

If you have any input for us, we would love to hear from you and appreciate every contribution. Our goal is to learn from projects for projects such that nobody has to reinvent the wheel.

Let's collect our experiences together to make room to explore the novel!

To contribute click on Contribute to this page on the toolbar.

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
bash

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 {}
typescript
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 }}
html

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

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

It is possible to use with inputs:

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

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);
  }
}
typescript

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"
}
json

Or with an optional parameter:

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

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

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

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>
typescript

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>
typescript

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>
typescript

Pipe

The use of pipes can be possible too:

template:

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

component:

param = {value: 'world'};
typescript

Attribute Directive

The last option available with transloco is the attribute directive:

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

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'
});
typescript
You can find a complete example at https://github.com/devonfw/devon4ng-application-template.

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