To extract message, run following command:
yarn extract-i18n
| { | |
| "projects": { | |
| "my-app": { | |
| "architech": { | |
| ... | |
| ... | |
| "xliffmerge": { | |
| "builder": "@ngx-i18nsupport/tooling:xliffmerge", | |
| "options": { | |
| "xliffmergeOptions": { | |
| "i18nFormat": "xlf", | |
| "srcDir": "src/i18n", | |
| "genDir": "src/i18n", | |
| "defaultLanguage": "en", | |
| "languages": [ | |
| "en", | |
| "fr" | |
| "ru" | |
| "vi" | |
| ] | |
| } | |
| } | |
| }, | |
| ... | |
| } | |
| } | |
| } | |
| } |
| // path: tools/xlf-merge/index.js | |
| #!/usr/bin/env node | |
| const program = require('commander'); | |
| const fs = require('fs'); | |
| const convert = require('xml-js'); | |
| const shell = require('shelljs'); | |
| const mergeXlf = require('./merge-xlf'); | |
| function runMerge(inputPaths, outputPath) { | |
| const inputFiles = (function*() { yield* shell.ls(inputPaths); })(); | |
| const sourceFile = inputFiles.next().value; | |
| console.log('Initial file', sourceFile); | |
| let fileContent = fs.readFileSync(sourceFile).toString(); | |
| let output = convert.xml2js(fileContent); | |
| for (let fileIter = inputFiles.next(); !fileIter.done; fileIter = inputFiles.next()) { | |
| fileContent = fs.readFileSync(fileIter.value).toString(); | |
| output = mergeXlf(output, convert.xml2js(fileContent), fileIter.value); | |
| } | |
| const outXml = convert.js2xml(output); | |
| fs.writeFileSync(outputPath, outXml); | |
| console.log('Generated output file', outputPath); | |
| } | |
| //runMerge(['data/test3/generic.xlf', 'data/test3/home-page.xlf', 'data/test3/lesson.xlf'], 'data/test3/out.xlf'); | |
| //return; | |
| program | |
| .version('1.0.3') | |
| .usage('[options] <input files or pattern such as *.xlf ...>') | |
| .option('-o, --output <output>', 'Output file name') | |
| .parse(process.argv); | |
| if (program.args === 0 || !program.output) { | |
| program.help(); | |
| } | |
| try { | |
| runMerge(program.args, program.output); | |
| } | |
| catch (err) { | |
| console.error(err); | |
| } |
| # Angular 9 come with new Ivy engine, xi18n tool do not support for new engine so we can't extract translate messages. | |
| # This script tool support extract i18n from templates and ts file | |
| # Install require package | |
| yarn add shx @locl/cli xml-js @ngx-i18nsupport/ngx-i18nsupport @ngx-i18nsupport/tooling |
| // path: tools/xlf-merge/merge-xlf.js | |
| module.exports = function(first, second, fileName) { | |
| function fail(message) { | |
| throw new Error(message + ' File name: ' + fileName + '.'); | |
| } | |
| function getElement(src, path, isOptional) { | |
| let result = src; | |
| let breadcrumbs = ''; | |
| for (const pnode of path) { | |
| breadcrumbs += '/' + pnode; | |
| if (!result.elements) { | |
| if (!isOptional) { | |
| fail(breadcrumbs + ' - expected element ' + pnode + ' not found. Make sure that the XLF file schema is correct.'); | |
| } else { | |
| return null; | |
| } | |
| } | |
| result = result.elements.find(e => e.name === pnode); | |
| if (!result) { | |
| if (!isOptional) { | |
| fail('Element ' + breadcrumbs + ' not found. Make sure that the XLF file schema is correct.'); | |
| } else { | |
| return null; | |
| } | |
| } | |
| } | |
| return result; | |
| } | |
| function getContent(src) { | |
| const result = ((src && src.elements) || []).find(e => e.type === 'text'); | |
| return result ? result.text : ''; | |
| } | |
| function* getTransUnits(root) { | |
| if (!root.elements) { | |
| console.log('Skipping ', fileName, '- no trans-units found.'); | |
| return; | |
| } | |
| for (const el of root.elements) { | |
| if (el.name === 'trans-unit') { | |
| yield el; | |
| } | |
| } | |
| } | |
| const transPath = ['xliff', 'file', 'body']; | |
| const srcRoot = getElement(first, transPath); | |
| const tgtRoot = getElement(second, transPath); | |
| const tgtTransUnits = [...getTransUnits(tgtRoot)]; | |
| let numMergedTransUnits = 0; | |
| function findTgtById(id) { | |
| return tgtTransUnits.find(t => t.attributes && t.attributes.id === id); | |
| } | |
| for (const srcTransUnit of getTransUnits(srcRoot)) { | |
| const id = srcTransUnit.attributes.id; | |
| const content = getContent(getElement(srcTransUnit, ['target'], true)); | |
| const matchingTgt = findTgtById(id); | |
| if (matchingTgt) { | |
| const tgtContent = getContent(getElement(matchingTgt, ['target'], true)); | |
| if (content !== tgtContent) { | |
| console.log(`"${content}"`, ' <- ', id, ' -> ', `"${tgtContent}"`); | |
| } | |
| } else { | |
| tgtRoot.elements.push(srcTransUnit); | |
| numMergedTransUnits++; | |
| } | |
| } | |
| console.log(fileName, ' -> ', numMergedTransUnits, 'translations merged'); | |
| return second; | |
| } |
| // Add following scripts to package.json file | |
| // Asume | |
| { | |
| "merge-i18n": "node ./tools/xlf-merge/ src/i18n/tool/*.en.xlf -o src/i18n/messages.xlf", | |
| "gen-i18n": "yarn shx rm -rf src/i18n/tool && yarn locl extract -s=dist/web/*.js -f=xlf -o=src/i18n/tool/ && yarn merge-i18n", | |
| "extract-i18n": "ng build --prod && yarn gen-i18n && ng run my-app:xliffmerge && yarn shx rm -rf src/i18n/tool", | |
| } |