dictionary content:
{}
Pure Angular 2+ localization (l10n) library.
or
To install this component to an external project, follow the procedure:
npm install @iplab/ngx-l10n --save
import { L10nModule, L10nService } from '@iplab/ngx-l10n'; ... ... @Injectable() export class LocalizationResolve implements Resolve<any> { constructor(private localization: L10nService){ this.localization.languageChanges.subscribe(({ code }) => { /** * second parameter is used if we don't want to merge result set * to previus one, use this only if in memory we want to store only * one language */ this.localization.setFromFile(`${code}.locales.properties`, false); }) } public resolve(): Observable<any>|Promise<any> { return this.localization.setFromFile(`${this.localization.languageCode}.locales.properties`); } } @NgModule({ imports: [ BrowserModule, L10nModule.forRoot({ config: {defaultLanguage: LanguageCodes.EnglishUnitedStates} }), RouterModule.forRoot([ { path: '', component: AppComponent, resolve: { localization: LocalizationResolve }} ]) ], providers: [LocalizationResolve], bootstrap: [AppComponent] }) export class AppModule {}
By default, if you want to load .properties, .po or .json files you don't need to configure anything.
But depending on your needs, you can write your own loader, parser or storage provider,
also it is possible to write custom formatter and error handler
import { IL10nLoaderResponse, IL10nFileRequest, L10nBaseLoader, L10nBaseStorage, L10nBaseParser, L10nBaseFormatter, L10nBaseErrorHandler, LanguageCodes } from '@iplab/ngx-l10n'; @Injectable() export class CustomLoader extends L10nBaseLoader { constructor( private http: HttpClient ){ super(); } public getFile({ url, code }: IL10nFileRequest ): Observable<IL10nLoaderResponse> { let subject = new Subject<IL10nLoaderResponse>(); let fileType = this.getFileExtension( url ); ... return subject.asObservable(); } } @Injectable() export class CustomStorage extends L10nBaseStorage { public getSentance( key: string ): string { return this._dictionary[key]; } public setSentence( key: string, sentence: string ): void { this._dictionary[ key ] = sentence; } } @Injectable() export class CustomParser extends L10nBaseParser { public parse( response: any, fileType: string ): Observable<{ key: string; sentence: string }> {} } @Injectable() export class CustomFormatter extends L10nBaseFormatter { public abstract interpolate(sentence: string, args: IL10nArguments): string; } @Injectable() export class CustomErrorHandler extends L10nBaseErrorHandler { public abstract handleError(error: any): void; } @NgModule({ imports: [ BrowserModule, // each config property is optional L10nModule.forRoot({ loader: CustomLoader, storage: CustomStorage, parser: CustomParser, formatter: CustomFormatter, errorHandler: CustomErrorHandler, config: { defaultLanguage: LanguageCodes.EnglishUnitedStates, bindingProperty: 'textContent' } }) ], providers: [CustomLoader, CustomStorage, CustomParser, CustomFormatter], bootstrap: [AppComponent] }) export class AppModule {}
Once you've configurated L10n module, you can put your translations to file/s or use existing one.
.properties
app.hello.key = Hello ${value}
.po
msgid "app.hello.key" msgstr "Hello ${value}"
.json
{ "app.hello.key": "Hello ${value}" }
default defined interpolations are ${ } or {{ }} or { }.
Hello ${value} => L10nService.get('app.hello.key', {value: "world"}) => Hello world Hello ${0} => L10nService.get('app.hello.key', ["world"]) => Hello world
Hello {value} => L10nService.get('app.hello.key', {value: "world"}) => Hello world Hello {0} => L10nService.get('app.hello.key', ["world"]) => Hello world
Hello {{value}} => L10nService.get('app.hello.key', {value: "world"}) => Hello world Hello {{0}} => L10nService.get('app.hello.key', ["world"]) => Hello world
It is possible to change default interpolations with something custom
import { L10nModule, L10nBaseFormatter, defineInterpolation, IL10nArguments } from '@iplab/ngx-l10n'; @Injectable() export class CustomFormatter extends L10nBaseFormatter { public interpolate(sentence: string, args: IL10nArguments): string { return sentence.replace( defineInterpolation(['[[', ']]']), (match, interpolates) => { if (!IsNullOrEmpty(args)) { return args[this.trim(interpolates)]; } return match; }); } } @NgModule({ imports: [ ..., L10nModule.forRoot({ formatter: CustomFormatter }) ] }) export class AppModule {}
app.hello.key = Hello [[value]]
possible is to use other key from dictionary as value
app.world.key = world app.hello.key = Hello ${app.world.key} L10nService.get('app.hello.key') => Hello world
when setting up a dictionary it is possible to use three built-in methods, setFromObject(), setFromFile() or set()
L10nService.setFromObject({ 'app.hello.key': 'Hello ${app.hello.world}', 'app.hello.world': 'world' });
L10nService.setFromFile('http://some.url');
L10nService.set('app.hello.key', 'Hello world!');
you can use Ln10 service:
let translation = L10nService.get('app.hello.key', { value: 'world' }); console.log( translation ); => Hello world
it's possible to observe changes on specific key, an observer will also initially return a translated value
let subscription = L10nService.observe('app.hello.key', { value: 'world' }) .subscribe((sentence) => { console.log( sentence ); });
directive by default use HTMLElement.textContent as property for translation,
and this is how you use it:
<div l10n="app.hello.key" [l10n-args]="params"></div> <div l10n="app.hello.key" [l10n-args]="{value: 'world'}"></div> <div l10n="app.hello.key" l10n-args="{value: 'world'}"></div> <div [l10n]="'app.hello.key'" [l10n-args]="params"></div> <div [l10n]="'app.hello.key'" l10n-args="{value: 'world'}"></div>
l10n-args can be property in component or inline written JSON
also easily you can use the pipe
<div>{{'app.hello.key' | l10n:param }}</div> <div [innerHTML]="'app.hello.key' | l10n"></div> <div>{{'app.hello.key' | l10n: {'key': 'value'} }}</div>
param can be property in component or inline written JSON
To configure and use with NativeScript is easy
tns plugin add @iplab/ngx-l10n
Now we need to prepare custom File loader and Localization resolver
import { L10nModule, L10nService, L10nBaseLoader } from '@iplab/ngx-l10n'; import { knownFolders } from "file-system"; import { Subject, Observable, from } from 'rxjs'; import { map } from 'rxjs/operators'; import { Resolve } from "@angular/router"; ... import { NativeScriptModule } from "nativescript-angular/nativescript.module"; import { NativeScriptRouterModule } from "nativescript-angular/router"; ... ... @Injectable() export class CustomLoader extends L10nBaseLoader { private readonly folderName = 'locales'; // folder where you place your locale files, // in our case that is locales/en.locales.properties private readonly documents = knownFolders.currentApp(); private readonly folder = this.documents.getFolder(this.folderName); public getFile({ url, code }: IL10nFileRequest ): Observable<IL10nLoaderResponse> { let fileType = this.getFileExtension( url ); let file = this.folder.getFile(url); return from(file.readText()) .pipe(map((response) => { return { response, fileType } })); } } @Injectable() export class LocalizationResolve implements Resolve<any> { constructor(private localization: L10nService){ this.localization.languageChanges.subscribe(({ code }) => { this.localization.setFromFile(`${code}.locales.properties`); }) } public resolve(): Observable<any>|Promise<any> { return this.localization.setFromFile(`${this.localization.languageCode}.locales.properties`); } } @NgModule({ imports: [ NativeScriptModule, L10nModule.forRoot({ config: {defaultLanguage: LanguageCodes.EnglishUnitedStates, bindingProperty: 'text' }, loader: CustomLoader }), NativeScriptRouterModule.forRoot([ { path: '', component: AppComponent, resolve: { localization: LocalizationResolve }} ]) ], providers: [ LocalizationResolve, L10nService, // because currently NativeScript doesn't work with @Injectable({ providedIn: 'root' }) CustomLoader ], bootstrap: [AppComponent] }) export class AppModule {}
Use case is same as it is for HTML
<ActionBar title="{{ 'app.header.title' | l10n }}" class="action-bar"></ActionBar>
Property | Type | Description |
---|---|---|
language | Setter.String | Used to set language |
language | Getter.String | Return language ISO code |
languageCode | Getter.String | Return language code from ISO string |
direction | Getter.String | Return direction (ltr|rtl) of the current language |
dictionary | Getter.Object | Return dictionary object |
get | Function | Used to return localized word |
observe | Function.Observable | Used to return the localized word and observe any changes on it |
set | Function.Void | Used to add word by word to dictionary |
setFromObject | Function.Promise | Used to add words to dictionary |
setFromFile | Function.Promise | Used to add words to dictionary |
clear | Function.Void | Used to clear dictionary storage and maped urls by loader class |
languageChanges | Getter.Observable | Used to observe language change |
dictionaryReady | Getter.Observable | Used to be notified when data are loaded, parsed and mapped in dictionary |