Home

Awesome

ngx-easy-i18n-js

Pure version angular for internalization (i18n).

Translations are static. If you change language you must refresh the page or use bootstrap extension.

Use EasyI18 Js library https://github.com/gabrie-allaigre/easy-i18n-js

Download and Installation

Install using npm:

npm install easy-i18n-js @ngx-easy-i18n-js/core --save

Open angular.json and under allowedCommonJsDependencies add:

"allowedCommonJsDependencies": [
"easy-i18n-js"
]

Usage in app.module.ts, add imports

import localeFr from '@angular/common/locales/fr';
import localeEn from '@angular/common/locales/en';

imports: [
  EasyI18nModule.forRoot({
    options: {
      logging: false
    },
    ngLocales: {
      'fr': localeFr,
      'en': localeEn,
    },
    defaultLanguage: 'en-US'
  })
]

Configuration

export interface EasyI18nModuleConfig {
  // Options fo easy i18 js library
  options?: EasyI18nOptions;
  // Use specific loader
  loader?: Provider;
  // Add Angular locale <code>import localeFr from '@angular/common/locales/fr';</code>
  ngLocales?: { [key: string]: any; };
  // Use browser language
  useBrowserLanguage?: boolean;
  // Default fallback language use if current language not found
  defaultLanguage?: string;
  // <code>exact</code> only fr-FR, <code>minimum</code> only fr, <code>all</code> fr-FR and fr
  discover?: 'exact' | 'minimum' | 'all';
}

In child module

imports: [
  EasyI18nModule
]

For change current locale use EasyI18nService

export class MyComponent {

  constructor(
    private easyI18nService: EasyI18nService
  ) {
  }

  public doChangeLanguage(locale: string): void {
    this.easyI18nService.registerCulture('fr');
  }
}

Force reload if change culture

 this.easyI18nService.registerCulture('fr', { reload: true });

Locale pipes

In HTML, uses locales pipes to get dates, numbers in locale format

pipedescriptionexample
localeDateSame as date<code>{{ mydate | localeDate:'short' }}</code>
localeNumberSame as number<code>{{ mydate | localeNumber }}</code>
localeCurrencySame as currency<code>{{ mydate | localeCurrency }}</code>
localePercentSame as percent<code>{{ mydate | localePercent }}</code>

Translate

Main function for translate your language keys

HTML file

In HTML template, with pipe, parameter is TrOptions

{{ 'hello' | tr }}
{{ 'hello_with_genre' | tr: { gender: 'male' } }}
{{ 'My name is {}' | tr: { args: ['Gabriel'] } }}

TrOptions arguments

Nametypeexample
argsstring[]['Gabriel', '20']
namedArgs{ [key: string]: string; } }{ name : 'Gabriel', age : '20' }
namespacestring'common'
gender<code>'male' | 'female' | 'other'</code>gender: 'other'

Directives

There are 2 differents directives

First is simple, translate [tr]

Directivedescriptionexample
trActive directive translate<code><span tr>hello</span></code>
trNamespaceAdd namespace<code><span tr trNamespace="common">hello</span></code>
trKeySet key (if empty use content)<code><span tr trKey="hello" trNamespace="common"></span></code>
trGenderGender<code><span tr trGender="male">hello_with_genre</span></code>
trArgsArguments<code><span tr [trArgs]="['Gabriel']">hello</span></code>
trNamedArgsNamed arguments<code><span tr [trNamedArgs]="{ name: 'Gabriel' }">hello</span></code>

Second, use HTML named arguments [trContent], replace {namedArg} with child element *trElement

Directivedescription
trContentActive content directive translate, get a key
trNamespaceAdd namespace
trGenderGender
trArgsArguments
trNamedArgsNamed arguments
demarcChange token start, end identifier

Examples

<!-- "hello_name": "My name is {name}" -->
<div trContent="hello_name">
    <span *trElement="'name'" style="color: red; font-size: 2rem; font-weight: bold">Gabriel</span>
</div>

<div trContent="My name is {name} and I live in {country}" style="color: blue;">
    <span *trElement="'name'" style="color: red; font-size: 2rem; font-weight: bold">Gabriel</span>
    <span *trElement="'country'">{{ var_country }}</span>
</div>

Typescript file

You can use extension methods of [String], you can also use tr() as a static function.

In typescript file, there is no need to inject EasyI18nService

'hello'.tr();
'hello_with_genre'.tr({ gender: 'male' });
tr('hello');
tr('hello_with_genre', { gender: 'male' });

Translate Plural

You can translate with pluralization. To insert a number in the translated string, use {}.

HTML file

In HTML template, with pipe, first parameter is number and second PluralOptions

{{ 'money' | plural:10 }}
{{ 'money_with_args' | plural:3: { args: ['Gabriel'] } }}

PluralOptions arguments

Nametypeexample
argsstring[]['Gabriel', '20']
namedArgs{ [key: string]: string; } }{ name : 'Gabriel', age : '20' }
namespacestring'common'
namestringmoney
numberFormatterFn(value: number) => string(value) => value.Precision(3)
gender<code>'male' | 'female' | 'other'</code>gender: 'other'

Directives

There are 2 different directives

First is simple, translate plural [plural]

Directivedescriptionexample
pluralActive directive translate<code><span [plural]="10">money</span></code>
pluralNamespaceAdd namespace<code><span [plural]="100" pluralNamespace="common">money</span></code>
pluralKeySet key (if empty use content)<code><span [plural]="100" pluralKey="money" pluralNamespace="common"></span></code>
pluralGenderGender<code><span [plural]="1" pluralGender="male">money_with_genre</span></code>
pluralArgsArguments<code><span [plural]="5" [pluralArgs]="['Gabriel']">money</span></code>
pluralNamedArgsNamed arguments<code><span [plural]="13" [pluralNamedArgs]="{ name: 'Gabriel' }">money</span></code>
pluralNameName value<code><span [plural]="4" pluralName="value">money</span></code>
pluralNumberFormatterFnFormatter function<code><span [plural]="10000" [pluralNumberFormatterFn]="myFn">money</span></code>

Second, use HTML named arguments [pluralContent], replace {namedArg} with child element *pluralElement

Directivedescription
pluralContentActive content directive translate, get a key
pluralValueActive content directive translate, get a value
pluralNamespaceAdd namespace
pluralGenderGender
pluralArgsArguments
pluralNamedArgsNamed arguments
pluralNameName value
pluralNumberFormatterFnFormatter function
demarcChange token start, end identifier

Examples

<!-- "money_content": { 
    "zero": "{name} not have money",
    "one": "{name} have {money} dollar",
    "two": "{name} have {money} dollars",
    "many": "{name} have {money} dollars",
    "other": "{name} have {money} dollars"
} -->
<div pluralContent="money_content" [pluralValue]="var_money" class="fst-italic text-gray-500">
    <span *pluralElement="'name'" style="color: red; font-size: 2rem; font-weight: bold">Gabriel</span>
    <span *pluralElement="'money'" style="color: blueviolet; font-weight: bold"
          [style.font-size]="(var_money / 10) + 'vw'">{{ var_money }}</span>
</div>

Typescript file

You can use extension methods of [String], you can also use plural() as a static function.

In typescript file, there is no need to inject EasyI18nService

'money_args'.plural(0, { args: ['Gabriel'] });
'money_args'.plural(1.5, { args: ['Gabriel'] });
plural('money_args', { args: ['Gabriel'] });

Store

Default store is EmptyEasyI18nStore

Use localStorage store, usage in app.module.ts, add provider

providers: [
  {
    provide: EasyI18nStore,
    useFactory: () => new LocalStorageEasyI18nStore('current-lang')
  }
]

Add HttpLoader

Standard

Load messages with HttpClient

Install using npm:

npm install @ngx-easy-i18n-js/http-loader --save

Usage in app.module.ts, add provider

providers: [
  {
    provide: EasyI18nLoader,
    deps: [HttpClient],
    useFactory: (httpClient: HttpClient) => new HttpEasyI18nLoader(httpClient)
  }
]

Change prefix or suffix with options

new HttpEasyI18nLoader(httpClient, {
  prefix: 'assets/',
  suffix: '.json5'
});
new HttpEasyI18nLoader(httpClient, {
  prefix: ['assets/common/i18n', 'assets/i18n'],
  suffix: '.json5'
});

Scoped loader

Load multiples files with scope

Usage in app.module.ts, add provider

providers: [
  {
    provide: EasyI18nLoader,
    deps: [HttpClient],
    useFactory: (httpClient: HttpClient) => new ScopedHttpEasyI18nLoader(httpClient, [
      { prefix: `/assets/i18n/` },
      { prefix: ['assets/common/i18n', 'assets/i18n/common'], scope: 'common' },
      { prefix: `/assets/i18n/errors/`, scope: 'errors' }
    ])
  }
]
{{ 'common.save' | tr }}
{{ 'errors.internal_server_error' | tr }}

Change suffix

new ScopedHttpEasyI18nLoader(httpClient, [
    { prefix: `/assets/i18n/` }
  ], {
  suffix: '.json5'
});

Append scoped loader for lazy routes

const routes: Routes = [
  {
    path: 'login',
    loadChildren: () => import('./login/login.module').then(m => m.LoginModule),
    canActivate: [
      appendScopedHttpEasyI18nLoader([
        { prefix: `/assets/i18n/login/`, scope: 'login' }
      ])
    ]
  }
];

Add Bootstrap

Bootstrap application, refresh application when culture change without reload page

Install using npm:

npm install @angular/cdk @ngx-easy-i18n-js/bootstrap --save

Usage

imports: [
  EasyI18nBootstrapModule.forRoot({
    bootstrap: AppComponent
  })
]

bootstrap: [EasyI18nBootstrapComponent]

And in index.html, replace <app-root></app-root> by <ngx-easy-i18n></ngx-easy-i18n>

For custom loading component

imports: [
  EasyI18nBootstrapModule.forRoot({
    bootstrap: AppComponent,
    loadingComponent: MyLoadingComponent
  })
]

bootstrap: [EasyI18nBootstrapComponent]