diff --git a/src/config/settings.h b/src/config/settings.h index 92ad11952..78f7fb93f 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -167,6 +167,7 @@ typedef struct { //uint16_t wakeUp; //uint16_t sleepAt; uint8_t contrast; + uint8_t language; uint8_t disp_data; uint8_t disp_clk; uint8_t disp_cs; @@ -455,8 +456,9 @@ class settings { memset(&mCfg.inst, 0, sizeof(cfgInst_t)); mCfg.plugin.display.pwrSaveAtIvOffline = false; - mCfg.plugin.display.contrast = 60; mCfg.plugin.display.screenSaver = 1; // default: 1 .. pixelshift for OLED for downward compatibility + mCfg.plugin.display.contrast = 60; + mCfg.plugin.display.language = 0; // 0 .. EN, 1 .. GE, 2 .. FR mCfg.plugin.display.rot = 0; mCfg.plugin.display.disp_data = DEF_PIN_OFF; // SDA mCfg.plugin.display.disp_clk = DEF_PIN_OFF; // SCL @@ -675,10 +677,11 @@ class settings { disp[F("type")] = mCfg.plugin.display.type; disp[F("pwrSafe")] = (bool)mCfg.plugin.display.pwrSaveAtIvOffline; disp[F("screenSaver")] = mCfg.plugin.display.screenSaver; + disp[F("contrast")] = mCfg.plugin.display.contrast; + disp[F("dispLanguage")] = mCfg.plugin.display.language; disp[F("rotation")] = mCfg.plugin.display.rot; //disp[F("wake")] = mCfg.plugin.display.wakeUp; //disp[F("sleep")] = mCfg.plugin.display.sleepAt; - disp[F("contrast")] = mCfg.plugin.display.contrast; disp[F("data")] = mCfg.plugin.display.disp_data; disp[F("clock")] = mCfg.plugin.display.disp_clk; disp[F("cs")] = mCfg.plugin.display.disp_cs; @@ -691,10 +694,11 @@ class settings { getVal(disp, F("type"), &mCfg.plugin.display.type); getVal(disp, F("pwrSafe"), &mCfg.plugin.display.pwrSaveAtIvOffline); getVal(disp, F("screenSaver"), &mCfg.plugin.display.screenSaver); + getVal(disp, F("contrast"), &mCfg.plugin.display.contrast); + getVal(disp, F("dispLanguage"), &mCfg.plugin.display.language); getVal(disp, F("rotation"), &mCfg.plugin.display.rot); //mCfg.plugin.display.wakeUp = disp[F("wake")]; //mCfg.plugin.display.sleepAt = disp[F("sleep")]; - getVal(disp, F("contrast"), &mCfg.plugin.display.contrast); getVal(disp, F("data"), &mCfg.plugin.display.disp_data); getVal(disp, F("clock"), &mCfg.plugin.display.disp_clk); getVal(disp, F("cs"), &mCfg.plugin.display.disp_cs); diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 0cfbd7105..1b543e8d8 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -54,7 +54,7 @@ class Display { default: mMono = NULL; break; } if(mMono) { - mMono->config(mCfg->pwrSaveAtIvOffline, mCfg->screenSaver, mCfg->contrast); + mMono->config(mCfg->pwrSaveAtIvOffline, mCfg->screenSaver, mCfg->contrast, mCfg->language); mMono->init(mCfg->type, mCfg->rot, mCfg->disp_cs, mCfg->disp_dc, 0xff, mCfg->disp_clk, mCfg->disp_data, &mDisplayData); } diff --git a/src/plugins/Display/Display_Mono.h b/src/plugins/Display/Display_Mono.h index 3fc691c21..7139e9e3a 100644 --- a/src/plugins/Display/Display_Mono.h +++ b/src/plugins/Display/Display_Mono.h @@ -25,7 +25,7 @@ class DisplayMono { DisplayMono() {}; virtual void init(uint8_t type, uint8_t rot, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, DisplayData *displayData) = 0; - virtual void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum) = 0; + virtual void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t lang) = 0; virtual void disp(void) = 0; // Common loop function, manages display on/off functions for powersave and screensaver with motionsensor @@ -72,6 +72,7 @@ class DisplayMono { bool mEnPowerSave; uint8_t mScreenSaver = 1; // 0 .. off; 1 .. pixelShift; 2 .. motionsensor uint8_t mLuminance; + uint8_t mLanguage; uint8_t mLoopCnt; uint8_t mLineXOffsets[5] = {}; diff --git a/src/plugins/Display/Display_Mono_128X32.h b/src/plugins/Display/Display_Mono_128X32.h index fa0cacdf9..3ff205d6c 100644 --- a/src/plugins/Display/Display_Mono_128X32.h +++ b/src/plugins/Display/Display_Mono_128X32.h @@ -12,10 +12,11 @@ class DisplayMono128X32 : public DisplayMono { mExtra = 0; } - void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum) { + void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t lang) { mEnPowerSave = enPowerSave; mScreenSaver = screenSaver; mLuminance = lum; + mLanguage = lang; } void init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, DisplayData *displayData) { diff --git a/src/plugins/Display/Display_Mono_128X64.h b/src/plugins/Display/Display_Mono_128X64.h index 7b7b7920b..20ce29d37 100644 --- a/src/plugins/Display/Display_Mono_128X64.h +++ b/src/plugins/Display/Display_Mono_128X64.h @@ -12,10 +12,11 @@ class DisplayMono128X64 : public DisplayMono { mExtra = 0; } - void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum) { + void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t lang) { mEnPowerSave = enPowerSave; mScreenSaver = screenSaver; mLuminance = lum; + mLanguage = lang; } void init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, DisplayData *displayData) { @@ -70,12 +71,12 @@ class DisplayMono128X64 : public DisplayMono { printText(mFmtText, l_TotalPower, 0xff); } else { - printText("offline", l_TotalPower, 0xff); + printText("---", l_TotalPower, 0xff); } // print Date and time if (0 != mDisplayData->utcTs) - printText(ah::getDateTimeStrShort(gTimezone.toLocal(mDisplayData->utcTs)).c_str(), l_Time, 0xff); + printText(ah::getDateTimeStrShort_i18n(gTimezone.toLocal(mDisplayData->utcTs), (ah::lang) mLanguage).c_str(), l_Time, 0xff); // dynamic status bar, alternatively: // print ip address diff --git a/src/plugins/Display/Display_Mono_64X48.h b/src/plugins/Display/Display_Mono_64X48.h index 68cac96f7..a4af4335e 100644 --- a/src/plugins/Display/Display_Mono_64X48.h +++ b/src/plugins/Display/Display_Mono_64X48.h @@ -12,10 +12,11 @@ class DisplayMono64X48 : public DisplayMono { mExtra = 0; } - void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum) { + void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t lang) { mEnPowerSave = enPowerSave; mScreenSaver = screenSaver; mLuminance = lum; + mLanguage = lang; } void init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, DisplayData *displayData) { diff --git a/src/plugins/Display/Display_Mono_84X48.h b/src/plugins/Display/Display_Mono_84X48.h index df27a414f..a5506d1f8 100644 --- a/src/plugins/Display/Display_Mono_84X48.h +++ b/src/plugins/Display/Display_Mono_84X48.h @@ -13,10 +13,11 @@ class DisplayMono84X48 : public DisplayMono { mExtra = 0; } - void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum) { + void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t lang) { mEnPowerSave = enPowerSave; mScreenSaver = screenSaver; mLuminance = lum; + mLanguage = lang; } void init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, DisplayData *displayData) { @@ -54,12 +55,12 @@ class DisplayMono84X48 : public DisplayMono { printText(mFmtText, l_TotalPower, 0xff); } else { - printText("offline", l_TotalPower, 0xff); + printText("---", l_TotalPower, 0xff); } // print Date and time if (0 != mDisplayData->utcTs) - printText(ah::getDateTimeStrShort(gTimezone.toLocal(mDisplayData->utcTs)).c_str(), l_Time, 0xff); + printText(ah::getDateTimeStrShort_i18n(gTimezone.toLocal(mDisplayData->utcTs), (ah::lang) mLanguage).c_str(), l_Time, 0xff); // alternatively: // print ip address diff --git a/src/utils/helper.cpp b/src/utils/helper.cpp index e606ad8bf..ba1922fbf 100644 --- a/src/utils/helper.cpp +++ b/src/utils/helper.cpp @@ -61,6 +61,64 @@ namespace ah { return String(str); } + #define dt_SHORT_STR_LEN_i18n 3 // the length of short strings + static char buffer[dt_SHORT_STR_LEN_i18n + 1]; // must be big enough for longest string and the terminating null + const char monthShortNames_ge_P[] PROGMEM = "ErrJanFebMrzAprMaiJunJulAugSepOktNovDez"; + const char dayShortNames_ge_P[] PROGMEM = "ErrSonMonDi.Mi.Do.Fr.Sam"; + const char monthShortNames_fr_P[] PROGMEM = "ErrJanFevMarAvrMaiJunJulAouSepOctNovDec"; + const char dayShortNames_fr_P[] PROGMEM = "ErrDimLunMarMerJeuVenSam"; + + char* monthShortStr_i18n(uint8_t month, enum lang language) + { + const char *monthShortNames_P; + + switch (language) { + case LANG_EN: + return(monthShortStr(month)); + case LANG_GE: + monthShortNames_P =monthShortNames_ge_P; + break; + case LANG_FR: + monthShortNames_P =monthShortNames_fr_P; + break; + } + for (int i=0; i < dt_SHORT_STR_LEN_i18n; i++) + buffer[i] = pgm_read_byte(&(monthShortNames_P[i + month * dt_SHORT_STR_LEN_i18n])); + buffer[dt_SHORT_STR_LEN_i18n] = 0; + return buffer; + } + + char* dayShortStr_i18n(uint8_t day, enum lang language) + { + const char *dayShortNames_P; + + switch (language) { + case LANG_EN: + return(dayShortStr(day)); + case LANG_GE: + dayShortNames_P = dayShortNames_ge_P; + break; + case LANG_FR: + dayShortNames_P = dayShortNames_fr_P; + break; + } + for (int i=0; i < dt_SHORT_STR_LEN_i18n; i++) + buffer[i] = pgm_read_byte(&(dayShortNames_P[i + day * dt_SHORT_STR_LEN_i18n])); + buffer[dt_SHORT_STR_LEN_i18n] = 0; + return buffer; + } + + String getDateTimeStrShort_i18n(time_t t, enum lang language) { + char str[20]; + if(0 == t) + sprintf(str, "n/a"); + else { + sprintf(str, "%3s ", dayShortStr_i18n(dayOfWeek(t), language)); + sprintf(str+4, "%2d.%3s %02d:%02d", day(t), monthShortStr_i18n(month(t), language), hour(t), minute(t)); + } + return String(str); + } + String getTimeStr(time_t t) { char str[9]; if(0 == t) diff --git a/src/utils/helper.h b/src/utils/helper.h index 607214144..acb53844b 100644 --- a/src/utils/helper.h +++ b/src/utils/helper.h @@ -37,11 +37,17 @@ static Timezone gTimezone(CEST, CET); } while (0) namespace ah { + enum lang { + LANG_EN=0, + LANG_GE=1, + LANG_FR=2 + }; void ip2Arr(uint8_t ip[], const char *ipStr); void ip2Char(uint8_t ip[], char *str); double round3(double value); String getDateTimeStr(time_t t); String getDateTimeStrShort(time_t t); + String getDateTimeStrShort_i18n(time_t t, enum lang); String getDateTimeStrFile(time_t t); String getTimeStr(time_t t); String getTimeStrMs(time_t t); diff --git a/src/web/RestApi.h b/src/web/RestApi.h index d431c4742..eaed96316 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -580,8 +580,9 @@ class RestApi { obj[F("disp_typ")] = (uint8_t)mConfig->plugin.display.type; obj[F("disp_pwr")] = (bool)mConfig->plugin.display.pwrSaveAtIvOffline; obj[F("disp_screensaver")] = (uint8_t)mConfig->plugin.display.screenSaver; - obj[F("disp_rot")] = (uint8_t)mConfig->plugin.display.rot; obj[F("disp_cont")] = (uint8_t)mConfig->plugin.display.contrast; + obj[F("disp_language")]= (uint8_t)mConfig->plugin.display.language; + obj[F("disp_rot")] = (uint8_t)mConfig->plugin.display.rot; obj[F("disp_clk")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_clk; obj[F("disp_data")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_data; obj[F("disp_cs")] = (mConfig->plugin.display.type < 3) ? DEF_PIN_OFF : mConfig->plugin.display.disp_cs; diff --git a/src/web/html/setup.html b/src/web/html/setup.html index fecebd81c..439b6a14e 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -287,6 +287,7 @@
Luminance
+

Pinout

@@ -1008,6 +1009,16 @@ ]) ); + var opts2 = [[0, "english"], [1, "german"], [2, "french"]]; + var language_sel = sel("disp_language", opts2, obj["disp_language"]); + language_sel.id = 'disp_language'; + document.getElementById("dispLanguage").append( + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-12 col-sm-3 my-2"}, "Language"), + ml("div", {class: "col-12 col-sm-9"}, language_sel) + ]) + ); + var esp8266pirpins = [[255, "off / default"], [17, "A0"]]; document.getElementById("pirPin").append( diff --git a/src/web/web.h b/src/web/web.h index 75d06e199..f1b08bf4c 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -568,6 +568,7 @@ class Web { // display mConfig->plugin.display.pwrSaveAtIvOffline = (request->arg("disp_pwr") == "on"); mConfig->plugin.display.screenSaver = request->arg("disp_screensaver").toInt(); + mConfig->plugin.display.language = request->arg("disp_language").toInt(); mConfig->plugin.display.rot = request->arg("disp_rot").toInt(); mConfig->plugin.display.type = request->arg("disp_typ").toInt(); mConfig->plugin.display.contrast = (mConfig->plugin.display.type == 0) ? 60 : request->arg("disp_cont").toInt();