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

Locale App & Handling #105

Closed
gfwilliams opened this issue Feb 25, 2020 · 38 comments
Closed

Locale App & Handling #105

gfwilliams opened this issue Feb 25, 2020 · 38 comments

Comments

@gfwilliams
Copy link
Member

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
Copy link
Contributor

MaBecker commented Feb 26, 2020

How many countries Bangle.js has been ordered from?

Can you please name them?

@gfwilliams
Copy link
Member Author

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
Copy link
Contributor

MaBecker commented Feb 26, 2020

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
Copy link
Contributor

MaBecker commented Feb 26, 2020

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
Copy link
Contributor

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
Copy link
Contributor

How should this app be designed?

  • select the wanted locale out of maintained ones via html setting page
  • create a single file with the requested locale data
  • sample name "locale"
  • content: locale data and functions
  • include into other apps via var DF = require('locales')
  • used something similar than DF suggested by allObjects

@gfwilliams
Copy link
Member Author

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:

  • require('locale').name -> string - localeString
  • require('locale').translate(string) -> string could be called for any text string. I can build that into E.showMenu/etc so menus/messages magically get translated
  • require('locale').date(Date) -> string
  • require('locale').time(Date) -> string
  • require('locale').dow(0..6,short:bool) -> string - day of week
  • require('locale').month(0..11,short:bool) -> string
  • require('locale').number(number) -> string
  • require('locale').currency(number) -> string
  • require('locale').currencySym -> string
  • require('locale').distance(number) -> string
  • require('locale').speed(number) -> string
  • require('locale').geo(gps_fix) -> string - maybe? Some countries have particular coordinate systems, but this may be going a bit too far

@MaBecker
Copy link
Contributor

MaBecker commented Feb 27, 2020

looks like FontDylex7x13 can handle the selected locales.

@MaBecker
Copy link
Contributor

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

  • require('locale').temp(number) -> string

@gfwilliams
Copy link
Member Author

gfwilliams commented Feb 28, 2020

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
Copy link
Contributor

extend the 6x8 font

Hope that fits into firmware

@gfwilliams
Copy link
Member Author

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
Copy link
Member Author

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
Copy link
Contributor

MaBecker commented Feb 28, 2020

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
Copy link
Member Author

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

@MaBecker
Copy link
Contributor

MaBecker commented Mar 1, 2020

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
Copy link
Contributor

MaBecker commented Mar 1, 2020

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

  • date
    • a : abday
    • A : day
    • b : abmonth
    • B : month
    • y : year like 20 l
    • yy : year like 2020 century and
    • m : month numeric
    • mm : month numeric with leading 0
    • d : day numeric
    • dd : day numeric with leading 0
  • time
    • HH : hour
    • MM : minute
    • SS : second

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

@gfwilliams
Copy link
Member Author

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
Copy link
Contributor

MaBecker commented Mar 4, 2020

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
Copy link
Contributor

MaBecker commented Mar 4, 2020

What about calling function currency?

Should this include decimal point replacement?

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

@gfwilliams
Copy link
Member Author

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

@gfwilliams
Copy link
Member Author

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
Copy link
Contributor

MaBecker commented Mar 4, 2020

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

@MaBecker
Copy link
Contributor

MaBecker commented Mar 4, 2020

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
Copy link
Contributor

MaBecker commented Mar 4, 2020

This is a unique feature and Espruino is the first!

@gfwilliams
Copy link
Member Author

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
Copy link
Member Author

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
Copy link
Contributor

MaBecker commented Mar 4, 2020

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:

  • Have you thought about app dependencies, like if a app uses locale, only upload if locale is already available otherwise inform via popup.

  • What about the font 6x8 font, I will test with FontDylex7x13

@gfwilliams
Copy link
Member Author

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:

  • Have to come up with complete new fonts (6x8 came from http://uzebox.org/wiki/index.php?title=File:Sebasic_charset_192w.png which is very basic)
  • Create a mapping for built-in fonts - í to i/etc. Potentially we could manually add a handful of extra chars for commonly used ones?
  • Pre-map all the translations in locales.js to char codes<128 for now (apart from euro, which was easy to add)

@gfwilliams
Copy link
Member Author

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

@MaBecker
Copy link
Contributor

MaBecker commented Mar 5, 2020

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
Copy link
Member Author

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
Copy link
Contributor

MaBecker commented Mar 5, 2020

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
Copy link
Contributor

MaBecker commented Mar 5, 2020

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
Copy link
Member Author

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
Copy link
Member Author

Well that took a while... I think the result is pretty cool though: espruino/Espruino@9c17b44

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
Copy link
Contributor

MaBecker commented Apr 3, 2020

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

+ tr_TR
+ hu_HU
+ pt_BR
+ cz_CS
+ it_IT

@MaBecker
Copy link
Contributor

MaBecker commented Apr 3, 2020

Wow, app Languages now got flags.

Bildschirmfoto 2020-04-03 um 22 57 07

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants