vvc
Version:
Vivocha Command Line Tools
212 lines • 7.99 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const eredita_1 = require("eredita");
const fs_1 = require("fs");
const _ = require("lodash");
const util_1 = require("util");
const ws_1 = require("./ws");
const PO = require('pofile');
const poload = util_1.promisify(PO.load);
const VVC_STRING_ID = 'vivocha-string-id';
function reducer(o, i) {
o[i.id] = {
id: i.id,
values: i.values
};
if (i.description) {
o[i.id].description = i.description;
}
return o;
}
function getPaths(strings) {
let data = strings.map(s => s.id).reduce((o, i) => {
eredita_1.Eredita.dot(o, i, true);
return o;
}, {});
function _getPaths(data, curr_path, curr_depth) {
const keys = Object.keys(data);
if (keys.length > 1) {
if (curr_depth > 1 || keys.length > 2) {
return curr_path;
}
else {
return keys.map(k => _getPaths(data[k], `${curr_path}${curr_path ? '.' : ''}${k}`, curr_depth + 1)).join(',');
}
}
else if (typeof data[keys[0]] === 'boolean') {
return curr_path;
}
else {
return _getPaths(data[keys[0]], `${curr_path}${curr_path ? '.' : ''}${keys[0]}`, curr_depth + 1);
}
}
return _getPaths(data, '', 0);
}
function fetchStrings(path, global) {
return ws_1.ws(`strings${global ? '?global=true' : ''}`, { qs: { path } });
}
exports.fetchStrings = fetchStrings;
async function uploadString(str, global) {
return ws_1.ws(`strings/${str.id}${global ? '?global=true' : ''}`, {
method: 'PUT',
body: str
});
}
exports.uploadString = uploadString;
async function fetchWidgetStrings(widgetId, global) {
const prefix = `WIDGET.${widgetId}.`;
const prefix_re = new RegExp(`^${prefix}`);
return (await fetchStrings(prefix, global)).map(i => {
i.id = i.id.replace(prefix_re, '');
return i;
});
}
exports.fetchWidgetStrings = fetchWidgetStrings;
async function uploadWidgetString(widgetId, str, global) {
let wstr = Object.assign({}, str, { id: `WIDGET.${widgetId}.${str.id}` });
return uploadString(wstr, global).then(() => str.id);
}
exports.uploadWidgetString = uploadWidgetString;
async function uploadWidgetStringChanges(widgetId, newStrings, global) {
const o = (await fetchWidgetStrings(widgetId, global)).reduce(reducer, {});
const n = newStrings.reduce(reducer, {});
const stringIds = Object.keys(n);
for (let k of stringIds) {
if (!o[k] || !_.isEqual(o[k], n[k])) {
console.log(`string ${k} changed, uploading`);
await uploadWidgetString(widgetId, n[k], global);
}
}
return stringIds;
}
exports.uploadWidgetStringChanges = uploadWidgetStringChanges;
async function uploadStringChanges(newStrings, global) {
let paths = getPaths(newStrings);
const o = (await fetchStrings(paths, global)).reduce(reducer, {});
const n = newStrings.reduce(reducer, {});
const stringIds = Object.keys(n);
for (let k of stringIds) {
if (!o[k] || !_.isEqual(o[k], n[k])) {
console.log(`string ${k} changed, uploading`);
await uploadString(n[k], global);
}
}
return stringIds;
}
exports.uploadStringChanges = uploadStringChanges;
async function importPOFiles(files, mergeTo, filter) {
const out = mergeTo ? mergeTo.reduce(reducer, {}) : {};
const pofiles = {};
for (let f of files) {
const data = await poload(f);
if (!data || !data.headers || !data.headers.Language) {
throw new Error('bad_file');
}
pofiles[data.headers.Language] = data;
}
const languages = Object.keys(pofiles).sort();
for (let l of languages) {
const data = pofiles[l];
for (let i of (data.items || [])) {
/*
A po file can have multiple comments that reference different ids for the same translation,
so for each comment we should check if it's a vvc_string_id reference
*/
for (let comment of (i.comments || [])) {
if (comment.startsWith(VVC_STRING_ID)) {
const stringId = comment.split(':')[1].trim();
if (filter && stringId.indexOf(filter) !== 0) {
continue;
}
if (!out[stringId]) {
out[stringId] = {
id: stringId,
values: {}
};
}
if (i.msgstr[0]) {
out[stringId].values[l] = {
value: i.msgstr[0],
state: (i.flags && i.flags.fuzzy ? 'needs-review' : 'final')
};
}
if (i.msgctxt) {
out[stringId].description = i.msgctxt;
}
}
}
}
}
return Object.values(out);
}
exports.importPOFiles = importPOFiles;
async function exportPOFiles(source_language, files, project, language, prefix, basename, referenceLanguage) {
const out = {};
function newPO(lang) {
const po = new PO();
po.headers = {
'MIME-Version': '1.0',
'Content-Type': 'text/plain; charset=UTF-8',
'Content-Transfer-Encoding': '8bit',
'X-Generator': 'vvc',
'Project-Id-Version': project,
'Language': lang
};
po.headerOrder = ['MIME-Version', 'Content-Type', 'Content-Transfer-Encoding', 'X-Generator', 'Project-Id-Version', 'Language'];
return po;
}
const _languages = new Set();
const data = [];
for (let f of files) {
const file = JSON.parse(fs_1.readFileSync(f, 'utf8'));
data.push(file);
for (let i of file) {
for (let l in (i.values || {})) {
_languages.add(l);
}
}
}
const languages = [..._languages].sort();
for (let file of data) {
for (let i of file) {
const values = i.values || {};
for (let l of languages) {
const value = values[l] || {};
if (!out[l]) {
out[l] = newPO(l);
}
const item = new PO.Item();
const stringId = i.id;
item.msgid = (values[source_language] || {}).value || '';
item.msgstr = value.value || '';
if (i.description) {
item.extractedComments.push(i.description);
}
if (referenceLanguage && l !== referenceLanguage && values[referenceLanguage] && values[referenceLanguage].value) {
if (item.extractedComments.length) {
item.extractedComments.push("");
}
item.extractedComments.push(`REFERENCE ${referenceLanguage.toLocaleUpperCase()} TRANSLATION:`);
values[referenceLanguage].value.split('\n').forEach(r => item.extractedComments.push(r));
}
if (value.value && (value.state === 'needs-review' || value.state === 'new')) {
item.flags = { fuzzy: true };
}
if (!item.comments) {
item.comments = [];
}
item.comments.push(`${VVC_STRING_ID}: ${stringId}`);
out[l].items.push(item);
}
}
}
for (let l in out) {
if (!language || language === l) {
const filename = `${basename}_${source_language}_${l}.po`;
console.log(`Writing ${filename}`);
await util_1.promisify(out[l].save.bind(out[l]))(filename);
}
}
}
exports.exportPOFiles = exportPOFiles;
//# sourceMappingURL=strings.js.map