Created
December 11, 2018 14:48
-
-
Save leye0/5cb118fa6821ab81122864ac8e57d0e1 to your computer and use it in GitHub Desktop.
xlf-translate.js - Support ng-bootstrap i18n entry id format
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
'use strict'; | |
// Based on | |
// Fix on https://github.com/tsvetomir/xlf-translate to... | |
// -> support ID fields directly on a trans-unit 'id' attribute instead of trans-unit.node.meaning (ex: ng-bootstrap i18n) | |
// -> support description generated from id and source instead of missing trans-unit.node.description | |
// See: https://github.com/tsvetomir/xlf-translate/issues/9 | |
const jp = require('jsonpath'); | |
const yaml = require('js-yaml'); | |
const fs = require('fs'); | |
const cheerio = require('cheerio'); | |
const indent = node => { | |
const indent = node.parent().html().match(/^\s+/); | |
return indent !== null ? indent[0] : ''; | |
}; | |
/** | |
* Fills in translations in XLIFF files based on 'meaning' metadata as a key. | |
* | |
* @param doc an XLIFF document parsed with cheerio | |
* @param lang a tree of keys and their corresponding translations | |
* @return statistics the messages will be filled in-place | |
*/ | |
const translate = (doc, lang, force) => { | |
const units = doc('trans-unit').toArray(); | |
let stats = { count: 0, skip: 0 }; | |
units | |
// .filter(unit => unit.find('note').length > 0) // Fix for ng-bootstrap; | |
.map(unit => { | |
const source = doc(unit).find('source'); | |
let target = doc(unit).find('target'); | |
if (target.length === 0 && source.length === 1) { | |
target = doc('<target />'); | |
source.after(indent(source), target); | |
} | |
return { | |
target: target, | |
id: doc(unit).find('note[from=meaning]').text() || (unit.attribs ? unit.attribs['id'] : null) // Fix for ng-bootstrap; | |
}; | |
}) | |
.filter(({ id }) => id && isKey(id)) | |
.forEach(({ id, target }) => { | |
const parts = id.split('.').map(part => `['${part}']`); | |
const query = '$' + parts.join(''); | |
const match = jp.query(lang, query); | |
if (match.length === 1) { | |
if (target.text() === '' || force) { | |
target.text(match[0]); | |
stats.count++; | |
} else if (!force) { | |
stats.skip++; | |
} | |
} | |
}); | |
return stats; | |
}; | |
const isKey = val => val.match(/^[a-zA-Z0-9.\-_]*$/); // Fix for ng-bootstrap; | |
const args = (() => { | |
const argparse = require('argparse'); | |
const parser = new argparse.ArgumentParser({ | |
addHelp: true, | |
description: 'Looks-up translations based on unique keys' | |
}); | |
parser.addArgument('file', { | |
help: 'XLIFF (.xlf) file to translate' | |
}); | |
parser.addArgument([ '-l', '--lang-file' ], { | |
help: 'YAML file containing translated messages', | |
required: true | |
}); | |
parser.addArgument([ '-f', '--force' ], { | |
help: 'Overwrites existing translation targets', | |
defaultValue: false, | |
action: 'storeTrue' | |
}); | |
parser.addArgument([ '-e', '--encoding' ], { | |
help: 'Specifies the XLIFF file encoding. Default is "utf-8".', | |
defaultValue: 'utf-8' | |
}); | |
return parser.parseArgs(); | |
})(); | |
const langData = fs.readFileSync(args.lang_file); | |
const lang = yaml.safeLoad(langData); | |
const messageData = fs.readFileSync(args.file, { encoding: args.encoding }); | |
const messages = cheerio.load(messageData, { xmlMode: true, decodeEntities: false }); | |
const stats = translate(messages, lang, args.force); | |
const out = messages.html(); | |
fs.writeFileSync(args.file, out); | |
console.log(`Done. Replaced ${stats.count} units, skipped ${stats.skip}.`); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment