📜 ⬆️ ⬇️

Internationalization (i18n) in Angular 2

To create multilingual interfaces Angular offers to use the HTML markup mechanism of the templates with a special marker i18n, which after compilation is removed from the final code. To do this, it is enough to specify this marker as an attribute of the tag surrounding the text.

<h1 i18n>Hello baby!</h1> 

For a marker, you can specify additional parameters that are displayed in specialized editors used for translation and complement the translated text with service information designed to help the translator. These parameters are transmitted in the format "Value | Description" or only "Description".

 <h1 i18n="An introduction header for this sample">Hello baby!</h1> <h1 i18n="User welcome|An introduction header for this sample">Hello baby!</h1> 

It is possible to specify a marker for text that is not surrounded by a tag. For this purpose, either a special empty tag is used which is not rendered in the final code.

 <ng-container i18n>I don't output any element</ng-container> 

or special comment
')
 <!--i18n: optional meaning|optional description --> I don't output any element either<!--/i18n--> 

It is also possible to do a translation for tag attributes. Such as alt, title, ...

 <img [src]="logo" i18n-title title="Angular logo" /> 

Plural


The ending of words for the plural is based on the rules http://unisource.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules and http://cldr.unisource.org/index/cldr-spec/plural-rules in the format:

 <span i18n>{wolves, plural, =0 {no wolves} =1 {one wolf} =2 {two wolves} other {a wolf pack}}</span> 

wolves - the name of the variable containing the number
plural - the name of the type of transformation
= 0 - possible variable value, {no wolves} - displayed text for this value
= 1 - the possible value of the variable, {one wolf} - the displayed text for this value
= 2 - possible variable value, {two wolves} - displayed text for this value
other - if the variable value is not specified, {a wolf pack} - the displayed text for this value

The following options are possible:


Select


Allows you to select a value based on a literal variable:

 <span i18n>The hero is {gender, select, m {male} f {female}}</span> 

gender - the name of the variable containing the value
select - the name of the conversion type
m is the possible value of the variable, {male} is the displayed text for the given value
f - possible variable value, {female} - displayed text for this value

ng-xi18n


To extract the lines from the application, the special utility ng-xi18n is included in the angular-cli:

 ./node_modules/.bin/ng-xi18n -p src/tsconfig.json 

This utility searches for i18n marker in templates and copies the corresponding text to form an XML file of XLIFF format (version 1.2) from it.

The XML Message Bundle (XMB) format is also supported. To do this, set the appropriate key:

 ./node_modules/.bin/ng-xi18n --i18nFormat=xmb -p src/tsconfig.json 

Then the XML file can be sent to the translator who can edit it with one of the specialized editors. The resulting file should be saved in the i18n folder and contain the localization language in its name. For example, in the case of the Spanish language, from the original messages.xlf we get messages.es.xlf . A separate file must be created for each interface language.

In order for the translation file to be used by Angular, you need to add the following code to main.ts:

 //    import {TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID} from '@angular/core'; //    XML    let current_language = 'ru'; import {RU_TRANS} from './i18n/messages.' + current_language; 

There is one remark. If we use angular-cli, then at present we cannot independently (officially) change the configuration of the webpack and accordingly we cannot add the raw rule for files with the xlf extension, which allows importing them directly. Therefore, for the time being, you have to insert them into the wrapper file (messages.ru.ts):

 export const RU_TRANS = ` //      . //     XML  messages.ru.xlf `; 

Configuring in main.ts

 platformBrowserDynamic().bootstrapModule(AppModule, { providers: [ {provide: TRANSLATIONS, useValue: RU_TRANS}, {provide: TRANSLATIONS_FORMAT, useValue: 'xlf'}, {provide: LOCALE_ID, useValue: current_language} ] }); 


Unfortunately, the internalization described above has a number of pitfalls and limitations due to which it can only be used in projects with the simplest interface:

  • when changing the contents of the tag, even those not related to the text being translated, subsequent extraction can change the ID, which in turn leads to compilation errors of the application.
  • extraction occurs only from HTML files and is not possible for dynamic content (for example, any lists or dropboxes)



This puts an end to this approach for use in most projects saturated with dynamic content and using interrelated dropboxes.

Work on these issues is happening and perhaps in versions Angular 4 or 5 internationalization will be brought to mind.

Therefore, the only working solution, as before, remains the ng2-translate.

ng2-translate


ngx-translate.com

It is the indirect heir to the well-known angular-translate module.
Also uses the translate filter. In addition, translation texts are stored in JSON files in the same format as in angular-translate.

All this makes it very easy to transfer patterns from ng1 to ng2. In essence, all that is required is to do the following:

Add dependency to the application module in the src / app / app.module.ts file

 import { HttpModule, Http } from '@angular/http'; import { TranslateModule, TranslateLoader, TranslateStaticLoader } from 'ng2-translate/ng2-translate'; @NgModule({ ... imports: [ ... HttpModule, TranslateModule.forRoot({ provide: TranslateLoader, //       i18n      useFactory: (http: Http) => new TranslateStaticLoader(http, '/assets/i18n', '.json'), deps: [Http] }) ], providers: [], bootstrap: [AppComponent] }) 

The above example of loading dependencies is relevant for the 5th version of ng2-translate .

The module itself connects JSON files located in the i18n folder. Therefore, manually importing them is not required.

It is also necessary to specify the used language in the root component:

 import {TranslateService} from 'ng2-translate'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { title = 'app works!'; constructor(translate: TranslateService) { // this language will be used as a fallback when a translation isn't found in the current language translate.setDefaultLang('ru'); // the lang to use, if the lang isn't available, it will use the current loader to get them translate.use('ru'); } } 

Actually this is all that is needed. The module is ready for operation.

The JSON file format is very simple (key: translation):

 { "HELLO": "" } 

Further, in HTML, you can respectively use translate in the following forms:

 <div>{{'HELLO' | translate}}</div> <div [translate]="'HELLO'" [translateParams]="{value: 'world'}"></div> <div translate [translateParams]="{value: 'world'}">HELLO</div> 

You can also use TranslateService in components.

Update (4.3.2017):

Literally the day before, the 6th version was released, in which ng2-translate was renamed to ngx-translate to comply with the official convention.

In addition, fundamental changes have occurred . The only TranslateStaticLoader was rendered into a standalone module and renamed to TranslateHttpLoader. Accordingly, the syntax for loading a module in app.module.ts is as follows:

 import { HttpModule, Http } from '@angular/http'; import {TranslateModule, TranslateLoader} from "@ngx-translate/core"; // import {TranslateHttpLoader} from "@ngx-translate/http-loader"; // @NgModule({ ... imports: [ ... HttpModule, TranslateModule.forRoot({ provide: TranslateLoader, //       i18n      useFactory: (http: Http) => new TranslateHttpLoader(http, "i18n/", ".json"), // deps: [Http] }) ], providers: [], bootstrap: [AppComponent] }) 

Source: https://habr.com/ru/post/323180/


All Articles