Internationalization (i18n)

Application internationalization is a many-faceted area of development, focused on making applications available and user-friendly to a worldwide audience. This tutorial describes Angular's internationalization (i18n) tools, which can help you make your application available in multiple languages.

Angular and i18n

Internationalization is the process of designing and preparing your app to be usable in different languages. Localization is the process of translating your internationalized app into specific languages for particular locales.

Angular simplifies the following aspects of internationalization:

  • Displaying dates, number, percentages, and currencies in a local format.
  • Preparing text in component templates for translation.
  • Handling plural forms of words.
  • Handling alternative text.

For localization, you can use the Angular CLI to generate most of the boilerplate necessary to create files for translators, and to publish your app in multiple languages. After you have set up your app to use i18n, the CLI can help you with the following steps:

  • Extracting localizable text into a file that you can send out to be translated.
  • Building and serving the app for a given locale, using the translated text.
  • Creating multiple language versions of your app.

Setting up the locale of your app

A locale is an identifier (id) that refers to a set of user preferences that tend to be shared within a region of the world, such as country. This document refers to a locale identifier as a "locale" or "locale id".

A Unicode locale identifier is composed of a Unicode language identifier and (optionally) the character - followed by a locale extension. For example, in the locale id `fr-CA` the `fr` refers to the French language identifier, and the `CA` refers to the locale extension Canada.

Angular follows the Unicode LDML convention that uses stable identifiers (Unicode locale identifiers) based on the norm BCP47. It is very important that you follow this convention when you define your locale, because the Angular i18n tools use this locale id to find the correct corresponding locale data.

By default, Angular uses the locale en-US, which is English as spoken in the United States of America.

The locale identifiers used by CLDR and Angular are based on BCP47. These specifications change over time; the following table maps previous identifiers to current ones at the time of writing:

Indonesian in id
Hebrew iw he
Romanian Moldova mo ro-MD
Norwegian Bokmål no, no-NO nb
Chinese Simplified zh-cn, zh-Hans-CN zh-Hans
Chinese Traditional zh-tw, zh-Hant-TW zh-Hant

i18n pipes

Angular pipes can help you with internationalization: the DatePipe, CurrencyPipe, DecimalPipe, and PercentPipe use locale data to format data based on the LOCALE_ID.

By default, Angular only contains locale data for en-US. If you set the value of LOCALE_ID to another locale, you must import locale data for that new locale. The CLI imports the locale data for you when you use the parameter --configuration with ng serve and ng build.

If you want to import locale data for other languages, you can do it manually by adding it in the src/app/app.module.ts

import { registerLocaleData } from '@angular/common';
import localeFr from '@angular/common/locales/fr';
// the second parameter 'fr' is optional
registerLocaleData(localeFr, 'fr');

Live Demo:

It is just a code snippet explaining a particular concept and may not have any output

See the Pen src/app/app.module.ts by w3resource (@w3resource) on CodePen.

The first parameter is an object containing the locale data imported from @angular/common/locales. By default, the imported locale data is registered with the locale id that is defined in the Angular locale data itself. If you want to register the imported locale data with another locale id, use the second parameter to specify a custom locale id. For example, Angular's locale data defines the locale id for French as "fr". You can use the second parameter to associate the imported French locale data with the custom locale id "fr-FR" instead of "fr".

The files in @angular/common/locales contain most of the locale data that you need, but some advanced formatting options might only be available in the extra dataset that you can import from @angular/common/locales/extra. An error message informs you when this is the case

import { registerLocaleData } from '@angular/common';
import localeFr from '@angular/common/locales/fr';
import localeFrExtra from '@angular/common/locales/extra/fr';

registerLocaleData(localeFr, 'fr-FR', localeFrExtra);

Live Demo:

It is just a code snippet explaining a particular concept and may not have any output

See the Pen qGqxbj by w3resource (@w3resource) on CodePen.

Template translations

The i18n template translation process has four phases:

  1. Mark static text messages in your component templates for translation.
  2. Create a translation file: Use the Angular CLI xi18n command to extract the marked text into an industry-standard translation source file.
  3. Edit the generated translation file: Translate the extracted text into the target language.
  4. Merge the completed translation file into the app. To do this, use the Angular CLI build command to compile the app, choosing a locale-specific configuration, or specifying the following command options.
    • --i18nFile=path to the translation file
    • --i18nFormat=format of the translation file
    • --i18nLocale= locale id

The command replaces the original messages with translated text and generates a new version of the app in the target language.

You need to build and deploy a separate version of the app for each supported language.

Mark text with the i18n attribute

The Angular i18n attribute marks translatable content. Place it on every element tag whose fixed text is to be translated.

In the example below, an <h1> tag displays a simple English language greeting, "Hello i18n!" written in the src/app/app.component.html file

```<h1>Hello i18n!</h1>```

To mark the greeting for translation, add the i18n attribute to the <h1> tag.

```<h1 i18n>Hello i18n!</h1>```

i18n is a custom attribute, recognized by Angular tools and compilers. After translation, the compiler removes it. It is not an Angular directive.

Help the translator with a description and meaning

To translate a text message accurately, the translator may need additional information or context.

You can add a description of the text message as the value of the i18n attribute, as shown in the example below:

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

The translator may also need to know the meaning or intent of the text message within this particular app context.

You add context by beginning the i18n attribute value with the meaning and separating it from the description with the | character: <meaning>|<description>

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

All occurrences of a text message that have the same meaning will have the same translation. A text message that is associated with different meanings can have different translations.

The Angular extraction tool preserves both the meaning and the description in the translation source file to facilitate contextually-specific translations, but only the combination of meaning and text message are used to generate the specific id of a translation. If you have two similar text messages with different meanings, they are extracted separately. If you have two similar text messages with different descriptions (not different meanings), then they are extracted only once.

Set a custom id for persistence and maintenance

The angular i18n extractor tool generates a file with a translation unit entry for each i18n attribute in a template. By default, it assigns each translation unit a unique id such as this one:

<trans-unit id="ba0cc104d3d69bf669f97b8d96a4c5d8d9559aa3" datatype="html"> 

When you change the translatable text, the extractor tool generates a new id for that translation unit. You must then update the translation file with the new id.

Alternatively, you can specify a custom id in the i18n attribute by using the prefix @@. The example below defines the custom id introductionHeader:

<h1 i18n="@@introductionHeader">Hello i18n!</h1> 

When you specify a custom id, the extractor tool and compiler generate a translation unit with that custom id.

<trans-unit id="introductionHeader" datatype="html"> 

The custom id is persistent. The extractor tool does not change it when the translatable text changes. Therefore, you do not need to update the translation. This approach makes maintenance easier.

Use a custom id with a description

You can use a custom id in combination with a description by including both in the value of the i18n attribute. In the example below, the i18n attribute value includes a description, followed by the custom id:

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

You also can add a meaning, as shown in this example:

<h1 i18n="site header|An introduction header for this sample@@introductionHeader">Hello i18n!</h1> 

Define unique custom ids

Be sure to define custom ids that are unique. If you use the same id for two different text messages, only the first one is extracted, and its translation is used in place of both original text messages.

In the example below the custom id myId is used for two different messages:

<h3 i18n="@@myId">Hello</h3> 
<p i18n="@@myId">Good  bye</p>

Consider this translation to French:

<trans-unit id="myId" datatype="html"> 
<target state="new">Bonjour</target> 

Because the custom id is the same, both of the elements in the resulting translation contain the same text, Bonjour:


Translate text without creating an element

If there is a section of text that you would like to translate, you can wrap it in a <span> tag. However, if you don't want to create a new DOM element merely to facilitate translation, you can wrap the text in an <ng-container> element. The <ng-container> is transformed into an HTML comment:

<ng-container i18n>I don't output any element</ng-container> 

Translate attributes

Displayed text is sometimes supplied as the value of an attribute, rather than the content of the tag. For example, if your template has an image with a title attribute, the text value of the title attribute needs to be translated.

<img [src]="logo" title="Angular logo"> 

To mark an attribute for translation, add an attribute in the form of i18n-x, where x is the name of the attribute to translate. The following example shows how to mark the title attribute for translation by adding the i18n-title attribute on the img tag:

<img [src]="logo" i18n-title title="Angular logo" /> 

This technique works for any attribute of any element. You also can assign a meaning, description, and id with the i18n-x="<meaning>|<description>@@<id>" syntax.

Previous: Server-side Rendering (SSR): An intro to Angular Universal
Next: Workspace and project file structure

Follow us on Facebook and Twitter for latest update.