Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Internationalization of alarm app #202

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apps.json
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,10 @@
"name": "Default Alarm",
"shortName":"Alarms",
"icon": "app.png",
"version":"0.07",
"version":"0.08",
"description": "Set and respond to alarms",
"tags": "tool,alarm,widget",
"custom": "alarm.html",
"storage": [
{"name":"alarm.app.js","url":"app.js"},
{"name":"alarm.boot.js","url":"boot.js"},
Expand Down
1 change: 1 addition & 0 deletions apps/alarm/ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
0.05: Add alarm.boot.js and move code from the bootloader
0.06: Change 'New Alarm' to 'Save', allow Deletion of Alarms
0.07: Don't overwrite existing settings on app update
0.08: Internationalization
103 changes: 103 additions & 0 deletions apps/alarm/alarm.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<html>
<head>
<link rel="stylesheet" href="../../css/spectre.min.css">
</head>
<body>

<p><button id="fetch" class="btn btn-primary">Fetch Language from Bangle.js</button></p>
<div id="formGroup" class="form-group" style="visibility: hidden;">
<p>Then please choose a language from the following list:</p>
<select id="languages" class="form-select">
</select>
</div>
<p><button id="upload" class="btn btn-primary" style="visibility: hidden;">Then Upload</button></p>

<script src="../../lib/customize.js"></script>
<script src="https://www.puck-js.com/puck.js"></script>

<script>
let request = url => new Promise( (resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response);
} else {
reject(xhr.statusText);
}
};
xhr.onerror = () => reject(xhr.statusText);
xhr.onabort = () => reject(xhr.statusText);
xhr.send();
});

let translated = {};
let translate = () => {
Promise.all([translateFile("app.js"), translateFile("alarm.js")]).then(() => {
document.getElementById("upload").style.visibility = 'visible';
}).catch( error => {
console.log(error);
document.getElementById("upload").style.visibility = 'hidden';
});
};
let translateFile = (fileName) => {
var languageSelector = document.getElementById("languages");
var lang = languageSelector.options[languageSelector.selectedIndex].value;
console.log(lang);
request(fileName).then( fileContent =>
request("app_" + lang + ".json")
.catch( () => request("app_" + lang.substring(0,2) + ".json"))
.catch( () => request("app.json"))
.then( langjson => {
var trans = JSON.parse(langjson);
fileContent = fileContent.replace(/"([^"]*?)"\/\*LANG\*\//g, function(m, p1) { return '"' + (trans[p1]||p1) + '"' + (trans[p1]?'':'/*LANG*/'); });
fileContent = fileContent.replace(/'([^']*?)'\/\*LANG\*\//g, function(m, p1) { return "'" + (trans[p1]||p1) + "'" + (trans[p1]?'':'/*LANG*/'); });
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is clever, but I think it would be better to just use a function in the callsite, something like https://www.i18next.com/translation-function/essentials#passing-a-default-value (and many others) use:

locale.t('new', 'New Alarm')

Using the English (here) as the key is not good, if the English text “New Alarm” changes, then you can't reuse the translations properly.

Actually, there's already a locale.translate function: https://www.espruino.com/Bangle.js+Locale#translation
but it uses the English text, and doesn't support Application resources.

Needs some work!

return fileContent;
}).catch( error => {
console.log(error);
return fileContent; // unmodified
})
).then( fileContent => {
translated[fileName] = fileContent;
});
};

document.getElementById("fetch").addEventListener("click", () => {
new Promise((resolve,reject) => {
Puck.write("\x03",(result) => {
if (result===null) return reject("");
Puck.eval(`require("locale").name`, (content,err) => {
if (content===null) return reject(err || "");
resolve(content);
});
});
}).catch( error => {
console.log("Error getting langFromDevice, using fallback en_GB, error was: " + error);
return "en_GB";
}).then( lang => {
document.getElementById("languages").innerHTML = ["en_GB","de_DE","fr_FR","en_US","en_JP","nl_NL","en_CA","sv_SE","en_AU","de_AT","en_IL","es_ES","fr_BE","fi_FI","de_CH","fr_CH","it_CH","tr_TR","hu_HU"].map(l=>`<option value="${l}"${(l===lang)?" selected":""}>${l}</option>`).join("\n");
document.getElementById("formGroup").style.visibility = 'visible';
translate();
});
});

document.getElementById("languages").addEventListener("onchange", () => {
translate();
});

document.getElementById("upload").addEventListener("click", function() {
console.log("app.js is:", translated["app.js"]);
console.log("alarm.js is:", translated["alarm.js"]);
sendCustomizedApp({
storage:[
{"name":"alarm.app.js",content: translated["app.js"]},
{"name":"alarm.boot.js","url":"boot.js"},
{"name": "alarm.js", content: translated["alarm.js"]},
{"name":"alarm.img","url":"app-icon.js","evaluate":true},
{"name":"alarm.wid.js","url":"widget.js"}
]
});
});
</script>
</body>
</html>
11 changes: 8 additions & 3 deletions apps/alarm/alarm.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
const locale = require("locale");
// Chances are boot0.js got run already and scheduled *another*
// 'load(alarm.js)' - so let's remove it first!
clearInterval();

function formatTime(t) {
var hrs = 0|t;
var mins = Math.round((t-hrs)*60);
return hrs+":"+("0"+mins).substr(-2);
var d = new Date();
d.setHours(hrs);
d.setMinutes(mins);
return locale.time(d, true);
}

function getCurrentHr() {
Expand All @@ -18,9 +22,10 @@ function showAlarm(alarm) {
var buzzCount = 10;
if (alarm.msg)
msg += "\n"+alarm.msg;
const ok = locale.translate("Ok");
E.showPrompt(msg,{
title:"ALARM!",
buttons : {"Sleep":true,"Ok":false} // default is sleep so it'll come back in 10 mins
title:"ALARM!"/*LANG*/,
buttons : {"Sleep"/*LANG*/:true,ok:false} // default is sleep so it'll come back in 10 mins
}).then(function(sleep) {
buzzCount = 0;
if (sleep) {
Expand Down
34 changes: 20 additions & 14 deletions apps/alarm/app.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const locale = require("locale");
Bangle.loadWidgets();
Bangle.drawWidgets();

Expand All @@ -14,7 +15,10 @@ var alarms = require("Storage").readJSON("alarm.json",1)||[];
function formatTime(t) {
var hrs = 0|t;
var mins = Math.round((t-hrs)*60);
return hrs+":"+("0"+mins).substr(-2);
var d = new Date();
d.setHours(hrs);
d.setMinutes(mins);
return locale.time(d, true);
}

function getCurrentHr() {
Expand All @@ -24,17 +28,19 @@ function getCurrentHr() {

function showMainMenu() {
const menu = {
'': { 'title': 'Alarms' },
'New Alarm': ()=>editAlarm(-1)
'': { 'title': 'Alarms'/*LANG*/ },
'New Alarm'/*LANG*/: ()=>editAlarm(-1)
};
alarms.forEach((alarm,idx)=>{
txt = (alarm.on?"on ":"off ")+formatTime(alarm.hr);
if (alarm.rp) txt += " (repeat)";
txt = alarm.on?locale.translate("On"):locale.translate("Off");
txt += " ".repeat(Math.max(locale.translate("On").length,locale.translate("Off").length) - txt.length);
txt += " " + formatTime(alarm.hr);
if (alarm.rp) txt += " (" + "rpt"/*LANG*/ + ")";
menu[txt] = function() {
editAlarm(idx);
};
});
menu['< Back'] = ()=>{load();};
menu['< ' + 'Back'/*LANG*/] = ()=>{load();};
return E.showMenu(menu);
}

Expand All @@ -52,21 +58,21 @@ function editAlarm(alarmIndex) {
repeat = a.rp;
}
const menu = {
'': { 'title': 'Alarms' },
'Hours': {
'': { 'title': 'Alarms'/*LANG*/ },
'Hours'/*LANG*/: {
value: hrs,
onchange: function(v){if (v<0)v=23;if (v>23)v=0;hrs=v;this.value=v;} // no arrow fn -> preserve 'this'
},
'Minutes': {
'Minutes'/*LANG*/: {
value: mins,
onchange: function(v){if (v<0)v=59;if (v>59)v=0;mins=v;this.value=v;} // no arrow fn -> preserve 'this'
},
'Enabled': {
'Enabled'/*LANG*/: {
value: en,
format: v=>v?"On":"Off",
onchange: v=>en=v
},
'Repeat': {
'Repeat'/*LANG*/: {
value: en,
format: v=>v?"Yes":"No",
onchange: v=>repeat=v
Expand All @@ -84,20 +90,20 @@ function editAlarm(alarmIndex) {
last : day, rp : repeat
};
}
menu["> Save"] = function() {
menu["> " + "Save"/*LANG*/] = function() {
if (newAlarm) alarms.push(getAlarm());
else alarms[alarmIndex] = getAlarm();
require("Storage").write("alarm.json",JSON.stringify(alarms));
showMainMenu();
};
if (!newAlarm) {
menu["> Delete"] = function() {
menu["> " + "Delete"/*LANG*/] = function() {
alarms.splice(alarmIndex,1);
require("Storage").write("alarm.json",JSON.stringify(alarms));
showMainMenu();
};
}
menu['< Back'] = showMainMenu;
menu['< ' + 'Back'/*LANG*/] = showMainMenu;
return E.showMenu(menu);
}

Expand Down
14 changes: 14 additions & 0 deletions apps/alarm/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"Alarms":"Alarms",
"Hours":"Hours",
"Minutes":"Minutes",
"Enabled":"Enabled",
"New Alarm":"New Alarm",
"Save":"Save",
"Back":"Back",
"Repeat":"Repeat",
"Delete":"Delete",
"rpt":"rpt",
"ALARM!":"ALARM!",
"Sleep":"Sleep"
}
14 changes: 14 additions & 0 deletions apps/alarm/app_de.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"Alarms" : "Wecker",
"Hours" : "Stunden",
"Minutes" : "Minuten",
"Enabled" : "Aktiviert",
"New Alarm" : "Neuer Wecker",
"Save" : "Speichern",
"Back" : "Zurück",
"Repeat" : "Wiederholen",
"Delete" : "Löschen",
"rpt" : "Wdh.",
"ALARM!" : "ALARM!",
"Sleep" : "Schlummern"
}
14 changes: 14 additions & 0 deletions apps/alarm/app_en_GB.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"Alarms" : "Alarms",
"Hours" : "Hours",
"Minutes" : "Minutes",
"Enabled" : "Enabled",
"New Alarm" : "New Alarm",
"Save" : "Save",
"Back" : "Back",
"Repeat" : "Repeat",
"Delete" : "Delete",
"rpt" : "repeat",
"ALARM!" : "ALARM!",
"Sleep" : "Sleep"
}
14 changes: 14 additions & 0 deletions apps/alarm/app_es.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"Alarms" : "Alarmas",
"Hours" : "Horas",
"Minutes" : "Minutos",
"Enabled" : "Activados",
"New Alarm" : "Alarma nueva",
"Save" : "Grabar",
"Back" : "Atrás",
"Repeat" : "Repetición",
"Delete" : "Borrar",
"rpt" : "rep.",
"ALARM!" : "ALARM",
"Sleep" : "Dormir"
}
14 changes: 14 additions & 0 deletions apps/alarm/app_fi.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"Alarms" : "Hälytykset",
"Hours" : "Tunnit",
"Minutes" : "Minuutit",
"Enabled" : "Aktivoitu",
"New Alarm" : "Uusi hälytys",
"Save" : "Tallenna",
"Back" : "Paluu",
"Repeat" : "Toista",
"Delete" : "Poista",
"rpt" : "toistaa",
"ALARM!" : "ALARM",
"Sleep" : "Nukkuminen"
}
14 changes: 14 additions & 0 deletions apps/alarm/app_fr.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"Alarms" : "Réveils",
"Hours" : "Heures",
"Minutes" : "Minutes",
"Enabled" : "Activé",
"New Alarm" : "Nouveau Réveil",
"Save" : "Sauvegarder",
"Back" : "Retour",
"Repeat" : "Répétition",
"Delete" : "Supprimer",
"rpt" : "rép.",
"ALARM!" : "ALARM!",
"Sleep" : "Sommeil"
}
14 changes: 14 additions & 0 deletions apps/alarm/app_hu.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"Alarms" : "Riasztások",
"Hours" : "Óra",
"Minutes" : "Perc",
"Enabled" : "Aktiválva",
"New Alarm" : "Új riasztás",
"Save" : "Mentés",
"Back" : "Vissza",
"Repeat" : "Ismétlés",
"Delete" : "Törlés",
"rpt" : "ismétlés",
"ALARM!" : "ALARM!",
"Sleep" : "Alvás"
}
14 changes: 14 additions & 0 deletions apps/alarm/app_it.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"Alarms" : "Allarmi",
"Hours" : "Ore",
"Minutes" : "Minuti",
"Enabled" : "Attivato",
"New Alarm" : "Nuovo allarme",
"Save" : "Salvare",
"Back" : "Indietro",
"Repeat" : "Ripetere",
"Delete" : "Cancellare",
"rpt" : "ripetere",
"ALARM!" : "ALARM!",
"Sleep" : "Dormire"
}
14 changes: 14 additions & 0 deletions apps/alarm/app_nl.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"Alarms" : "Alarmen",
"Hours" : "Uren",
"Minutes" : "Minuten",
"Enabled" : "Geactiveerd",
"New Alarm" : "Nieuw alarm",
"Save" : "Opslaan",
"Back" : "Terug",
"Repeat" : "Herhalen",
"Delete" : "Verwijderen",
"rpt" : "herhalen",
"ALARM!" : "ALARV.",
"Sleep" : "Stand-by"
}
Loading