espruino / BangleApps

Bangle.js App Loader (and Apps)
https://banglejs.com/apps
MIT License
491 stars 1.15k forks source link

Locale App & Handling #105

Closed gfwilliams closed 4 years ago

gfwilliams commented 4 years ago

As discussed here: http://forum.espruino.com/conversations/290058/#15120253

Add an app and code to handle output of time/distance/etc in a locale-sensitive way

MaBecker commented 4 years ago

How many countries Bangle.js has been ordered from?

Can you please name them?

gfwilliams commented 4 years ago

So far...

Australia
Austria
Belgium
Brazil
Bulgaria
Canada
Chile
China
Colombia
Croatia
Czechia
Denmark
Egypt
Estonia
Finland
France
Germany
Greece
Hong Kong
Hungary
India
Ireland
Israel
Italy
Japan
Korea, Republic of
Latvia
Lithuania
Luxembourg
Malaysia
Mexico
Moldova, Republic of
Montenegro
Netherlands
New Zealand
Norway
Poland
Portugal
Romania
Russia
Saudi Arabia
Singapore
Slovakia
Slovenia
South Africa
Spain
Sweden
Switzerland
Taiwan
Thailand
United Kingdom
United States
Vietnam
Åland Islands
MaBecker commented 4 years ago

thanks, I guess not all of them can be handle with a single font.

source: https://sourceware.org/git/?p=glibc.git;a=tree;f=localedata/locales;h=a2ce1fa9fbee768b50a689e17d2c7c680c48e498;hb=refs/heads/master

git clone git://sourceware.org/git/glibc.git
cd localedata/locales
MaBecker commented 4 years ago

Lets talk about the content that should be available as a locale set.

Suggest to use short names instead of long names

lc : {
    nol : name of locale, eg "de_DE"
    mon : month full as comma separated array  "%B"
    abmon : month short form as comma separated array  "%b"
    day  : day as comma separated array "%A"
    abday : day short form as comma separated array  "%s"
    dp : decimal_point 
    ts: thousands_sep 
    cs: currency_symbol 
    ics: int_curr_symbol 
    ys: yesstr 
    ns: nostr    
    apm : am_pm eq eg 0 or 1
}

Anything else you see to have in that set to start?

n=>n.toString().replace(lc.ts,lc.dp)

MaBecker commented 4 years ago
en_AU : Australia    
de_AT : Austria
de_BE : Belgium
pt_BR : Brazil
bg_BG : Bulgaria
en_CA : Canada
es_CL : Chile
zh_CN : China
es_CO : Colombia
hr_HR : Croatia
cs_CZ : Czechia
da_DK : Denmark
ar_EG : Egypt
et_EE : Estonia
fi_FI : Finland
fr_FR : France
de_DE : Germany
elGR : Greece
en_HK : Hong Kong
hu_HU : Hungary
en_IN : India
en_IE : Ireland
en_IL : Israel
it_IT : Italy
ja_JP : Japan
ko_KR : Korea, Republic of
lv_LV : Latvia
lt_LT : Lithuania
de_LU : Luxembourg
ms_ MY : Malaysia
es_MX : Mexico
? :  Moldova, Republic of
sr_ME :  Montenegro
nl_NL : Netherlands
en_NZ : New Zealand
nb_NO : Norway
pl_PL :  Poland
pt_PT : Portugal
ro_RO : Romania
ru _RU : Russia
arr_SA : Saudi Arabia
en_SG : Singapore
sk_SK : Slovakia
si_SI : Slovenia
EN_ZA : South Africa
sp_SP : Spain
sv_SE : Sweden
de_CH : Switzerland
fr_CH : Switzerland
it_CH : Switzerland
wae_CH : Switzerland
? :  Taiwan
th_TH :  Thailand
en_GB : United Kingdom
en_US : United States
vi_VN : Vietnam
? : Åland Islands
MaBecker commented 4 years ago

How should this app be designed?

gfwilliams commented 4 years ago

I just sorted by number of backers, and I think working back would be a good start:

Finland : 10
Belgium : 12
Spain : 12
Israel : 20
Austria : 24
Australia : 25
Sweden : 29
France : 33
Switzerland : 35
Canada : 37
Netherlands : 41
Japan : 52
United Kingdom : 189
United States : 252
Germany : 348

I think Japan/Israel are unlikely to be sensible right now. At some point it might be possible to supply bitmaps for text, but I think that's going too far atm.

ys: yesstr, ns: nostr

Maybe we should have:

translate : { yes : ..., no: ..., ok : ..., on: ..., off: .... } then we could basically just look phrases up in translate before displaying them. It'd make code nice and readable since it's basically english, and more translations could easily be added over time.

select the wanted locale out of maintained ones via html setting page

This sounds like an amazing idea (rather than trying to upload every possible translation to the watch).

As you say, I reckon we just put everything (code and data) in one file called locale. Once we figure out what API it'll have I can put a placeholder in the Bangle.js firmware for English, then if you upload the 'Locale' app you'll get whatever locale you wanted.

So in terms of API:

MaBecker commented 4 years ago

looks like FontDylex7x13 can handle the selected locales.

MaBecker commented 4 years ago

let’s add temperature (°C, °F) too.

gfwilliams commented 4 years ago

Good plan re:temperature - in terms of fonts, I wonder if we can't extend the 6x8 font to handle the extended ASCII chars? Ideally we would use something built-in.

MaBecker commented 4 years ago

extend the 6x8 font

Hope that fits into firmware

gfwilliams commented 4 years ago

Ok, first draft:

exports = { name : "en_GB", currencySym:"£",
  translate : str=>str, // as-is
  date : (d,short) => short?("0"+d.getDate()).substr(-2)+"/"+("0"+(d.getMonth()+1)).substr(-2)+"/"+d.getFullYear():d.toString().substr(4,11), // Date to "Feb 28 2020" or "28/02/2020"(short)
  time : (d,short) => { // Date to  "4:15.28 pm" or "15:42.59"(short)
    if (short)
      return d.toString().substr(16,5)+"."+d.toString().substr(22,2);
    else {
      var h = d.getHours(), m = d.getMinutes(), r = "am";
      if (h==0) { h=12; }
      else if (h>=12) {
        if (h>12) h-=12;
        r = "pm";
      }
      return (" "+h).substr(-2)+":"+("0"+m).substr(-2)+"."+("0"+d.getSeconds()).substr(-2)+" "+r;
    }
  },
  dow : (d,short) => short?d.toString().substr(0,3):"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday".split(",")[d.getDay()], // Date to "Monday" or "Mon"(short)
  month : (d,short) => short?d.toString().substr(4,3):"January,February,March,April,May,June,July,August,September,October,November,December".split(",")[d.getMonth()], // Date to "February" or "Feb"(short)
  number : n => n.toString(), // more fancy?
  currency : n => "£"+n.toFixed(2), // number to "£1.00"
  distance : m => (m<1000)?Math.round(m)+"m":Math.round(m/160.934)/10+"mi", // meters to "123m" or "1.2mi" depending on size
  speed : s => Math.round(s)+"mph",// kph to "123mph"
  temp : t => Math.round(t)+"'C" // degrees C to degrees C
};

/*
print(exports.date(new Date()));     
print(exports.date(new Date(),true));
print(exports.time(new Date()));
print(exports.time(new Date(),true));
print(exports.dow(new Date()));
print(exports.dow(new Date(),true));
print(exports.month(new Date()));
print(exports.month(new Date(),true));
print(exports.number(12345));
print(exports.currency(12345));
print(exports.distance(123));
print(exports.speed(123));
print(exports.temp(12));
*/

Does that seem reasonable?

If you save it to a file called 'locale' then you can do:

require("locale.js").date(new Date())

So assuming the API looks ok, I can add that to Bangle.js firmware, then we can start using it in apps and maybe producing that locale app which will

gfwilliams commented 4 years ago

I guess we could maybe modify time so it always did 12 or 24, but so there was a meridian() function which returned "am"/"pm"/""(if 24)

MaBecker commented 4 years ago

Edit: It could work like the splash screen, if it exist use it, else use the default.

I will continue to work on the locales set and generating a locale.

gfwilliams commented 4 years ago

Ok, great! The newest firmware builds now have the locale module in, so we should be able to start using it for stuff...

MaBecker commented 4 years ago

this is the locale set that could be used with app local:

Edit: fixed some errors

var locales = {
    "de_DE": {
        name: "de_DE",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "\x80",
        int_curr_symbol: "EUR",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°C",
        ampm: {0:"",1:""},
        timePattern: { 0: "HH:MM:SS ", 1: "HH:MM" },
        datePattern: { 0: "A, d. B Y", "1": "dd.mm.y" }, // Sonntag, 1. März 2020 // 01.01.20
        abmonth: "Jan,Feb,März,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez",
        month: "Januar,Februar,März,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember",
        abday: "So,Mo,Di,Mi,Do,Fr,Sa",
        day: "Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag",
        trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus" }},
    "en_GB": { // this is default
        name: "en_GB",
        decimal_point: ".",
        thousands_sep: ",",
        currency_symbol: "£",
        int_curr_symbol: "GBP",
        speed: 'mph',
        distance: { "0": "mi", "1": "kmi" },
        temperatur: '°C',
        ampm: {0:"am",1:"pm"},
        timePattern: { 0: "HH:MM:SS ", 1: "HH:MM" },
        datePattern: { 0: "b dd Y", 1: "dd/mm/Y" }, // Feb 28 2020" // "01/03/2020"(short)
        abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
        month: "January,February,March,April,May,June,July,August,September,October,November,December",
        abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
        day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
        trans: { yes: "yes", Yes: "Yes", no: "no", No: "No", ok: "ok", on: "on", off: "off" }},
    "en_US": {
        name: "en_US",
        decimal_point: ".",
        thousands_sep: ",",
        currency_symbol: "$",
        int_curr_symbol: "USD",
        speed: "mph",
        distance: { 0: "mi", 1: "kmi" },
        temperature: "°F",
        ampm: {0:"am",1:"pm"},
        timePattern: { 0: "HH:MM:SS ", 1: "HH:MM" },
        datePattern: { 0: "", 1: "M/d/yy" },
        abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
        month: "January,February,March,April,May,June,July,August,September,October,November,December",
        abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
        day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
        trans: { yes: "yes", Yes: "Yes", no: "no", No: "No", ok: "ok", on: "on", off: "off" }},
    "en_JP": { // we do not have the font, so it is not ja_JP 
        name: "en_JP",
        decimal_point: ".",
        thousands_sep: ",",
        currency_symbol: "¥",
        int_curr_symbol: "JPY",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°F",
        ampm: {0:"",1:""},
        timePattern: { 0: "HH:MM:SS ", 1: "HH:MM" },
        datePattern: { 0: "y/MM/dd", 1: "y/MM/dd" },
        abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
        month: "January,February,March,April,May,June,July,August,September,October,November,December",
        abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
        day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
        trans: { yes: "yes", Yes: "Yes", no: "no", No: "No", ok: "ok", on: "on", off: "off" }},
    "nl_NL": {
        name: "nl_NL",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "€",
        int_curr_symbol: "EUR",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°C",
        ampm: {0:"",1:""},
        dimePattern: { 0: "HH:MM:SS ", 1: "HH:MM" },
        datePattern: { 0: "A B d Y", "1": "d.m.y" }, // zondag 1 maart 2020  // 01.01.20    
        abday: "zo,ma,di,wo,do,vr,za",
        day: "zondag,maandag,dinsdag,woensdag,donderdag,vrijdag,zaterdag",
        abmon: "jan,feb,mrt,apr,mei,jun,jul,aug,sep,okt,nov,dec",
        month: "januari,februari,maart,april,mei,juni,juli,augustus,september,oktober,november,december",
        trans: { yes: "yes", Yes: "Yes", no: "no", No: "No", ok: "ok", on: "on", off: "off" }},
    "en_CA": {
        name: "en_CA",
        decimal_point: ".",
        thousands_sep: ",",
        currency_symbol: "$",
        int_curr_symbol: "CAD",
        speed: "mph",
        distance: { 0: "mi", 1: "kmi" },
        temperature: "°F",
        ampm: {0:"am",1:"pm"},
        timePattern: { 0: "HH:MM:SS ", 1: "HH:MM" },
        datePattern: { 0: "A, B d, Y", "1": "Y-mm-dd" }, //  Sunday, March 1, 2020  // 2012-12-20
        abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
        month: "January,February,March,April,May,June,July,August,September,October,November,December",
        abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
        day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
        trans: { yes: "yes", Yes: "Yes", no: "no", No: "No", ok: "ok", on: "on", off: "off" }},
    "fr_FR": {
        name: "fr_FR",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "\x80",
        int_curr_symbol: "EUR",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°C",
        ampm: {0:"",1:""},
        timePattern: { 0: "HH:MM:SS ", 1: "HH:MM" },
        datePattern: { 0: "A B d Y", "1": "d/m/Y" }, // dimanche 1 mars 2020 //  01/03/2020   
        abmon: "anv.,févr.,mars,avril,mai,juin,juil.,août,sept.,oct.,nov.,déc.",
        mon: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre",
        abday: "dim,lun,mar,mer,jeu,ven,sam",
        day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi",
        trans : { yes : "oui", Yes: "Oui", no: "no", No: "No", ok : "ok", on: "on", off: "off" }},
    "sv_SE": {
        name: "sv_SE",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "kr",
        int_curr_symbol: "SKR",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°C",
        ampm: {0:"fm",1:"em"},
        timePattern: { 0: "HH:MM:SS ", 1: "HH:MM" },
        datePattern: { 0: "A B d Y", "1": "Y-mm-dd" }, // söndag 1 mars 2020 //  2020-03-01  
        abmonth: "jan,feb,mars,apr,maj,juni,juli,aug,sep,okt,nov,dec",
        month: "januari,februari,mars,april,maj,juni,juli,augusti,september,oktober,november,december",
        abday: "sön, mån, tis, ons, tors, fre, lör",    
        day: "söndag,måndag,tisdag,onsdag,torsdag,fredag,lördag",
        trans : { yes : "ja", Yes: "Ja", no: "nej", No: "Nej", ok : "ok", on: "on", off: "off" }},
    "en_AU": {
        name: "en_AU",
        decimal_point: ".",
        thousands_sep: ",",
        currency_symbol: "$",
        int_curr_symbol: "AUD",
        speed: "mph",
        distance: { 0: "mi", 1: "kmi" },
        temperature: "°F",
        ampm: {0:"am",1:"pm"},
        timePattern: { 0: "HH:MM:SS ", 1: "HH:MM" },
        datePattern: { 0: "A, B d, Y", "1": "m/d/y" }, //  Sunday, 1 March 2020  // 1/3/20
        abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
        month: "January,February,March,April,May,June,July,August,September,October,November,December",
        abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
        day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
        trans: { yes: "yes", Yes: "Yes", no: "no", No: "No", ok: "ok", on: "on", off: "off" }},
    "de_AT": {
        name: "de_AT",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "\x80",
        int_curr_symbol: "EUR",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°C",
         timePattern: { 0: "HH:MM:SS ", 1: "HH:MM" },
        datePattern: { 0: "A, d. B Y", "1": "dd.mm.y" }, // Sonntag, 1. März 2020 // 01.03.20
        abmonth: "Jän,Feb,März,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez",
        month: "Jänner,Februar,März,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember",
        abday: "So,Mo,Di,Mi,Do,Fr,Sa",
        day: "Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag",
        trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus" }},
    "en_IL": {
        name: "en_IL",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "₪",
        int_curr_symbol: "ILS",
        speed: "mph",
        distance: { 0: "mi", 1: "kmi" },
        temperature: "°F",
        ampm: {0:"am",1:"pm"},
        timePattern: { 0: "HH:MM:SS ", 1: "HH:MM" },
        datePattern: { 0: "A, B d, Y", "1": "dd/mm/Y" }, //  Sunday, 1 March 2020  // 01/03/2020
        abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
        month: "January,February,March,April,May,June,July,August,September,October,November,December",
        abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
        day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
        trans: { yes: "yes", Yes: "Yes", no: "no", No: "No", ok: "ok", on: "on", off: "off" }},
    "es_ES": {
        name: "es_ES",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "\x80",
        int_curr_symbol: "EUR",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°C",
        ampm: {0:"",1:""},
        timePattern: { 0: "HH:MM:SS ", 1: "HH:MM" },
        datePattern: { 0: "A, d de B de Y", "1": "dd/mm/y" }, //  domingo, 1 de marzo de 2020  // 01/03/20
        abmonth: "ene,feb,mar,abr,may,jun,jul,ago,sept,oct,nov,dic",
        month: "enero,febrero,marzo,abril,mayo,junio,julio,agosto,septiembre,octubre,noviembre,diciembre",
        abday: "dom,lun,mar,mié,jue,vie,sáb.",
        day: "domingo,lunes,martes,miércoles,jueves,viernes,sábado",
        trans: { yes : "sí", Yes: "Sí",no: "no", No: "No", ok : "ok", on: "on", off: "off" }},
    "fr_BE": {
        name: "fr_BE",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "\x80",
        int_curr_symbol: "EUR",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°C",   
        ampm: {0: "",1: ""},
        timePattern: { 0: "HH:MM:SS ", 1: "HH:MM" },
        datePattern: { 0: "A B d Y", "1": "dd/mm/Y" }, // dimanche 1 mars 2020 // 01/03/20  
        abmonth: "anv.,févr.,mars,avril,mai,juin,juil.,août,sept.,oct.,nov.,déc.",
        month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre",
        abday: "dim,lun,mar,mer,jeu,ven,sam",
        day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi",
        trans : { yes : "oui", Yes: "Oui", no: "no", No: "No", ok : "ok", on: "on", off: "off" }},
    "fi_FI": {
        name: "fi_FI",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "\x80",
        int_curr_symbol: "EUR",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°C",   
        ampm: {0: "ap",1: "ip"},
        timePattern: { 0: "HH:MM:SS ", 1: "HH:MM" }, // 17.00.00  // 17.00
        datePattern: { 0: "A B d Y", "1": "d/m/Y" }, // sunnuntai 1. maaliskuuta 2020 // 1.3.2020
        abmonth: "tammik,helmik,maalisk,huhtik,toukok,kesäk,heinäk,elok,syysk,lokak,marrask,jouluk",
        month: "tammikuuta,helmikuuta,maaliskuuta,huhtikuuta,toukokuuta,kesäkuuta,heinäkuuta,elokuuta,syyskuuta,lokakuuta,marraskuuta,joulukuuta",
        abday: "su,ma,ti,ke,to,pe,la",
        day: "sunnuntaina,maanantaina,tiistaina,keskiviikkona,torstaina,perjantaina,lauantaina",
        trans : { yes : "oui", Yes: "Oui", no: "no", No: "No", ok : "ok", on: "on", off: "off" }},
    "de_CH": {
        name: "de_CH",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "CHF",
        int_curr_symbol: "CHF",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°C",
        ampm: {0:"vorm",1:" nachm"},
        timePattern: { 0: "HH:MM:SS", 1: "HH:MM" },
        datePattern: { 0: "A, d. B yy", "1": "dd.mm.yy" }, // Sonntag, 1. März 2020 // 1.3.2020
        abmonth: "Jan,Feb,März,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez",
        month: "Januar,Februar,März,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember",
        abday: "So,Mo,Di,Mi,Do,Fr,Sa",
        day: "Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag",
        trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus" }},
    "fr_CH": {
        name: "fr_CH",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "CHF",
        int_curr_symbol: "CHF",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°C",
        ampm: {0:"AM",1:"PM"},
        timePattern: { 0: "HH:MM:SS", 1: "HH:MM" },
        datePattern: { 0: "A d B yy", "1": "dd/mm/y" }, // dimanche 1 mars 2020 //  01/03/202  
        abmon: "anv.,févr.,mars,avril,mai,juin,juil.,août,sept.,oct.,nov.,déc.",
        mon: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre",
        abday: "dim,lun,mar,mer,jeu,ven,sam",
        day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi",
        trans : { yes : "oui", Yes: "Oui", no: "no", No: "No", ok : "ok", on: "on", off: "off" }},
    "it_CH": {
        name: "it_CH",
        decimal_point: ",",
        thousands_sep: ".", 
        currency_symbol: "CHF",
        int_curr_symbol: "CHF",
        speed: 'kmh',
        distance: { "0": "km", "1": "kmi" },
        temperatur: '°C',
        timePattern: { 0: "HH.MM.SS ", 1: "HH.MM" }, // 17.00.00  // 17.00
        datePattern: { 0: "A B d Y", "1": "d/m/Y" }, // sunnuntai 1. maaliskuuta 2020 // 1.3.2020
        abmon: "gen,feb,mar,apr,mag,giu,lug,ago,set,ott,nov,dic",
        month: "gennaio,febbraio,marzo,aprile,maggio,giugno,luglio,agosto,settembre,ottobre,novembre,dicembre",
        abday : "dom,lun,mar,mer,gio,ven,sab",
        day: "domenica,lunedì,martedì,mercoledì,giovedì,venerdì, sabato",
        trans : { yes: "sì", Yes: "Sì", no: "no", No: "No", ok: "ok", on: "on", off: "off" }},
    "wae_CH" : {
        name: "wae_CH",
        decimal_point: ",",
        thousands_sep: ".", 
        currency_symbol: "CHF",
        int_curr_symbol: "CHF",
        speed: 'kmh',
        distance: { "0": "km", "1": "kmi" },
        temperatur: '°C',
        timePattern: { 0: "HH.MM.SS ", 1: "HH.MM" }, // 17.00.00  // 17.00
        datePattern: { 0: "A, d. B yy", "1": "yy-mm-dd" }, // Sunntag, 1. Märze 2020 //  2020-03-01
        abmon: "Jen,Hor,Mär,Abr,Mei,Brá,Hei,Öig,Her,Wím,Win,Chr",
        month: "Jenner,Hornig,Märze,Abrille,Meije,Bráčet,Heiwet,Öigšte,Herbštmánet,Wímánet,Wintermánet,Chrištmánet",
        abday: "Sun,Män,Ziš,Mit,Fró,Fri,Sam",
        day: "Sunntag,Mäntag,Zištag,Mittwuč,Fróntag,Fritag,Samštag",
        trans : { yes: "sì", Yes: "Sì", no: "no", No: "No", ok: "ok", on: "on", off: "off" }}
};
MaBecker commented 4 years ago

this seem's to be the easiest way to create locale.js

s.write('locale', `

locale = ${JSON.stringify(locales[lang])};

exports  = {
    name: locale.lang,
    currencySym: String.fromCharCode(locale.currency_symbol),
    dow:   (d,short) => {day = d.getDay();return (short) ? locale.abday.split(",")[day] : locale.day.split(",")[day];},
    month: (d,short) => { month = d.getMonth(); return (short) ? locale.abmonth.split(",")[month] : locale.month.split(",")[month];},
    number: n => n.toString().replace(locale.thousands_sep, locale.decimal_point),
    currency: n => n.toFixed(2) + locale.int_curr_symbol,
    distance: n => (n < 1000) ? Math.round(n) + locale.distance[0] : Math.round(n/1000) + locale.distance[1],
    speed: s => Math.round(s) +locale.speed,
    temp: t => Math.round(t) + locale.temperature,
    translate: s => (locale.lang.substr(2) == "en")? s: locale.trans[s]
};`);

Missing function for time and date because not sure about timePattern and datePattern

What do you think about patterns and a DateTimeFormater DTF like allObject has suggested?

gfwilliams commented 4 years ago

I'd maybe just add code to which outputs the actual JS rather than including the whole formatter...

var f = "yy-mm-dd";
f = f.replace("yy","${d.getFullYear().substr(-2)}");
// ...
s.write('locale', `
...
exports  = {
  date  : d => \`${f}\`
};`);

something like that? So all that code would then live in the HTML bit of the app and what was stored on Bangle.js would be a templated string?

MaBecker commented 4 years ago

Yes, it's all in the .htlm app file, only local and functions are saved on the device. I like that idea, so let's build a replacement list to replace all possible entries.

Ok, decided to use Unix date format otherwise replacement can destroy function names.

%Y  year four digits
%y  last two digits of year (00..99)
%m  month (01..12)
%d  day of month (e.g, 01)

%a  locale's abbreviated weekday name (e.g., Sun)
%A  locale's full weekday name (e.g., Sunday)
%b  locale's abbreviated month name (e.g., Jan)
%B  locale's full month name (e.g., January) 

%H  hour (00..23)
%M  minute (00..59)
%S  second (00..60)
%p  locale's equivalent of either AM or PM; blank if not known
%P      like %p, but lower case
MaBecker commented 4 years ago

What about calling function currency?

Should this include decimal point replacement?

console.log(require('locale').currency(4.98));
// 4.98€ or 4,98€
gfwilliams commented 4 years ago

Hmm - I guess it probably should, yes...

gfwilliams commented 4 years ago

Are you already writing the locale HTML file for BangleApps? Because if you're not and you have some code already done for making the locale JS file, if you sent it over/post it up I'd be more than happy to integrate something with BangleApps for you.

MaBecker commented 4 years ago

Great, just running all locales to check for typos and then I will post locales and code generator.

MaBecker commented 4 years ago

Thanks for creating that local HTML file.

// locale.js
/* jshint esversion: 6 */

s = require('Storage');

/*
    %Y  year four digits
    %y  last two digits of year (00..99)
    %m  month (01..12)
    %d  day of month (e.g, 01)

    %a  locale's abbreviated weekday name (e.g., Sun)
    %A  locale's full weekday name (e.g., Sunday)
    %b  locale's abbreviated month name (e.g., Jan)
    %B  locale's full month name (e.g., January) 

    %H  hour (00..23)
    %M  minute (00..59)
    %S  second (00..60)
    %p  locale's equivalent of either AM or PM; blank if not known
    %P  like %p, but lower case
*/

var locales = {
    "de_DE": {
        lang: "de_DE",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "\x80",
        int_curr_symbol: "EUR",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°C",
        ampm: {0:"",1:""},
        timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
        datePattern: { 0: "%A, %d. %B %Y", "1": "%d.%m.%Y" }, // Sonntag, 1. März 2020 // 01.01.20
        abmonth: "Jan,Feb,Mär,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez",
        month: "Januar,Februar,März,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember",
        abday: "So,Mo,Di,Mi,Do,Fr,Sa",
        day: "Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag",
        trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus" }},
    "en_GB": { // this is default
        lang: "en_GB",
        decimal_point: ".",
        thousands_sep: ",",
        currency_symbol: "£",
        int_curr_symbol: "GBP",
        speed: 'mph',
        distance: { "0": "mi", "1": "kmi" },
        temperatur: '°C',
        ampm: {0:"am",1:"pm"},
        timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
        datePattern: { 0: "%b %d %Y", 1: "%d/%m/%Y" }, // Feb 28 2020" // "01/03/2020"(short)
        abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
        month: "January,February,March,April,May,June,July,August,September,October,November,December",
        abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
        day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
        trans: { yes: "yes", Yes: "Yes", no: "no", No: "No", ok: "ok", on: "on", off: "off" }},
    "en_US": {
        lang: "en_US",
        decimal_point: ".",
        thousands_sep: ",",
        currency_symbol: "$",
        int_curr_symbol: "USD",
        speed: "mph",
        distance: { 0: "mi", 1: "kmi" },
        temperature: "°F",
        ampm: {0:"am",1:"pm"},
        timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
        datePattern: { 0: "", 1: "%m/%d/%y" },
        abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
        month: "January,February,March,April,May,June,July,August,September,October,November,December",
        abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
        day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
        trans: { yes: "yes", Yes: "Yes", no: "no", No: "No", ok: "ok", on: "on", off: "off" }},
    "en_JP": { // we do not have the font, so it is not ja_JP 
        lang: "en_JP",
        decimal_point: ".",
        thousands_sep: ",",
        currency_symbol: "¥",
        int_curr_symbol: "JPY",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°F",
        ampm: {0:"",1:""},
        timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
        datePattern: { 0: "%y/%M/%d", 1: "%y/%m;/%d" },
        abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
        month: "January,February,March,April,May,June,July,August,September,October,November,December",
        abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
        day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
        trans: { yes: "yes", Yes: "Yes", no: "no", No: "No", ok: "ok", on: "on", off: "off" }},
    "nl_NL": {
        lang: "nl_NL",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "\x80",
        int_curr_symbol: "EUR",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°C",
        ampm: {0:"",1:""},
        timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
        datePattern: { 0: "%A %B %d %Y", 1: "%d.%m.%y" }, // zondag 1 maart 2020  // 01.01.20
        abday: "zo,ma,di,wo,do,vr,za",
        day: "zondag,maandag,dinsdag,woensdag,donderdag,vrijdag,zaterdag",
        abmonth: "jan,feb,mrt,apr,mei,jun,jul,aug,sep,okt,nov,dec",
        month: "januari,februari,maart,april,mei,juni,juli,augustus,september,oktober,november,december",
        trans: { yes: "yes", Yes: "Yes", no: "no", No: "No", ok: "ok", on: "on", off: "off" }},
    "en_CA": {
        lang: "en_CA",
        decimal_point: ".",
        thousands_sep: ",",
        currency_symbol: "$",
        int_curr_symbol: "CAD",
        speed: "mph",
        distance: { 0: "mi", 1: "kmi" },
        temperature: "°F",
        ampm: {0:"am",1:"pm"},
        timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
        datePattern: { 0: "%A, %B %d, %Y", "1": "%Y-%m-%d" }, //  Sunday, March 1, 2020  // 2012-12-20
        abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
        month: "January,February,March,April,May,June,July,August,September,October,November,December",
        abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
        day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
        trans: { yes: "yes", Yes: "Yes", no: "no", No: "No", ok: "ok", on: "on", off: "off" }},
    "fr_FR": {
        lang: "fr_FR",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "\x80",
        int_curr_symbol: "EUR",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°C",
        ampm: {0:"",1:""},
        timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
        datePattern: { 0: "%A %B %d %Y", "1": "%d/%m/%Y" }, // dimanche 1 mars 2020 //  01/03/2020   
        abmonth: "anv,févr,mars,avril,mai,juin,juil,août,sept,oct,nov,déc",
        month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre",
        abday: "dim,lun,mar,mer,jeu,ven,sam",
        day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi",
        trans : { yes : "oui", Yes: "Oui", no: "no", No: "No", ok : "ok", on: "on", off: "off" }},
    "sv_SE": {
        lang: "sv_SE",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "kr",
        int_curr_symbol: "SKR",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°C",
        ampm: {0:"fm",1:"em"},
        timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
        datePattern: { 0: "%A %B %d %Y", "1": "%Y-%m-%d" }, // söndag 1 mars 2020 //  2020-03-01  
        abmonth: "jan,feb,mars,apr,maj,juni,juli,aug,sep,okt,nov,dec",
        month: "januari,februari,mars,april,maj,juni,juli,augusti,september,oktober,november,december",
        abday: "sön,mån,tis,ons,tors,fre,lör",
        day: "söndag,måndag,tisdag,onsdag,torsdag,fredag,lördag",
        trans : { yes : "ja", Yes: "Ja", no: "nej", No: "Nej", ok : "ok", on: "on", off: "off" }},
    "en_AU": {
        lang: "en_AU",
        decimal_point: ".",
        thousands_sep: ",",
        currency_symbol: "$",
        int_curr_symbol: "AUD",
        speed: "mph",
        distance: { 0: "mi", 1: "kmi" },
        temperature: "°F",
        ampm: {0:"am",1:"pm"},
        timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
        datePattern: { 0: "%A, %B %d, %Y", "1": "%m/%d/%y" }, //  Sunday, 1 March 2020  // 1/3/20
        abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
        month: "January,February,March,April,May,June,July,August,September,October,November,December",
        abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
        day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
        trans: { yes: "yes", Yes: "Yes", no: "no", No: "No", ok: "ok", on: "on", off: "off" }},
    "de_AT": {
        lang: "de_AT",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "\x80",
        int_curr_symbol: "EUR",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°C",
         timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
        datePattern: { 0: "%A, %d. %B %Y", "1": "%d.%m.%y" }, // Sonntag, 1. März 2020 // 01.03.20
        abmonth: "Jän,Feb,März,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez",
        month: "Jänner,Februar,März,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember",
        abday: "So,Mo,Di,Mi,Do,Fr,Sa",
        day: "Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag",
        trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus" }},
    "en_IL": {
        lang: "en_IL",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "₪",
        int_curr_symbol: "ILS",
        speed: "kmh",
        distance: { 0: "km", 1: "m" },
        temperature: "°F",
        ampm: {0:"am",1:"pm"},
        timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
        datePattern: { 0: "%A, %B %d, %Y", "1": "%d/%m/%Y" }, //  Sunday, 1 March 2020  // 01/03/2020
        abmonth: "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
        month: "January,February,March,April,May,June,July,August,September,October,November,December",
        abday: "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
        day: "Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday",
        trans: { yes: "yes", Yes: "Yes", no: "no", No: "No", ok: "ok", on: "on", off: "off" }},
    "es_ES": {
        lang: "es_ES",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "\x80",
        int_curr_symbol: "EUR",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°C",
        ampm: {0:"",1:""},
        timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
        datePattern: { 0: "%A, %d de %B de %Y", "1": "%d/%m/%y" }, //  domingo, 1 de marzo de 2020  // 01/03/20
        abmonth: "ene,feb,mar,abr,may,jun,jul,ago,sept,oct,nov,dic",
        month: "enero,febrero,marzo,abril,mayo,junio,julio,agosto,septiembre,octubre,noviembre,diciembre",
        abday: "dom,lun,mar,mié,jue,vie,sáb.",
        day: "domingo,lunes,martes,miércoles,jueves,viernes,sábado",
        trans: { yes : "sí", Yes: "Sí",no: "no", No: "No", ok : "ok", on: "on", off: "off" }},
    "fr_BE": {
        lang: "fr_BE",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "\x80",
        int_curr_symbol: "EUR",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°C",   
        ampm: {0: "",1: ""},
        timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" },
        datePattern: { 0: "%A %B %d %Y", "1": "%d/%m/%y" }, // dimanche 1 mars 2020 // 01/03/20  
        abmonth: "anv.,févr.,mars,avril,mai,juin,juil.,août,sept.,oct.,nov.,déc.",
        month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre",
        abday: "dim,lun,mar,mer,jeu,ven,sam",
        day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi",
        trans : { yes : "oui", Yes: "Oui", no: "no", No: "No", ok : "ok", on: "on", off: "off" }},
    "fi_FI": {
        lang: "fi_FI",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "\x80",
        int_curr_symbol: "EUR",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°C",   
        ampm: {0: "ap",1: "ip"},
        timePattern: { 0: "%HH:%MM:%SS ", 1: "%HH:%MM" }, // 17.00.00  // 17.00
        datePattern: { 0: "%A %d. %B %Y", "1": "%-d/%-m/%Y" }, // sunnuntai 1. maaliskuuta 2020 // 1.3.2020
        abmonth: "tammik,helmik,maalisk,huhtik,toukok,kesäk,heinäk,elok,syysk,lokak,marrask,jouluk",
        month: "tammikuuta,helmikuuta,maaliskuuta,huhtikuuta,toukokuuta,kesäkuuta,heinäkuuta,elokuuta,syyskuuta,lokakuuta,marraskuuta,joulukuuta",
        abday: "su,ma,ti,ke,to,pe,la",
        day: "sunnuntaina,maanantaina,tiistaina,keskiviikkona,torstaina,perjantaina,lauantaina",
        trans : { yes : "oui", Yes: "Oui", no: "no", No: "No", ok : "ok", on: "on", off: "off" }},
    "de_CH": {
        lang: "de_CH",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "CHF",
        int_curr_symbol: "CHF",
        speed: "kmh",
        distance: { 0: "m", 1: "km" },
        temperature: "°C",
        ampm: {0:"vorm",1:" nachm"},
        timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
        datePattern: { 0: "%A, %d. %B %Y", "1": "%d.%m.%Y" }, // Sonntag, 1. März 2020 // 1.3.2020
        abmonth: "Jan,Feb,März,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez",
        month: "Januar,Februar,März,April,Mai,Juni,Juli,August,September,Oktober,November,Dezember",
        abday: "So,Mo,Di,Mi,Do,Fr,Sa",
        day: "Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag",
        trans: { yes: "ja", Yes: "Ja", no: "nein", No: "Nein", ok: "ok", on: "an", off: "aus" }},
    "fr_CH": {
        lang: "fr_CH",
        decimal_point: ",",
        thousands_sep: ".",
        currency_symbol: "CHF",
        int_curr_symbol: "CHF",
        speed: "kmh",
        distance: { 0: "km", 1: "m" },
        temperature: "°C",
        ampm: {0:"AM",1:"PM"},
        timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" },
        datePattern: { 0: "%A %d %B %Y", "1": "%d/%m/%y" }, // dimanche 1 mars 2020 //  01/03/20
        abmonth: "anv.,févr.,mars,avril,mai,juin,juil.,août,sept.,oct.,nov.,déc.",
        month: "janvier,février,mars,avril,mai,juin,juillet,août,septembre,octobre,novembre,décembre",
        abday: "dim,lun,mar,mer,jeu,ven,sam",
        day: "dimanche,lundi,mardi,mercredi,jeudi,vendredi,samedi",
        trans : { yes : "oui", Yes: "Oui", no: "no", No: "No", ok : "ok", on: "on", off: "off" }},
    "it_CH": {
        lang: "it_CH",
        decimal_point: ",",
        thousands_sep: ".", 
        currency_symbol: "CHF",
        int_curr_symbol: "CHF",
        speed: 'kmh',
        distance: { "0": "km", "1": "m" },
        temperatur: '°C',
        timePattern: { 0: "%HH.%MM.%SS ", 1: "%HH.%MM" }, // 17.00.00  // 17.00
        datePattern: { 0: "%A %B %d %Y", "1": "%d/%m/%Y" }, // sunnuntai 1. maaliskuuta 2020 // 1.3.2020
        abmonth: "gen,feb,mar,apr,mag,giu,lug,ago,set,ott,nov,dic",
        month: "gennaio,febbraio,marzo,aprile,maggio,giugno,luglio,agosto,settembre,ottobre,novembre,dicembre",
        abday : "dom,lun,mar,mer,gio,ven,sab",
        day: "domenica,lunedì,martedì,mercoledì,giovedì,venerdì, sabato",
        trans : { yes: "sì", Yes: "Sì", no: "no", No: "No", ok: "ok", on: "on", off: "off" }},
    "wae_CH" : {
        lang: "wae_CH",
        decimal_point: ",",
        thousands_sep: ".", 
        currency_symbol: "CHF",
        int_curr_symbol: "CHF",
        speed: 'kmh',
        distance: { "0": "km", "1": "m" },
        temperatur: '°C',
        timePattern: { 0: "%HH.%MM.%SS ", 1: "%HH.%MM" }, // 17.00.00  // 17.00
        datePattern: { 0: "%A, %d. %B %Y", "1": "%Y-%m-%d" }, // Sunntag, 1. Märze 2020 //  2020-03-01
        abmonth: "Jen,Hor,Mär,Abr,Mei,Brá,Hei,Öig,Her,Wím,Win,Chr",
        month: "Jenner,Hornig,Märze,Abrille,Meije,Bráčet,Heiwet,Öigšte,Herbštmánet,Wímánet,Wintermánet,Chrištmánet",
        abday: "Sun,Män,Ziš,Mit,Fró,Fri,Sam",
        day: "Sunntag,Mäntag,Zištag,Mittwuč,Fróntag,Fritag,Samštag",
        trans : { yes: "sì", Yes: "Sì", no: "no", No: "No", ok: "ok", on: "on", off: "off" }}
};

var lang = "de_DE";//"en_US";//""en_JP"; //nl_NL";//"en_CA";//"fr_FR";//sv_SE"; //"en_AU";// de_AT"; //"en_IL";//"es_ES";//"fr_BE";//"fi_FI";//"de_CH";//"fr_CH";//"it_CH"; // "wae_CH";
locale = locales[lang];

var replaceList  = {
  "%Y":  "${d.getFullYear()}", 
  "%y":  "${(d.getFullYear().toString()).substr(-2)}",
  "%m":  "${('0'+(d.getMonth()+1).toString()).substr(-2)}",
  "%-m": "${d.getMonth()+1}",
  "%d":  "${('0'+d.getDate()).substr(-2)}",
  "%-d": "${d.getDate()}",
  "%HH": "${('0'+d.getHours()).substr(-2)}",
  "%MM": "${('0'+d.getMinutes()).substr(-2)}",
  "%SS": "${('0'+d.getSeconds()).substr(-2)}",
  "%A":  "${locale.day.split(',')[d.getDay()]}",
  "%a":  "${locale.abday.split(',')[d.getDay()]}",
  "%B":  "${locale.month.split(',')[d.getMonth()]}",
  "%b":  "${locale.abmonth.split(',')[d.getMonth()]}",
  "%p":  "${(d.getHours()<12)?locale.ampm[0].toUpperCase():locale.ampm[1].toUpperCase()}",
  "%P":  "${(d.getHours()<12)?locale.ampm[0].toLowerCase():locale.ampm[1].toLowerCase()}"
};

var timeN = locales[lang].timePattern[0];
var timeS = locales[lang].timePattern[1];
var dateN = locales[lang].datePattern[0];
var dateS = locales[lang].datePattern[1];
Object.keys(replaceList).forEach(e => {
  timeN = timeN.replace(e,replaceList[e]);
  timeS = timeS.replace(e,replaceList[e]);
  dateN = dateN.replace(e,replaceList[e]);
  dateS = dateS.replace(e,replaceList[e]);
});

s.write('locale', `

locale = ${JSON.stringify(locales[lang])};

exports  = {
    lang: locale.lang,
    currencySym: String.fromCharCode(locale.currency_symbol),
    dow:   (d,short) => {day = d.getDay();return (short) ? locale.abday.split(",")[day] : locale.day.split(",")[day];},
    month: (d,short) => { month = d.getMonth(); return (short) ? locale.abmonth.split(",")[month] : locale.month.split(",")[month];},
    number: n => n.toString().replace(locale.thousands_sep, locale.decimal_point),
    currency: n => n.toFixed(2).replace(locale.thousands_sep, locale.decimal_point) + locale.currency_symbol,
    distance: n => (n < 1000) ? Math.round(n) + locale.distance[0] : Math.round(n/1000) + locale.distance[1],
    speed: s => Math.round(s) +locale.speed,
    temp: t => Math.round(t) + locale.temperature,
    translate: s => (locale.lang.substr(2) == "en")? s: locale.trans[s],
    date: (d,short) =>  (short) ? \`${dateS}\`: \`${dateN}\`,
    time: (d,short) =>  (short) ? \`${timeS}\`: \`${timeN}\`,
};`);

console.log(require('locale').lang);

console.log(require('locale').currencySym);

console.log(require('locale').dow(new Date()));
console.log(require('locale').dow(new Date(), 1));
console.log(require('locale').month(new Date()));
console.log(require('locale').month(new Date(), 1));

console.log(require('locale').number(4.98));
console.log(require('locale').currency(4.98));
console.log(require('locale').distance(150));
console.log(require('locale').distance(15000));
console.log(require('locale').speed(150));
console.log(require('locale').temp(150));

console.log(require('locale').translate("off"));

console.log(require('locale').date(new Date()));
console.log(require('locale').date(new Date(),1));
console.log(require('locale').time(new Date()));
console.log(require('locale').time(new Date(),1));
MaBecker commented 4 years ago

This is a unique feature and Espruino is the first!

gfwilliams commented 4 years ago

Just pushed! It's not live on banglejs.com/apps yet, but you should be able to try it with:

https://espruino.github.io/BangleApps/

Just gave it a quick try and it seems to work pretty well, so I guess now we just need to modify the apps to use it :/

gfwilliams commented 4 years ago

Thanks for all your work on this - it looks awesome!

Just a note on this: we should tweak require('locale').translate such that if there is no translation it just returns the original String, so it can just be blanket applied to all text strings without having to have any other checks involved.

Not had a chance to test yet but:

translate: s => (locale.lang.substr(2) == "en")? s: (locale.trans[s]||s),

would probably do it. In fact come to think of it, translate: s => locale.trans[s.toLowerCase()]||s, is probably fine. Americans may still want colour -> color and stuff like that.

MaBecker commented 4 years ago

Just pushed! It's not live on banglejs.com/apps yet, but you should be able to try it with:

Thanks, so let's do some further testing including a clock.

Some questions came up on my site:

gfwilliams commented 4 years ago

Have you thought about app dependencies, like if a app uses locale

This one in particular is easy - I've now built en_GB locale into the Bangle.js firmware - so if there is no locale installed everything will still work great.

But something more general as you suggest would be really cool, and I guess now Storage filenames are bigger we could actually load required modules in the same way. Maybe that's something for a new issue...

What about the font 6x8 font

Hmm. I extended both fonts to use char code 128 for euro, but there's nothing in there for vector. It doesn't help with accented chars like or miércoles or even °C either. Either we:

gfwilliams commented 4 years ago

New Bangle.js firmwares now auto-translate menu/prompt/etc

MaBecker commented 4 years ago

This one in particular is easy - I've now built en_GB locale into the Bangle.js firmware - so if there is no locale installed everything will still work great.

That's perfect.

Hmm. I extended both fonts to use char code 128 for euro, but there's nothing in there for vector. It doesn't help with accented chars like Sí or miércoles or even °C either. Either we:

I think a 6x8 ISO10646-1 loading from flash will do, if possible as overload to the existing one. Do you have one in mind?

gfwilliams commented 4 years ago

The thing is because we're using it for menus as well, we'd basically have to use the font for everything, and somehow override the built-in font for the menus and stuff like that.

Assuming we could find a 6x8 font in ISO10646-1, I think I should just build it in and replace the original (it'd use another 850 bytes maybe).

MaBecker commented 4 years ago

If this space is available we should go for it.

From my side we can close this issue and continue with that font in a new issue

MaBecker commented 4 years ago

Assuming we could find a 6x8 font in ISO10646-1, I think I should just build it in and replace the original (it'd use another 850 bytes maybe).

This one looks nice: http://uzebox.org/wiki/images/f/f4/6x8font.gif

Bildschirmfoto 2020-03-05 um 16 44 55

gfwilliams commented 4 years ago

I'm on it. Damn, that one does look good - not sure if it's the same character set though? No euro at char position 128...

gfwilliams commented 4 years ago

Well that took a while... I think the result is pretty cool though: https://github.com/espruino/Espruino/commit/9c17b44f6a7b18639d536a7bf60807c1bdf3e0c9

I'm not 100% sure it's the right charset, but it definitely has euro and we can tweak it now. I also think I prefer the look.

MaBecker commented 4 years ago

23 of 57 locales are available, updated 2020-04-08

+ tr_TR + hu_HU + pt_BR + cz_CS + it_IT

MaBecker commented 4 years ago

Wow, app Languages now got flags.

Bildschirmfoto 2020-04-03 um 22 57 07