mirror of https://github.com/espruino/BangleApps
Add menu option for language translations (fix #136)
parent
5a4f15435f
commit
85be6af02e
|
@ -2,15 +2,20 @@
|
||||||
/* Scans for strings that may be in English in each app, and
|
/* Scans for strings that may be in English in each app, and
|
||||||
outputs a list of strings that have been found.
|
outputs a list of strings that have been found.
|
||||||
|
|
||||||
Early work towards internationalisation.
|
See https://github.com/espruino/BangleApps/issues/1311
|
||||||
See https://github.com/espruino/BangleApps/issues/136
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var IGNORE_STRINGS = [
|
||||||
|
"5x5",
|
||||||
|
"5x9Numeric7Seg",
|
||||||
|
"Vector"
|
||||||
|
];
|
||||||
|
|
||||||
var BASEDIR = __dirname+"/../";
|
var BASEDIR = __dirname+"/../";
|
||||||
Espruino = require(BASEDIR+"core/lib/espruinotools.js");
|
Espruino = require(BASEDIR+"core/lib/espruinotools.js");
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
|
|
||||||
var APPSDIR = BASEDIR+"apps/";
|
var APPSDIR = BASEDIR+"apps/";
|
||||||
|
|
||||||
function ERROR(s) {
|
function ERROR(s) {
|
||||||
console.error("ERROR: "+s);
|
console.error("ERROR: "+s);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
@ -18,6 +23,9 @@ function ERROR(s) {
|
||||||
function WARN(s) {
|
function WARN(s) {
|
||||||
console.log("Warning: "+s);
|
console.log("Warning: "+s);
|
||||||
}
|
}
|
||||||
|
function log(s) {
|
||||||
|
console.log(s);
|
||||||
|
}
|
||||||
|
|
||||||
var appsFile, apps;
|
var appsFile, apps;
|
||||||
try {
|
try {
|
||||||
|
@ -39,31 +47,65 @@ function isNotString(s) {
|
||||||
if (s.endsWith(".json") || s.endsWith(".img")) return true; // a filename
|
if (s.endsWith(".json") || s.endsWith(".img")) 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
|
||||||
return false;
|
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) => {
|
apps.forEach((app,appIdx) => {
|
||||||
var appDir = APPSDIR+app.id+"/";
|
var appDir = APPSDIR+app.id+"/";
|
||||||
app.storage.forEach((file) => {
|
app.storage.forEach((file) => {
|
||||||
if (!file.url || !file.name.endsWith(".js")) return;
|
if (!file.url || !file.name.endsWith(".js")) return;
|
||||||
var fileContents = fs.readFileSync(appDir+file.url).toString();
|
var fileContents = fs.readFileSync(appDir+file.url).toString();
|
||||||
var lex = Espruino.Core.Utils.getLexer(fileContents);
|
var lex = Espruino.Core.Utils.getLexer(fileContents);
|
||||||
|
var lastIdx = 0;
|
||||||
var tok = lex.next();
|
var tok = lex.next();
|
||||||
while (tok!==undefined) {
|
while (tok!==undefined) {
|
||||||
|
var previousString = fileContents.substring(lastIdx, tok.startIdx);
|
||||||
if (tok.type=="STRING") {
|
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)) {
|
if (!isNotString(tok.value)) {
|
||||||
//console.log(tok.str);
|
if (!untranslatedStrings.includes(tok.value))
|
||||||
if (!textStrings.includes(tok.value))
|
untranslatedStrings.push(tok.value);
|
||||||
textStrings.push(tok.value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
lastIdx = tok.endIdx;
|
||||||
tok = lex.next();
|
tok = lex.next();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
console.log("Done");
|
untranslatedStrings.sort();
|
||||||
textStrings.sort();
|
translatedStrings.sort();
|
||||||
console.log(textStrings.join("\n"));
|
|
||||||
|
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.");
|
||||||
|
|
|
@ -141,6 +141,11 @@
|
||||||
<input type="checkbox" id="settings-settime">
|
<input type="checkbox" id="settings-settime">
|
||||||
<i class="form-icon"></i> Always update time when we connect
|
<i class="form-icon"></i> Always update time when we connect
|
||||||
</label>
|
</label>
|
||||||
|
<div class="form-group">
|
||||||
|
<select class="form-select form-inline" id="settings-lang" style="width: 10em">
|
||||||
|
<option value="">None (English)</option>
|
||||||
|
</select> <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>
|
<button class="btn" id="defaultsettings">Default settings</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -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",
|
"//":"British English language translations - the default strings in apps are all english anyway, so no need to have translations for most things",
|
||||||
"GLOBAL": {
|
"GLOBAL": {
|
||||||
"//":"Translations that apply for all apps",
|
"//":"Translations that apply for all apps"
|
||||||
},
|
},
|
||||||
"alarm": {
|
"alarm": {
|
||||||
"//":"App-specific overrides",
|
"//":"App-specific overrides"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
42
loader.js
42
loader.js
|
@ -164,6 +164,48 @@ window.addEventListener('load', (event) => {
|
||||||
showToast("App Install failed, "+err,"error");
|
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() {
|
function onAppJSONLoaded() {
|
||||||
|
|
Loading…
Reference in New Issue