Angular2 and webpack - i18n plugin vs ng2-translate
Asked Answered
V

5

8

I want to build a web-application with angular2 and bundle this with webpack. What is the best way for providing multiple languages:

i18n-plugin: https://github.com/webpack/i18n-webpack-plugin

or

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

Valentine answered 14/9, 2016 at 19:54 Comment(1)
I've wrote a blogpost about this: lingohub.com/blog/2016/10/… comparing angular-translate with the Angular 2 approachHydrogeology
M
9

I got it working with webpack using the cookbook. The xliff file has to be converted to ts like so:

export const TRANSLATION_SV = `<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
  <file source-language="en" datatype="plaintext" original="ng2.template">
    <body>
    <trans-unit id="a73e2898b9e1126ed19dbabe4b5c3715a84db61a" datatype="html">
      <source>Category</source>
      <target>Kategori</target>
    </trans-unit>
    </body>
  </file>
</xliff>`;

Then in the main.ts it has to be added

import { TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID  } from '@angular/core';
import { TRANSLATION_SV } from './locale/messages.sv';

and inserted to the bootstrap step:

platformBrowserDynamic().bootstrapModule(AppModule, {
    providers: [
      {provide: TRANSLATIONS, useValue: TRANSLATION_SV},
      {provide: TRANSLATIONS_FORMAT, useValue: "xlf"},
      {provide: LOCALE_ID, useValue:'sv'}
    ];
});
Michaelis answered 2/12, 2016 at 10:34 Comment(11)
IMHO that's a simpler approach than what the cookbook suggests. The only drawback being that you have to wrap the translation file manually in a TypeScript file.Snapback
very nice answer! it helped a lot to understand whats going on. The converting of the xlf file can be avoided with using the raw-loader.Shill
something like: { test: /\.xlf$/, include: helpers.root('locale'), loader: ['raw-loader'] }Shill
and than use import * as translationText from './locale/messages.xlf'Shill
@SimonSeyock how exactly do you import the text as messages.xlf when you have multiple files in your locale directory (ie: messages.en.xlf, messages.de.xlf, etc.)? The import doesn't seem known until runtime?Dictation
You can import multiple files and use the one you need. Another option is to use AOT compiler (angular.io/docs/ts/latest/cookbook/i18n.html#!#aot) and compile different packages for each language and then decide inside of the .html file which file to load.Shill
I opted to use different bundles for translations as you mentioned with AOT. I am also using dynamic imports via webpack to conditionally load any additional locale specific assets I need (in my case moment js locale file).Dictation
@Dictation How did you realized the conditional load together with AOT? Can you post an example or a plunkr, please.Osrick
@Osrick that is probably a different question to post but from a high-level here is what's involved: * webpack config file using string-replace-loader and a compiler directive like comment (ex: // #DynamicImport-Locale can be whatever you want though) * A function in your main.ts or bootstrapper that returns a promise and then calls the platformBrowserDynamic().boostrapModule(module) method * Function that returns a resolved promise that uses the compiler directive you defined and webpack should replace it with result = System.import('<file>'); or the like for your scenario And...Dictation
* Probably need systemjs type file until ts adds support for dynamic importsDictation
I avoided compiling multiple packages with provider factories: {provide: TRANSLATIONS, useFactory: (locale) => locale==='en'?TRANSLATION_EN:TRANSLATION_PL, deps:[LOCALE_ID]} and {provide: LOCALE_ID, useFactory: () => { ... some logic to find out browser language and store in cookie ... return locale;} }Exodus
D
8

If you are using angular-cli you can follow these steps:

Be aware that your app must be AOT compatibe, so you should be able to build it with --aot switch:

ng build --aot
  1. Extract messages with ng xi18n command with location for translation file given:

    ng xi18n --output-path src/i18n
    
  2. You will get src/i18n/messages.xlf file. Copy this file and translate messages to languages you need:

    src/i18n/messages.en.xlf
    src/i18n/messages.pl.xlf
    
  3. Serve/build your app with ng serve / ng build command (change locale accordingly):

    ng serve --i18n-file=src/i18n/messages.en.xlf --locale=en --i18n-format=xlf --aot
    
Disvalue answered 28/2, 2017 at 11:0 Comment(4)
What is the most profitable difference to the i18n plugin from webpack?Valentine
and how can you change the language of the app within the app? This is my main problem and the reason why I want to do this with JIT instead of AOT, but I can find no help for thisBazemore
unfortunately, you have to make separate build for each language and provide correct routing on the server side eg. using custom url localhost:8080/webapp/enDisvalue
@Disvalue - holy shit, that's such a bad design. Who in the world decided that, was everyone in Google high that day? I think I'll try my luck with ng2-translate first...Uvula
I
6

in case someone still wondering how to use angular 2 localization with webpack loader, i have modified the provider angular 2 cookbook provided;

First create i18n.provider.ts

import { TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID } from '@angular/core';
import { Observable } from "rxjs/Rx";
export function getTranslationProviders(): Promise<Object[]> {


  // Get the locale id from the global
  const locale = document['locale'] as string;
  // return no providers if fail to get translation file for locale
  const noProviders: Object[] = [];
  // No locale or U.S. English: no translation providers
  if (!locale || locale === 'en') {
    return Promise.resolve(noProviders);
  }
  // Ex: 'locale/messages.fr.xlf`
  const translationFile = `./src/app/localezation/messages.${locale}.xlf`;
  var provider = getTranslationsWithSystemJs(translationFile)
    .then((translations: string) => [
      { provide: TRANSLATIONS, useValue: translations },
      { provide: TRANSLATIONS_FORMAT, useValue: 'xlf' },
      { provide: LOCALE_ID, useValue: locale }
    ])
    .catch(() => noProviders); // ignore if file not found

  debugger;
  return provider;
}
declare var System: any;
function getTranslationsWithSystemJs(file: string) {
// changes Start here 
  var text = "";
  var fileRequest = new XMLHttpRequest();
  fileRequest.open("GET", file, false);
  fileRequest.onerror = function (err) {
    console.log(err);
  }
  fileRequest.onreadystatechange = function () {
    if (fileRequest.readyState === 4) {
      if (fileRequest.status === 200 || fileRequest.status == 0) {
        text = fileRequest.responseText;
      }
    }
  }
  fileRequest.send()
  var observable = Observable.of(text);
  var prom = observable.toPromise();
  return prom; 
}

notice the changes are :

  1. i used jxjs library to create observable/ promise
  2. i used XMLHttpRequest to get the localezation files

Second in the main.ts files change the bootstrapping the same as mentioned in angular cookbook

getTranslationProviders().then(providers => {
  const options = { providers };
  platformBrowserDynamic().bootstrapModule(AppModule, options);
});
Intrados answered 12/4, 2017 at 12:9 Comment(0)
K
3

Angular 2 Final release has i18n native support https://angular.io/docs/ts/latest/cookbook/i18n.html

Check another answer https://mcmap.net/q/384721/-angular2-i18n-at-this-point with example and some details about usage.

ng2-translate is too verbose comparing to the native implementation. Also the author of ng2-translate is a big contributor to angular 2 i18n documentation

Krauss answered 4/10, 2016 at 13:24 Comment(3)
But this cookbook still refers to SystemJS as an integration mechanism instead of Webpack. How do we integrate the XLIFF file into compilation with Webpack?Yann
@Yann If you don't want to do it in a separate process, you can use the AoT Webpack plugin from npmjs.com/package/@ngtools/webpackQuartis
For anyone who has come from AngularJS's angular-translate, the i18n native support seems like a bizarre approach. It requires the app to be completely rebuilt and separately deployed for each language. I can't imagine what the admin overhead on this is like when you get into 4/5/6 languages which would be typical on an internal business app. At first glance it looks like ngx-translate is closer to angular-translate in that it can set up language from the server on startup, switch languages on the fly etc.Jahvist
F
0

A slightly modified version of @M.Nour Berro's answer.

I made this change as synchronous xhr's are deprecated and possibly support might be removed later.

function getTranslations(filePath: string): Promise<string> {
  var text = '';
  return new Promise<string> ((resolve, reject) => {
    const fileRequest = new XMLHttpRequest();
    fileRequest.open('GET', filePath, true);
    fileRequest.onerror = function (err) {
      console.log(err);
      reject(err);
    };
    fileRequest.onreadystatechange = function () {
      if (fileRequest.readyState === 4) {
        if (fileRequest.status === 200 || fileRequest.status === 0) {
          text = fileRequest.responseText;
          resolve(text);
        }
      }
    };
    fileRequest.send();
  });
}
Fruit answered 13/10, 2017 at 6:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.