Updated script to add more accurate string finding and auto translation

pull/1414/head
copoer 2022-02-09 19:52:49 -04:00
parent 1f48344d16
commit 4ce761dab9
1 changed files with 66 additions and 7 deletions

View File

@ -5,6 +5,16 @@ outputs a list of strings that have been found.
See https://github.com/espruino/BangleApps/issues/1311 See https://github.com/espruino/BangleApps/issues/1311
*/ */
let AUTO_TRANSLATE = false;
let translate = false;
if (process.env.DEEPL) {
translate = require("translate");
translate.engine = "deepl"; // Or "yandex", "libre", "deepl"
translate.key = process.env.DEEPL;
translate.url = "https://api-free.deepl.com/v2/translate";
AUTO_TRANSLATE = true;
}
var IGNORE_STRINGS = [ var IGNORE_STRINGS = [
"5x5","6x8","6x8:2","4x6","12x20","6x15","5x9Numeric7Seg", "Vector", // fonts "5x5","6x8","6x8:2","4x6","12x20","6x15","5x9Numeric7Seg", "Vector", // fonts
"---","...","*","##","00","GPS","ram", "---","...","*","##","00","GPS","ram",
@ -12,7 +22,13 @@ var IGNORE_STRINGS = [
"sortorder","tl","tr", "sortorder","tl","tr",
"function","object", // typeof=== "function","object", // typeof===
"txt", // layout styles "txt", // layout styles
"play","stop","pause", // music state "play","stop","pause", "volumeup", "volumedown", // music state
"${hours}:${minutes}:${seconds}", "${hours}:${minutes}",
"BANGLEJS",
"NONE",
"fgH", "bgH",
"m/s",
"undefined", "kbmedia"
]; ];
var IGNORE_FUNCTION_PARAMS = [ var IGNORE_FUNCTION_PARAMS = [
@ -64,13 +80,20 @@ function isNotString(s, wasFnCall, wasArrayAccess) {
if (wasArrayAccess && IGNORE_ARRAY_ACCESS.includes(wasArrayAccess)) return true; if (wasArrayAccess && IGNORE_ARRAY_ACCESS.includes(wasArrayAccess)) return true;
if (s=="Storage") console.log("isNotString",s,wasFnCall); if (s=="Storage") console.log("isNotString",s,wasFnCall);
if (s.length<2) return true; // too short if (s.length<3) return true; // too short
if (s.length>40) return true; // too long if (s.length>40) return true; // too long
if (s[0]=="#") return true; // a color if (s[0]=="#") return true; // a color
if (s.endsWith(".json") || s.endsWith(".img")) return true; // a filename if (s.endsWith('.log') || s.endsWith('.js') || s.endsWith(".info") || s.endsWith(".csv") || s.endsWith(".json") || s.endsWith(".img") || s.endsWith(".txt")) return true; // a filename
if (s.endsWith("=")) return true; // probably base64 if (s.endsWith("=")) return true; // probably base64
if (s.startsWith("BTN")) return true; // button name if (s.startsWith("BTN")) return true; // button name
if (IGNORE_STRINGS.includes(s)) return true; // one we know to ignore if (IGNORE_STRINGS.includes(s)) return true; // one we know to ignore
if (!isNaN(parseFloat(s)) && isFinite(s)) return true; //is number
if (s.match(/^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/)) return true; //roman number
if (!s.match(/.*[A-Z].*/i)) return true; // No letters
if (s.match(/.*[0-9].*/i)) return true; // No letters
if (s.match(/.*\(.*\).*/)) return true; // is function
if (s.match(/[A-Za-z]+[A-Z]([A-Z]|[a-z])*/)) return true; // is camel case
if (s.includes('_')) return true;
return false; return false;
} }
@ -115,6 +138,7 @@ apps.forEach((app,appIdx) => {
if (previousString.includes("/*LANG*/")) { // translated! if (previousString.includes("/*LANG*/")) { // translated!
addString(translatedStrings, tok.value, shortFilePath); addString(translatedStrings, tok.value, shortFilePath);
} else { // untranslated - potential to translate? } else { // untranslated - potential to translate?
// filter out numbers
if (!isNotString(tok.value, wasFnCall, wasArrayAccess)) { if (!isNotString(tok.value, wasFnCall, wasArrayAccess)) {
addString(untranslatedStrings, tok.value, shortFilePath); addString(untranslatedStrings, tok.value, shortFilePath);
} }
@ -137,6 +161,26 @@ untranslatedStrings.sort((a,b)=>a.uses - b.uses);
translatedStrings.sort((a,b)=>a.uses - b.uses); translatedStrings.sort((a,b)=>a.uses - b.uses);
/*
* @description Add lang to start of string
* @param str string to add LANG to
* @param file file that string is found
* @returns void
*/
function applyLANG(str, file) {
fs.readFile(file, 'utf8', function (err,data) {
if (err) {
return console.log(err);
}
const regex = new RegExp(`(.*)((?<!\/\*LANG\*\/)["|']${str}[^A-Z].*)`, 'gi');
const result = data.replace(regex, '$1/*LANG*/$2');
console.log(str, file);
fs.writeFile(file, result, 'utf8', function (err) {
if (err) return console.log(err);
});
});
}
var report = ""; var report = "";
log("Translated Strings that are not tagged with LANG"); log("Translated Strings that are not tagged with LANG");
@ -144,8 +188,12 @@ log("=================================================================");
log(""); log("");
log("Maybe we should add /*LANG*/ to these automatically?"); log("Maybe we should add /*LANG*/ to these automatically?");
log(""); log("");
log(untranslatedStrings.filter(e => translatedStrings.find(t=>t.str==e.str)).map(e=>`${JSON.stringify(e.str)} (${e.files.join(",")})`).join("\n")); const wordsToAdd = untranslatedStrings.filter(e => translatedStrings.find(t=>t.str==e.str));
// Uncomment to add LANG to all strings
//wordsToAdd.forEach(e => e.files.forEach(a => applyLANG(e.str, a)));
log(wordsToAdd.map(e=>`${JSON.stringify(e.str)} (${e.uses} uses)`).join("\n"));
log(""); log("");
//process.exit(1); //process.exit(1);
log("Possible English Strings that could be translated"); log("Possible English Strings that could be translated");
log("================================================================="); log("=================================================================");
@ -158,15 +206,16 @@ log("");
//process.exit(1); //process.exit(1);
let languages = JSON.parse(fs.readFileSync(`${BASEDIR}/lang/index.json`).toString()); let languages = JSON.parse(fs.readFileSync(`${BASEDIR}/lang/index.json`).toString());
languages.forEach(language => { for (let language of languages) {
if (language.code == "en_GB") { if (language.code == "en_GB") {
console.log(`Ignoring ${language.code}`); console.log(`Ignoring ${language.code}`);
return; continue;
} }
console.log(`Scanning ${language.code}`); console.log(`Scanning ${language.code}`);
log(language.code); log(language.code);
log("=========="); log("==========");
let translations = JSON.parse(fs.readFileSync(`${BASEDIR}/lang/${language.url}`).toString()); let translations = JSON.parse(fs.readFileSync(`${BASEDIR}/lang/${language.url}`).toString());
let translationPromises = [];
translatedStrings.forEach(translationItem => { translatedStrings.forEach(translationItem => {
if (!translations.GLOBAL[translationItem.str]) { if (!translations.GLOBAL[translationItem.str]) {
console.log(`Missing GLOBAL translation for ${JSON.stringify(translationItem)}`); console.log(`Missing GLOBAL translation for ${JSON.stringify(translationItem)}`);
@ -176,11 +225,21 @@ languages.forEach(language => {
let appName = m[0].replaceAll("/", ""); let appName = m[0].replaceAll("/", "");
if (translations[appName] && translations[appName][translationItem.str]) { if (translations[appName] && translations[appName][translationItem.str]) {
console.log(` but LOCAL translation found in \"${appName}\"`); console.log(` but LOCAL translation found in \"${appName}\"`);
} else if (AUTO_TRANSLATE && language.code !== "tr_TR") { // Auto Translate
translationPromises.push(new Promise(async (resolve) => {
const translation = await translate(translationItem.str, language.code.split("_")[0]);
console.log("Translating:", translationItem.str, translation);
translations.GLOBAL[translationItem.str] = translation;
resolve()
}))
} }
} }
}); });
} }
}); });
Promise.all(translationPromises).then(() => {
fs.writeFileSync(`${BASEDIR}/lang/${language.url}`, JSON.stringify(translations, null, 4))
});
log(""); log("");
}); }
console.log("Done."); console.log("Done.");