Add menu option for language translations (fix #136)

pull/1315/head
Gordon Williams 2022-01-18 16:21:30 +00:00
parent 5a4f15435f
commit 85be6af02e
4 changed files with 103 additions and 14 deletions

View File

@ -2,15 +2,20 @@
/* Scans for strings that may be in English in each app, and
outputs a list of strings that have been found.
Early work towards internationalisation.
See https://github.com/espruino/BangleApps/issues/136
See https://github.com/espruino/BangleApps/issues/1311
*/
var IGNORE_STRINGS = [
"5x5",
"5x9Numeric7Seg",
"Vector"
];
var BASEDIR = __dirname+"/../";
Espruino = require(BASEDIR+"core/lib/espruinotools.js");
var fs = require("fs");
var APPSDIR = BASEDIR+"apps/";
function ERROR(s) {
console.error("ERROR: "+s);
process.exit(1);
@ -18,6 +23,9 @@ function ERROR(s) {
function WARN(s) {
console.log("Warning: "+s);
}
function log(s) {
console.log(s);
}
var appsFile, apps;
try {
@ -39,31 +47,65 @@ function isNotString(s) {
if (s.endsWith(".json") || s.endsWith(".img")) return true; // a filename
if (s.endsWith("=")) return true; // probably base64
if (s.startsWith("BTN")) return true; // button name
if (IGNORE_STRINGS.includes(s)) return true; // one we know to ignore
return false;
}
var textStrings = [];
// A string that *could* be translated?
var untranslatedStrings = [];
// Strings that are marked with 'LANG'
var translatedStrings = [];
console.log("Scanning...");
console.log("Scanning apps...");
apps.forEach((app,appIdx) => {
var appDir = APPSDIR+app.id+"/";
app.storage.forEach((file) => {
if (!file.url || !file.name.endsWith(".js")) return;
var fileContents = fs.readFileSync(appDir+file.url).toString();
var lex = Espruino.Core.Utils.getLexer(fileContents);
var lastIdx = 0;
var tok = lex.next();
while (tok!==undefined) {
var previousString = fileContents.substring(lastIdx, tok.startIdx);
if (tok.type=="STRING") {
if (previousString.includes("/*LANG*/")) { // translated!
if (!translatedStrings.includes(tok.value))
translatedStrings.push(tok.value);
} else { // untranslated - potential to translate?
if (!isNotString(tok.value)) {
//console.log(tok.str);
if (!textStrings.includes(tok.value))
textStrings.push(tok.value);
if (!untranslatedStrings.includes(tok.value))
untranslatedStrings.push(tok.value);
}
}
}
lastIdx = tok.endIdx;
tok = lex.next();
}
});
});
console.log("Done");
textStrings.sort();
console.log(textStrings.join("\n"));
untranslatedStrings.sort();
translatedStrings.sort();
var report = "";
/* // too many! don't output these
log("Possible English Strings that could be translated");
log("=================================================================");
log("");
log("Add these to IGNORE_STRINGS if the don't make sense...");
log("");
log(untranslatedStrings.map(s=>JSON.stringify(s)).join(",\n"));*/
log("");
var languages = JSON.parse(fs.readFileSync(BASEDIR+"/lang/index.json").toString());
languages.forEach(language => {
console.log("Scanning "+language.code);
log(language.code);
log("==========");
var translations = JSON.parse(fs.readFileSync(BASEDIR+"/lang/"+language.url).toString());
translatedStrings.forEach(str => {
if (!translations.GLOBAL[str])
console.log(`Missing translation for ${JSON.stringify(str)}`);
});
log("");
});
console.log("Done.");

View File

@ -141,6 +141,11 @@
<input type="checkbox" id="settings-settime">
<i class="form-icon"></i> Always update time when we connect
</label>
<div class="form-group">
<select class="form-select form-inline" id="settings-lang" style="width: 10em">
<option value="">None (English)</option>
</select>&nbsp;&nbsp;<span>Translations (<a href="https://github.com/espruino/BangleApps/issues/1311" target="_blank">BETA - more info</a>)</span>
</div>
<button class="btn" id="defaultsettings">Default settings</button>
</div>
</div>

View File

@ -1,9 +1,9 @@
{
"//":"British English language translations - the default strings in apps are all english anyway, so no need to have translations for most things",
"GLOBAL": {
"//":"Translations that apply for all apps",
"//":"Translations that apply for all apps"
},
"alarm": {
"//":"App-specific overrides",
"//":"App-specific overrides"
}
}

View File

@ -164,6 +164,48 @@ window.addEventListener('load', (event) => {
showToast("App Install failed, "+err,"error");
});
});
// Load language list
httpGet("lang/index.json").then(languagesJSON=>{
var languages;
try {
languages = JSON.parse(languagesJSON);
} catch(e) {
console.error("lang/index.json Corrupted", e);
}
function reloadLanguage() {
LANGUAGE = undefined;
if (SETTINGS.language) {
var language = languages.find(l=>l.code==SETTINGS.language);
if (language) {
var langURL = "lang/"+language.url;
httpGet(langURL).then(languageJSON=>{
try {
LANGUAGE = JSON.parse(languageJSON);
console.log(`${langURL} loaded successfully`);
} catch(e) {
console.error(`${langURL} Corrupted`, e);
}
});
} else {
console.error(`Language code ${JSON.stringify(SETTINGS.language)} not found in lang/index.json`);
}
}
}
var selectLang = document.getElementById("settings-lang");
console.log(languages);
languages.forEach(lang => {
selectLang.innerHTML += `<option value="${lang.code}" ${SETTINGS.language==lang.code?"selected":""}>${lang.name} (${lang.code})</option>`;
});
selectLang.addEventListener("change",event=>{
SETTINGS.language = event.target.value;
reloadLanguage();
saveSettings();
});
reloadLanguage();
});
});
function onAppJSONLoaded() {