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}
+ //
+ //
+ // `;
+ // }).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}
+
+`;
+ }).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",