Skip to content

Commit

Permalink
Rewrite display language handling to work with locale strings instead…
Browse files Browse the repository at this point in the history
… of magic numbers.

This is required to implement further i18n functions using the language packs
  • Loading branch information
tbnobody committed Oct 25, 2024
1 parent 6113e07 commit d259042
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 39 deletions.
5 changes: 3 additions & 2 deletions include/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <cstdint>

#define CONFIG_FILENAME "/config.json"
#define CONFIG_VERSION 0x00011c00 // 0.1.28 // make sure to clean all after change
#define CONFIG_VERSION 0x00011d00 // 0.1.29 // make sure to clean all after change

#define WIFI_MAX_SSID_STRLEN 32
#define WIFI_MAX_PASSWORD_STRLEN 64
Expand All @@ -30,6 +30,7 @@
#define CHAN_MAX_NAME_STRLEN 31

#define DEV_MAX_MAPPING_NAME_STRLEN 63
#define LOCALE_STRLEN 2

struct CHANNEL_CONFIG_T {
uint16_t MaxChannelPower;
Expand Down Expand Up @@ -144,7 +145,7 @@ struct CONFIG_T {
bool ScreenSaver;
uint8_t Rotation;
uint8_t Contrast;
uint8_t Language;
char Locale[LOCALE_STRLEN + 1];
struct {
uint32_t Duration;
uint8_t Mode;
Expand Down
13 changes: 11 additions & 2 deletions include/Display_Graphic.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class DisplayGraphicClass {
void setContrast(const uint8_t contrast);
void setStatus(const bool turnOn);
void setOrientation(const uint8_t rotation = DISPLAY_ROTATION);
void setLanguage(const uint8_t language);
void setLocale(const String& locale);
void setDiagramMode(DiagramMode_t mode);
void setStartupDisplay();

Expand All @@ -65,14 +65,23 @@ class DisplayGraphicClass {

DisplayType_t _display_type = DisplayType_t::None;
DiagramMode_t _diagram_mode = DiagramMode_t::Off;
uint8_t _display_language = DISPLAY_LANGUAGE;
String _display_language = DISPLAY_LOCALE;
uint8_t _mExtra;
const uint16_t _period = 1000;
const uint16_t _interval = 60000; // interval at which to power save (milliseconds)
uint32_t _previousMillis = 0;
char _fmtText[32];
bool _isLarge = false;
uint8_t _lineOffsets[5];

String _i18n_offline;
String _i18n_yield_today_kwh;
String _i18n_yield_today_wh;
String _i18n_date_format;
String _i18n_current_power_kw;
String _i18n_current_power_w;
String _i18n_yield_total_mwh;
String _i18n_yield_total_kwh;
};

extern DisplayGraphicClass Display;
2 changes: 1 addition & 1 deletion include/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
#define DISPLAY_SCREENSAVER true
#define DISPLAY_ROTATION 2U
#define DISPLAY_CONTRAST 60U
#define DISPLAY_LANGUAGE 0U
#define DISPLAY_LOCALE "en"
#define DISPLAY_DIAGRAM_DURATION (10UL * 60UL * 60UL)
#define DISPLAY_DIAGRAM_MODE 1U

Expand Down
20 changes: 18 additions & 2 deletions src/Configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ bool ConfigurationClass::write()
display["screensaver"] = config.Display.ScreenSaver;
display["rotation"] = config.Display.Rotation;
display["contrast"] = config.Display.Contrast;
display["language"] = config.Display.Language;
display["locale"] = config.Display.Locale;
display["diagram_duration"] = config.Display.Diagram.Duration;
display["diagram_mode"] = config.Display.Diagram.Mode;

Expand Down Expand Up @@ -282,7 +282,7 @@ bool ConfigurationClass::read()
config.Display.ScreenSaver = display["screensaver"] | DISPLAY_SCREENSAVER;
config.Display.Rotation = display["rotation"] | DISPLAY_ROTATION;
config.Display.Contrast = display["contrast"] | DISPLAY_CONTRAST;
config.Display.Language = display["language"] | DISPLAY_LANGUAGE;
strlcpy(config.Display.Locale, display["locale"] | DISPLAY_LOCALE, sizeof(config.Display.Locale));
config.Display.Diagram.Duration = display["diagram_duration"] | DISPLAY_DIAGRAM_DURATION;
config.Display.Diagram.Mode = display["diagram_mode"] | DISPLAY_DIAGRAM_MODE;

Expand Down Expand Up @@ -383,6 +383,22 @@ void ConfigurationClass::migrate()
}
}

if (config.Cfg.Version < 0x00011d00) {
JsonObject device = doc["device"];
JsonObject display = device["display"];
switch (display["language"] | 0U) {
case 0U:
strlcpy(config.Display.Locale, "en", sizeof(config.Display.Locale));
break;
case 1U:
strlcpy(config.Display.Locale, "de", sizeof(config.Display.Locale));
break;
case 2U:
strlcpy(config.Display.Locale, "fr", sizeof(config.Display.Locale));
break;
}
}

f.close();

config.Cfg.Version = CONFIG_VERSION;
Expand Down
44 changes: 26 additions & 18 deletions src/Display_Graphic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,11 @@ std::map<DisplayType_t, std::function<U8G2*(uint8_t, uint8_t, uint8_t, uint8_t)>
{ DisplayType_t::ST7567_GM12864I_59N, [](uint8_t reset, uint8_t clock, uint8_t data, uint8_t cs) { return new U8G2_ST7567_ENH_DG128064I_F_HW_I2C(U8G2_R0, reset, clock, data); } },
};

// Language defintion, respect order in languages[] and translation lists
// Language defintion, respect order in translation lists
#define I18N_LOCALE_EN 0
#define I18N_LOCALE_DE 1
#define I18N_LOCALE_FR 2

// Languages supported. Note: the order is important and must match locale_translations.h
const uint8_t languages[] = {
I18N_LOCALE_EN,
I18N_LOCALE_DE,
I18N_LOCALE_FR
};

static const char* const i18n_offline[] = { "Offline", "Offline", "Offline" };

static const char* const i18n_current_power_w[] = { "%.0f W", "%.0f W", "%.0f W" };
Expand Down Expand Up @@ -166,9 +159,24 @@ void DisplayGraphicClass::setOrientation(const uint8_t rotation)
calcLineHeights();
}

void DisplayGraphicClass::setLanguage(const uint8_t language)
void DisplayGraphicClass::setLocale(const String& locale)
{
_display_language = language < sizeof(languages) / sizeof(languages[0]) ? language : DISPLAY_LANGUAGE;
_display_language = locale;
uint8_t idx = I18N_LOCALE_EN;
if (locale == "de") {
idx = I18N_LOCALE_DE;
} else if (locale == "fr") {
idx = I18N_LOCALE_FR;
}

_i18n_offline = i18n_offline[idx];
_i18n_yield_today_kwh = i18n_yield_today_kwh[idx];
_i18n_yield_today_wh = i18n_yield_today_wh[idx];
_i18n_date_format = i18n_date_format[idx];
_i18n_current_power_kw = i18n_current_power_kw[idx];
_i18n_current_power_w = i18n_current_power_w[idx];
_i18n_yield_total_mwh = i18n_yield_total_mwh[idx];
_i18n_yield_total_kwh = i18n_yield_total_kwh[idx];
}

void DisplayGraphicClass::setDiagramMode(DiagramMode_t mode)
Expand Down Expand Up @@ -225,9 +233,9 @@ void DisplayGraphicClass::loop()
if (showText) {
const float watts = Datastore.getTotalAcPowerEnabled();
if (watts > 999) {
snprintf(_fmtText, sizeof(_fmtText), i18n_current_power_kw[_display_language], watts / 1000);
snprintf(_fmtText, sizeof(_fmtText), _i18n_current_power_kw.c_str(), watts / 1000);
} else {
snprintf(_fmtText, sizeof(_fmtText), i18n_current_power_w[_display_language], watts);
snprintf(_fmtText, sizeof(_fmtText), _i18n_current_power_w.c_str(), watts);
}
printText(_fmtText, 0);
}
Expand All @@ -237,7 +245,7 @@ void DisplayGraphicClass::loop()

//=====> Offline ===========
else {
printText(i18n_offline[_display_language], 0);
printText(_i18n_offline.c_str(), 0);
// check if it's time to enter power saving mode
if (millis() - _previousMillis >= (_interval * 2)) {
displayPowerSave = enablePowerSafe;
Expand All @@ -249,16 +257,16 @@ void DisplayGraphicClass::loop()
// Daily production
float wattsToday = Datastore.getTotalAcYieldDayEnabled();
if (wattsToday >= 10000) {
snprintf(_fmtText, sizeof(_fmtText), i18n_yield_today_kwh[_display_language], wattsToday / 1000);
snprintf(_fmtText, sizeof(_fmtText), _i18n_yield_today_kwh.c_str(), wattsToday / 1000);
} else {
snprintf(_fmtText, sizeof(_fmtText), i18n_yield_today_wh[_display_language], wattsToday);
snprintf(_fmtText, sizeof(_fmtText), _i18n_yield_today_wh.c_str(), wattsToday);
}
printText(_fmtText, 1);

// Total production
const float wattsTotal = Datastore.getTotalAcYieldTotalEnabled();
auto const format = (wattsTotal >= 1000) ? i18n_yield_total_mwh : i18n_yield_total_kwh;
snprintf(_fmtText, sizeof(_fmtText), format[_display_language], wattsTotal);
auto const format = (wattsTotal >= 1000) ? _i18n_yield_total_mwh : _i18n_yield_total_kwh;
snprintf(_fmtText, sizeof(_fmtText), format.c_str(), wattsTotal);
printText(_fmtText, 2);

//=====> IP or Date-Time ========
Expand All @@ -268,7 +276,7 @@ void DisplayGraphicClass::loop()
} else {
// Get current time
time_t now = time(nullptr);
strftime(_fmtText, sizeof(_fmtText), i18n_date_format[_display_language], localtime(&now));
strftime(_fmtText, sizeof(_fmtText), _i18n_date_format.c_str(), localtime(&now));
printText(_fmtText, 3);
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/WebApi_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ void WebApiDeviceClass::onDeviceAdminGet(AsyncWebServerRequest* request)
display["power_safe"] = config.Display.PowerSafe;
display["screensaver"] = config.Display.ScreenSaver;
display["contrast"] = config.Display.Contrast;
display["language"] = config.Display.Language;
display["locale"] = config.Display.Locale;
display["diagramduration"] = config.Display.Diagram.Duration;
display["diagrammode"] = config.Display.Diagram.Mode;

Expand Down Expand Up @@ -137,7 +137,7 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
config.Display.PowerSafe = root["display"]["power_safe"].as<bool>();
config.Display.ScreenSaver = root["display"]["screensaver"].as<bool>();
config.Display.Contrast = root["display"]["contrast"].as<uint8_t>();
config.Display.Language = root["display"]["language"].as<uint8_t>();
strlcpy(config.Display.Locale, root["display"]["locale"].as<String>().c_str(), sizeof(config.Display.Locale));
config.Display.Diagram.Duration = root["display"]["diagramduration"].as<uint32_t>();
config.Display.Diagram.Mode = root["display"]["diagrammode"].as<DiagramMode_t>();

Expand All @@ -151,7 +151,7 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request)
Display.enablePowerSafe = config.Display.PowerSafe;
Display.enableScreensaver = config.Display.ScreenSaver;
Display.setContrast(config.Display.Contrast);
Display.setLanguage(config.Display.Language);
Display.setLocale(config.Display.Locale);
Display.Diagram().updatePeriod();

WebApi.writeConfig(retMsg);
Expand Down
2 changes: 1 addition & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ void setup()
Display.enablePowerSafe = config.Display.PowerSafe;
Display.enableScreensaver = config.Display.ScreenSaver;
Display.setContrast(config.Display.Contrast);
Display.setLanguage(config.Display.Language);
Display.setLocale(config.Display.Locale);
Display.setStartupDisplay();
MessageOutput.println("done");

Expand Down
2 changes: 1 addition & 1 deletion webapp/src/types/DeviceConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export interface Display {
power_safe: boolean;
screensaver: boolean;
contrast: number;
language: number;
locale: string;
diagramduration: number;
diagrammode: number;
}
Expand Down
18 changes: 9 additions & 9 deletions webapp/src/views/DeviceAdminView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -160,13 +160,13 @@
{{ $t('deviceadmin.DisplayLanguage') }}
</label>
<div class="col-sm-10">
<select class="form-select" v-model="deviceConfigList.display.language">
<select class="form-select" v-model="deviceConfigList.display.locale">
<option
v-for="language in displayLanguageList"
:key="language.key"
:value="language.key"
v-for="locale in displayLocaleList"
:key="locale.key"
:value="locale.key"
>
{{ $t(`deviceadmin.` + language.value) }}
{{ $t(`deviceadmin.` + locale.value) }}
</option>
</select>
</div>
Expand Down Expand Up @@ -289,10 +289,10 @@ export default defineComponent({
{ key: 2, value: 'rot180' },
{ key: 3, value: 'rot270' },
],
displayLanguageList: [
{ key: 0, value: 'en' },
{ key: 1, value: 'de' },
{ key: 2, value: 'fr' },
displayLocaleList: [
{ key: 'en', value: 'en' },
{ key: 'de', value: 'de' },
{ key: 'fr', value: 'fr' },
],
diagramModeList: [
{ key: 0, value: 'off' },
Expand Down

0 comments on commit d259042

Please sign in to comment.