add content hash to individual language files
This commit is contained in:
parent
2e60037d9f
commit
878190ba27
|
@ -125,6 +125,7 @@
|
||||||
"karma-spec-reporter": "0.0.31",
|
"karma-spec-reporter": "0.0.31",
|
||||||
"karma-summary-reporter": "^1.5.1",
|
"karma-summary-reporter": "^1.5.1",
|
||||||
"karma-webpack": "4.0.0-beta.0",
|
"karma-webpack": "4.0.0-beta.0",
|
||||||
|
"loader-utils": "^1.2.3",
|
||||||
"matrix-mock-request": "^1.2.2",
|
"matrix-mock-request": "^1.2.2",
|
||||||
"matrix-react-test-utils": "^0.2.0",
|
"matrix-react-test-utils": "^0.2.0",
|
||||||
"minimist": "^1.2.0",
|
"minimist": "^1.2.0",
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const loaderUtils = require("loader-utils");
|
||||||
|
|
||||||
// copies the resources into the webapp directory.
|
// copies the resources into the webapp directory.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@ -61,12 +63,6 @@ const COPY_LIST = [
|
||||||
["./config.json", "webapp", { directwatch: 1 }],
|
["./config.json", "webapp", { directwatch: 1 }],
|
||||||
];
|
];
|
||||||
|
|
||||||
INCLUDE_LANGS.forEach(function(l) {
|
|
||||||
COPY_LIST.push([
|
|
||||||
l.value, "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');
|
||||||
|
@ -77,8 +73,8 @@ const argv = parseArgs(
|
||||||
process.argv.slice(2), {}
|
process.argv.slice(2), {}
|
||||||
);
|
);
|
||||||
|
|
||||||
var watch = argv.w;
|
const watch = argv.w;
|
||||||
var verbose = argv.v;
|
const verbose = argv.v;
|
||||||
|
|
||||||
function errCheck(err) {
|
function errCheck(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -136,39 +132,11 @@ 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.lang) {
|
|
||||||
const reactSdkFile = 'node_modules/matrix-react-sdk/src/i18n/strings/' + source + '.json';
|
|
||||||
const riotWebFile = 'src/i18n/strings/' + source + '.json';
|
|
||||||
|
|
||||||
// XXX: Use a debounce because for some reason if we read the language
|
|
||||||
// file immediately after the FS event is received, the file contents
|
|
||||||
// appears empty. Possibly https://github.com/nodejs/node/issues/6112
|
|
||||||
let makeLangDebouncer;
|
|
||||||
const makeLang = () => {
|
|
||||||
if (makeLangDebouncer) {
|
|
||||||
clearTimeout(makeLangDebouncer);
|
|
||||||
}
|
|
||||||
makeLangDebouncer = setTimeout(() => {
|
|
||||||
genLangFile(source, dest);
|
|
||||||
}, 500);
|
|
||||||
};
|
|
||||||
|
|
||||||
[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);
|
|
||||||
} 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.lang) {
|
|
||||||
genLangFile(source, dest);
|
|
||||||
next(i + 1, err);
|
|
||||||
} else {
|
} else {
|
||||||
cpx.copy(cb);
|
cpx.copy(cb);
|
||||||
}
|
}
|
||||||
|
@ -195,21 +163,28 @@ function genLangFile(lang, dest) {
|
||||||
|
|
||||||
translations = weblateToCounterpart(translations);
|
translations = weblateToCounterpart(translations);
|
||||||
|
|
||||||
fs.writeFileSync(dest + lang + '.json', JSON.stringify(translations, null, 4));
|
const json = JSON.stringify(translations, null, 4);
|
||||||
|
const jsonBuffer = Buffer.from(json);
|
||||||
|
const digest = loaderUtils.getHashDigest(jsonBuffer, "sha512", "base64", 7);
|
||||||
|
const filename = `${lang}.${digest}.json`;
|
||||||
|
|
||||||
|
fs.writeFileSync(dest + filename, json);
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
console.log("Generated language file: " + lang);
|
console.log("Generated language file: " + filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
function genLangList() {
|
function genLangList(langFileMap) {
|
||||||
const languages = {};
|
const languages = {};
|
||||||
INCLUDE_LANGS.forEach(function(lang) {
|
INCLUDE_LANGS.forEach(function(lang) {
|
||||||
const normalizedLanguage = lang.value.toLowerCase().replace("_", "-");
|
const normalizedLanguage = lang.value.toLowerCase().replace("_", "-");
|
||||||
const languageParts = normalizedLanguage.split('-');
|
const languageParts = normalizedLanguage.split('-');
|
||||||
if (languageParts.length == 2 && languageParts[0] == languageParts[1]) {
|
if (languageParts.length == 2 && languageParts[0] == languageParts[1]) {
|
||||||
languages[languageParts[0]] = {'fileName': lang.value + '.json', 'label': lang.label};
|
languages[languageParts[0]] = {'fileName': langFileMap[lang.value], 'label': lang.label};
|
||||||
} else {
|
} else {
|
||||||
languages[normalizedLanguage] = {'fileName': lang.value + '.json', 'label': lang.label};
|
languages[normalizedLanguage] = {'fileName': langFileMap[lang.value], 'label': lang.label};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
fs.writeFile('webapp/i18n/languages.json', JSON.stringify(languages, null, 4), function(err) {
|
fs.writeFile('webapp/i18n/languages.json', JSON.stringify(languages, null, 4), function(err) {
|
||||||
|
@ -257,5 +232,50 @@ function weblateToCounterpart(inTrs) {
|
||||||
return outTrs;
|
return outTrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
genLangList();
|
/**
|
||||||
|
watch the input files for a given language,
|
||||||
|
regenerate the file, adding its content-hashed filename to langFileMap
|
||||||
|
and regenerating languages.json with the new filename
|
||||||
|
*/
|
||||||
|
function watchLanguage(lang, dest, langFileMap) {
|
||||||
|
const reactSdkFile = 'node_modules/matrix-react-sdk/src/i18n/strings/' + lang + '.json';
|
||||||
|
const riotWebFile = 'src/i18n/strings/' + lang + '.json';
|
||||||
|
|
||||||
|
// XXX: Use a debounce because for some reason if we read the language
|
||||||
|
// file immediately after the FS event is received, the file contents
|
||||||
|
// appears empty. Possibly https://github.com/nodejs/node/issues/6112
|
||||||
|
let makeLangDebouncer;
|
||||||
|
const makeLang = () => {
|
||||||
|
if (makeLangDebouncer) {
|
||||||
|
clearTimeout(makeLangDebouncer);
|
||||||
|
}
|
||||||
|
makeLangDebouncer = setTimeout(() => {
|
||||||
|
const filename = genLangFile(lang, dest);
|
||||||
|
langFileMap[lang]=filename;
|
||||||
|
genLangList(langFileMap);
|
||||||
|
}, 500);
|
||||||
|
};
|
||||||
|
|
||||||
|
[reactSdkFile, riotWebFile].forEach(function(f) {
|
||||||
|
chokidar.watch(f)
|
||||||
|
.on('add', makeLang)
|
||||||
|
.on('change', makeLang)
|
||||||
|
.on('error', errCheck);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// language resources
|
||||||
|
const I18N_DEST = "webapp/i18n/";
|
||||||
|
const I18N_FILENAME_MAP = INCLUDE_LANGS.reduce((m, l) => {
|
||||||
|
const filename = genLangFile(l.value, I18N_DEST);
|
||||||
|
m[l.value] = filename;
|
||||||
|
return m;
|
||||||
|
}, {});
|
||||||
|
genLangList(I18N_FILENAME_MAP);
|
||||||
|
|
||||||
|
if (watch) {
|
||||||
|
INCLUDE_LANGS.forEach(l => watchLanguage(l.value, I18N_DEST, I18N_FILENAME_MAP));
|
||||||
|
}
|
||||||
|
|
||||||
|
// non-language resources
|
||||||
next(0);
|
next(0);
|
||||||
|
|
Loading…
Reference in New Issue