diff --git a/grunt/helpers/Translate.js b/grunt/helpers/Translate.js index 54a38b41e..00b8b6ad3 100644 --- a/grunt/helpers/Translate.js +++ b/grunt/helpers/Translate.js @@ -2,6 +2,7 @@ const path = require('path'); const _ = require('lodash'); const fs = require('fs-extra'); const csv = require('csv'); +const { XMLParser } = require('fast-xml-parser'); const async = require('async'); const globs = require('globs'); const jschardet = require('jschardet'); @@ -177,7 +178,60 @@ class Translate { const filePath = path.join(outputFolder, 'export.json'); this.log(`Exporting json to ${filePath}`); fs.writeJSONSync(filePath, exportTextData, { spaces: 2 }); - return; + return this; + } + + if (['xliff', 'xlf'].includes(this.format)) { + // create csv for each file + const outputGroupedByFile = exportTextData.reduce((prev, current) => { + if (!prev.hasOwnProperty(current.file)) { + prev[current.file] = []; + } + prev[current.file].push(current); + return prev; + }, {}); + + // xliff 2.0 + // const output = ` + // + // ${Object.entries(outputGroupedByFile).map(([fileName, entries]) => { + // return ` + // ${entries.map(item => { + // const value = /[<>&"'/]/.test(item.value) + // ? `` + // : item.value; + // return ` + // + // ${value} + // ${value} + // + // + // `; + // }).filter(Boolean).join('')} + // `; + // }).join('')}`; + + // xliff 1.2 + const output = ` + +${Object.entries(outputGroupedByFile).map(([fileName, entries]) => { + return ` +${entries.map(item => { + const value = /[<>&"'/]/.test(item.value) + ? `` + : item.value; + return ` + ${value} + ${value} + +`; + }).filter(Boolean).join('')} +`; + }).join('')}`; + const filePath = path.join(outputFolder, 'source.xlf'); + this.log(`Exporting xliff to ${filePath}`); + fs.writeFileSync(filePath, `${output}`); + return this; } // create csv for each file @@ -246,6 +300,8 @@ class Translate { } format = uniqueFileExtensions[0]; switch (format) { + case 'xlf': + case 'xliff': case 'csv': case 'json': this.log(`Format autodetected as ${format}`); @@ -255,6 +311,8 @@ class Translate { } } + if (format === 'xliff') format = 'xlf'; + // discover import files const langFiles = globs.sync([`${inputFolder}/*.${format}`]); if (langFiles.length === 0) { @@ -281,8 +339,46 @@ class Translate { case 'json': importData = fs.readJSONSync(langFiles[0]); break; + case 'xliff': + case 'xlf': { + importData = []; + await async.each(langFiles, (filename, done) => { + const XMLData = fs.readFileSync(filename); + const parser = new XMLParser({ + ignoreAttributes: false, + attributeNamePrefix: '' + }); + const xml = parser.parse(XMLData); + // xliff 2.0 + // for (const file of xml.xliff.file) { + // for (const unit of file.unit) { + // const [ id, ...path ] = unit.id.split('/'); + // importData.push({ + // file: file.id, + // id, + // path: path.filter(Boolean).join('/'), + // value: unit.segment.target['#text'] + // }); + // } + // } + // xliff 1.2 + for (const file of xml.xliff.file) { + for (const unit of file.body['trans-unit']) { + const [ id, ...path ] = unit.id.split('/'); + importData.push({ + file: file.original, + id, + path: path.filter(Boolean).join('/'), + value: unit.source + }); + } + } + done(); + }); + break; + } case 'csv': - default: + default: { importData = []; const lines = []; await async.each(langFiles, (filename, done) => { @@ -349,6 +445,7 @@ class Translate { throw new Error(`Error processing CSV files: ${err}`); }); break; + } } // check import validity diff --git a/package-lock.json b/package-lock.json index 75e03d8a9..b908eb7c3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "chalk": "^2.4.1", "columnify": "^1.5.4", "csv": "^5.5.3", + "fast-xml-parser": "^4.5.0", "fs-extra": "^8.1.0", "globs": "^0.1.4", "grunt": "^1.6.1", @@ -8595,9 +8596,9 @@ "dev": true }, "node_modules/fast-xml-parser": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", - "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz", + "integrity": "sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==", "funding": [ { "type": "github", @@ -8608,7 +8609,7 @@ "url": "https://paypal.me/naturalintelligence" } ], - "optional": true, + "license": "MIT", "dependencies": { "strnum": "^1.0.5" }, @@ -20866,8 +20867,7 @@ "node_modules/strnum": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", - "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", - "optional": true + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" }, "node_modules/supports-color": { "version": "5.5.0", @@ -28621,10 +28621,9 @@ "dev": true }, "fast-xml-parser": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", - "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", - "optional": true, + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz", + "integrity": "sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==", "requires": { "strnum": "^1.0.5" } @@ -37527,8 +37526,7 @@ "strnum": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", - "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", - "optional": true + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" }, "supports-color": { "version": "5.5.0", diff --git a/package.json b/package.json index 770110919..4a050e844 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "chalk": "^2.4.1", "columnify": "^1.5.4", "csv": "^5.5.3", + "fast-xml-parser": "^4.5.0", "fs-extra": "^8.1.0", "globs": "^0.1.4", "grunt": "^1.6.1",