docs(i18n): copy edits to internationalization cookbook (#2980)

* docs(i18n): copy edits

* docs(i18n): copy edit to data.json

* docs(i18n): Ward requested copy edits
This commit is contained in:
Kapunahele Wong 2016-12-14 18:53:09 -05:00 committed by Ward Bell
parent 9a3cbd611f
commit 41833ed08a
2 changed files with 97 additions and 76 deletions

View File

@ -48,7 +48,7 @@
"i18n": { "i18n": {
"title": "Internationalization (i18n)", "title": "Internationalization (i18n)",
"intro": "Translate the app's template text into multiple languages" "intro": "Translate the app's template text into multiple languages."
}, },
"set-document-title": { "set-document-title": {

View File

@ -2,7 +2,7 @@ include ../_util-fns
a#top a#top
:marked :marked
Angular's _internationalization_ ("_i18n_") tools help make your app available in multiple languages. Angular's _internationalization_ (_i18n_) tools help make your app available in multiple languages.
## Table of contents ## Table of contents
@ -11,11 +11,11 @@ a#top
* [Add _i18n-..._ translation attributes](#translate-attributes) * [Add _i18n-..._ translation attributes](#translate-attributes)
* [Handle singular and plural](#cardinality) * [Handle singular and plural](#cardinality)
* [Select among alternative texts](#select) * [Select among alternative texts](#select)
* [Use the **_ng-xi18n_ extraction tool** to create a translation source file](#ng-xi18n) * [Create a translation source file with the **_ng-xi18n_ extraction tool**](#ng-xi18n)
* [Translate](#translate) * [Translate text messages](#translate)
* [Merge the completed translation file into the app](#merge) * [Merge the completed translation file into the app](#merge)
* [JIT configuration](#jit) * [Merge with the JIT compiler](#jit)
* [AOT configuration](#aot) * [Internationalization with the AOT compiler](#aot)
* [Translation file maintenance and _id_ changes](#maintenance) * [Translation file maintenance and _id_ changes](#maintenance)
:marked :marked
@ -32,7 +32,7 @@ a#angular-i18n
takes dedication and enduring commitment. takes dedication and enduring commitment.
Angular's _i18n_ internationalization facilities can help. Angular's _i18n_ internationalization facilities can help.
This page describes the _i18n_ tools to assist translation of component template text This page describes the _i18n_ tools available to assist translation of component template text
into multiple languages. into multiple languages.
@ -55,7 +55,7 @@ a#angular-i18n
replaces the original messages with translated text, and generates a new version of the application replaces the original messages with translated text, and generates a new version of the application
in the target language. in the target language.
You build and deploy a separate version of the application for each supported language. You need to build and deploy a separate version of the application for each supported language.
a#i18n-attribute a#i18n-attribute
.l-main-section .l-main-section
@ -69,10 +69,11 @@ a#i18n-attribute
:marked :marked
`i18n` is not an Angular _directive_. `i18n` is not an Angular _directive_.
It's a custom _attribute_, recognized by Angular tools and compilers. It's a custom _attribute_, recognized by Angular tools and compilers.
It will be removed by the compiler _after_ translation. After translation, the compiler removes it.
:marked :marked
In the accompanying sample, an `<h1>` tag displays a simple English language greeting which you will translate to Spanish: In the accompanying sample, an `<h1>` tag displays a simple English language greeting
that you translate into Spanish:
+makeExample('cb-i18n/ts/app/app.component.1.html', 'greeting', 'app/app.component.html')(format=".") +makeExample('cb-i18n/ts/app/app.component.1.html', 'greeting', 'app/app.component.html')(format=".")
:marked :marked
Add the `i18n` attribute to the tag to mark it for translation. Add the `i18n` attribute to the tag to mark it for translation.
@ -82,30 +83,31 @@ a#i18n-attribute
:marked :marked
### Help the translator with a _description_ and _intent_ ### Help the translator with a _description_ and _intent_
The translator may need a description of the message to translate it accurately. In order to translate it accurately, the translator may
need a description of the message.
Assign a description to the i18n attribute: Assign a description to the i18n attribute:
+makeExample('cb-i18n/ts/app/app.component.1.html', 'i18n-attribute-desc', 'app/app.component.html')(format=".") +makeExample('cb-i18n/ts/app/app.component.1.html', 'i18n-attribute-desc', 'app/app.component.html')(format=".")
:marked :marked
The translator may need to know your _intent_ &mdash; In order to deliver a correct translation, the translator may need to
the true _meaning_ of the text within _this particular_ application context &mdash; know your _intent_&mdash;the true _meaning_ of the text
in order to deliver a correct translation. within _this particular_ application context.
Add some contextual meaning to the assigned string, in front of the description, In front of the description, add some contextual meaning to the assigned string,
separating it from the description with the `|` character (`<meaning>|<description>`): separating it from the description with the `|` character (`<meaning>|<description>`):
+makeExample('cb-i18n/ts/app/app.component.html', 'i18n-attribute-meaning', 'app/app.component.html')(format=".") +makeExample('cb-i18n/ts/app/app.component.html', 'i18n-attribute-meaning', 'app/app.component.html')(format=".")
:marked :marked
While all appearances of a message with the _same_ meaning have the _same_ translation, While all appearances of a message with the _same_ meaning have the _same_ translation,
a message with *different meanings* could have different translations. 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 The Angular extraction tool preserves both the _meaning_ and the _description_ in the translation source file
to facilitiate contextually-specific translations. to facilitiate contextually-specific translations.
### Translate text without creating an element ### Translate text without creating an element
Suppose there is a stretch of text that you'd like to translate. Suppose there is a stretch of text that you'd like to translate.
You could wrap it in a `<span>` but for some reason (CSS comes to mind) You could wrap it in a `<span>` tag but for some reason (CSS comes to mind)
you don't want to create a new DOM element merely to facilitate translation. you don't want to create a new DOM element merely to facilitate translation.
Here are two techniques to try. Here are two techniques to try.
@ -123,7 +125,7 @@ a#i18n-attribute
a#translate-attributes a#translate-attributes
:marked :marked
## Add _i18n-..._ translation attributes ## Add _i18n-..._ translation attributes
You've added an image to your template. You care about accessibility too so you add a `title` tag: You've added an image to your template. You care about accessibility too so you add a `title` attribute:
+makeExample('cb-i18n/ts/app/app.component.1.html', 'i18n-title', 'app/app.component.html')(format=".") +makeExample('cb-i18n/ts/app/app.component.1.html', 'i18n-title', 'app/app.component.html')(format=".")
@ -150,14 +152,16 @@ a#cardinality
In English, depending upon the number of wolves, you could display "no wolves", "one wolf", "two wolves", or "a wolf pack". 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. Other languages might express the _cardinality_ differently.
Here's how you could markup the component template to display the phrase appropriate to the number of wolves: Here's how you could mark up the component template to display the phrase appropriate to the number of wolves:
+makeExample('cb-i18n/ts/app/app.component.html', 'i18n-plural', 'app/app.component.html')(format=".") +makeExample('cb-i18n/ts/app/app.component.html', 'i18n-plural', 'app/app.component.html')(format=".")
:marked :marked
* The first parameter is the key. It will be bound to the component property (`wolves`) that determines the number of wolves. * The first parameter is the key. It is bound to the component property (`wolves`)
* The second parameter indentifies this as a `plural` translation type. that determines the number of wolves.
* The third parameter defines a pluralization pattern consisting of pluralization categories and their matching values. * 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: Pluralization categories include:
* =0 * =0
@ -179,14 +183,14 @@ a#cardinality
:marked :marked
This syntax conforms to the This syntax conforms to the
<a href="http://userguide.icu-project.org/formatparse/messages" target="_blank" title="ICU Message Format">ICU Message Format</a> <a href="http://userguide.icu-project.org/formatparse/messages" target="_blank" title="ICU Message Format">ICU Message Format</a>
which derives from the that derives from the
<a href="http://cldr.unicode.org/" target="_blank" title="CLDR">Common Locale Data Repository (CLDR)</a> <a href="http://cldr.unicode.org/" target="_blank" title="CLDR">Common Locale Data Repository (CLDR),</a>
which specifies the which specifies the
<a href="http://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules" target="_blank" title="Pluralization Rules">pluralization rules</a>. <a href="http://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules" target="_blank" title="Pluralization Rules">pluralization rules</a>.
a#select a#select
:marked :marked
## Select ## Select among alternative texts
The application displays different text depending upon whether the hero is male or female. The application displays different text depending upon whether the hero is male or female.
These text alternatives require translation too. These text alternatives require translation too.
@ -195,7 +199,8 @@ a#select
<a href="http://userguide.icu-project.org/formatparse/messages" target="_blank" title="ICU Message Format">ICU message syntax</a>. <a href="http://userguide.icu-project.org/formatparse/messages" target="_blank" title="ICU Message Format">ICU message syntax</a>.
You choose among alternative translation based on a string value instead of a number. 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 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: The message maps those values to the appropriate translation:
+makeExample('cb-i18n/ts/app/app.component.html', 'i18n-select', 'app/app.component.html')(format=".") +makeExample('cb-i18n/ts/app/app.component.html', 'i18n-select', 'app/app.component.html')(format=".")
@ -222,10 +227,10 @@ code-example(language="sh" class="code-shell").
.l-sub-section .l-sub-section
:marked :marked
Windows users may have to quote the command: like this `"./node_modules/.bin/ng-xi18n"` Windows users may have to quote the command like this: `"./node_modules/.bin/ng-xi18n"`
:marked :marked
By default the tool generates a translation file named **`messages.xlf`** in the By default, the tool generates a translation file named **`messages.xlf`** in the
<a href="https://en.wikipedia.org/wiki/XLIFF" target="_blank">XML Localisation Interchange File Format (XLIFF, version 1.2)</a>. <a href="https://en.wikipedia.org/wiki/XLIFF" target="_blank">XML Localisation Interchange File Format (XLIFF, version 1.2)</a>.
a#other-formats a#other-formats
@ -246,7 +251,8 @@ a#ng-xi18n-options
:marked :marked
### Other options ### Other options
You may have to specify additional options. You may have to specify additional options.
For example, if the `tsconfig.json` TypeScript configuration file is located other than in the root folder, 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: you must identify the path to it with the `-p` option:
code-example(language="sh" class="code-shell"). code-example(language="sh" class="code-shell").
./node_modules/.bin/ng-xi18n -p path/to/tsconfig.json ./node_modules/.bin/ng-xi18n -p path/to/tsconfig.json
@ -272,15 +278,17 @@ code-example(language="sh" class="code-shell").
npm run i18n -- --i18nFormat=xmb -p path/to/tsconfig.json npm run i18n -- --i18nFormat=xmb -p path/to/tsconfig.json
:marked :marked
Note the `--` flag before the options. Note the `--` flag before the options.
It tells _npm_ that every flag thereafter should be passed through to `ng-xi18n`. It tells _npm_ to pass every flag thereafter to `ng-xi18n`.
a#translate a#translate
.l-main-section .l-main-section
:marked :marked
## Translate _los mensajes de texto_ ## Translate text messages
The `ng-xi18n` command generated a translation source file in the project root folder named `messages.xlf`. The `ng-xi18n` command generates a translation source file
The next step is to translate the English language template text into the specific language translation 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 cookbook sample creates a Spanish translation file. files. The cookbook sample creates a Spanish translation file.
a#localization-folder a#localization-folder
@ -291,13 +299,13 @@ a#localization-folder
for the project structure to reflect your entire internationalization effort. for the project structure to reflect your entire internationalization effort.
One approach is to dedicate a folder to localization and store related assets One approach is to dedicate a folder to localization and store related assets
(e.g. internationalization files) there. (for example, internationalization files) there.
.l-sub-section .l-sub-section
:marked :marked
Localization and internationalization are Localization and internationalization are
<a href="https://en.wikipedia.org/wiki/Internationalization_and_localization" target="_blank">different but closely related terms</a>. <a href="https://en.wikipedia.org/wiki/Internationalization_and_localization" target="_blank">different but closely related terms</a>.
:marked :marked
This sample follows that suggestion. It has a `locale` folder under the project root. This cookbook follows that suggestion. It has a `locale` folder under the project root.
Assets within the folder carry a filename extension that matches a language-culture code from a 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" target="_blank">well-known codeset</a>. <a href="https://msdn.microsoft.com/en-us/library/ee825488(v=cs.20).aspx" target="_blank">well-known codeset</a>.
@ -323,10 +331,10 @@ a#localization-folder
.alert.is-important .alert.is-important
:marked :marked
Note that the `id` is generated by the tool. **Don't touch it.** Note that the tool generates the `id`. **Don't touch it.**
Its value depends on the content of the message and its assigned meaning. Its value depends on the content of the message and its assigned meaning.
Change either factor and the `id` changes as well. Change either factor and the `id` changes as well.
See the **[translation file maintenance discussion](#maintenance)** below. See the **[translation file maintenance discussion](#maintenance)**.
:marked :marked
Translate the other text nodes the same way: Translate the other text nodes the same way:
@ -338,9 +346,10 @@ a#translate-plural-select
## Translate _plural_ and _select_ ## Translate _plural_ and _select_
Translating _plural_ and _select_ messages is a little tricky. 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 `<source>` tag is empty for `plural` and `select` translation
The ICU rules are not yet supported in the `XLIFF` format; they soon will be. units, which makes them hard to correlate with the original template.
The ICU rules _are_ supported in the `XMB` format. The `XLIFF` format doesn't yet support the ICU rules; it soon will.
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. 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. In this example, you know the translation unit for the `select` must be just below the translation unit for the logo.
@ -378,13 +387,14 @@ a#translate-plural-select
.l-main-content .l-main-content
:marked :marked
The entire template translation is complete. It's time to incorporate that translation in the application. The entire template translation is complete. It's
time to incorporate that translation into the application.
#app-pre-translation #app-pre-translation
:marked :marked
### The app before translation ### The app before translation
After the previous steps, the sample app _and_ its translation file are as follows: When the previous steps finish, the sample app _and_ its translation file are as follows:
+makeTabs(` +makeTabs(`
cb-i18n/ts/app/app.component.html, cb-i18n/ts/app/app.component.html,
@ -403,12 +413,12 @@ a#translate-plural-select
a#merge a#merge
.l-main-section .l-main-section
:marked :marked
## Merge the completed translation file ## Merge the completed translation file into the app
To merge the translated text into component templates, To merge the translated text into component templates,
you compile the application with the completed translation file. compile the application with the completed translation file.
The process is the same whether the file is in `.xlf` format or The process is the same whether the file is in `.xlf` format or
in one of the other formats (`.xlif` and `.xtb`) that Angular understands. in another format (`.xlif` and `.xtb`) that Angular understands.
You provide the Angular compiler with three new pieces of information: You provide the Angular compiler with three new pieces of information:
* the translation file * the translation file
@ -419,23 +429,23 @@ a#merge
_How_ you provide this information depends upon whether you compile with _How_ you provide this information depends upon whether you compile with
the JIT (_Just-in-Time_) compiler or the AOT (_Ahead-of-Time_) compiler. the JIT (_Just-in-Time_) compiler or the AOT (_Ahead-of-Time_) compiler.
* with [JIT](#jit), you provide the information at bootstrap time. * With [JIT](#jit), you provide the information at bootstrap time.
* with [AOT](#aot), you pass the information as `ngc` options. * With [AOT](#aot), you pass the information as `ngc` options.
a#jit a#jit
.l-main-section .l-main-section
:marked :marked
### Merge with the JIT compiler ### Merge with the JIT compiler
The JIT (_Just-in-Time_) compiler compiles the application in the browser as the application loads. The JIT compiler compiles the application in the browser as the application loads.
Translation with the JIT compiler is a dynamic process of ... Translation with the JIT compiler is a dynamic process of:
1. determining the language version for the current user, 1. Determining the language version for the current user.
2. importing the appropriate language translation file as a string constant, 2. Importing the appropriate language translation file as a string constant.
3. creating corresponding translation providers to guide the JIT compiler, 3. Creating corresponding translation providers to guide the JIT compiler.
4. bootstrapping the application with those providers. 4. Bootstrapping the application with those providers.
Open `index.html` and revise the launch script as shown here: Open `index.html` and revise the launch script as follows:
+makeExample('cb-i18n/ts/index.html', 'i18n', 'index.html (launch script)')(format='.') +makeExample('cb-i18n/ts/index.html', 'i18n', 'index.html (launch script)')(format='.')
:marked :marked
In this sample, the user's language is hardcoded as a global `document.locale` variable In this sample, the user's language is hardcoded as a global `document.locale` variable
@ -446,7 +456,7 @@ a#text-plugin
### SystemJS Text plugin ### SystemJS Text plugin
Notice the SystemJS mapping of `text` to a `systemjs-text-plugin.js`. Notice the SystemJS mapping of `text` to a `systemjs-text-plugin.js`.
With the help of a text pluglin, SystemJS can read any file as raw text and With the help of a text plugin, SystemJS can read any file as raw text and
return the contents as a string. return the contents as a string.
You'll need it to import the language translation file. You'll need it to import the language translation file.
@ -460,7 +470,7 @@ a#text-plugin
while compiling the application: while compiling the application:
* `TRANSLATIONS` is a string containing the content of the translation file. * `TRANSLATIONS` is a string containing the content of the translation file.
* `TRANSLATIONS_FORMAT` is the format of the file: `xlf`, `xlif` or `xtb` * `TRANSLATIONS_FORMAT` is the format of the file: `xlf`, `xlif` or `xtb`.
* `LOCALE_ID` is the locale of the target language. * `LOCALE_ID` is the locale of the target language.
The `getTranslationProviders` function in the following `app/i18n-providers.ts` The `getTranslationProviders` function in the following `app/i18n-providers.ts`
@ -468,21 +478,21 @@ a#text-plugin
and the corresponding translation file: and the corresponding translation file:
+makeExample('cb-i18n/ts/app/i18n-providers.ts', null, 'app/i18n-providers.ts') +makeExample('cb-i18n/ts/app/i18n-providers.ts', null, 'app/i18n-providers.ts')
:marked :marked
* It gets the locale from the global `document.locale` variable that was set in `index.html`. 1. 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. 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`. 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. It must return a `Promise` because this function could read a translation file asynchronously from the server.
* It creates a transaction filename from the locale according to the name and location convention 1. It creates a transaction filename from the locale according to the name and location convention
[described earlier](#localization-folder). [described earlier](#localization-folder).
* The `getTranslationsWithSystemJs` method reads the translation and returns the contents as a string. 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](#text-plugin). Notice that it appends `!text` to the filename, telling SystemJS to use the [text plugin](#text-plugin).
* The callback composes a providers array with the three translation providers. 1. The callback composes a providers array with the three translation providers.
* Finally, `getTranslationProviders` returns the entire effort as a promise. 1. Finally, `getTranslationProviders` returns the entire effort as a promise.
### Bootstrap the app with translation providers ### Bootstrap the app with translation providers
@ -505,21 +515,27 @@ a#aot
:marked :marked
### _Internationalize_ with the AOT compiler ### _Internationalize_ with the AOT compiler
The JIT compiler translates the application into the target language while compiling dynamically in the browser. 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. 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. The AOT (_Ahead-of-Time_) compiler is part of a build process that
When you internationalize with the AOT compiler, you pre-build a separate application package for each produces a small, fast, ready-to-run application package.
language. Then in the host web page (`index.html`), you determine which language the user needs 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. and serve the appropriate application package.
This cookbook doesn't cover how to build multiple application packages and This cookbook doesn't cover how to build multiple application packages and
serve them according to the user's language preference. serve them according to the user's language preference.
It does explain the few steps necessary to tell the AOT to apply a translations file. 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. Internationalization with the AOT compiler requires
Start with application project as shown [just before merging the translation file](#app-pre-translationStart) some setup specifically for AOT compilation.
and refer to the [AOT cookbook](aot-compiler.html) to make it _AoT-ready_. Start with the application project as shown
[just before merging the translation file](#app-pre-translation)
and refer to the [AOT cookbook](aot-compiler.html) to make it _AOT-ready_.
Next, issue an `ngc` compile command for each supported language (including English). Next, issue an `ngc` compile command for each supported language (including English).
The result is a separate version of the application for each language. The result is a separate version of the application for each language.
@ -543,13 +559,18 @@ a#maintenance
:marked :marked
## Translation file maintenance and _id_ changes ## Translation 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. As the application evolves, you will change the _i18n_ markup
The _new_ markup that you add is not a problem. and re-run the `ng-xi18n` extraction tool many times.
But _most_ changes to _existing_ markup will trigger generation of _new_ `id`s for the affected translation units. The _new_ markup that you add is not a problem;
but _most_ changes to _existing_ markup trigger
generation of _new_ `id`s for the affected translation units.
After an `id` changes, the translation files are no longer in-sync. After an `id` changes, the translation files are no longer in-sync.
**All translated versions of the application will fail** during re-compilation. **All translated versions of the application will fail** during re-compilation.
The error messages identify the old `id`s that are no longer valid but they don't tell you what the new `id`s should be. The error messages identify the old `id`s that are no longer valid but
they don't tell you what the new `id`s should be.
**Commit all translation message files to source control**, especially the English source `messages.xlf`. **Commit all translation message files to source control**,
The difference between the old and the new `messages.xlf` file will help you find and update `id` changes across your translation files. especially the English source `messages.xlf`.
The difference between the old and the new `messages.xlf` file
help you find and update `id` changes across your translation files.