xlf-merge
Version:
Command-line tool for merging XLF files
162 lines (131 loc) • 5.26 kB
JavaScript
const process = require('process');
const fs = require('fs');
const path = require('path');
const program = require('commander');
const shell = require('shelljs');
const logger = require('./logger.js');
const xlfHandler = require('./xlf-handler');
const jsonHandler = require('./json-handler');
const arbHandler = require('./arb-handler');
function resolveHandler(fileName) {
switch (path.extname(fileName.toLowerCase())) {
case '.json':
return jsonHandler;
case '.arb':
return arbHandler;
default:
return xlfHandler;
}
}
function parseFileContent(fileName, allItems, allowConflicts) {
const handler = resolveHandler(fileName);
const fileContent = fs.readFileSync(fileName).toString();
const parser = handler.createParser(fileContent);
let count = 0;
for (const item of parser.parse(fileContent)) {
const duplicate = allItems.find(t => t.id === item.id);
if (duplicate) {
if (duplicate.text === item.text) {
logger.warn(`Duplicate ${item.id} found in files ${fileName} and ${duplicate.fileName}`);
continue;
} else {
const errMsg = `Item with ID ${item.id} found in files ${fileName} and ${duplicate.fileName}. Both instances contain different text.`;
if (allowConflicts) {
logger.warn(errMsg);
} else {
throw new Error(errMsg);
}
}
}
allItems.push({ ...item, fileName });
count++;
}
if (count) {
logger.info(`Parsed ${count} translations in file ${fileName}`);
} else {
logger.warn(`Parsed file ${fileName}. No translations found.`);
}
return parser.getLocale();
}
function readInputs(inputPaths, operation) {
for (const fileName of shell.ls(inputPaths)) {
try {
operation(fileName);
} catch (err) {
logger.error('Couldn\'t parse file ' + fileName);
throw err;
}
}
}
function convertTranslationFiles(inputPaths, outputFormat, allowConflicts) {
let counter = 0;
readInputs(
inputPaths,
fileName => {
const transItems = [];
const locale = parseFileContent(fileName, transItems, allowConflicts);
if (transItems.length) {
const baseName = path.basename(fileName, path.extname(fileName));
const newExt = '.' + outputFormat;
const outputPath = path.join(path.dirname(fileName), baseName + newExt);
const convertedContent = resolveHandler(outputPath).save(transItems, locale);
fs.writeFileSync(outputPath, convertedContent);
logger.info(`Converted file ${fileName} into ${outputPath}`);
}
}
);
logger.success(`xlf-merge converted all ${counter} input files`);
}
function mergeTranslationFiles(inputPaths, outputPath, allowConflicts) {
const transItems = [];
let locale = null;
readInputs(inputPaths, fileName => {
let fileLocale = parseFileContent(fileName, transItems, allowConflicts);
if (locale && fileLocale && locale !== fileLocale) {
throw new Error(`Locales among input file don't match. File ${fileName} has locale ${fileLocale}, expected ${locale}.`);
}
locale = fileLocale;
});
logger.info(`All input files parsed. Found ${transItems.length} translated texts.`);
if (transItems.length) {
const handler = resolveHandler(outputPath);
const output = handler.save(transItems, locale);
fs.writeFileSync(outputPath, output);
logger.success('xlf-merge generated output file ' + outputPath);
}
}
program
.name('xlf-merge')
.version('2.0.1')
.addHelpText(
'before',
'Xlf-merge 2.0.1\n' +
'Merges and/or converts translation dictionary files. Supports XLF 1.2, JSON, and ARB.\n' +
'Generates single translation dictionary required by Angular compiler from multiple input files.\n'
)
.usage('[options] <input files or pattern such as *.xlf, *.json ...>')
.option('-o --output <output>', 'Output file name')
.addOption(new program.Option('-c --convert <format>', 'Converts all input files in place').choices(['xlf', 'json', 'arb']))
.option('-q --quiet', 'Quiet mode. Doesn\'t show warnings and info messages.')
.option('-ac --allow-conflicts', 'Does not fail if the same key is present multiple times with different content')
.addHelpText('after', '\nEither --output or --convert option is required')
.parse(process.argv);
const options = program.opts();
if (program.args === 0 || (!options.output && !options.convert)) {
program.help();
}
if (options.quiet) {
logger.quietMode = true;
}
try {
if (options.convert) {
convertTranslationFiles(program.args, options.convert, options.allowConflicts);
}
if (options.output) {
mergeTranslationFiles(program.args, options.output, options.allowConflicts);
}
} catch (err) {
logger.error('xlf-merge failed\n' + err.toString());
process.exitCode = 1;
}