767 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			767 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # Internationalization (i18n)
 | |
| 
 | |
| Angular's _internationalization_ (_i18n_) tools help make your app available in multiple languages.
 | |
| 
 | |
| Try this <live-example name="i18n" title="i18n Example in Spanish">live example</live-example>
 | |
| of a JIT-compiled app, translated into Spanish.
 | |
| 
 | |
| {@a angular-i18n}
 | |
| 
 | |
| ## 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.
 | |
| 
 | |
| This page describes the _i18n_ tools available to assist translation of component template text
 | |
| into multiple languages.
 | |
| 
 | |
| <div class="l-sub-section">
 | |
| 
 | |
| Practitioners of _internationalization_ refer to a translatable text as a "_message_".
 | |
| This page uses the words "_text_" and "_message_" interchangeably and in the combination, "_text message_".
 | |
| 
 | |
| </div>
 | |
| 
 | |
| The _i18n_ template translation process has four phases:
 | |
| 
 | |
| 1. Mark static text messages in your component templates for translation.
 | |
| 
 | |
| 1. An angular _i18n_ tool extracts the marked messages into an industry standard translation source file.
 | |
| 
 | |
| 1. A translator edits that file, translating the extracted text messages into the target language,
 | |
| and returns the file to you.
 | |
| 
 | |
| 1. The Angular compiler imports the completed translation files,
 | |
| replaces the original messages with translated text, and generates a new version of the application
 | |
| in the target language.
 | |
| 
 | |
| You need to build and deploy a separate version of the application for each supported language.
 | |
| 
 | |
| {@a i18n-attribute}
 | |
| 
 | |
| ## i18n pipes
 | |
| 
 | |
| Angular pipes can help you with internationalization: the `DatePipe`, `CurrencyPipe`, `DecimalPipe`
 | |
| and `PercentPipe` use locale data to format your data based on your `LOCALE_ID`.
 | |
| 
 | |
| By default Angular only contains locale data for the language `en-US`, if you set the value of
 | |
| `LOCALE_ID` to another locale, you will have to import new locale data for this language:
 | |
| 
 | |
| <code-example path="i18n/src/app/app.locale_data.ts" region="import-locale" title="src/app/app.locale_data.ts" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| <div class="l-sub-section">
 | |
| 
 | |
| Note that the files in `@angular/common/locales` contain most of the locale data that you will
 | |
| need, but some advanced formatting options might only be available in the extra dataset that you can
 | |
| import from `@angular/common/locales/extra`:
 | |
| 
 | |
| <code-example path="i18n/src/app/app.locale_data_extra.ts" region="import-locale-extra" title="src/app/app.locale_data_extra.ts" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| </div>
 | |
| 
 | |
| ## Mark text with the _i18n_ attribute
 | |
| 
 | |
| The Angular `i18n` attribute is a marker for translatable content.
 | |
| Place it on every element tag whose fixed text should be translated.
 | |
| 
 | |
| 
 | |
| <div class="alert is-helpful">
 | |
| 
 | |
| `i18n` is not an Angular _directive_.
 | |
| It's a custom _attribute_, recognized by Angular tools and compilers.
 | |
| After translation, the compiler removes it.
 | |
| 
 | |
| </div>
 | |
| 
 | |
| In the accompanying sample, an `<h1>` tag displays a simple English language greeting
 | |
| that you translate into Spanish:
 | |
| 
 | |
| <code-example path="i18n/src/app/app.component.1.html" region="greeting" title="src/app/app.component.html" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| Add the `i18n` attribute to the tag to mark it for translation.
 | |
| 
 | |
| <code-example path="i18n/src/app/app.component.1.html" region="i18n-attribute" title="src/app/app.component.html" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| {@a help-translator}
 | |
| 
 | |
| ### Help the translator with a _description_ and _meaning_
 | |
| 
 | |
| In order to translate it accurately, the translator may
 | |
| need a description of the message.
 | |
| Assign a description to the i18n attribute:
 | |
| 
 | |
| <code-example path="i18n/src/app/app.component.1.html" region="i18n-attribute-desc" title="src/app/app.component.html" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| In order to deliver a correct translation, the translator may need to
 | |
| know the _meaning_ or _intent_ of the text within _this particular_ application context.
 | |
| 
 | |
| You add context by beginning the string with the _meaning_ and
 | |
| separating it from the _description_ with the `|` character (`<meaning>|<description>`):
 | |
| 
 | |
| <code-example path="i18n/src/app/app.component.1.html" region="i18n-attribute-meaning" title="src/app/app.component.html" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| While all appearances of a message with the _same_ meaning have the _same_ translation,
 | |
| a message with *a variety of possible meanings* could have different translations.
 | |
| The Angular extraction tool preserves both the _meaning_ and the _description_ in the translation source file
 | |
| to facilitate contextually-specific translations.
 | |
| 
 | |
| 
 | |
| {@a custom-id}
 | |
| 
 | |
| ### Set a custom _id_ to improve search 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:
 | |
| 
 | |
| <code-example path="i18n/src/locale/messages.es.xlf.html" region="generated-id" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| This _id_ is obscure and difficult for humans to read or remember.
 | |
| 
 | |
| Worse, when you change the translatable text, perhaps to fix a typo,
 | |
| the extractor tool generates a new _id_ for that translation.
 | |
| You will lose the translation unless you update it with the new _id_.
 | |
| That [complicates maintenance](#maintenance).
 | |
| 
 | |
| Consider specifying your own, meaningful _id_ in the `i18n` attribute, **prefixed with `@@`**.
 | |
| 
 | |
| <code-example path='i18n/src/app/app.component.1.html' region='i18n-attribute-solo-id' title='app/app.component.html' linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| Now the extractor tool and compiler will generate a translation unit with _your custom id_ and never change it.
 | |
| 
 | |
| <code-example path="i18n/src/locale/messages.es.xlf.html" region="custom-id" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| Here is the `i18n` attribute with a _description_, followed by the custom `id`:
 | |
| 
 | |
| <code-example path='i18n/src/app/app.component.1.html' region='i18n-attribute-id' title='app/app.component.html' linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| Here is a _meaning_ and a _description_ and the _id_ at the end:
 | |
| 
 | |
| <code-example path='i18n/src/app/app.component.1.html' region='i18n-attribute-meaning-and-id' title='app/app.component.html' linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| <div class="l-sub-section">
 | |
| 
 | |
|   Be sure to define _unique_ custom ids. If you use the same id for 2 _different_ blocks of text, only the first one will be extracted,
 | |
|   and its translation used in both blocks of text.
 | |
| 
 | |
|   For example:
 | |
| 
 | |
|   ```html
 | |
|     <p i18n="@@myId">Hello</p>
 | |
|     <p i18n="@@myId">Good bye</p>
 | |
|   ```
 | |
| 
 | |
|   with the translation:
 | |
| 
 | |
|   ```xml
 | |
|     <trans-unit id="myId" datatype="html">
 | |
|       <source>Hello</source>
 | |
|       <target state="new">Hola</target>
 | |
|     </trans-unit>
 | |
|   ```
 | |
| 
 | |
|   Both `<p>` elements will contain the text `Hola`.
 | |
| 
 | |
| </div>
 | |
| 
 | |
| {@a no-element}
 | |
| 
 | |
| ### Translate text without creating an element
 | |
| 
 | |
| If there is a stretch of text that you'd like to translate, you could wrap it in a `<span>` tag.
 | |
| But 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>` will be transformed into an html comment:
 | |
| 
 | |
| <code-example path="i18n/src/app/app.component.html" region="i18n-ng-container" title="src/app/app.component.html" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| {@a translate-attributes}
 | |
| 
 | |
| ## Add _i18n_ translation attributes
 | |
| You've added an image to your template. You care about accessibility too so you add a `title` attribute:
 | |
| 
 | |
| <code-example path="i18n/src/app/app.component.1.html" region="i18n-title" title="src/app/app.component.html" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| The `title` attribute needs to be translated.
 | |
| Angular i18n support has more translation attributes in the form,`i18n-x`, where `x` is the
 | |
| name of the attribute to translate.
 | |
| 
 | |
| To translate the `title` on the `img` tag from the previous example, write:
 | |
| 
 | |
| <code-example path="i18n/src/app/app.component.html" region="i18n-title-translate" title="src/app/app.component.html" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| You can also assign a meaning and a description with the `i18n-x="<meaning>|<description>"` syntax.
 | |
| 
 | |
| {@a cardinality}
 | |
| 
 | |
| ## Handle singular and plural
 | |
| 
 | |
| Different languages have different pluralization rules.
 | |
| 
 | |
| Suppose your application says something about a collection of wolves.
 | |
| In English, depending upon the number of wolves, you could display "no wolves", "one wolf", "two wolves", or "a wolf pack".
 | |
| Other languages might express the _cardinality_ differently.
 | |
| 
 | |
| Here's how you could mark up the component template to display the phrase appropriate to the number of wolves:
 | |
| 
 | |
| <code-example path="i18n/src/app/app.component.html" region="i18n-plural" title="src/app/app.component.html" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| * The first parameter is the key. It is bound to the component property (`wolves`)
 | |
| that determines the number of wolves.
 | |
| * The second parameter identifies this as a `plural` translation type.
 | |
| * The third parameter defines a pluralization pattern consisting of pluralization
 | |
| categories and their matching values.
 | |
| 
 | |
| Pluralization categories include:
 | |
| 
 | |
| * =0 (or any other number)
 | |
| * zero
 | |
| * one
 | |
| * two
 | |
| * few
 | |
| * many
 | |
| * other
 | |
| 
 | |
| Put the default _English_ translation in braces (`{}`) next to the pluralization category.
 | |
| 
 | |
| * When you're talking about one wolf, you could write `=1 {one wolf}`.
 | |
| 
 | |
| * For zero wolves, you could write `=0 {no wolves}`.
 | |
| 
 | |
| * For two wolves, you could write `=2 {two wolves}`.
 | |
| 
 | |
| You could keep this up for three, four, and every other number of wolves.
 | |
| Or you could specify the **`other`** category as a catch-all for any unmatched cardinality
 | |
| and write something like: `other {a wolf pack}`.
 | |
| 
 | |
| <div class="l-sub-section">
 | |
| 
 | |
| This syntax conforms to the
 | |
| <a href="http://userguide.icu-project.org/formatparse/messages" title="ICU Message Format">ICU Message Format</a>
 | |
| that derives from the
 | |
| <a href="http://cldr.unicode.org/" title="CLDR">Common Locale Data Repository (CLDR)</a>,
 | |
| which specifies the
 | |
| <a href="http://cldr.unicode.org/index/cldr-spec/plural-rules" title="Pluralization Rules">pluralization rules</a>.
 | |
| 
 | |
| </div>
 | |
| 
 | |
| {@a select}
 | |
| 
 | |
| ## Select among alternative texts
 | |
| 
 | |
| The application displays different text depending upon whether the hero is male or female.
 | |
| These text alternatives require translation too.
 | |
| 
 | |
| You can handle this with a `select` translation.
 | |
| A `select` also follows the
 | |
| <a href="http://userguide.icu-project.org/formatparse/messages" title="ICU Message Format">ICU message syntax</a>.
 | |
| You choose among alternative translation based on a string value instead of a number.
 | |
| 
 | |
| The following format message in the component template binds to the component's `gender`
 | |
| property, which outputs either an "m" or an "f".
 | |
| The message maps those values to the appropriate translation:
 | |
| 
 | |
| <code-example path="i18n/src/app/app.component.html" region="i18n-select" title="src/app/app.component.html" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| ## Nesting pluralization and selection expressions
 | |
| 
 | |
| You can also nest different ICU expressions together. For example:
 | |
| 
 | |
| <code-example path="i18n/src/app/app.component.html" region="i18n-nested" title="src/app/app.component.html">
 | |
| </code-example>
 | |
| 
 | |
| {@a ng-xi18n}
 | |
| 
 | |
| ## Create a translation source file with the _ng-xi18n_ tool
 | |
| 
 | |
| Use the **_ng-xi18n_ extraction tool** to extract the `i18n`-marked texts
 | |
| into a translation source file 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:
 | |
| 
 | |
| <code-example language="sh" class="code-shell">
 | |
|   npm install @angular/compiler-cli @angular/platform-server --save
 | |
| </code-example>
 | |
| 
 | |
| Open a terminal window at the root of the application project and enter the `ng-xi18n` command:
 | |
| 
 | |
| <code-example language="sh" class="code-shell">
 | |
|   ./node_modules/.bin/ng-xi18n
 | |
| </code-example>
 | |
| 
 | |
| <div class="l-sub-section">
 | |
| 
 | |
| Windows users may have to quote the command like this: `"./node_modules/.bin/ng-xi18n"`
 | |
| 
 | |
| </div>
 | |
| 
 | |
| By default, the tool generates a translation file named **`messages.xlf`** in the
 | |
| <a href="https://en.wikipedia.org/wiki/XLIFF">XML Localization Interchange File Format (XLIFF, version 1.2)</a>.
 | |
| 
 | |
| {@a other-formats}
 | |
| 
 | |
| ### Other translation formats
 | |
| 
 | |
| Angular i18n tooling supports XLIFF 1.2 and XLIFF 2 as well as the
 | |
| <a href="http://cldr.unicode.org/development/development-process/design-proposals/xmb" >XML Message Bundle (XMB)</a>.
 | |
| 
 | |
| You can specify your choice of format _explicitly_ with the `--i18nFormat` flag as illustrated in these example commands
 | |
| 
 | |
| <code-example language="sh" class="code-shell">
 | |
| ./node_modules/.bin/ng-xi18n  --i18nFormat=xlf  --outFile=messages.xlf
 | |
| ./node_modules/.bin/ng-xi18n  --i18nFormat=xlf2 --outFile=messages.xliff2.xlf
 | |
| ./node_modules/.bin/ng-xi18n  --i18nFormat=xmb  --outFile=messages.xmb
 | |
| </code-example>
 | |
| 
 | |
| The sample in _this_ guide sticks with the default _XLIFF 1.2_ format.
 | |
| 
 | |
| {@a ng-xi18n-options}
 | |
| 
 | |
| ### Other options
 | |
| 
 | |
| You may have to specify additional options.
 | |
| For example, if the `tsconfig.json` TypeScript configuration
 | |
| file is located somewhere other than in the root folder,
 | |
| you must identify the path to it with the `-p` option:
 | |
| 
 | |
| <code-example language="sh" class="code-shell">
 | |
|   ./node_modules/.bin/ng-xi18n -p path/to/tsconfig.json
 | |
|   ./node_modules/.bin/ng-xi18n  --i18nFormat=xmb -p path/to/tsconfig.json
 | |
| </code-example>
 | |
| 
 | |
| {@a npm-i18n-script}
 | |
| 
 | |
| ### Add an _npm_ script for convenience
 | |
| 
 | |
| Consider adding a convenience shortcut to the `scripts` section of the `package.json`
 | |
| to make the command easier to remember and run:
 | |
| 
 | |
| <code-example format='.' language='sh'>
 | |
|   "scripts": {
 | |
|     "i18n": "ng-xi18n",
 | |
|     ...
 | |
|   }
 | |
| </code-example>
 | |
| 
 | |
| Now you can issue command variations such as these:
 | |
| 
 | |
| <code-example language="sh" class="code-shell">
 | |
|   npm run i18n
 | |
|   npm run i18n -- -p path/to/tsconfig.json
 | |
|   npm run i18n -- --i18nFormat=xmb -p path/to/tsconfig.json
 | |
| </code-example>
 | |
| 
 | |
| Note the `--` flag before the options.
 | |
| It tells _npm_ to pass every flag thereafter to `ng-xi18n`.
 | |
| 
 | |
| {@a translate}
 | |
| 
 | |
| ## Translate text messages
 | |
| 
 | |
| The `ng-xi18n` command generates a translation source file
 | |
| in the project root folder named `messages.xlf`.
 | |
| The next step is to translate the English language template
 | |
| text into the specific language translation
 | |
| files. The guide sample creates a Spanish translation file.
 | |
| 
 | |
| {@a localization-folder}
 | |
| 
 | |
| ### 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 reflect your entire internationalization effort.
 | |
| 
 | |
| One approach is to dedicate a folder to localization and store related assets,
 | |
| such as internationalization files, there.
 | |
| 
 | |
| <div class="l-sub-section">
 | |
| 
 | |
| Localization and internationalization are
 | |
| <a href="https://en.wikipedia.org/wiki/Internationalization_and_localization">different but closely related terms</a>.
 | |
| 
 | |
| </div>
 | |
| 
 | |
| This guide follows that suggestion. It has a `locale` folder under `src/`.
 | |
| Assets within the folder carry a filename extension that matches a language-culture code from a
 | |
| <a href="https://msdn.microsoft.com/en-us/library/ee825488(v=cs.20).aspx">well-known codeset</a>.
 | |
| 
 | |
| Make a copy of the `messages.xlf` file, put it in the `locale` folder and
 | |
| rename it `messages.es.xlf`for the Spanish language translation.
 | |
| Do the same for each target language.
 | |
| 
 | |
| {@a translate-text-nodes}
 | |
| 
 | |
| ### Translate text nodes
 | |
| In the real world, you send the `messages.es.xlf` file to a Spanish translator who fills in the translations
 | |
| using one of the
 | |
| <a href="https://en.wikipedia.org/wiki/XLIFF#Editors">many XLIFF file editors</a>.
 | |
| 
 | |
| This sample file is easy to translate without a special editor or knowledge of Spanish.
 | |
| Open `messages.es.xlf` and find the first `<trans-unit>` section:
 | |
| 
 | |
| <code-example path="i18n/src/locale/messages.es.xlf.html" region="translated-hello" title="src/locale/messages.es.xlf (<trans-unit>)" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| This XML element represents the translation of the `<h1>` greeting tag you marked with the `i18n` attribute.
 | |
| 
 | |
| <div class="l-sub-section">
 | |
| 
 | |
| Note that the translation unit `id=introductionHeader` is derived from the [_custom_ `id`](#custom-id "Set a custom id") that you set earlier, but **without the `@@` prefix** required in the source HTML.
 | |
| 
 | |
| </div>
 | |
| 
 | |
| Using the _source_, _description_, and _meaning_ elements to guide your translation,
 | |
| replace the `<target/>` tag with the Spanish greeting:
 | |
| 
 | |
| <code-example path="i18n/src/locale/messages.es.xlf.html" region="translated-hello" title="src/locale/messages.es.xlf (<trans-unit>, after translation)" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| Translate the other text nodes the same way:
 | |
| 
 | |
| <code-example path="i18n/src/locale/messages.es.xlf.html" region="translated-other-nodes" title="src/locale/messages.es.xlf (<trans-unit>)" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| <div class="alert is-important">
 | |
| 
 | |
| **The tool generated the `id`s for _these_ translation units. Don't touch them.**
 | |
| Each `id` depends upon the content of the message and its assigned meaning.
 | |
| Change either factor and the `id` changes as well.
 | |
| See the **[translation file maintenance discussion](#maintenance)**.
 | |
| 
 | |
| This is why you should **[specify custom ids](#custom-id "Set a custom id")** and avoid tool generated ids.
 | |
| 
 | |
| </div>
 | |
| 
 | |
| {@a translate-plural-select}
 | |
| 
 | |
| ## Translate _plural_ and _select_
 | |
| Translating _plural_ and _select_ messages is a little tricky.
 | |
| 
 | |
| The `<source>` tag is empty for `plural` and `select` translation
 | |
| units, which makes them hard to correlate with the original template.
 | |
| The `XLIFF` format doesn't yet support the ICU rules.
 | |
| However, the `XMB` format does support the ICU rules.
 | |
| 
 | |
| You'll just have to look for them in relation to other translation units that you recognize from elsewhere in the source template.
 | |
| In this example, you know the translation unit for the `select` must be just below the translation unit for the logo.
 | |
| 
 | |
| {@a translate-plural}
 | |
| 
 | |
| ### Translate _plural_
 | |
| To translate a `plural`, translate its ICU format match values:
 | |
| 
 | |
| <code-example path="i18n/src/locale/messages.es.xlf.html" region="translated-plural" title="src/locale/messages.es.xlf (<trans-unit>)" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| {@a translate-select}
 | |
| 
 | |
| ### Translate _select_
 | |
| The `select` behaves a little differently. Here again is the ICU format message in the component template:
 | |
| 
 | |
| <code-example path="i18n/src/app/app.component.html" region="i18n-select" title="src/app/app.component.html" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| The extraction tool broke that into _two_ translation units.
 | |
| 
 | |
| The first unit contains the text that was _outside_ the `select`.
 | |
| In place of the `select` is a placeholder, `<x id="ICU">`, that represents the `select` message.
 | |
| Translate the text and leave the placeholder where it is.
 | |
| 
 | |
| <code-example path="i18n/src/locale/messages.es.xlf.html" region="translate-select-1" title="src/locale/messages.es.xlf (<trans-unit>)" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| The second translation unit, immediately below the first one, contains the `select` message. Translate that.
 | |
| 
 | |
| <code-example path="i18n/src/locale/messages.es.xlf.html" region="translate-select-2" title="src/locale/messages.es.xlf (<trans-unit>)" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| Here they are together, after translation:
 | |
| 
 | |
| <code-example path="i18n/src/locale/messages.es.xlf.html" region="translated-select" title="src/locale/messages.es.xlf (<trans-unit>)" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| ### Translate a nested expression
 | |
| 
 | |
| A nested expression is not different from the previous ones. As in the previous example, we have _two_ translation units.
 | |
| 
 | |
| The first one contains the text outside the nested expression:
 | |
| 
 | |
| <code-example path="i18n/src/locale/messages.es.xlf.html" region="translate-nested-1" title="src/locale/messages.es.xlf (<trans-unit>)" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| The second unit contains the complete nested expression:
 | |
| 
 | |
| <code-example path="i18n/src/locale/messages.es.xlf.html" region="translate-nested-2" title="src/locale/messages.es.xlf (<trans-unit>)" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| And both together:
 | |
| 
 | |
| <code-example path="i18n/src/locale/messages.es.xlf.html" region="translate-nested" title="src/locale/messages.es.xlf (<trans-unit>)" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| 
 | |
| 
 | |
| The entire template translation is complete. It's
 | |
| time to incorporate that translation into the application.
 | |
| 
 | |
| <a id='app-pre-translation'></a>
 | |
| 
 | |
| ### The app before translation
 | |
| 
 | |
| When the previous steps finish, the sample app _and_ its translation file are as follows:
 | |
| 
 | |
| <code-tabs>
 | |
|   <code-pane title="src/app/app.component.html" path="i18n/src/app/app.component.html">
 | |
|   </code-pane>
 | |
|   <code-pane title="src/app/app.component.ts" path="i18n/src/app/app.component.ts">
 | |
|   </code-pane>
 | |
|   <code-pane title="src/app/app.module.ts" path="i18n/src/app/app.module.ts">
 | |
|   </code-pane>
 | |
|   <code-pane title="src/main.ts" path="i18n/src/main.1.ts">
 | |
|   </code-pane>
 | |
|   <code-pane title="src/locale/messages.es.xlf" path="i18n/src/locale/messages.es.xlf.html">
 | |
|   </code-pane>
 | |
| </code-tabs>
 | |
| 
 | |
| {@a merge}
 | |
| 
 | |
| ## Merge the completed translation file into the app
 | |
| 
 | |
| To merge the translated text into component templates,
 | |
| compile the application with the completed translation file.
 | |
| The process is the same whether the file is in `.xlf` format or
 | |
| in another format that Angular understands, such as `.xtb`.
 | |
| 
 | |
| You provide the Angular compiler with three new pieces of information:
 | |
| 
 | |
|   * The translation file.
 | |
|   * The translation file format.
 | |
|   * The   <a href="https://en.wikipedia.org/wiki/XLIFF">_Locale ID_</a>
 | |
|   (`es` 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](guide/i18n#jit), you provide the information at bootstrap time.
 | |
|   * With [AOT](guide/i18n#aot), you pass the information as `ngc` options.
 | |
| 
 | |
| {@a jit}
 | |
| 
 | |
| ### Merge with the JIT compiler
 | |
| 
 | |
| The JIT 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 file 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 follows:
 | |
| 
 | |
| <code-example path="i18n/src/index.html" region="i18n" title="index.html (launch script)" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| In this sample, the user's language is hard-coded as a global `document.locale` variable
 | |
| in the `index.html`.
 | |
| 
 | |
| {@a text-plugin}
 | |
| 
 | |
| ### SystemJS text plugin
 | |
| 
 | |
| <div class="alert is-important">
 | |
| 
 | |
|   This plugin only applies to an application using SystemJS. If you are using the Angular CLI, please refer to their
 | |
|   [docs](https://github.com/angular/angular-cli/wiki/xi18n).
 | |
| 
 | |
| </div>
 | |
| 
 | |
| Notice the SystemJS mapping of `text` to a `systemjs-text-plugin.js`.
 | |
| With the help of a text plugin, SystemJS can read any file as raw text and
 | |
| return the contents as a string.
 | |
| You'll need it to import the language translation file.
 | |
| 
 | |
| SystemJS doesn't ship with a raw text plugin but it's easy to add.
 | |
| Create the following `systemjs-text-plugin.js` in the `src/` folder:
 | |
| 
 | |
| <code-example path="i18n/src/systemjs-text-plugin.js" title="src/systemjs-text-plugin.js" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| {@a create-translation-providers}
 | |
| 
 | |
| ### 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 file.
 | |
| * `TRANSLATIONS_FORMAT` is the format of the file: `xlf`, `xlf2`, or `xtb`.
 | |
| * `LOCALE_ID` is the locale of the target language.
 | |
| 
 | |
| The `getTranslationProviders()` function in the following `src/app/i18n-providers.ts`
 | |
| creates those providers based on the user's _locale_
 | |
| and the corresponding translation file:
 | |
| 
 | |
| <code-example path="i18n/src/app/i18n-providers.ts" region="without-missing-translation" title="src/app/i18n-providers.ts">
 | |
| </code-example>
 | |
| 
 | |
| 1. It gets the locale from the global `document.locale` variable that was set in `index.html`.
 | |
| 
 | |
| 1. 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 file asynchronously from the server.
 | |
| 
 | |
| 1. It creates a transaction filename from the locale according to the name and location convention
 | |
| [described earlier](guide/i18n#localization-folder).
 | |
| 
 | |
| 1. The `getTranslationsWithSystemJs()` method reads the translation and returns the contents as a string.
 | |
| Notice that it appends `!text` to the filename, telling SystemJS to use the [text plugin](guide/i18n#text-plugin).
 | |
| 
 | |
| 1. The callback composes a providers array with the three translation providers.
 | |
| 
 | |
| 1. Finally, `getTranslationProviders()` returns the entire effort as a promise.
 | |
| 
 | |
| <div class="alert is-important">
 | |
| 
 | |
|   The `LOCALE_ID` has to be a valid locale id as explained in [here](http://userguide.icu-project.org/locale).
 | |
| 
 | |
| </div>
 | |
| 
 | |
| {@a bootstrap-the-app}
 | |
| 
 | |
| ### Bootstrap with translation providers
 | |
| 
 | |
| The Angular `bootstrapModule()` method has a second _options_ parameter
 | |
| that can influence the behavior of the compiler.
 | |
| 
 | |
| You'll create an _options_ object with the translation providers from `getTranslationProviders()`
 | |
| and pass it to `bootstrapModule`.
 | |
| Open the `src/main.ts` and modify the bootstrap code as follows:
 | |
| 
 | |
| <code-example path="i18n/src/main.ts" title="src/main.ts" linenums="false">
 | |
| </code-example>
 | |
| 
 | |
| Notice that it waits for the `getTranslationProviders()` promise to resolve before
 | |
| bootstrapping the app.
 | |
| 
 | |
| The app is now _internationalized_ for English and Spanish and there is a clear path for adding
 | |
| more languages.
 | |
| 
 | |
| {@a aot}
 | |
| 
 | |
| ### _Internationalization_ with the AOT compiler
 | |
| 
 | |
| The JIT compiler translates the application into the target language
 | |
| while compiling dynamically in the browser.
 | |
| That's flexible but may not be fast enough for your users.
 | |
| 
 | |
| 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, in this case `index.html`,
 | |
| you determine which language the user needs
 | |
| and serve the appropriate application package.
 | |
| 
 | |
| This guide 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 compiler to apply a translations file.
 | |
| 
 | |
| Internationalization with the AOT compiler requires
 | |
| some setup specifically for AOT compilation.
 | |
| Start with the application project as shown
 | |
| [just before merging the translation file](guide/i18n#app-pre-translation)
 | |
| and refer to the [AOT guide](guide/aot-compiler) 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 file.
 | |
|   * `--locale`: the name of the locale.
 | |
|   * `--i18nFormat`: the format of the localization file.
 | |
| 
 | |
| For this sample, the Spanish language command would be:
 | |
| 
 | |
| <code-example language="sh" class="code-shell">
 | |
|   ./node_modules/.bin/ngc --i18nFile=./locale/messages.es.xlf --locale=es --i18nFormat=xlf
 | |
| </code-example>
 | |
| 
 | |
| <div class="l-sub-section">
 | |
| 
 | |
| Windows users may have to quote the command:
 | |
| 
 | |
| <code-example language="sh" class="code-shell">
 | |
|   "./node_modules/.bin/ngc" --i18nFile=./locale/messages.es.xlf --locale=es --i18nFormat=xlf
 | |
| </code-example>
 | |
| 
 | |
| </div>
 | |
| 
 | |
| ### Report missing translations
 | |
| 
 | |
| If you forgot to provide a translation, the build will succeed with a warning that you might easily overlook.
 | |
| You can configure the Angular compiler for different "missing translation" behaviors:
 | |
| 
 | |
| * Error
 | |
| * Warning (default)
 | |
| * Ignore
 | |
| 
 | |
| To change the behavior in JIT, you can use the following configuration:
 | |
| 
 | |
| <code-example language="typescript">
 | |
|   { provide: CompilerConfig, useValue: new CompilerConfig({ missingTranslation: MissingTranslationStrategy.Error }) }
 | |
| </code-example>
 | |
| 
 | |
| A good place to use it is the translation providers:
 | |
| 
 | |
| <code-example path="i18n/src/app/i18n-providers.ts" region="missing-translation" title="src/app/i18n-providers.ts"></code-example>
 | |
| 
 | |
| To change the behavior in AOT, add the `--missingTranslation` flag to the compilation command:
 | |
| 
 | |
| <code-example language="sh" class="code-shell">
 | |
|   ./node_modules/.bin/ngc --i18nFile=./locale/messages.es.xlf --locale=es --i18nFormat=xlf --missingTranslation=error
 | |
| </code-example>
 | |
| 
 | |
| {@a maintenance}
 | |
| 
 | |
| ## File maintenance and _id_ changes
 | |
| 
 | |
| As the application evolves, you will change the _i18n_ markup
 | |
| and re-run the `ng-xi18n` extraction tool many times.
 | |
| The _new_ markup that you add is not a problem.
 | |
| But the `id` _can be a serious problem!_
 | |
| 
 | |
| If the `id` is generated by the tool, _most_ changes to _existing_ markup
 | |
| cause the tool to generate a _new_ `id` for the affected translation unit.
 | |
| 
 | |
| After an `id` changes, the translation files are no longer in sync.
 | |
| Because of that, you get some warning messages during re-compilation.
 | |
| The warning messages identify that some translations are missing, but they don't tell you which
 | |
| old `ids` are no longer valid.
 | |
| 
 | |
| If you use a [custom id](#custom-id "Set a custom id"),
 | |
| the tooling preserves the custom `id` as you make changes to the corresponding translation unit. **Use custom _ids_ unless you have a very good reason to do otherwise.**
 | |
| 
 | |
| Whether you use generated or custom `ids`, **always commit all translation message files to source control**,
 | |
| especially the English source `messages.xlf`.
 | |
| The difference between the old and the new `messages.xlf` file
 | |
| will help you find and update `ids` and other changes across your translation files.
 | |
| 
 |