lumen-react-javascript
Version:
Lumen React bridge
163 lines (132 loc) • 4.38 kB
JavaScript
import { parse } from 'intl-messageformat-parser';
import * as fs from 'fs';
import { sync as globSync } from 'glob';
import { sync as mkdirpSync } from 'mkdirp';
const MESSAGES_PATTERN = './i18n/**/*.json';
const LANG_DIR = './static/locale/';
const LANGS = require('./src/languages.json');
const ESCAPED_CHARS = {
'\\' : '\\\\',
'\\#': '\\#',
'{' : '\\{',
'}' : '\\}',
};
const ESAPE_CHARS_REGEXP = /\\#|[{}\\]/g;
export default function printICUMessage(ast) {
return ast.elements.reduce((message, el) => {
let {format, id, type, value} = el;
if (type === 'messageTextElement') {
return message + value.replace(ESAPE_CHARS_REGEXP, (char) => {
return ESCAPED_CHARS[char];
});
}
if (!format) {
return message + `{${id}}`;
}
let formatType = format.type.replace(/Format$/, '');
let style, offset, options;
switch (formatType) {
case 'number':
case 'date':
case 'time':
style = format.style ? `, ${format.style}` : '';
return message + `{${id}, ${formatType}${style}}`;
case 'plural':
case 'selectOrdinal':
case 'select':
offset = format.offset ? `, offset:${format.offset}` : '';
options = format.options.reduce((str, option) => {
let optionValue = printICUMessage(option.value);
return str + ` ${option.selector} {${optionValue}}`;
}, '');
return message + `{${id}, ${formatType}${offset},${options}}`;
}
}, '');
}
class Translator {
constructor(translateText) {
this.translateText = translateText;
}
translate(message) {
let ast = parse(message);
let translated = this.transform(ast);
return print(translated);
}
transform(ast) {
ast.elements.forEach((el) => {
if (el.type === 'messageTextElement') {
el.value = this.translateText(el.value);
} else {
let options = el.format && el.format.options;
if (options) {
options.forEach((option) => this.transform(option.value));
}
}
});
return ast;
}
}
const defaultMessages = () => {
return globSync(MESSAGES_PATTERN)
.map((filename) => fs.readFileSync(filename, 'utf8'))
.map((file) => JSON.parse(file))
.reduce((collection, descriptors) => {
descriptors.forEach(({id, defaultMessage}) => {
if (collection.hasOwnProperty(id) && collection[id] != defaultMessage) {
throw new Error(`Duplicate message id with different message: ${id}, ${collection[id]}`);
}
collection[id] = defaultMessage;
});
return collection;
}, {});
};
mkdirpSync(LANG_DIR);
let newnew = defaultMessages();
let oldDefault = null;
if (fs.existsSync(LANG_DIR + 'default.json')) {
oldDefault = require(LANG_DIR + 'default.json');
}
for (let lang in LANGS.supported) {
let filename = LANG_DIR + lang +'.json';
let messages;
if (fs.existsSync(filename)) {
let current = require(filename);
messages = {...newnew, ...current};
} else {
messages = newnew;
}
fs.writeFileSync(LANG_DIR + lang +'.json', JSON.stringify(messages, null, 2));
}
fs.writeFileSync(LANG_DIR + 'default.json', JSON.stringify(newnew, null, 2));
function arr_diff (a1, a2) {
let a = [], diff = [];
for (let i = 0; i < a1.length; i++) {
a[a1[i]] = true;
}
for (let i = 0; i < a2.length; i++) {
if (a[a2[i]]) {
delete a[a2[i]];
} else {
a[a2[i]] = true;
}
}
for (let k in a) {
diff.push(k);
}
return diff;
}
if (oldDefault) {
let oldDefaultKeys = [];
for (let key in oldDefault) {
oldDefaultKeys.push(key);
}
let newDefaultKeys = [];
for (let key in newnew) {
newDefaultKeys.push(key);
}
let diff = arr_diff(oldDefaultKeys, newDefaultKeys);
if (diff) {
diff = diff.join("\n");
fs.writeFileSync(LANG_DIR + 'LANG_DIFF', "THE FOLLOWING NEW TRANSLATION KEYS HAVE BEEN ADDED:\n" + diff);
}
}