Language generation and file structure
* Move language files to strings/ subdir to be consistent with react-sdk * Only copy static list of languages (to avoid including languages that are only a few percent translated) * Make copy-res script work with watch mode * Other general cleanups like only write each language file once, rather than n times.
This commit is contained in:
parent
e07f9a8bc9
commit
6c3c4fc547
|
@ -3,6 +3,23 @@
|
||||||
// copies the resources into the webapp directory.
|
// copies the resources into the webapp directory.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
// Languages are listed manually so we can choose when to include
|
||||||
|
// a translation in the app (because having a translation with only
|
||||||
|
// 3 strings translated is just frustrating)
|
||||||
|
// This could readily be automated, but it's nice to explicitly
|
||||||
|
// control when we languages are available.
|
||||||
|
const INCLUDE_LANGS = [
|
||||||
|
//'be' Omitted because no translations in react-sdk
|
||||||
|
'en_EN',
|
||||||
|
'da',
|
||||||
|
'de_DE',
|
||||||
|
'fr',
|
||||||
|
'be',
|
||||||
|
'pt',
|
||||||
|
'pt_BR',
|
||||||
|
'ru',
|
||||||
|
];
|
||||||
|
|
||||||
// cpx includes globbed parts of the filename in the destination, but excludes
|
// cpx includes globbed parts of the filename in the destination, but excludes
|
||||||
// common parents. Hence, "res/{a,b}/**": the output will be "dest/a/..." and
|
// common parents. Hence, "res/{a,b}/**": the output will be "dest/a/..." and
|
||||||
// "dest/b/...".
|
// "dest/b/...".
|
||||||
|
@ -14,32 +31,20 @@ const COPY_LIST = [
|
||||||
["node_modules/emojione/assets/svg/*", "webapp/emojione/svg/"],
|
["node_modules/emojione/assets/svg/*", "webapp/emojione/svg/"],
|
||||||
["node_modules/emojione/assets/png/*", "webapp/emojione/png/"],
|
["node_modules/emojione/assets/png/*", "webapp/emojione/png/"],
|
||||||
["./config.json", "webapp", { directwatch: 1 }],
|
["./config.json", "webapp", { directwatch: 1 }],
|
||||||
["src/i18n/", "webapp/i18n/", { languages: 1 }],
|
|
||||||
["node_modules/matrix-react-sdk/src/i18n/strings/", "webapp/i18n/", { languages: 1 }],
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
INCLUDE_LANGS.forEach(function(l) {
|
||||||
|
COPY_LIST.push([
|
||||||
|
l, "webapp/i18n/", { lang: 1 },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
const parseArgs = require('minimist');
|
const parseArgs = require('minimist');
|
||||||
const Cpx = require('cpx');
|
const Cpx = require('cpx');
|
||||||
const chokidar = require('chokidar');
|
const chokidar = require('chokidar');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const rimraf = require('rimraf');
|
const rimraf = require('rimraf');
|
||||||
|
|
||||||
// cleanup language files before copying them.
|
|
||||||
//rimraf("webapp/", function () { console.log('cleanup language files'); });
|
|
||||||
|
|
||||||
//From http://stackoverflow.com/a/20525865/4929236
|
|
||||||
function generateFileArray(dir, files_) {
|
|
||||||
files_ = files_ || [];
|
|
||||||
var files = fs.readdirSync(dir);
|
|
||||||
for (var i in files) {
|
|
||||||
var name = files[i];
|
|
||||||
if (name != 'basefile.json') {
|
|
||||||
files_.push(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return files_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const argv = parseArgs(
|
const argv = parseArgs(
|
||||||
process.argv.slice(2), {}
|
process.argv.slice(2), {}
|
||||||
);
|
);
|
||||||
|
@ -54,6 +59,15 @@ function errCheck(err) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if webapp exists
|
||||||
|
if (!fs.existsSync('webapp')) {
|
||||||
|
fs.mkdirSync('webapp');
|
||||||
|
}
|
||||||
|
// Check if i18n exists
|
||||||
|
if (!fs.existsSync('webapp/i18n/')) {
|
||||||
|
fs.mkdirSync('webapp/i18n/');
|
||||||
|
}
|
||||||
|
|
||||||
function next(i, err) {
|
function next(i, err) {
|
||||||
errCheck(err);
|
errCheck(err);
|
||||||
|
|
||||||
|
@ -67,32 +81,11 @@ function next(i, err) {
|
||||||
const opts = ent[2] || {};
|
const opts = ent[2] || {};
|
||||||
let cpx = undefined;
|
let cpx = undefined;
|
||||||
|
|
||||||
if (opts.languages) {
|
if (!opts.lang) {
|
||||||
const sourceFiles = generateFileArray(source);
|
|
||||||
let Sourcelanguages = {};
|
|
||||||
if (!fs.existsSync(dest)) {
|
|
||||||
fs.mkdirSync(dest);
|
|
||||||
}
|
|
||||||
sourceFiles.forEach(file => {
|
|
||||||
const fileContents = fs.readFileSync(source + file).toString();
|
|
||||||
Sourcelanguages[file] = JSON.parse(fileContents);
|
|
||||||
});
|
|
||||||
sourceFiles.forEach(file => {
|
|
||||||
if (!fs.existsSync(dest + file)) {
|
|
||||||
let o = Object.assign({}, Sourcelanguages[file]);
|
|
||||||
fs.writeFileSync(dest + file, JSON.stringify(o, null, 4));
|
|
||||||
} else {
|
|
||||||
const fileContents = fs.readFileSync(dest + file).toString();
|
|
||||||
let o = Object.assign(JSON.parse(fileContents), Sourcelanguages[file]);
|
|
||||||
fs.writeFileSync(dest + file, JSON.stringify(o, null, 4));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
cpx = new Cpx.Cpx(source, dest);
|
cpx = new Cpx.Cpx(source, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose && cpx) {
|
||||||
cpx.on("copy", (event) => {
|
cpx.on("copy", (event) => {
|
||||||
console.log(`Copied: ${event.srcPath} --> ${event.dstPath}`);
|
console.log(`Copied: ${event.srcPath} --> ${event.dstPath}`);
|
||||||
});
|
});
|
||||||
|
@ -115,59 +108,68 @@ function next(i, err) {
|
||||||
.on('change', copy)
|
.on('change', copy)
|
||||||
.on('ready', cb)
|
.on('ready', cb)
|
||||||
.on('error', errCheck);
|
.on('error', errCheck);
|
||||||
} else if (opts.languages) {
|
} else if (opts.lang) {
|
||||||
if (verbose) {
|
const reactSdkFile = 'node_modules/matrix-react-sdk/src/i18n/strings/' + source + '.json';
|
||||||
console.log('don\'t copy language file');
|
const riotWebFile = 'src/i18n/strings/' + source + '.json';
|
||||||
}
|
|
||||||
|
const translations = {};
|
||||||
|
const makeLang = () => { genLangFile(source, dest) };
|
||||||
|
[reactSdkFile, riotWebFile].forEach(function(f) {
|
||||||
|
chokidar.watch(f)
|
||||||
|
.on('add', makeLang)
|
||||||
|
.on('change', makeLang)
|
||||||
|
//.on('ready', cb) We'd have to do this when both files are ready
|
||||||
|
.on('error', errCheck);
|
||||||
|
});
|
||||||
next(i + 1, err);
|
next(i + 1, err);
|
||||||
} else {
|
} else {
|
||||||
cpx.on('watch-ready', cb);
|
cpx.on('watch-ready', cb);
|
||||||
cpx.on("watch-error", cb);
|
cpx.on("watch-error", cb);
|
||||||
cpx.watch();
|
cpx.watch();
|
||||||
}
|
}
|
||||||
} else if (opts.languages) {
|
} else if (opts.lang) {
|
||||||
if (verbose) {
|
genLangFile(source, dest);
|
||||||
console.log('don\'t copy language file');
|
|
||||||
}
|
|
||||||
next(i + 1, err);
|
next(i + 1, err);
|
||||||
} else {
|
} else {
|
||||||
cpx.copy(cb);
|
cpx.copy(cb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate Language List
|
function genLangFile(lang, dest) {
|
||||||
|
const reactSdkFile = 'node_modules/matrix-react-sdk/src/i18n/strings/' + lang + '.json';
|
||||||
|
const riotWebFile = 'src/i18n/strings/' + lang + '.json';
|
||||||
|
|
||||||
const testFolder = 'src/i18n/';
|
const translations = {};
|
||||||
let languages = {};
|
[reactSdkFile, riotWebFile].forEach(function(f) {
|
||||||
// Check if webapp exists
|
if (fs.existsSync(f)) {
|
||||||
if (!fs.existsSync('webapp')) {
|
Object.assign(
|
||||||
fs.mkdirSync('webapp');
|
translations,
|
||||||
}
|
JSON.parse(fs.readFileSync(f).toString())
|
||||||
// Check if i18n exists
|
);
|
||||||
if (!fs.existsSync('webapp/i18n/')) {
|
|
||||||
fs.mkdirSync('webapp/i18n/');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fs.existsSync('webapp/i18n/languages.json')) {
|
|
||||||
rimraf("webapp/i18n/languages.json", function() { console.log('cleanup languages.json file'); });
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.readdir(testFolder, function(err, files) {
|
|
||||||
if (err) {
|
|
||||||
throw err;
|
|
||||||
}
|
}
|
||||||
files.forEach(function(file) {
|
});
|
||||||
var normalizedLanguage = file.toLowerCase().replace("_", "-").split('.json')[0];
|
fs.writeFileSync(dest + lang + '.json', JSON.stringify(translations, null, 4));
|
||||||
var languageParts = normalizedLanguage.split('-');
|
if (verbose) {
|
||||||
if (file != 'basefile.json') {
|
console.log("Generated language file: " + lang);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function genLangList() {
|
||||||
|
const languages = {};
|
||||||
|
INCLUDE_LANGS.forEach(function(lang) {
|
||||||
|
const normalizedLanguage = lang.toLowerCase().replace("_", "-");
|
||||||
|
const languageParts = normalizedLanguage.split('-');
|
||||||
if (languageParts.length == 2 && languageParts[0] == languageParts[1]) {
|
if (languageParts.length == 2 && languageParts[0] == languageParts[1]) {
|
||||||
languages[languageParts[0]] = file;
|
languages[languageParts[0]] = lang;
|
||||||
} else {
|
} else {
|
||||||
languages[normalizedLanguage] = file;
|
languages[normalizedLanguage] = lang;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
fs.writeFile('webapp/i18n/languages.json', JSON.stringify(languages, null, 4));
|
fs.writeFile('webapp/i18n/languages.json', JSON.stringify(languages, null, 4));
|
||||||
})
|
if (verbose) {
|
||||||
|
console.log("Generated language list");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
genLangList();
|
||||||
next(0);
|
next(0);
|
Loading…
Reference in New Issue