You are on page 1of 15

11/20/2016 Internationalization 

(i18n) ­ ts ­ COOKBOOK

INTERNATIONALIZATION (I18N)

Translate the app's template text into multiple languages

Angular's internationalization ("i18n") tools help make your app available in multiple
languages.

Table of contents
Angular and i18n template translation
Mark text with the i18n attribute
Create a translation source 䅉怀le with the ng-xi18n tool
Translate
Merge the completed translation 䅉怀le into the app
JiT con䅉怀guration
AoT con䅉怀guration

Try this live example of a JiT-compiled app, translated into French.

Angular and i18n template translation


Application internationalization is a challenging, many-faceted effort that takes
dedication and enduring commitment. Angular's i18n internationalization facilities
can help.

https://angular.io/docs/ts/latest/cookbook/i18n.html 1/15
11/20/2016 Internationalization (i18n) ­ ts ­ COOKBOOK

This page describes the i18n tools to assist translation of component template text
into multiple languages.

Practitioners of internationalization refer to a translatable text as a


"message". This page uses the words "text" and "message" interchangably
and in the combination, "text message".

The i18n template translation process has four phases:

1. Mark static text messages in your component templates for translation.

2. An angular i18n tool extracts the marked messages into an industry standard
translation source 䅉怀le.

3. A translator edits that 䅉怀le, translating the extracted text messages into the
target language, and returns the 䅉怀le to you.

4. The Angular compiler imports the completed translation 䅉怀les, replaces the
original messages with translated text, and generates a new version of the
application in the target language.

You build and deploy a separate version of the application for each supported
language.

Mark text with the i18n attribute


The Angular i18n attribute is a marker for translatable content. Place it on every
element tag whose 䅉怀xed text should be translated.

https://angular.io/docs/ts/latest/cookbook/i18n.html 2/15
11/20/2016 Internationalization (i18n) ­ ts ­ COOKBOOK

i18n is not an Angular directive. It's a custom attribute, recognized by Angular

tools and compilers. It will be removed by the compiler after translation.

In the accompanying sample, an <h1> tag displays a simple English language


greeting which you will translate to French:

app/app.component.html

<h1>Hello i18n!</h1>

Add the i18n attribute to the tag to mark it for translation.

app/app.component.html

<h1 i18n>Hello i18n!</h1>

The translator may need a description of the message to translate it accurately.


Assign a description to the i18n attribute:

app/app.component.html

<h1 i18n="An introduction header for this sample">Hello i18n!</h1>

The true meaning of the text may require some application context. Add a
contextual meaning to the assigned string, separating it from the description with
the | character:

https://angular.io/docs/ts/latest/cookbook/i18n.html 3/15
11/20/2016 Internationalization (i18n) ­ ts ­ COOKBOOK

app/app.component.html

<h1 i18n="User welcome|An introduction header for this


sample">Hello i18n!</h1>

While all appearance of a message with the same meaning should have the same
translation, a message with different meanings could have different translations.
The Angular extraction tool preserves both the meaning and the description in the
translation source 䅉怀le to facilitiate contextually-speci䅉怀c translations.

Create a translation source 䈀le with the ng-xi18n tool


Use the ng-xi18n extraction tool to extract the i18n -marked texts into a
translation source 䅉怀le in an industry standard format.

This is an Angular CLI tool in the @angular/compiler-cli npm package. If you


haven't already installed the CLI and its platform-server peer dependency, do so
now:

npm install @angular/compiler-cli @angular/platform-server --save

Open a terminal window at the root of the application project and enter the ng-
xi18n command:

./node_modules/.bin/ng-xi18n

https://angular.io/docs/ts/latest/cookbook/i18n.html 4/15
11/20/2016 Internationalization (i18n) ­ ts ­ COOKBOOK

By default the tool generates a translation 䅉怀le named messages.xlf in the XML
Localisation Interchange File Format (XLIFF, version 1.2).

./node_modules/.bin/ng-xi18n --i18nFormat=xmb

Windows users may have to quote the command:

"./node_modules/.bin/ng-xi18n"

Consider adding a convenience shortcut to the scripts section of the


package.json to make the command easier to remember and run:

"scripts": {
"i18n": "ng-xi18n",
...
}

Now you can enter:

npm run i18n

Other translation formats


You can generate a 䅉怀le named messages.xmb in the XML Message Bundle (XMB)
format by adding the --i18nFormat=xmb switch.

This sample sticks with the XLIFF format.


https://angular.io/docs/ts/latest/cookbook/i18n.html 5/15
11/20/2016 Internationalization (i18n) ­ ts ­ COOKBOOK

Translate le message textuel


The ng-xi18n command generated a translation source 䅉怀le in the project root
folder named messages.xlf . The next step is to translate the English language
template text into the speci䅉怀c language translation 䅉怀les. The cookbook sample
creates a French translation 䅉怀le.

Create a localization folder


You will probably translate into more than one other language so it's a good idea for
the project structure to re䆫倀ect your entire internationalization effort.

One approach is to dedicate a folder to localization and store related assets (e.g.
internationalization 䅉怀les) there.

Localization and internationalization are different but closely related


terms.

This sample follows that suggestion. It has locale folder immediately under the
project root. Assets within the folder carry a 䅉怀lename extension that matches a
language-culture code from a well-known codeset.

Move messages.xlf into the locale folder where it will become the source for
all language-speci䅉怀c translations. Then make a copy for the French language named
messages.fr.xlf .

Follow the same convention for each target language.

Translate

https://angular.io/docs/ts/latest/cookbook/i18n.html 6/15
11/20/2016 Internationalization (i18n) ­ ts ­ COOKBOOK

In the real world, you send the messages.fr.xlf 䅉怀le to a French translator who
would 䅉怀ll in the translations using one of the many XLIFF 䅉怀le editors.

This sample 䅉怀le is easy to translate without a special editor or knowledge of French.
Open messages.fr.xlf and 䅉怀nd the <trans-unit> section:

locale/messages.fr.xlf (<trans-unit>)

<trans-unit id="af2ccf4b5dba59616e92cf1531505af02da8f6d2"
datatype="html">
<source>Hello i18n!</source>
<target/>
<note priority="1" from="description">An introduction header for
this sample</note>
<note priority="1" from="meaning">User welcome</note>
</trans-unit>

This XML element represents the translation of the <h1> greeting tag you marked
with the i18n attribute.

Using the source, description, and meaning elements to guide your translation,
replace the <target/> tag with the French greeting:

locale/messages.fr.xlf (<trans-unit>, after translation)

<trans-unit id="af2ccf4b5dba59616e92cf1531505af02da8f6d2"
datatype="html">
<source>Hello i18n!</source>
<target>Bonjour i18n!</target>
<note priority="1" from="description">An introduction header for
this sample</note>
<note priority="1" from="meaning">User welcome</note>
</trans-unit>

https://angular.io/docs/ts/latest/cookbook/i18n.html 7/15
11/20/2016 Internationalization (i18n) ­ ts ­ COOKBOOK

Note that the id is generated by the tool. Don't touch it. Its value depends on the
content of the message and its assigned meaning. Change either factor and the id
changes as well.

Repeat the extraction process whenever you add new app messages or edit
existing ones. Be careful not to lose the previous translations. Specialized
software can help manage the change process.

The app before translation


After the previous steps, the sample app and its translation 䅉怀le are as follows:

1. <h1 i18n="User welcome|An introduction header for this


sample">Hello i18n!</h1>

Merge the completed translation 䈀le


To merge the translated text into component templates, you compile the application
with the completed translation 䅉怀le. The process is the same whether the 䅉怀le is in
.xlf format or in one of the other formats ( .xlif and .xtb ) that Angular

understands.

You provide the Angular compiler with three new pieces of information:

the translation 䅉怀le


the translation 䅉怀le format

https://angular.io/docs/ts/latest/cookbook/i18n.html 8/15
11/20/2016 Internationalization (i18n) ­ ts ­ COOKBOOK

the Locale ID ( fr or en-US for instance)

How you provide this information depends upon whether you compile with the JiT
(Just-in-Time) compiler or the AoT (Ahead-of-Time) compiler.

with JiT, you provide the information at bootstrap time.


with AoT, you pass the information as ngc options.

Merge with the JiT compiler


The JiT (Just-in-Time) compiler compiles the application in the browser as the
application loads. Translation with the JiT compiler is a dynamic process of ...

1. determining the language version for the current user,


2. importing the appropriate language translation 䅉怀le as a string constant,
3. creating corresponding translation providers to guide the JiT compiler,
4. bootstrapping the application with those providers.

Open index.html and revise the launch script as shown here:

index.html (launch script)

<script>
// Get the locale id somehow
document.locale = 'fr';

// Map to the text plugin


System.config({
map: {
text: 'systemjs-text-plugin.js'
}
});

// Launch the app

https://angular.io/docs/ts/latest/cookbook/i18n.html 9/15
11/20/2016 Internationalization (i18n) ­ ts ­ COOKBOOK

System.import('app').catch(function(err){ console.error(err);
});
</script>

In this sample, the user's language is hardcoded as a global document.locale


variable in the index.html .

SystemJS Text plugin


Notice the SystemJS mapping of text to a systemjs-text-plugin.js . With
the help of a text pluglin, SystemJS can read any 䅉怀le as raw text and return the
contents as a string. You'll need it to import the language translation 䅉怀le.

SystemJS doesn't ship with a raw text plugin but it's easy to add. Create the
following systemjs-text-plugin.js in the root folder:

systemjs-text-plugin.js

/*
SystemJS Text plugin from
https://github.com/systemjs/plugin-text/blob/master/text.js
*/
exports.translate = function(load) {
if (this.builder && this.transpiler) {
load.metadata.format = 'esm';
return 'exp' + 'ort var __useDefault = true; exp' + 'ort
default ' + JSON.stringify(load.source) + ';';
}

load.metadata.format = 'amd';
return 'def' + 'ine(function() {\nreturn ' +
JSON.stringify(load.source) + ';\n});';
}

https://angular.io/docs/ts/latest/cookbook/i18n.html 10/15
11/20/2016 Internationalization (i18n) ­ ts ­ COOKBOOK

Create translation providers


Three providers tell the JiT compiler how to translate the template texts for a
particular language while compiling the application:

TRANSLATIONS is a string containing the content of the translation 䅉怀le.

TRANSLATIONS_FORMAT is the format of the 䅉怀le: xlf , xlif or xtb

LOCALE_ID is the locale of the target language.

The getTranslationProviders function in the following app/i18n-


providers.ts creates those providers based on the user's locale and the

corresponding translation 䅉怀le:

app/i18n-providers.ts

1. import { TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID } from


'@angular/core';
2.

3. export function getTranslationProviders(): Promise<Object[]> {


4.

5. // Get the locale id from the global


6. const locale = document['locale'] as string;
7.

8. // return no providers if fail to get translation file for locale


9. const noProviders: Object[] = [];
10.

11. // No locale or U.S. English: no translation providers


12. if (!locale || locale === 'en-US') {
13. return Promise.resolve(noProviders);
14. }
15.

16. // Ex: 'locale/messages.fr.xlf`


17. const translationFile = `./locale/messages.${locale}.xlf`;
18.

https://angular.io/docs/ts/latest/cookbook/i18n.html 11/15
11/20/2016 Internationalization (i18n) ­ ts ­ COOKBOOK

19. return getTranslationsWithSystemJs(translationFile)


20. .then( (translations: string ) => [
21. { provide: TRANSLATIONS, useValue: translations },
22. { provide: TRANSLATIONS_FORMAT, useValue: 'xlf' },
23. { provide: LOCALE_ID, useValue: locale }
24. ])
25. .catch(() => noProviders); // ignore if file not found
26. }
27.

28. declare var System: any;


29.

30. function getTranslationsWithSystemJs(file: string) {


31. return System.import(file + '!text'); // relies on text plugin
32. }

It gets the locale from the global document.locale variable that was set in
index.html .

If there is no locale or the language is U.S. English ( en-US ), there is no need to


translate. The function returns an empty noProviders array as a Promise . It
must return a Promise because this function could read a translation 䅉怀le
asynchronously from the server.

It creates a transaction 䅉怀lename from the locale according to the name and
location convention described earlier.

The getTranslationsWithSystemJs method reads the translation and


returns the contents as a string. Notice that it appends !text to the 䅉怀lename,
telling SystemJS to use the text plugin.

The callback composes a providers array with the three translation providers.

Finally, getTranslationProviders returns the entire effort as a promise.

https://angular.io/docs/ts/latest/cookbook/i18n.html 12/15
11/20/2016 Internationalization (i18n) ­ ts ­ COOKBOOK

Bootstrap the app with translation providers


The Angular bootstrapModule method has a second, options parameter that can
in䆫倀uence the behavior of the compiler.

You'll create an options object with the translation providers from


getTranslationProviders and pass it to bootstrapModule . Open the

app/main.ts and modify the bootstrap code as follows:

app/main.ts

import { platformBrowserDynamic } from '@angular/platform-


browser-dynamic';
import { getTranslationProviders } from './i18n-providers';

import { AppModule } from './app.module';

getTranslationProviders().then(providers => {
const options = { providers };
platformBrowserDynamic().bootstrapModule(AppModule, options);
});

Notice that it waits for the getTranslationProviders promise to resolve before


bootstrapping the app.

The app is now internationalized for English and French and there is a clear path for
adding more languages.

Internationalize with the AoT compiler


The JiT compiler translates the application into the target language while compiling
dynamically in the browser. That's 䆫倀exible but may not be fast enough for your
users.
https://angular.io/docs/ts/latest/cookbook/i18n.html 13/15
11/20/2016 Internationalization (i18n) ­ ts ­ COOKBOOK

The AoT (Ahead-of-Time) compiler is part of a build process that produces a small,
fast, ready-to-run application package. When you internationalize with the AoT
compiler, you pre-build a separate application package for each language. Then in
the host web page ( index.html ), you determine which language the user needs
and serve the appropriate application package.

This cookbook doesn't cover how to build multiple application packages and serve
them according to the user's language preference. It does explain the few steps
necessary to tell the AoT to apply a translations 䅉怀le.

Internationalization with the AoT compiler requires some setup speci䅉怀cally for AoT.
Start with application project as shown just before merging the translation 䅉怀le and
refer to the AoT cookbook to make it AoT-ready.

Next, issue an ngc compile command for each supported language (including
English). The result is a separate version of the application for each language.

Tell AoT how to translate by adding three options to the ngc command:

--i18nFile : the path to the translation 䅉怀le

--locale : the name of the locale

--i18nFormat : the format of the localization 䅉怀le

For this sample, the French language command would be

./node_modules/.bin/ngc --i18nFile=./locale/messages.fr.xlf --
locale=fr --i18nFormat=xlf

Windows users may have to quote the command:

https://angular.io/docs/ts/latest/cookbook/i18n.html 14/15
11/20/2016 Internationalization (i18n) ­ ts ­ COOKBOOK

"./node_modules/.bin/ngc" --
i18nFile=./locale/messages.fr.xlf --locale=fr --
i18nFormat=xlf

https://angular.io/docs/ts/latest/cookbook/i18n.html 15/15

You might also like