All Projects → robisim74 → Angular L10n

robisim74 / Angular L10n

Licence: mit
An Angular library to translate texts, dates and numbers

Programming Languages

typescript
32286 projects

Projects that are alternatives of or similar to Angular L10n

React Translated
A dead simple way to add complex translations (i18n) in a React (DOM/Native) project 🌎🌍🌏
Stars: ✭ 176 (-49.71%)
Mutual labels:  localization, translate
React Intl Hooks
React hooks for internationalization without the hassle ⚛️🌍
Stars: ✭ 64 (-81.71%)
Mutual labels:  localization, translate
Fluent
Fluent — planning, spec and documentation
Stars: ✭ 818 (+133.71%)
Mutual labels:  localization, translate
EzLocalization
Localize your flutter application quickly and easily.
Stars: ✭ 13 (-96.29%)
Mutual labels:  localization, translate
learnrxjs
Русскоязычная документация RxJS
Stars: ✭ 20 (-94.29%)
Mutual labels:  localization, translate
Flutter translate
Flutter Translate is a fully featured localization / internationalization (i18n) library for Flutter.
Stars: ✭ 245 (-30%)
Mutual labels:  localization, translate
Texterify
The localization management system.
Stars: ✭ 37 (-89.43%)
Mutual labels:  localization, translate
pdx-ymltranslator
Paradox Interactive YML Translator
Stars: ✭ 18 (-94.86%)
Mutual labels:  localization, translate
sketch-crowdin
Connect your Sketch and Crowdin projects together
Stars: ✭ 35 (-90%)
Mutual labels:  localization, translate
react-translator-component
React language translation module for developing a multilingual project.
Stars: ✭ 13 (-96.29%)
Mutual labels:  localization, translate
Icu4x
Solving i18n for client-side and resource-constrained environments.
Stars: ✭ 275 (-21.43%)
Mutual labels:  localization
Geomapnet
Geometry-Aware Learning of Maps for Camera Localization (CVPR2018)
Stars: ✭ 281 (-19.71%)
Mutual labels:  localization
Deep Learning Localization Mapping
A collection of deep learning based localization models
Stars: ✭ 300 (-14.29%)
Mutual labels:  localization
Hdl localization
Real-time 3D localization using a (velodyne) 3D LIDAR
Stars: ✭ 332 (-5.14%)
Mutual labels:  localization
Resnetcam Keras
Keras implementation of a ResNet-CAM model
Stars: ✭ 269 (-23.14%)
Mutual labels:  localization
Gatsby Plugin Intl
Gatsby plugin that turns your website into an internationalization-framework out of the box.
Stars: ✭ 300 (-14.29%)
Mutual labels:  localization
Tower
i18n & L10n library for Clojure/Script
Stars: ✭ 264 (-24.57%)
Mutual labels:  localization
Docs L10n
Translations of TensorFlow documentation
Stars: ✭ 262 (-25.14%)
Mutual labels:  localization
Identityserver4aspnetcoreidentitytemplate
An ASP.NET Core 3.1 IdentityServer4 Identity Bootstrap 4 template with localization
Stars: ✭ 262 (-25.14%)
Mutual labels:  localization
Ai Imu Dr
AI-IMU Dead-Reckoning
Stars: ✭ 337 (-3.71%)
Mutual labels:  localization

Angular l10n

Build Status npm version npm npm

An Angular library to translate texts, dates and numbers

This library is for localization of Angular apps. It allows, in addition to translation, to format dates and numbers through Internationalization API

Documentation

Angular l10n Specification

Architecture

Architecture

Table of Contents

Installation

npm install angular-l10n --save 

Usage

You can find a complete sample app here, and a live example on StackBlitz.

Configuration

Create the configuration:

export const l10nConfig: L10nConfig = {
    format: 'language-region',
    providers: [
        { name: 'app', asset: i18nAsset }
    ],
    cache: true,
    keySeparator: '.',
    defaultLocale: { language: 'en-US', currency: 'USD' },
    schema: [
        { locale: { language: 'en-US', currency: 'USD' }, dir: 'ltr', text: 'United States' },
        { locale: { language: 'it-IT', currency: 'EUR' }, dir: 'ltr', text: 'Italia' }
    ]
};

export function initL10n(l10nLoader: L10nLoader): () => Promise<void> {
    return () => l10nLoader.init();
}

const i18nAsset = {
    'en-US': {
        greeting: 'Hello world!',
        whoIAm: 'I am {{name}}',
        one: 'software developer'
    },
    'it-IT': {
        greeting: 'Ciao mondo!',
        whoIAm: 'Sono {{name}}',
        one: 'sviluppatore software'
    }
};

Import the modules and the configuration:

@NgModule({
    ...
    imports: [
        ...
        L10nTranslationModule.forRoot(l10nConfig),
        L10nIntlModule
    ],
    providers: [
        {
            provide: APP_INITIALIZER,
            useFactory: initL10n,
            deps: [L10nLoader],
            multi: true
        }
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

Getting the translation

Pure Pipes

<p title="{{ 'greeting' | translate:locale.language }}">{{ 'greeting' | translate:locale.language }}</p>
<p>{{ 'whoIAm' | translate:locale.language:{ name: 'Angular l10n' } }}</p>

<p>{{ today | l10nDate:locale.language:{ dateStyle: 'full', timeStyle: 'short' } }}</p>
<p>{{ timeAgo | l10nTimeAgo:locale.language:'second':{ numeric:'always', style:'long' } }}</p>

<p>{{ value | l10nNumber:locale.language:{ digits: '1.2-2', style: 'currency' } }}</p>

<p>1 {{ 1 | l10nPlural:locale.language }}</p>

<button *ngFor="let item of schema"
    (click)="setLocale(item.locale)">{{ item.locale.language | l10nDisplayNames:locale.language:{ type: 'language' } }}</button>

Pure pipes need to know when the locale changes. So import L10nLocale injection token in the component:

export class AppComponent {

    constructor(@Inject(L10N_LOCALE) public locale: L10nLocale) { }

}
OnPush Change Detection Strategy

To support this strategy, there is an async version of each pipe:

<p>{{ 'greeting' | translateAsync }}</p>

Directives

<p l10n-title title="greeting" l10nTranslate>greeting</p>
<p [params]="{ name: 'Angular l10n' }" l10nTranslate>whoIAm</p>
<!-- <p [l10nTranslate]="{ name: 'Angular l10n' }">whoIAm</p> -->

<p [options]="{ dateStyle: 'full', timeStyle: 'short' }" l10nDate>{{ today }}</p>
<p [options]="{ numeric:'always', style:'long' }" unit="second" l10nTimeAgo>{{ timeAgo }}</p>

<p [options]="{ digits: '1.2-2', style: 'currency' }" l10nNumber>{{ value }}</p>

You can dynamically change parameters and expressions values as with pipes, but not in attributes.

APIs

export class AppComponent implements OnInit {

    constructor(private translation: L10nTranslationService, private intl: L10nIntlService) { }

    ngOnInit() {
        this.translation.onChange().subscribe({
            next: () => {
                this.greeting = this.translation.translate('greeting');
                this.whoIAm = this.translation.translate('whoIAm', { name: 'Angular l10n' });

                this.formattedToday = this.intl.formatDate(this.today, { dateStyle: 'full', timeStyle: 'short' });
                this.formattedTimeAgo = this.intl.formatRelativeTime(this.timeAgo, 'second', { numeric: 'always', style: 'long' });
                this.formattedValue = this.intl.formatNumber(this.value, { digits: '1.2-2', style: 'currency' });
                this.formattedOnePlural = this.intl.plural(1);
            }
        });
    }

}

The L10nIntlService also provides methods for other Intl APIs, such as Collator & ListFormat.

Customize the library

The following features can be customized. You just have to implement the indicated class-interface and pass the token during configuration.

E.g.

@Injectable() export class HttpTranslationLoader implements L10nTranslationLoader {

    private headers = new HttpHeaders({ 'Content-Type': 'application/json' });

    constructor(@Optional() private http: HttpClient) { }

    public get(language: string, provider: L10nProvider): Observable<{ [key: string]: any }> {
        const url = `${provider.asset}-${language}.json`;
        const options = {
            headers: this.headers,
            params: new HttpParams().set('v', provider.options.version)
        };
        return this.http.get(url, options);
    }

}

export const l10nConfig: L10nConfig = {
    ...
    providers: [
        { name: 'app', asset: './assets/i18n/app', options: { version: '1.0.0' } },
    ],
    ...
};

@NgModule({
    ...
    imports: [
        ...
        L10nTranslationModule.forRoot(
            l10nConfig,
            {
                translationLoader: HttpTranslationLoader
            }
        )
    ],
    ...
})
export class AppModule { }

Storage

By default, the library does not store the locale. To store it implement the L10nStorage class-interface, so that the next time the user has the locale he selected.

User Language

By default, the library attempts to set the locale using the user's browser language, before falling back on the default locale. You can change this behavior by implementing the L10nUserLanguage class-interface, for example to get the language via server.

Translation Loader

By default, you can only pass JavaScript objects as translation data provider. To implement a different loader, you can implement the L10nTranslationLoader class-interface, as in the example above.

Translation Fallback

You can enable translation fallback during configuration:

export const l10nConfig: L10nConfig = {
    ...
    fallback: true,
    ...
};

By default, the translation data will be merged in the following order:

  • 'language'
  • 'language[-script]'
  • 'language[-script][-region]'

To change it, implement the L10nTranslationFallback class-interface.

Translation Handler

By default, the library only parse the params. L10nTranslationHandler is the class-interface to implement to modify the behavior.

Missing Translation Handler

If a key is not found, the same key is returned. To return a different value, you can implement the L10nMissingTranslationHandler class-interface.

Validation

There are two directives, that you can use with Template driven or Reactive forms: l10nValidateNumber and l10nValidateDate. To use them, you have to implement the L10nValidation class-interface, and import it with the validation module:

@Injectable() export class LocaleValidation implements L10nValidation {

    constructor(@Inject(L10N_LOCALE) private locale: L10nLocale) { }

    public parseNumber(value: string, options?: L10nNumberFormatOptions, language = this.locale.numberLanguage || this.locale.language): number | null {
        ...
    }

    public parseDate(value: string, options?: L10nDateTimeFormatOptions, language = this.locale.dateLanguage || this.locale.language): Date | null {
        ...
    }

}

@NgModule({
    ...
    imports: [
        ...
        L10nValidationModule.forRoot({ validation: LocaleValidation })
    ],
    ...
})
export class AppModule { }

Routing

You can enable the localized routing importing the routing module after others:

@NgModule({
    ...
    imports: [
        ...
        L10nRoutingModule.forRoot()
    ],
    ...
})
export class AppModule { }

A prefix containing the language is added to the path of each navigation, creating a semantic URL:

baseHref/[language][-script][-region]/path

https://example.com/en/home
https://example.com/en-US/home

If the localized link is called, the locale is also set automatically.

To achieve this, the router configuration in your app is not rewritten: the URL is replaced, in order to provide the different localized contents both to the crawlers and to the users that can refer to the localized links.

If you don't want a localized routing for default locale, you can enable it during the configuration:

export const l10nConfig: L10nConfig = {
    ...
    defaultRouting: true
};

You can change the localized path, implementing the L10nLocation class-interface, and import it with the routing module:

@Injectable() export class AppLocation implements L10nLocation {

    public path(): string {
        ...
    }

    public parsePath(path: string): string | null {
        ...
    }

    public getLocalizedSegment(path: string): string | null {
        ...
    }

    public toLocalizedPath(language: string, path: string): string {
        ...
    }

}

@NgModule({
    ...
    imports: [
        ...
        L10nRoutingModule.forRoot({ location: AppLocation })
    ],
    ...
})
export class AppModule { }

Lazy loading

If you want to add new providers to a lazy loaded module, you can use L10nResolver in your routing module:

const routes: Routes = [
    ...
    {
        path: 'lazy',
        loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule),
        resolve: { l10n: L10nResolver },
        data: {
            l10nProviders: [{ name: 'lazy', asset: './assets/i18n/lazy', options: { version: '1.0.0' } }]
        }
    }
];

Always import the modules you need:

@NgModule({
    declarations: [LazyComponent],
    imports: [
        ...
        L10nTranslationModule
    ]
})
export class LazyModule { }

Caching

Enable caching during configuration if you want to prevent reloading of the already loaded translation data:

export const l10nConfig: L10nConfig = {
    ...
    cache: true
};

Preloading data

If you need to preload some translation data, for example to use for missing values, L10nTranslationService exposes the translation data in the data attribute. You can merge data by calling the addData method:

export function l10nPreload(translation: L10nTranslationService, translationLoader: L10nTranslationLoader): () => Promise<void> {
    return () => new Promise((resolve) => {
        translationLoader.get('en-US', { name: 'app', asset: './assets/i18n/app', options: { version: '1.0.0' } })
            .subscribe({
                next: (data) => translation.addData(data, 'en-US'),
                complete: () => resolve()
            });
    });
}

Then add the function to providers, before initL10n:

providers: [
    {
        provide: APP_INITIALIZER,
        useFactory: l10nPreload,
        deps: [L10nTranslationService, L10nTranslationLoader],
        multi: true
    },
    ...
],

Types

Angular l10n types that it is useful to know:

  • L10nLocale: contains a language, in the format language[-script][-region][-extension], where:

    • language: ISO 639 two-letter or three-letter code
    • script: ISO 15924 four-letter script code
    • region: ISO 3166 two-letter, uppercase code
    • extension: 'u' (Unicode) extensions

    Optionally:

    • dateLanguage: alternative language to translate dates
    • numberLanguage: alternative language to translate numbers
    • currency: ISO 4217 three-letter code
    • timezone: from the IANA time zone database
  • L10nFormat: shows the format of the language to be used for translations. The supported formats are: 'language' | 'language-script' | 'language-region' | 'language-script-region'. So, for example, you can have a language like en-US-u-ca-gregory-nu-latn to format dates and numbers, but only use the en-US for translations setting 'language-region'

  • L10nDateTimeFormatOptions: the type of options used to format dates. Extends the Intl DateTimeFormatOptions interface, adding the dateStyle and timeStyle attributes. See DateTimeFormat for more details on available options

  • L10nNumberFormatOptions: the type of options used to format numbers. Extends the Intl NumberFormatOptions interface, adding the digits attribute. See NumberFormat for more details on available options

Intl API

To format dates and numbers, this library uses the Intl API

Check the current browser support:

You can use polyfills to extend support to old browsers, or to use newest features:

  • Polyfill.io

    Just add one script tag in your index.html, for example:

    <script crossorigin="anonymous"
        src="https://polyfill.io/v3/polyfill.min.js?flags=gated&features=Intl.~locale.en-US"></script>
    

    When specifying the features, you have to specify what languages to load

  • Format.JS

    Import polyfills you need as in the sample app

Intl API in Node.js

To use Intl in Node.js, check the support according to the version in the official documentation: Internationalization Support

Server Side Rendering

You can find a complete sample app with @nguniversal/express-engine here

SSR doesn't work out of the box, so it is important to know:

  • src\app\universal-interceptor.ts: used to handle absolute URLs for HTTP requests on the server
  • src\app\l10n-config.ts:
    • AppStorage (implements L10nStorage): uses a cookie to store the locale client & server side
    • AppUserLanguage (implements L10nUserLanguage): server side, negotiates the language through acceptsLanguages to get the user language when the app starts

Previous versions

  • Angular v10 (Angular l10n v10.1.2)

  • Angular v9 (Angular l10n v9.3.0)

  • Angular v8 (Angular l10n v8.1.2)

  • Angular v7 (Angular l10n v7.2.0)

  • Angular v6 (Angular l10n v5.2.0)

  • Angular v5 (Angular l10n v4.2.0)

  • Angular v4 (Angular l10n v3.5.2)

  • Angular v2 (Angular l10n v2.0.11)

Contributing

  • First, install the packages & build the library:

    npm install
    npm run build
    
  • Testing:

    npm test
    
  • Serving the sample app:

    npm start
    
  • Serving the sample ssr app:

    npm run dev:ssr
    

License

MIT

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].