Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New: Added xliff translations (fixes #3624) #3625

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 99 additions & 3 deletions grunt/helpers/Translate.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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 = `<?xml version="1.0" encoding="UTF-8"?>
// <xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="${this.masterLang}" trgLang="${this.masterLang}">
// ${Object.entries(outputGroupedByFile).map(([fileName, entries]) => {
// return ` <file id="${fileName}">
// ${entries.map(item => {
// const value = /[<>&"'/]/.test(item.value)
// ? `<![CDATA[${item.value}]]>`
// : item.value;
// return ` <unit id="${item.id}${item.path}">
// <segment>
// <source xml:space="preserve">${value}</source>
// <target xml:space="preserve">${value}</target>
// </segment>
// </unit>
// `;
// }).filter(Boolean).join('')} </file>
// `;
// }).join('')}</xliff>`;

// xliff 1.2
const output = `<?xml version="1.0" encoding="UTF-8"?>
<xliff version="1.2">
${Object.entries(outputGroupedByFile).map(([fileName, entries]) => {
return ` <file original="${fileName}" source-language="${this.masterLang}" target-language="${this.masterLang}"><body>
${entries.map(item => {
const value = /[<>&"'/]/.test(item.value)
? `<![CDATA[${item.value}]]>`
: item.value;
return ` <trans-unit id="${item.id}${item.path}">
<source>${value}</source>
<target>${value}</target>
</trans-unit>
`;
}).filter(Boolean).join('')} </body></file>
`;
}).join('')}</xliff>`;
const filePath = path.join(outputFolder, 'source.xlf');
this.log(`Exporting xliff to ${filePath}`);
fs.writeFileSync(filePath, `${output}`);
return this;
}

// create csv for each file
Expand Down Expand Up @@ -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}`);
Expand All @@ -255,6 +311,8 @@ class Translate {
}
}

if (format === 'xliff') format = 'xlf';

// discover import files
const langFiles = globs.sync([`${inputFolder}/*.${format}`]);
if (langFiles.length === 0) {
Expand All @@ -281,8 +339,45 @@ class Translate {
case 'json':
importData = fs.readJSONSync(langFiles[0]);
break;
case 'csv':
default:
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':
oliverfoster marked this conversation as resolved.
Show resolved Hide resolved
default: {
importData = [];
const lines = [];
await async.each(langFiles, (filename, done) => {
Expand Down Expand Up @@ -349,6 +444,7 @@ class Translate {
throw new Error(`Error processing CSV files: ${err}`);
});
break;
}
}

// check import validity
Expand Down
22 changes: 10 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down