Angular 2 i18n dynamic/instant translation
Asked Answered
U

3

12

I've followed the angular.io cookbook for internationalization (https://angular.io/docs/ts/latest/cookbook/i18n.html#!#angular-i18n). Everything works fine, and if I change my locale in the index.html file:

document.locale = 'en';

But I wish to change this dynamically, as we used to do in AngularJS. I have found several solutions, such as this:

//mycomponent.component.ts
changeLang(){
localStorage.setItem('localeId', "es");
location.reload(true);

} //I hardcoded the locale, but you get the idea

Is there a way to translate the document on the go? Because this solution is not practical, and has a long reload time. Thank you for your help!

Unaccomplished answered 3/2, 2017 at 12:21 Comment(0)
W
12

In short it is not possible to change the locale without reloading the app as the translation work is done by Angular compiler.


As of today you have two options when using official Angular i18n:

Use AOT compiler

In this case a separate bundle will be created for every locale and you'll have to swap the whole application, i.e. reload it.

When you internationalize with the AOT compiler, you must pre-build a separate application package for each language and serve the appropriate package based on either server-side language detection or url parameters.

Use JIT compiler

This approach is less performant but you'll not necessarily need a bundle per language.
In this case you load your translation file with webpack and provide it to Angular compiler during bootstrap.

The JIT compiler compiles the app in the browser as the app loads. Translation with the JIT compiler is a dynamic process of:

  • Importing the appropriate language translation file as a string constant.
  • Creating corresponding translation providers for the JIT compiler.
  • Bootstrapping the app with those providers.

Although in the official documentation they only have examples with useValue providers, I'm pretty sure you can use useFactory to provide TRANSLATIONS and LOCALE_ID based on your configuration.
You'll still have to re-bootstrap your app upon language change, which, in turn, means reloading, but hey, the user have this bundle cached in the browser, so the reload should be pretty fast.


Anyways, as of now, if you want to get really dynamic translations I'd suggest you to use ngx-translate.
Besides translate pipe and service they have this nice speculative polyfill that might save you some headache when code translations will be supported officially by Angular i18n.

Waterworks answered 20/11, 2017 at 22:36 Comment(0)
F
5

You can check that out, for me it works flawlessly and has great performance (instant translation with no loading time nor reload) :

https://github.com/ocombe/ng2-translate

You can then use a local storage or anything with that to set the language :

translateService.use(window.localStorage.getItem('language'));

You can set your translations in a single file, and you can order the translations in JSON format : (I encapsulate one object per component)

"PASSWORD_CONFIRM": {
    "TITLE": "Merci !",
    "DESCRIPTION": "Votre nouveau mot de passe a bien été enregistré. Vous pouvez désormais accéder à la plateforme !",
    "BUTTON": "Entrer sur la plateforme"
  },
  ...

and then you can set your text in your HTML as follow :

  <div class="title">{{'PASSWORD_CONFIRM.TITLE' | translate}}</div>
  <div class="description">
      {{'PASSWORD_CONFIRM.DESCRIPTION' | translate}}
  </div>
Ferrite answered 3/2, 2017 at 16:15 Comment(4)
Thanks Alex, but I really wanted to use the official Angular 2 support for internationalization. This is a solution though, and I will be using it if I don't find an alternative. Thank you :)Unaccomplished
Hi Andre, Did you find any solution for your question as i also want to implement the same for my applicationPackage
Seem like official angular i18n will support dynamic translation with the release of ivy. github.com/angular/angular/issues/16477Jules
I ended up doing both.. using the i18n angular for static texts, and ngx-translate for anything containing html tags, or that needs to be used in components. HTML tags in xlif is a horrible messy experience that I had to give up upon.Hobbie
T
3

You can certainly do this if you're using JIT compilation. You'll need a factory provider for your translations. Add something like this to your root module:

  export function localeFactory(): string {
    return (window.clientInformation && window.clientInformation.language) || window.navigator.language;
  }

  providers:
  [
    {
      provide: TRANSLATIONS,
      useFactory: (locale) => {
        locale = locale || 'en'; // default to english if no locale provided
        return require(`raw-loader!../locale/messages.${locale}.xlf`);
      },
      deps: [LOCALE_ID]
    },
    {
      provide: LOCALE_ID,
      useFactory: localeFactory
    },
    {provide: TRANSLATIONS_FORMAT, useValue: 'xlf'},
Talbot answered 21/6, 2018 at 5:39 Comment(1)
With this method it's a 1 time decision though at bootstrap correct? (just verifying). It's not like there could be a dropdown with a local/country selection and this could be changed dynamically could it? It needs to be decided upon the provider being registered with Angular.Apocopate

© 2022 - 2024 — McMap. All rights reserved.