This repository was archived by the owner on Dec 4, 2017. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 877
/
Copy pathi18n.jade
607 lines (461 loc) · 25.1 KB
/
i18n.jade
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
include ../_util-fns
a#top
:marked
Angular's _internationalization_ (_i18n_) tools help make your app available in multiple languages.
## Table of contents
* [Angular and i18n template translation](#angular-i18n)
* [Mark text with the _i18n_ attribute](#i18n-attribute)
* [Add _i18n-..._ translation attributes](#translate-attributes)
* [Set translation ids explicitly](#explicit-id)
* [Handle singular and plural](#cardinality)
* [Select among alternative texts](#select)
* [Create a translation source file with the **_ng-xi18n_ extraction tool**](#ng-xi18n)
* [Translate text messages](#translate)
* [Merge the completed translation file into the app](#merge)
* [Merge with the JIT compiler](#jit)
* [Internationalization with the AOT compiler](#aot)
* [Translation file maintenance and _id_ changes](#maintenance)
:marked
**Try this** <live-example name="cb-i18n" title="i18n Example in Spanish">live example</live-example>
of a JIT-compiled app, translated into Spanish.
a#angular-i18n
.l-main-section
:marked
## 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.
.l-sub-section
:marked
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_".
:marked
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
.l-main-section
:marked
## 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.
.alert.is-helpful
:marked
`i18n` is not an Angular _directive_.
It's a custom _attribute_, recognized by Angular tools and compilers.
After translation, the compiler removes it.
:marked
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=".")
:marked
Add the `i18n` attribute to the tag to mark it for translation.
+makeExample('cb-i18n/ts/app/app.component.1.html', 'i18n-attribute', 'app/app.component.html')(format=".")
:marked
### 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:
+makeExample('cb-i18n/ts/app/app.component.1.html', 'i18n-attribute-desc', 'app/app.component.html')(format=".")
:marked
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>`):
+makeExample('cb-i18n/ts/app/app.component.1.html', 'i18n-attribute-meaning', 'app/app.component.html')(format=".")
:marked
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 facilitiate contextually-specific translations.
a#explicit-id
:marked
### Consider setting a custom _id_ explicitly to improve search and maintenance
By default, the angular _i18n_ extractor tool generates a unique ID for each `i18n` attribute in a template.
This _id_ is ugly, arbitrary, and unfit for humans.
Worse, when you change the translatable text, perhaps to fix a typo,
the extractor tool generates a new _id_ for that translation.
The new _id_ most likely breaks the application and it certainly [complicates maintenance](a#maintenance).
Consider specifying your own, meaninful _id_ in the `i18n` attribute, **prefixed with `@@`**.
+makeExample('cb-i18n/ts/app/app.component.1.html', 'i18n-attribute-solo-id', 'app/app.component.html')(format=".")
:marked
The extractor tool and compiler will use your _id_ and never change it.
Here is the attribute with a _definition_, followed by the explicit `id`:
+makeExample('cb-i18n/ts/app/app.component.1.html', 'i18n-attribute-id', 'app/app.component.html')(format=".")
:marked
Here is a _meaning_ and a _description_ and the _id_ at the end:
+makeExample('cb-i18n/ts/app/app.component.1.html', 'i18n-attribute-meaning-and-id', 'app/app.component.html')(format=".")
:marked
### Translate text without creating an element
Suppose there is a stretch of text that you'd like to translate.
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.
Here are two techniques to try.
(1) Wrap the text in an `<ng-container>` element. The `<ng-container>` is never renderered:
+makeExample('cb-i18n/ts/app/app.component.html', 'i18n-ng-container', 'app/app.component.html')(format=".")
:marked
(2) Wrap the text in a pair of HTML comments:
+makeExample('cb-i18n/ts/app/app.component.html', 'i18n-with-comment', 'app/app.component.html')(format=".")
.l-main-section
a#translate-attributes
:marked
## Add _i18n-..._ translation attributes
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=".")
:marked
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:
+makeExample('cb-i18n/ts/app/app.component.html', 'i18n-title-translate', 'app/app.component.html')(format=".")
:marked
You can also assign a meaning and a description with the `i18n-x="<meaning>|<description>"` syntax.
.l-main-section
a#cardinality
:marked
## 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:
+makeExample('cb-i18n/ts/app/app.component.html', 'i18n-plural', 'app/app.component.html')(format=".")
:marked
* 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
* =1
* =5
* few
* 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}`.
.l-sub-section
:marked
This syntax conforms to the
<a href="http://userguide.icu-project.org/formatparse/messages" target="_blank" title="ICU Message Format">ICU Message Format</a>
that derives from the
<a href="http://cldr.unicode.org/" target="_blank" title="CLDR">Common Locale Data Repository (CLDR),</a>
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#select
:marked
## 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" target="_blank" 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:
+makeExample('cb-i18n/ts/app/app.component.html', 'i18n-select', 'app/app.component.html')(format=".")
a#ng-xi18n
.l-main-section
:marked
## 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
:marked
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
.l-sub-section
:marked
Windows users may have to quote the command like this: `"./node_modules/.bin/ng-xi18n"`
:marked
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#other-formats
:marked
### Other translation formats
You can generate a file named **`messages.xmb`** in the
<a href="http://cldr.unicode.org/development/development-process/design-proposals/xmb" target="_blank">XML Message Bundle (XMB)</a> format
by adding the `--i18nFormat=xmb` flag.
code-example(language="sh" class="code-shell").
./node_modules/.bin/ng-xi18n --i18nFormat=xmb
:marked
This sample sticks with the _XLIFF_ format.
a#ng-xi18n-options
:marked
### 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
a#npm-i18n-script
:marked
### 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",
...
}
:marked
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
:marked
Note the `--` flag before the options.
It tells _npm_ to pass every flag thereafter to `ng-xi18n`.
a#translate
.l-main-section
:marked
## 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 cookbook sample creates a Spanish translation file.
a#localization-folder
:marked
### 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
(for example, internationalization files) there.
.l-sub-section
:marked
Localization and internationalization are
<a href="https://en.wikipedia.org/wiki/Internationalization_and_localization" target="_blank">different but closely related terms</a>.
:marked
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
<a href="https://msdn.microsoft.com/en-us/library/ee825488(v=cs.20).aspx" target="_blank">well-known codeset</a>.
Make a copy of the `messages.xlf` file in the `locale` folder and
rename it `messages.es.xlf`for the Spanish language translation.
Do the same for each target language.
### 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" target="_blank">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:
+makeExample('cb-i18n/ts/locale/messages.es.xlf.html', 'translated-hello', 'locale/messages.es.xlf (<trans-unit>)')(format=".")
:marked
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 Spanish greeting:
+makeExample('cb-i18n/ts/locale/messages.es.xlf.html', 'translated-hello', 'locale/messages.es.xlf (<trans-unit>, after translation)')(format=".")
:marked
Translate the other text nodes the same way:
+makeExample('cb-i18n/ts/locale/messages.es.xlf.html', 'translated-other-nodes', 'locale/messages.es.xlf (<trans-unit>)')(format=".")
.callout.is-critical
header.
Beware of generated ids
:marked
**The tool generated the `id`s for these translation units. Don't touch them.**
Each `id` depend 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)**.
a#translate-plural-select
:marked
## 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; 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.
In this example, you know the translation unit for the `select` must be just below the translation unit for the logo.
:marked
### Translate _plural_
To translate a `plural`, translate its ICU format match values:
+makeExample('cb-i18n/ts/locale/messages.es.xlf.html', 'translated-plural', 'locale/messages.es.xlf (<trans-unit>)')(format=".")
:marked
### Translate _select_
The `select` behaves a little differently. Here again is the ICU format message in the component template:
+makeExample('cb-i18n/ts/app/app.component.html', 'i18n-select', 'app/app.component.html')(format=".")
:marked
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.
+makeExample('cb-i18n/ts/locale/messages.es.xlf.html', 'translate-select-1', 'locale/messages.es.xlf (<trans-unit>)')(format=".")
:marked
The second translation unit, immediately below the first one, contains the `select` message. Translate that.
+makeExample('cb-i18n/ts/locale/messages.es.xlf.html', 'translate-select-2', 'locale/messages.es.xlf (<trans-unit>)')(format=".")
:marked
Here they are together, after translation:
+makeExample('cb-i18n/ts/locale/messages.es.xlf.html', 'translated-select', 'locale/messages.es.xlf (<trans-unit>)')(format=".")
.l-main-content
:marked
The entire template translation is complete. It's
time to incorporate that translation into the application.
#app-pre-translation
:marked
### The app before translation
When the previous steps finish, the sample app _and_ its translation file are as follows:
+makeTabs(`
cb-i18n/ts/app/app.component.html,
cb-i18n/ts/app/app.component.ts,
cb-i18n/ts/app/app.module.ts,
cb-i18n/ts/app/main.1.ts,
cb-i18n/ts/locale/messages.es.xlf.html
`, '', `
app/app.component.html,
app/app.component.ts,
app/app.module.ts,
app/main.ts,
locale/messages.es.xlf
`)
a#merge
.l-main-section
:marked
## 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 (`.xlif` and `.xtb`) that Angular understands.
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" target="_blank">_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](#jit), you provide the information at bootstrap time.
* With [AOT](#aot), you pass the information as `ngc` options.
a#jit
.l-main-section
:marked
### 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:
+makeExample('cb-i18n/ts/index.html', 'i18n', 'index.html (launch script)')(format='.')
:marked
In this sample, the user's language is hardcoded as a global `document.locale` variable
in the `index.html`.
a#text-plugin
:marked
### SystemJS Text plugin
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 root folder:
+makeExample('cb-i18n/ts/systemjs-text-plugin.js', null, 'systemjs-text-plugin.js')(format='.')
:marked
### 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`, `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 file:
+makeExample('cb-i18n/ts/app/i18n-providers.ts', null, 'app/i18n-providers.ts')
:marked
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](#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](#text-plugin).
1. The callback composes a providers array with the three translation providers.
1. Finally, `getTranslationProviders` returns the entire effort as a promise.
### Bootstrap the app 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 `app/main.ts` and modify the bootstrap code as follows:
+makeExample('cb-i18n/ts/app/main.ts', null, 'app/main.ts')(format=".")
:marked
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
.l-main-section
:marked
### _Internationalize_ 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 (`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 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](#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).
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
.l-sub-section
:marked
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
a#maintenance
:marked
## 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.
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.
**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.
You can avoid this problem by supplying your own [custom id explicitly](#explicit-id "Set a custom id explicitly").
The tooling preserves your `id` as you make changes to the corresponding translation unit.
Whether you use generated or explicit `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
help you find and update `id` and other changes across your translation files.