To merge the completed translations into your project, complete the following actions
- Use the
Angular CLI
to build a copy of the distributable files of your project
- Use the
"localize"
option to replace all of the i18n messages with the valid translations and build a localized variant application.
A variant application is a complete a copy of the distributable files of your application translated for a single locale.
After you merge the translations, serve each distributable copy of the application using server-side language detection or different subdirectories.
For a compile-time translation of the application, the build process uses ahead-of-time (AOT) compilation to produce a small, fast, ready-to-run application.
To build a separate distributable copy of the application for each locale,
define the locales in the build configuration
in the
angular.json
workspace build configuration file of your project.
This method shortens the build process by removing the requirement to perform a full application build for each locale.
To
generate application variants for each locale
, use the
"localize"
option in the
angular.json
workspace build configuration file.
Also, to
build from the command line
, use the
build
Angular CLI
command with the
--localize
option.
Use the
i18n
project option in the
angular.json
workspace build configuration file of your project to define locales for a project.
The following sub-options identify the source language and tell the compiler where to find supported translations for the project.
For example, the following excerpt of an
angular.json
workspace build configuration file sets the source locale to
en-US
and provides the path to the French (
fr
) locale translation file.
{
"$schema"
:
"./node_modules/@angular/cli/lib/config/schema.json"
,
"version"
:
1
,
"newProjectRoot"
:
"projects"
,
"projects"
: {
"angular.io-example"
: {
"projectType"
:
"application"
,
"root"
:
""
,
"sourceRoot"
:
"src"
,
"prefix"
:
"app"
,
"i18n"
: {
"sourceLocale"
:
"en-US"
,
"locales"
: {
"fr"
: {
"translation"
:
"src/locale/messages.fr.xlf"
,
"baseHref"
:
""
}
}
},
"architect"
: {
"build"
: {
"builder"
:
"@angular-devkit/build-angular:browser"
,
"options"
: {
"localize"
: true,
"outputPath"
:
"dist"
,
"index"
:
"src/index.html"
,
"main"
:
"src/main.ts"
,
"polyfills"
: [
"zone.js"
],
"tsConfig"
:
"tsconfig.app.json"
,
"assets"
: [
"src/favicon.ico"
,
"src/assets"
],
"styles"
: [
"src/styles.css"
],
"scripts"
: [],
"i18nMissingTranslation"
:
"error"
},
"configurations"
: {
"production"
: {
"budgets"
: [
{
"type"
:
"initial"
,
"maximumWarning"
:
"500kb"
,
"maximumError"
:
"1mb"
},
{
"type"
:
"anyComponentStyle"
,
"maximumWarning"
:
"2kb"
,
"maximumError"
:
"4kb"
}
],
"outputHashing"
:
"all"
},
"development"
: {
"localize"
: false,
"buildOptimizer"
: false,
"optimization"
: false,
"vendorChunk"
: true,
"extractLicenses"
: false,
"sourceMap"
: true,
"namedChunks"
: true
},
"fr"
: {
"localize"
: [
"fr"
]
}
},
"defaultConfiguration"
:
"production"
},
"serve"
: {
"builder"
:
"@angular-devkit/build-angular:dev-server"
,
"configurations"
: {
"production"
: {
"buildTarget"
:
"angular.io-example:build:production"
},
"development"
: {
"buildTarget"
:
"angular.io-example:build:development"
},
"fr"
: {
"buildTarget"
:
"angular.io-example:build:development,fr"
}
},
"defaultConfiguration"
:
"development"
},
"extract-i18n"
: {
"builder"
:
"@angular-devkit/build-angular:extract-i18n"
,
"options"
: {
"buildTarget"
:
"angular.io-example:build"
}
},
"test"
: {
"builder"
:
"@angular-devkit/build-angular:karma"
,
"options"
: {
"polyfills"
: [
"zone.js"
,
"zone.js/testing"
],
"tsConfig"
:
"tsconfig.spec.json"
,
"assets"
: [
"src/favicon.ico"
,
"src/assets"
],
"styles"
: [
"src/styles.css"
],
"scripts"
: []
}
},
"e2e"
: {
"builder"
:
"@angular-devkit/build-angular:protractor"
,
"options"
: {
"protractorConfig"
:
"e2e/protractor.conf.js"
,
"devServerTarget"
:
"angular.io-example:serve:fr"
},
"configurations"
: {
"production"
: {
"devServerTarget"
:
"angular.io-example:serve:production"
}
}
}
}
}
}
}
To use your locale definition in the build configuration, use the
"localize"
option in the
angular.json
workspace build configuration file to tell the CLI which locales to generate for the build configuration.
- Set
"localize"
to
true
for all the locales previously defined in the build configuration.
- Set
"localize"
to an array of a subset of the previously defined locale identifiers to build only those locale versions.
- Set
"localize"
to
false
to disable localization and not generate any locale-specific versions.
HELPFUL:
Ahead-of-time (AOT) compilation is required to localize component templates.
If you changed this setting, set
"aot"
to
true
in order to use AOT.
HELPFUL:
Due to the deployment complexities of i18n and the need to minimize rebuild time, the development server only supports localizing a single locale at a time.
If you set the
"localize"
option to
true
, define more than one locale, and use
ng serve
; then an error occurs.
If you want to develop against a specific locale, set the
"localize"
option to a specific locale.
For example, for French (
fr
), specify
"localize": ["fr"]
.
The CLI loads and registers the locale data, places each generated version in a locale-specific directory to keep it separate from other locale versions, and puts the directories within the configured
outputPath
for the project.
For each application variant the
lang
attribute of the
html
element is set to the locale.
The CLI also adjusts the HTML base HREF for each version of the application by adding the locale to the configured
baseHref
.
Set the
"localize"
property as a shared configuration to effectively inherit for all the configurations.
Also, set the property to override other configurations.
The following example displays the
"localize"
option set to
true
in the
angular.json
workspace build configuration file, so that all locales defined in the build configuration are built.
{
"$schema"
:
"./node_modules/@angular/cli/lib/config/schema.json"
,
"version"
:
1
,
"newProjectRoot"
:
"projects"
,
"projects"
: {
"angular.io-example"
: {
"projectType"
:
"application"
,
"root"
:
""
,
"sourceRoot"
:
"src"
,
"prefix"
:
"app"
,
"i18n"
: {
"sourceLocale"
:
"en-US"
,
"locales"
: {
"fr"
: {
"translation"
:
"src/locale/messages.fr.xlf"
,
"baseHref"
:
""
}
}
},
"architect"
: {
"build"
: {
"builder"
:
"@angular-devkit/build-angular:browser"
,
"options"
: {
"localize"
: true,
"outputPath"
:
"dist"
,
"index"
:
"src/index.html"
,
"main"
:
"src/main.ts"
,
"polyfills"
: [
"zone.js"
],
"tsConfig"
:
"tsconfig.app.json"
,
"assets"
: [
"src/favicon.ico"
,
"src/assets"
],
"styles"
: [
"src/styles.css"
],
"scripts"
: [],
"i18nMissingTranslation"
:
"error"
},
"configurations"
: {
"production"
: {
"budgets"
: [
{
"type"
:
"initial"
,
"maximumWarning"
:
"500kb"
,
"maximumError"
:
"1mb"
},
{
"type"
:
"anyComponentStyle"
,
"maximumWarning"
:
"2kb"
,
"maximumError"
:
"4kb"
}
],
"outputHashing"
:
"all"
},
"development"
: {
"localize"
: false,
"buildOptimizer"
: false,
"optimization"
: false,
"vendorChunk"
: true,
"extractLicenses"
: false,
"sourceMap"
: true,
"namedChunks"
: true
},
"fr"
: {
"localize"
: [
"fr"
]
}
},
"defaultConfiguration"
:
"production"
},
"serve"
: {
"builder"
:
"@angular-devkit/build-angular:dev-server"
,
"configurations"
: {
"production"
: {
"buildTarget"
:
"angular.io-example:build:production"
},
"development"
: {
"buildTarget"
:
"angular.io-example:build:development"
},
"fr"
: {
"buildTarget"
:
"angular.io-example:build:development,fr"
}
},
"defaultConfiguration"
:
"development"
},
"extract-i18n"
: {
"builder"
:
"@angular-devkit/build-angular:extract-i18n"
,
"options"
: {
"buildTarget"
:
"angular.io-example:build"
}
},
"test"
: {
"builder"
:
"@angular-devkit/build-angular:karma"
,
"options"
: {
"polyfills"
: [
"zone.js"
,
"zone.js/testing"
],
"tsConfig"
:
"tsconfig.spec.json"
,
"assets"
: [
"src/favicon.ico"
,
"src/assets"
],
"styles"
: [
"src/styles.css"
],
"scripts"
: []
}
},
"e2e"
: {
"builder"
:
"@angular-devkit/build-angular:protractor"
,
"options"
: {
"protractorConfig"
:
"e2e/protractor.conf.js"
,
"devServerTarget"
:
"angular.io-example:serve:fr"
},
"configurations"
: {
"production"
: {
"devServerTarget"
:
"angular.io-example:serve:production"
}
}
}
}
}
}
}
Also, use the
--localize
option with the
ng build
command and your existing
production
configuration.
The CLI builds all locales defined in the build configuration.
If you set the locales in build configuration, it is similar to when you set the
"localize"
option to
true
.
ng
add
@angular/localize
ng extract-i18n
ng extract-i18n --output-path src/locale
ng extract-i18n
--format
=xlf
ng extract-i18n
--format
=xlf2
ng extract-i18n
--format
=xmb
ng extract-i18n
--format
=json
ng extract-i18n
--format
=arb
ng extract-i18n --out-file source.xlf
ng build --localize
ng serve
--configuration
=fr
ng build
--configuration
=production,fr
To apply specific build options to only one locale, specify a single locale to create a custom locale-specific configuration.
IMPORTANT:
Use the
Angular CLI
development server (
ng serve
) with only a single locale.
The following example displays a custom locale-specific configuration using a single locale.
{
"$schema"
:
"./node_modules/@angular/cli/lib/config/schema.json"
,
"version"
:
1
,
"newProjectRoot"
:
"projects"
,
"projects"
: {
"angular.io-example"
: {
"projectType"
:
"application"
,
"root"
:
""
,
"sourceRoot"
:
"src"
,
"prefix"
:
"app"
,
"i18n"
: {
"sourceLocale"
:
"en-US"
,
"locales"
: {
"fr"
: {
"translation"
:
"src/locale/messages.fr.xlf"
,
"baseHref"
:
""
}
}
},
"architect"
: {
"build"
: {
"builder"
:
"@angular-devkit/build-angular:browser"
,
"options"
: {
"localize"
: true,
"outputPath"
:
"dist"
,
"index"
:
"src/index.html"
,
"main"
:
"src/main.ts"
,
"polyfills"
: [
"zone.js"
],
"tsConfig"
:
"tsconfig.app.json"
,
"assets"
: [
"src/favicon.ico"
,
"src/assets"
],
"styles"
: [
"src/styles.css"
],
"scripts"
: [],
"i18nMissingTranslation"
:
"error"
},
"configurations"
: {
"production"
: {
"budgets"
: [
{
"type"
:
"initial"
,
"maximumWarning"
:
"500kb"
,
"maximumError"
:
"1mb"
},
{
"type"
:
"anyComponentStyle"
,
"maximumWarning"
:
"2kb"
,
"maximumError"
:
"4kb"
}
],
"outputHashing"
:
"all"
},
"development"
: {
"localize"
: false,
"buildOptimizer"
: false,
"optimization"
: false,
"vendorChunk"
: true,
"extractLicenses"
: false,
"sourceMap"
: true,
"namedChunks"
: true
},
"fr"
: {
"localize"
: [
"fr"
]
}
},
"defaultConfiguration"
:
"production"
},
"serve"
: {
"builder"
:
"@angular-devkit/build-angular:dev-server"
,
"configurations"
: {
"production"
: {
"buildTarget"
:
"angular.io-example:build:production"
},
"development"
: {
"buildTarget"
:
"angular.io-example:build:development"
},
"fr"
: {
"buildTarget"
:
"angular.io-example:build:development,fr"
}
},
"defaultConfiguration"
:
"development"
},
"extract-i18n"
: {
"builder"
:
"@angular-devkit/build-angular:extract-i18n"
,
"options"
: {
"buildTarget"
:
"angular.io-example:build"
}
},
"test"
: {
"builder"
:
"@angular-devkit/build-angular:karma"
,
"options"
: {
"polyfills"
: [
"zone.js"
,
"zone.js/testing"
],
"tsConfig"
:
"tsconfig.spec.json"
,
"assets"
: [
"src/favicon.ico"
,
"src/assets"
],
"styles"
: [
"src/styles.css"
],
"scripts"
: []
}
},
"e2e"
: {
"builder"
:
"@angular-devkit/build-angular:protractor"
,
"options"
: {
"protractorConfig"
:
"e2e/protractor.conf.js"
,
"devServerTarget"
:
"angular.io-example:serve:fr"
},
"configurations"
: {
"production"
: {
"devServerTarget"
:
"angular.io-example:serve:production"
}
}
}
}
}
}
}
Pass this configuration to the
ng serve
or
ng build
commands.
The following code example displays how to serve the French language file.
ng
add
@angular/localize
ng extract-i18n
ng extract-i18n --output-path src/locale
ng extract-i18n
--format
=xlf
ng extract-i18n
--format
=xlf2
ng extract-i18n
--format
=xmb
ng extract-i18n
--format
=json
ng extract-i18n
--format
=arb
ng extract-i18n --out-file source.xlf
ng build --localize
ng serve
--configuration
=fr
ng build
--configuration
=production,fr
For production builds, use configuration composition to run both configurations.
ng
add
@angular/localize
ng extract-i18n
ng extract-i18n --output-path src/locale
ng extract-i18n
--format
=xlf
ng extract-i18n
--format
=xlf2
ng extract-i18n
--format
=xmb
ng extract-i18n
--format
=json
ng extract-i18n
--format
=arb
ng extract-i18n --out-file source.xlf
ng build --localize
ng serve
--configuration
=fr
ng build
--configuration
=production,fr
{
"$schema"
:
"./node_modules/@angular/cli/lib/config/schema.json"
,
"version"
:
1
,
"newProjectRoot"
:
"projects"
,
"projects"
: {
"angular.io-example"
: {
"projectType"
:
"application"
,
"root"
:
""
,
"sourceRoot"
:
"src"
,
"prefix"
:
"app"
,
"i18n"
: {
"sourceLocale"
:
"en-US"
,
"locales"
: {
"fr"
: {
"translation"
:
"src/locale/messages.fr.xlf"
,
"baseHref"
:
""
}
}
},
"architect"
: {
"build"
: {
"builder"
:
"@angular-devkit/build-angular:browser"
,
"options"
: {
"localize"
: true,
"outputPath"
:
"dist"
,
"index"
:
"src/index.html"
,
"main"
:
"src/main.ts"
,
"polyfills"
: [
"zone.js"
],
"tsConfig"
:
"tsconfig.app.json"
,
"assets"
: [
"src/favicon.ico"
,
"src/assets"
],
"styles"
: [
"src/styles.css"
],
"scripts"
: [],
"i18nMissingTranslation"
:
"error"
},
"configurations"
: {
"production"
: {
"budgets"
: [
{
"type"
:
"initial"
,
"maximumWarning"
:
"500kb"
,
"maximumError"
:
"1mb"
},
{
"type"
:
"anyComponentStyle"
,
"maximumWarning"
:
"2kb"
,
"maximumError"
:
"4kb"
}
],
"outputHashing"
:
"all"
},
"development"
: {
"localize"
: false,
"buildOptimizer"
: false,
"optimization"
: false,
"vendorChunk"
: true,
"extractLicenses"
: false,
"sourceMap"
: true,
"namedChunks"
: true
},
"fr"
: {
"localize"
: [
"fr"
]
}
},
"defaultConfiguration"
:
"production"
},
"serve"
: {
"builder"
:
"@angular-devkit/build-angular:dev-server"
,
"configurations"
: {
"production"
: {
"buildTarget"
:
"angular.io-example:build:production"
},
"development"
: {
"buildTarget"
:
"angular.io-example:build:development"
},
"fr"
: {
"buildTarget"
:
"angular.io-example:build:development,fr"
}
},
"defaultConfiguration"
:
"development"
},
"extract-i18n"
: {
"builder"
:
"@angular-devkit/build-angular:extract-i18n"
,
"options"
: {
"buildTarget"
:
"angular.io-example:build"
}
},
"test"
: {
"builder"
:
"@angular-devkit/build-angular:karma"
,
"options"
: {
"polyfills"
: [
"zone.js"
,
"zone.js/testing"
],
"tsConfig"
:
"tsconfig.spec.json"
,
"assets"
: [
"src/favicon.ico"
,
"src/assets"
],
"styles"
: [
"src/styles.css"
],
"scripts"
: []
}
},
"e2e"
: {
"builder"
:
"@angular-devkit/build-angular:protractor"
,
"options"
: {
"protractorConfig"
:
"e2e/protractor.conf.js"
,
"devServerTarget"
:
"angular.io-example:serve:fr"
},
"configurations"
: {
"production"
: {
"devServerTarget"
:
"angular.io-example:serve:production"
}
}
}
}
}
}
}
When a translation is missing, the build succeeds but generates a warning such as
Missing translation for message "{translation_text}"
.
To configure the level of warning that is generated by the Angular compiler, specify one of the following levels.
Specify the warning level in the
options
section for the
build
target of your
angular.json
workspace build configuration file.
The following example displays how to set the warning level to
error
.
{
"$schema"
:
"./node_modules/@angular/cli/lib/config/schema.json"
,
"version"
:
1
,
"newProjectRoot"
:
"projects"
,
"projects"
: {
"angular.io-example"
: {
"projectType"
:
"application"
,
"root"
:
""
,
"sourceRoot"
:
"src"
,
"prefix"
:
"app"
,
"i18n"
: {
"sourceLocale"
:
"en-US"
,
"locales"
: {
"fr"
: {
"translation"
:
"src/locale/messages.fr.xlf"
,
"baseHref"
:
""
}
}
},
"architect"
: {
"build"
: {
"builder"
:
"@angular-devkit/build-angular:browser"
,
"options"
: {
"localize"
: true,
"outputPath"
:
"dist"
,
"index"
:
"src/index.html"
,
"main"
:
"src/main.ts"
,
"polyfills"
: [
"zone.js"
],
"tsConfig"
:
"tsconfig.app.json"
,
"assets"
: [
"src/favicon.ico"
,
"src/assets"
],
"styles"
: [
"src/styles.css"
],
"scripts"
: [],
"i18nMissingTranslation"
:
"error"
},
"configurations"
: {
"production"
: {
"budgets"
: [
{
"type"
:
"initial"
,
"maximumWarning"
:
"500kb"
,
"maximumError"
:
"1mb"
},
{
"type"
:
"anyComponentStyle"
,
"maximumWarning"
:
"2kb"
,
"maximumError"
:
"4kb"
}
],
"outputHashing"
:
"all"
},
"development"
: {
"localize"
: false,
"buildOptimizer"
: false,
"optimization"
: false,
"vendorChunk"
: true,
"extractLicenses"
: false,
"sourceMap"
: true,
"namedChunks"
: true
},
"fr"
: {
"localize"
: [
"fr"
]
}
},
"defaultConfiguration"
:
"production"
},
"serve"
: {
"builder"
:
"@angular-devkit/build-angular:dev-server"
,
"configurations"
: {
"production"
: {
"buildTarget"
:
"angular.io-example:build:production"
},
"development"
: {
"buildTarget"
:
"angular.io-example:build:development"
},
"fr"
: {
"buildTarget"
:
"angular.io-example:build:development,fr"
}
},
"defaultConfiguration"
:
"development"
},
"extract-i18n"
: {
"builder"
:
"@angular-devkit/build-angular:extract-i18n"
,
"options"
: {
"buildTarget"
:
"angular.io-example:build"
}
},
"test"
: {
"builder"
:
"@angular-devkit/build-angular:karma"
,
"options"
: {
"polyfills"
: [
"zone.js"
,
"zone.js/testing"
],
"tsConfig"
:
"tsconfig.spec.json"
,
"assets"
: [
"src/favicon.ico"
,
"src/assets"
],
"styles"
: [
"src/styles.css"
],
"scripts"
: []
}
},
"e2e"
: {
"builder"
:
"@angular-devkit/build-angular:protractor"
,
"options"
: {
"protractorConfig"
:
"e2e/protractor.conf.js"
,
"devServerTarget"
:
"angular.io-example:serve:fr"
},
"configurations"
: {
"production"
: {
"devServerTarget"
:
"angular.io-example:serve:production"
}
}
}
}
}
}
}
HELPFUL:
When you compile your Angular project into an Angular application, the instances of the
i18n
attribute are replaced with instances of the
$localize
tagged message string.
This means that your Angular application is translated after compilation.
This also means that you can create localized versions of your Angular application without re-compiling your entire Angular project for each locale.
When you translate your Angular application, the
translation transformation
replaces and reorders the parts (static strings and expressions) of the template literal string with strings from a collection of translations.
For more information, see
$localize
.
TL;DR:
Compile once, then translate for each locale.