make translation linter identify mismatched substitution placeholders and markup

This commit is contained in:
ansuz 2022-09-16 18:37:42 +05:30
parent fd199db874
commit 610cd4570e
1 changed files with 50 additions and 46 deletions

View File

@ -1,5 +1,6 @@
var EN = require("../../www/common/translations/messages.json"); var EN = require("../../www/common/translations/messages.json");
var Util = require("../../www/common/common-util.js"); var Util = require("../../www/common/common-util.js");
var Fs = require("fs");
var simpleTags = [ var simpleTags = [
'<br>', '<br>',
@ -56,7 +57,7 @@ var getTags = S => {
if (typeof(S) !== 'string') { return []; } if (typeof(S) !== 'string') { return []; }
var tags = []; var tags = [];
S.replace(/<[\s\S]*?>/g, function (html) { S.replace(/(<[\s\S]*?>|\{\d+\})/g, function (html) {
tags.push(html); tags.push(html);
}); });
return tags; return tags;
@ -73,20 +74,22 @@ var getTagCount = T => {
// bidirectional comparison // bidirectional comparison
var compareMarkup = (A, B) => { var compareMarkup = (A, B) => {
// if the frequency of some key in A does not match that of the same key in B // if the frequency of some key in A does not match that of the same key in B
if (Object.keys(A).some(k => { var diff = {};
return A[k] !== B[k];
})) { var compare = k => {
return false; if (diff[k]) { return; }
}
var a = A[k] || 0;
var b = B[k] || 0;
if (a === b) { return; }
diff[k] = b - a;
};
Object.keys(A).forEach(compare);
// same for B // same for B
if (Object.keys(B).some(k => { Object.keys(B).forEach(compare);
return A[k] !== B[k]; return diff;
})) {
return false;
}
return true;
}; };
var getReferenceMarkup = (function () { var getReferenceMarkup = (function () {
@ -100,12 +103,13 @@ var getReferenceMarkup = (function () {
}; };
}()); }());
var finalErrorCount = 0;
var processLang = function (map, lang, primary) { var processLang = function (map, lang, primary) {
var announced = false; var announced = false;
var announce = function () { var announce = function () {
if (announced) { return; } if (announced) { return; }
announced = true; announced = true;
console.log("NEXT LANGUAGE: ", lang); console.log("## LANGUAGE: %s\n", lang);
}; };
var special = special_rules[lang] || noop; var special = special_rules[lang] || noop;
@ -120,11 +124,17 @@ var processLang = function (map, lang, primary) {
var ref = getReferenceMarkup(k); var ref = getReferenceMarkup(k);
var tags = getTags(s); var tags = getTags(s);
var tagCount = getTagCount(tags); var tagCount = getTagCount(tags);
var markupMatches = compareMarkup(ref, tagCount);
var markupDiff = compareMarkup(ref, tagCount);
//console.log(markupDiff);
var markupMatches = Object.keys(markupDiff).length === 0;
//console.log(ref); //console.log(ref);
tags.forEach(html => { tags.forEach(html => {
if (/\{\d+\}/.test(html)) { return; }
if (simpleTags.includes(html)) { if (simpleTags.includes(html)) {
found_tags[html] = 1; found_tags[html] = 1;
return; return;
@ -145,49 +155,39 @@ var processLang = function (map, lang, primary) {
var specialViolation = special(s); var specialViolation = special(s);
if (usesHTML || weirdCapitalization || specialViolation || !markupMatches) { if (usesHTML || weirdCapitalization || specialViolation || !markupMatches) {
finalErrorCount++;
announce(); announce();
console.log("%s", s); console.log("`[%s]`\n", k);
console.log("`%s`", s);
if (!markupMatches) { if (!markupMatches) {
console.log("Markup does not match base translation"); console.log("\nMarkup does not match base translation");
console.log("\nEnglish: \n\n%s\n", EN[k]); console.log("\n**Reference**: \n\n`%s`\n", EN[k]);
console.log(tagCount); //console.log('base', ref);
console.log(ref); //console.log('translation', tagCount);
console.log('**diff**:\n\n```\n%s\n```', JSON.stringify(markupDiff, null, 2));
console.log();
} }
//if (mismatchedTags.length) { console.log(mismatchedTags); } // XXX //if (mismatchedTags.length) { console.log(mismatchedTags); } // XXX
console.log("[%s]\n", k);
} }
}); });
}; };
var langs = Fs.readdirSync("www/common/translations").filter(name => {
return /messages\..+\.json$/.test(name);
}).map(name => {
var code;
name.replace(/messages\.(.+)\.json$/, (all, _code) => {
code = _code;
});
return code;
});
processLang(EN, 'en', true); processLang(EN, 'en', true);
[ langs.forEach(function (lang) {
'ar',
//'bn_BD',
'ca',
'cs',
'de',
'es',
'eu',
'fi',
'fr',
'hi',
'it',
'ja',
'nb',
'nl',
'pl',
'pt-br',
'ro',
'ru',
'sv',
//'te',
'tr',
'uk',
'zh',
].forEach(function (lang) {
try { try {
var map = require("../../www/common/translations/messages." + lang + ".json"); var map = require("../../www/common/translations/messages." + lang + ".json");
if (!Object.keys(map).length) { return; } if (!Object.keys(map).length) { return; }
@ -201,3 +201,7 @@ simpleTags.forEach(html => {
if (found_tags[html]) { return; } if (found_tags[html]) { return; }
console.log(`html exemption '${html}' is unnecessary.`); console.log(`html exemption '${html}' is unnecessary.`);
}); });
if (finalErrorCount) {
console.log(`\nTotal errors: ${finalErrorCount}`);
}