Open coder123er opened 3 years ago
I'm running this command in Angular 11: "ng extract-i18n projectName --ivy --format xlf --outputPath outputFolder && ng run projectName:xliffmerge"
@melcor76
"ng extract-i18n projectName --ivy --format xlf --outputPath outputFolder && ng run projectName:xliffmerge" Is the above command working for you??
In my case the first part of the command ng extract-i18n projectName --ivy --format xlf --outputPath outputFolder works fine and it generates message.xlf file but the second part of the command which is "ng run projectName:xliffmerge" gives an error as below
An unhandled exception occurred: Could not find the implementation for builder @ngx-i18nsupport/tooling:xliffmerge See "C:\Users\CENTRA~1\AppData\Local\Temp\ng-r6zg82\angular-errors.log" for further details.
I am stucked at merging the message.xlf file with other locale files.
@coder123er Yes, its working for me. It sounds from the error that its your configuration that might be missing something. I'll copy what I wrote about this in our docs so you can see if you are missing something.
Use the i18n project option in your app's build configuration file (angular.json
) 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:
sourceLocale
: The locale you use within the app source code (en-US by default)locales
: A map of locale identifiers to translation filesFor example, the following excerpt of an angular.json
file sets the source locale to en-US
and provides the path to the nb
(Norwegian) locale translation file:
"projects": {
"portal": {
"i18n": {
"sourceLocale": "en-US",
"locales": {
"nb": "i18n/messages.nb.xlf"
}
}
}
With this change you will be able to start the Norwegian version of the app and make sure the translations are working:
ng serve --configuration=nb --open
We use a tool called Xliffmerge to create the localized translation files. Add the new language to the configurations in angular.json
under projects -> portal -> architect -> xliffmerge
.
"xliffmerge": {
"options": {
"xliffmergeOptions": {
"defaultLanguage": "en-US",
"languages": ["nb"]
}
}
}
To apply specific build options to only one locale, you can create a custom locale-specific configuration in angular.json
by specifying a single locale as shown in the following example for Norwegian:
"build": {
"configurations": {
"nb": {
"localize": ["nb"]
}
}
},
"serve": {
"configurations": {
"nb": {
"browserTarget": "portal:build:nb"
}
}
}
You can then pass this configuration to the ng serve or ng build commands with --configuration=nb
.
Add a new line to the language specific start commands (start:xx
) in the scripts
section in package.json
. When done you can run the application with the new language with:
npm run start:nb
To create translation files for each language we copy the source language file. For example, to create a Norwegian translation file make a copy of the messages.xlf
file and rename it to messages.nb.xlf
.
Doing this for all files every time there is a new translation is a bit tedious so we can use tooling for this. With the help of xliffmerge we can run a script that extracts the translations and merges them into the language files with the command:
npm run translations
We send all the translations to the i18n
folder by providing the --output-path
in the script.
@melcor76
I tried with the above mentioned configurations, but faced the following error:
could you please help me with this.
Hi Martin,
When I use single locale as per the steps you have mentioned, I face the error as I shown in screenshot above.
My requirement is to translate multiple locale files at the same time so I need to use Xliffmerge tool. Could you please guide me , how can we do that on Angular 10.
I encounter following error for using builder as Xliffmerge:
{ "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "angular": { "root": "", "sourceRoot": "src", "projectType": "application", "prefix": "app", "schematics": {}, "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", "options": { "outputPath": "dist/angular", "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "src/tsconfig.app.json", "styles": [ { "input": "node_modules/@progress/kendo-theme-default/dist/all.css" }, "./node_modules/@angular/material/prebuilt-themes/purple-green.css", "node_modules/bootstrap/dist/css/bootstrap.min.css", "src/assets/css/scheduler.scss", "src/assets/css/styles.css", "src/assets/css/dev.css", "src/assets/css/responsive.css", "src/assets/css/mobile-chrome-fix.css", "src/assets/css/desktop.scss", "src/assets/css/mobile.scss" ], "scripts": [] }, "configurations": { "production": { "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" } ], "optimization": true, "outputHashing": "all", "sourceMap": false, "extractCss": true, "namedChunks": false, "aot": true, "extractLicenses": true, "vendorChunk": false, "buildOptimizer": true, "assets": [ "src/favicon.ico", { "glob": "*/", "input": "src/assets", "output": "./../assets" } ] }, "dev": { "assets": [ "src/favicon.ico", "src/assets" ] }, "es": { "aot": true, "outputPath": "dist/angular-es", "i18nFile": "src/i18n/messages.es.xlf", "i18nFormat": "xlf", "i18nLocale": "es" }, "fr": { "aot": true, "outputPath": "dist/angular-fr", "i18nFile": "src/i18n/messages.fr.xlf", "i18nFormat": "xlf", "i18nLocale": "fr" }, "de": { "aot": true, "outputPath": "dist/angular-de", "i18nFile": "src/i18n/messages.de.xlf", "i18nFormat": "xlf", "i18nLocale": "de" }, "en": { "aot": true, "i18nFile": "src/assets/locale/messages.en.xlf", "i18nFormat": "xlf", "i18nLocale": "en", "i18nMissingTranslation": "error" } } }, "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { "browserTarget": "angular:build" }, "configurations": { "production": { "browserTarget": "angular:build:production" }, "dev": { "browserTarget": "angular:build:dev" }, "de": { "browserTarget": "angular:build:de" }, "fr": { "browserTarget": "angular:build:fr" }, "es": { "browserTarget": "angular:build:es" } } }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { "browserTarget": "angular:build" } }, "test": { "builder": "@angular-devkit/build-angular:karma", "options": { "main": "src/test.ts", "polyfills": "src/polyfills.ts", "tsConfig": "src/tsconfig.spec.json", "karmaConfig": "src/karma.conf.js", "styles": [ "./node_modules/@angular/material/prebuilt-themes/purple-green.css", { "input": "node_modules/@progress/kendo-theme-default/dist/all.css" }, "src/styles.css" ], "scripts": [ "./node_modules/crypto-js/crypto-js.js" ], "assets": [ "src/favicon.ico", "src/assets" ] } }, "lint": { "builder": "@angular-devkit/build-angular:tslint", "options": { "tsConfig": [ "src/tsconfig.app.json", "src/tsconfig.spec.json" ], "exclude": [ "/node_modules/" ] } }, "xliffmerge": { "builder": "@ngx-i18nsupport/tooling:xliffmerge", "options": { "xliffmergeOptions": { "i18nFormat": "xlf", "srcDir": "src/assets/locale", "genDir": "src/assets/locale", "defaultLanguage": "en", "languages": [ "en", "de", "fr", "es" ] } } } } }, "angular-e2e": { "root": "e2e/", "projectType": "application", "architect": { "e2e": { "builder": "@angular-devkit/build-angular:protractor", "options": { "protractorConfig": "e2e/protractor.conf.js", "devServerTarget": "angular:serve" }, "configurations": { "production": { "devServerTarget": "angular:serve:production" } } }, "lint": { "builder": "@angular-devkit/build-angular:tslint", "options": { "tsConfig": "e2e/tsconfig.e2e.json", "exclude": [ "/node_modules/" ] } } } } }, "defaultProject": "angular" }
{ "name": "angular", "version": "0.0.0", "scripts": { "ng": "ng", "start": "ng serve", "build": "ng build", "buildci": "node --max_old_space_size=8192 ./node_modules/@angular/cli/bin/ng build --prod --build-optimizer --output-path=\"dist/portal\"", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e", "post-build": "node ./build/post-build.js", "build-i18n:en_test": "node --max_old_space_size=8192 ./node_modules/@angular/cli/bin/ng build --prod --sourceMap --build-optimizer --output-path=\"dist/portal/en\" --i18n-locale en --i18n-file=src/assets/locale/messages.en.xlf --i18n-format=xlf --baseHref /en/", "build-i18n:en": "node --max_old_space_size=8192 ./node_modules/@angular/cli/bin/ng build --prod --build-optimizer --output-path=\"dist/portal/en\" --i18n-locale en --i18n-file=src/assets/locale/messages.en.xlf --i18n-format=xlf --baseHref /en/", "build-i18n:fr": "node --max_old_space_size=8192 ./node_modules/@angular/cli/bin/ng build --prod --build-optimizer --output-path=\"dist/portal/fr\" --i18n-locale fr --i18n-file=src/assets/locale/messages.fr.xlf --i18n-format=xlf --baseHref /fr/", "build-i18n:es": "node --max_old_space_size=8192 ./node_modules/@angular/cli/bin/ng build --prod --build-optimizer --output-path=\"dist/portal/es\" --i18n-locale es --i18n-file=src/assets/locale/messages.es.xlf --i18n-format=xlf --baseHref /es/", "build-i18n:de": "node --max_old_space_size=8192 ./node_modules/@angular/cli/bin/ng build --prod --build-optimizer --output-path=\"dist/portal/de\" --i18n-locale de --i18n-file=src/assets/locale/messages.de.xlf --i18n-format=xlf --baseHref /de/", "build-i18n": "npm run build-i18n:en && npm run build-i18n:fr && npm run build-i18n:es && npm run build-i18n:de && npm run post-build", "build-i18n-dev": "npm run build-i18n:en", "build-i18n-dev-es": "npm run build-i18n:es", "build-i18n-dev-fr": "npm run build-i18n:fr", "build-i18n-dev-de": "npm run build-i18n:de", "extract-i18n": "ng xi18n angular --i18n-format xlf --output-path assets/locale --i18n-locale en && ng run angular:xliffmerge", "start-de": "ng serve --configuration=de", "start-fr": "ng serve --configuration=fr", "start-es": "ng serve --configuration=es", "dev": "node --max_old_space_size=8192 ./node_modules/@angular/cli/bin/ng serve --configuration=dev" }, "private": true, "dependencies": { "@angular-devkit/architect": "^0.13.10", "@angular-devkit/build-angular": "^0.1001.1", "@angular-devkit/build-optimizer": "^0.13.10", "@angular-devkit/build-webpack": "^0.1001.1", "@angular-devkit/core": "^10.1.1", "@angular/animations": "^10.1.1", "@angular/cdk": "^10.1.1", "@angular/common": "~10.1.1", "@angular/compiler": "~10.1.1", "@angular/core": "~10.1.1", "@angular/forms": "~10.1.1", "@angular/http": "^7.2.16", "@angular/material": "^7.3.7", "@angular/platform-browser": "~10.1.1", "@angular/platform-browser-dynamic": "~10.1.1", "@angular/router": "~10.1.1", "@ngtools/webpack": "^10.1.1", "@ngx-i18nsupport/tooling": "^1.1.3", "@progress/kendo-angular-buttons": "^5.4.1", "@progress/kendo-angular-charts": "^4.1.3", "@progress/kendo-angular-common": "^1.2.2", "@progress/kendo-angular-dateinputs": "^4.2.2", "@progress/kendo-angular-dialog": "^4.1.3", "@progress/kendo-angular-dropdowns": "^4.2.6", "@progress/kendo-angular-editor": "^0.9.0", "@progress/kendo-angular-excel-export": "^3.1.3", "@progress/kendo-angular-grid": "^4.7.0", "@progress/kendo-angular-inputs": "^6.5.1", "@progress/kendo-angular-intl": "^2.0.1", "@progress/kendo-angular-l10n": "^2.0.1", "@progress/kendo-angular-layout": "^4.2.3", "@progress/kendo-angular-listview": "^0.2.1", "@progress/kendo-angular-notification": "^2.1.2", "@progress/kendo-angular-pdf-export": "^2.0.3", "@progress/kendo-angular-popup": "^3.0.5", "@progress/kendo-angular-resize-sensor": "3.2.0", "@progress/kendo-angular-scheduler": "^1.1.4", "@progress/kendo-angular-scrollview": "^3.0.1", "@progress/kendo-angular-toolbar": "^2.2.1", "@progress/kendo-angular-tooltip": "^2.1.2", "@progress/kendo-angular-treeview": "^4.1.2", "@progress/kendo-angular-upload": "^5.2.1", "@progress/kendo-data-query": "^1.5.3", "@progress/kendo-date-math": "^1.5.1", "@progress/kendo-drawing": "^1.6.0", "@progress/kendo-recurrence": "^1.0.1", "@progress/kendo-theme-default": "4.9.0", "@progress/kendo-angular-sortable": "^3.0.6", "@telerik/kendo-intl": "^1.5.2", "adal-angular4": "^4.0.9", "ajv": "^6.10.0", "angular-dual-listbox": "^5.0.1", "angular-gridster2": "^7.2.0", "angular7-csv": "^0.2.12", "bootstrap": "^4.5.2", "classlist.js": "^1.1.20150312", "core-js": "^2.5.4", "guid-typescript": "^1.0.9", "hammerjs": "^2.0.8", "jquery": "^3.5.1", "jwt-decode": "^2.2.0", "moment": "^2.24.0", "moment-timezone": "^0.5.28", "ngx-bootstrap": "^6.2.0", "ngx-bootstrap-modal": "^2.0.1", "ngx-chips": "2.0.2", "ngx-clipboard": "^14.0.1", "ngx-color-picker": "^7.5.0", "ngx-device-detector": "^1.3.20", "ngx-json-viewer": "^2.4.0", "ngx-perfect-scrollbar": "^7.2.0", "ngx-text-overflow-clamp": "0.0.1", "popper.js": "^1.15.0", "rxjs": "^6.6.3", "rxjs-compat": "^6.6.3", "stream": "0.0.2", "timers": "^0.1.1", "tslib": "^1.10.0", "web-animations-js": "^2.3.1", "xml-writer": "^1.7.0", "zone.js": "~0.10.3", "@progress/kendo-angular-pager": "^1.0.0", "@angular/localize": "~10.1.1" }, "devDependencies": { "@angular/cli": "^10.1.1", "@angular/compiler-cli": "~10.1.1", "@angular/language-service": "~10.1.1", "@angular/localize": "^10.1.1", "@ngx-i18nsupport/ngx-i18nsupport": "^1.1.3", "@types/jasmine": "~2.8.8", "@types/jasminewd2": "~2.0.3", "@types/node": "~8.9.4", "codelyzer": "~4.5.0", "jasmine-core": "~2.99.1", "jasmine-spec-reporter": "~4.2.1", "karma": "~3.1.1", "karma-chrome-launcher": "~2.2.0", "karma-coverage-istanbul-reporter": "~2.0.1", "karma-jasmine": "~1.1.2", "karma-jasmine-html-reporter": "^0.2.2", "ngx-bootstrap": "^6.2.0", "node-sass": "^4.14.1", "protractor": "~5.4.0", "ts-node": "~7.0.1", "tslint": "~5.11.0", "typescript": "~4.0.2" } }
If you can spare some time, we can discuss the issue over a skype call so that you can take a look into my environment.
Thanks for you help, -Parv
@melcor76 I tried with the above mentioned configurations, but faced the following error:
could you please help me with this.
@parvdhunna Looking at your configurations it looks you are doing it the old way. The error message is also complaining about your build configuration.
The Angular docs have excellent explanations how you should do it now: https://angular.io/guide/i18n#define-locales-in-the-build-configuration
Basically when quickly looking at it you should change this:
"fr": {
"aot": true,
"outputPath": "dist/angular-fr",
"i18nFile": "src/i18n/messages.fr.xlf",
"i18nFormat": "xlf",
"i18nLocale": "fr"
},
To this:
"fr": {
"localize": ["fr"]
}
You also need to add this part:
"i18n": {
"sourceLocale": "en-US",
"locales": {
"da": "i18n/messages.da.xlf",
"fi": "i18n/messages.fi.xlf",
"sv": "i18n/messages.sv.xlf",
"nb": "i18n/messages.nb.xlf"
}
}
@melcor76 I have done changes in my angular.json file as mentioned by you and provided in the article.
This is my command which I execute
"extract-i18n": "ng xi18n angular --ivy --format xlf --outputPath assets/locale && ng run angular:xliffmerge"
And the error i get on executing it An unhandled exception occurred: Could not find the implementation for builder @ngx-i18nsupport/tooling:xliffmerge See "C:\Users\CENTRA~1\AppData\Local\Temp\ng-r6zg82\angular-errors.log" for further details.
If you can check there are any other changes to be done in angular.json Please find below my angular.json
{ "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "angular": { "root": "", "sourceRoot": "src", "projectType": "application", "prefix": "app", "schematics": {}, "i18n": { "sourceLocale": "en", "locales": { "de": "src/assets/locale/messages.de.xlf", "fr": "src/assets/locale/messages.fr.xlf", "es": "src/assets/locale/messages.es.xlf" } }, "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", "options": { "localize": true, "aot": true, "outputPath": "dist/angular", "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "src/tsconfig.app.json", "styles": [ { "input": "node_modules/@progress/kendo-theme-default/dist/all.css" }, "./node_modules/@angular/material/prebuilt-themes/purple-green.css", "node_modules/bootstrap/dist/css/bootstrap.min.css", "src/assets/css/scheduler.scss", "src/assets/css/styles.css", "src/assets/css/dev.css", "src/assets/css/responsive.css", "src/assets/css/mobile-chrome-fix.css", "src/assets/css/desktop.scss", "src/assets/css/mobile.scss" ], "scripts": [] }, "configurations": { "production": { "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" } ], "optimization": true, "outputHashing": "all", "sourceMap": false, "extractCss": true, "namedChunks": false, "aot": true, "extractLicenses": true, "vendorChunk": false, "buildOptimizer": true, "assets": [ "src/favicon.ico", { "glob": "*/", "input": "src/assets", "output": "./../assets" } ] }, "dev": { "assets": [ "src/favicon.ico", "src/assets" ] }, "es": { "localize": ["es"] }, "fr": { "localize": ["fr"] }, "de": { "localize": ["de"] }, "en": { "localize": ["en"] } } }, "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { "browserTarget": "angular:build" }, "configurations": { "production": { "browserTarget": "angular:build:production" }, "dev": { "browserTarget": "angular:build:dev" }, "de": { "browserTarget": "angular:build:de" }, "fr": { "browserTarget": "angular:build:fr" }, "es": { "browserTarget": "angular:build:es" } } }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { "browserTarget": "angular:build" } }, "test": { "builder": "@angular-devkit/build-angular:karma", "options": { "main": "src/test.ts", "polyfills": "src/polyfills.ts", "tsConfig": "src/tsconfig.spec.json", "karmaConfig": "src/karma.conf.js", "styles": [ "./node_modules/@angular/material/prebuilt-themes/purple-green.css", { "input": "node_modules/@progress/kendo-theme-default/dist/all.css" }, "src/styles.css" ], "scripts": [ "./node_modules/crypto-js/crypto-js.js" ], "assets": [ "src/favicon.ico", "src/assets" ] } }, "lint": { "builder": "@angular-devkit/build-angular:tslint", "options": { "tsConfig": [ "src/tsconfig.app.json", "src/tsconfig.spec.json" ], "exclude": [ "/node_modules/" ] } }, "xliffmerge": { "builder": "@ngx-i18nsupport/tooling:xliffmerge", "options": { "xliffmergeOptions": { "i18nFormat": "xlf", "srcDir": "src/assets/locale", "genDir": "src/assets/locale", "defaultLanguage": "en", "languages": [ "en", "de", "fr", "es" ] } } } } }, "angular-e2e": { "root": "e2e/", "projectType": "application", "architect": { "e2e": { "builder": "@angular-devkit/build-angular:protractor", "options": { "protractorConfig": "e2e/protractor.conf.js", "devServerTarget": "angular:serve" }, "configurations": { "production": { "devServerTarget": "angular:serve:production" } } }, "lint": { "builder": "@angular-devkit/build-angular:tslint", "options": { "tsConfig": "e2e/tsconfig.e2e.json", "exclude": [ "/node_modules/" ] } } } } }, "defaultProject": "angular", "cli": { "analytics": false } }
@coder123er Can't see anything wrong. Reading the error message I would try reinstalling xliffmerge to the latest version.
Check this tool https://www.codeandweb.com/babeledit/tutorials/how-to-translate-your-angular9-app-with-xlf-files
I have the same problem as you when updating to Angular 11, it seems that the xliffmerge tool is no longer supported and there are no updates in the Github repository. Babel's translation program merges the xlf files that you enter, establishing the primary language you can translate in as many languages as you need and the string extraction is always performed on the primary language.
I have been working on an Angular i18n article and while doing it I did some experimentation to get Xliffmerge working on a new project. This is the important part of what I write in the article:
The documentation for Xliffmerge is targeting older versions of Angular but after some experimentation I found that it’s enough to install the @ngx-i18nsupport/tooling
package:
npm install -D @ngx-i18nsupport/tooling --legacy-peer-deps
Then we can add new languages to the configurations in angular.json under projects -> projectName -> architect -> xliffmerge
.
"xliffmerge": {
"builder": "@ngx-i18nsupport/tooling:xliffmerge",
"options": {
"xliffmergeOptions": {
"defaultLanguage": "en-US",
"languages": ["nb"]
}
}
}
After adding new translations we can extract them and migrate them to our translation files by running this script:
ng extract-i18n && ng run projectName:xliffmerge
We get a couple of warnings running the script which tells us its working!
WARNING: merged 1 trans-units from master to "nb"
WARNING: please translate file "messages.nb.xlf" to target-language="nb"
Earlier we were using Angular 7 for our project and the following command worked for us for Localization
"extract-i18n": "ng xi18n projectName --i18n-format xlf --output-path src/locale --i18n-locale en && ng run projectName:xliffmerge"
The above command generated xlf file and also merged it with other localized files.
But now We have upgraded to Angular version 10 and on executing above command the terminal gives us error.
What is the new approach in Angular 10 to generate and merge localized files.