Skip to content

A speculative polyfill to support i18n code translations in Angular

License

Notifications You must be signed in to change notification settings

ngx-translate/i18n-polyfill

Repository files navigation

@ngx-translate/i18n-polyfill Travis Status npm version

Extraction tool + service to add support for code translations in Angular using the same implementation that is used for template translations.

Out of Date: You should use @angular/localize

Angular 9 now supports code based localization via

$localize:`meaning|description@@id:message`

Locl is the new tool that lets you extract the string from your files (since angular CLI again does not support it yet)

Migration

  1. Replace all occurrences with the new syntax:
    • You can use this regex in VSCode: Search:
      (.*)this\.i18n\(\{\n[\s\/]*meaning:[\s\n]*'(.*)',\n[\s\/]*description:[\s\n]*'(.*)',\n[\s\/]*id:[\s\n]*'(.*)',\n[\s\/]*value:[\s\n]*['`](.*)['`]\n[\s\/]*\}\)
      
      Replace:
      $1$localize`:$5|$3@@$4:$2`
      
  2. Remove all i18n usings such as:
import { I18n } from '@ngx-translate/i18n-polyfill';
private i18n: I18n

Some Caveats:

  • be aware of existing tranlation functions that are named differently or whose attributes are in a different order
  • be aware that meaning, description and id can no longer contain :-symbol
  • be aware that message should not contain ```

⚠️ Disclamer

This library is a speculative polyfill, it means that it's supposed to replace an API that is coming in the future. Once code translations are available in Angular, this library will be deprecated. But since it's a polyfill, we expect the API to be pretty similar. If the API is different, a migration tool will be provided if it's possible and necessary.

Installation

To install this library, run:

$ npm install @ngx-translate/i18n-polyfill --save

How to use

The API is quite simple, you get a service called I18n that takes 2 parameters: the content to translate and the parameters (optional). It'll return the content translated synchronously. The signature of the service is:

I18n: (def: string | I18nDef, params?: {[key: string]: any}) => string.

The content can be a simple string or an i18n definition:

I18nDef: {
  value: string;
  id?: string;
  meaning?: string;
  description?: string;
}

Prepare your application to use i18n, as described on the official documentation, and then provide the TRANSLATIONS file and I18n service in your module or component:

import { BrowserModule } from '@angular/platform-browser';
import {
  NgModule,
  TRANSLATIONS
} from '@angular/core';

import { AppComponent } from './app.component';

// Import the service
import { I18n } from '@ngx-translate/i18n-polyfill';

declare const require; // Use the require method provided by webpack
const translations = require(`raw-loader!../locale/messages.fr.xlf`).default;

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [
    {provide: TRANSLATIONS, useValue: translations},
    I18n
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

To dynamically load the translations file based on locale you can use a factory provider.

Replace

{provide: TRANSLATIONS, useValue: translations}

with:

{
  provide: TRANSLATIONS,
  useFactory: (locale) => {
    locale = locale || 'en'; // default to english if no locale provided
    return require(`raw-loader!../locale/messages.${locale}.xlf`).default;
  },
  deps: [LOCALE_ID]
}

Once the I18n service and TRANSLATIONS are imported & provided, you can use the service in your Angular application:

import { Component } from "@angular/core";
import { I18n } from "@ngx-translate/i18n-polyfill";

@Component({
  selector: "app-root",
  template: "./app.component.html"
})
export class AppComponent {
  constructor(i18n: I18n) {
    console.log(i18n("This is a test {{myVar}} !", {myVar: "^_^"}));
  }
}

Content supported

You can use strings, interpolations and ICU expressions exactly like in template translations. Don't use elements, it makes no sense and you should use a template translation for that instead.

Interpolations will be replaced by the values that you provide in the object that you pass as the second parameter of the service. You should use the same names for your keys than the ones that you use in your interpolations. For example: i18n("This is a test {{myVar}} !", {myVar: "^_^"})

Extraction

There is an extraction tool called ngx-extractor that will extract the messages. You should first extract the messages from the templates using the ng-xi18n extraction tool from @angular/compiler-cli which will create an xliff or xmb file, and then run ngx-extractor on the same file to add the messages extracted from your code. The messages will be merged.

The cli parameters are the following:

  • --input (alias: -i, required): Paths you would like to extract strings from. You can use path expansion, glob patterns and multiple paths.

    Example: -i src/**/*.ts.

  • --format (alias -f, optional, default xlf): Output format, either xlf, xlf2 or xmb.

    Example: -f xlf.

  • --outFile (alias -o, required): Path and name of the file where you would like to save extracted strings. If the file exists then the messages will be merged.

    Example: -o src/i18n/source.xlf.

  • --locale (alias -l, optional, default: en): Source language of the application.

    Example: -l de.

And here is how you would extract the messages from your ng cli application to a file named src/i18n/source.xlf:

  • run ng-xi18n: ng xi18n -of i18n/source.xlf -f xlf --locale en
  • run ng-extractor: ngx-extractor -i src/**/*.ts -f xlf -o src/i18n/source.xlf

Special thanks

The service was written using source code from Angular and the extraction tool used code from ngx-translate-extract by @biesbjerg.

License

MIT © Olivier Combe