diff --git a/include/text_utils.h b/include/text_utils.h new file mode 100644 index 0000000..3a1c768 --- /dev/null +++ b/include/text_utils.h @@ -0,0 +1,35 @@ +#pragma once +#include + +// The M5Stack default font does not correctly render UTF-8 encoded German +// umlauts (ä, ö, ü, ß), they show up as garbled characters or boxes. +// This helper replaces them with their common ASCII transliteration +// (ö -> oe, ä -> ae, ü -> ue, ß -> ss) before printing to the display. +// This is the simplest, most robust fix without needing a custom font. +inline String sanitizeGermanText(const String &input) { + String out; + out.reserve(input.length()); + + for (size_t i = 0; i < input.length(); i++) { + unsigned char c1 = input[i]; + + // UTF-8 two-byte sequences for German umlauts start with 0xC3 + if (c1 == 0xC3 && i + 1 < input.length()) { + unsigned char c2 = input[i + 1]; + switch (c2) { + case 0xA4: out += "ae"; i++; continue; // ä + case 0xB6: out += "oe"; i++; continue; // ö + case 0xBC: out += "ue"; i++; continue; // ü + case 0x84: out += "Ae"; i++; continue; // Ä + case 0x96: out += "Oe"; i++; continue; // Ö + case 0x9C: out += "Ue"; i++; continue; // Ü + case 0x9F: out += "ss"; i++; continue; // ß + default: break; + } + } + + out += (char)c1; + } + + return out; +} diff --git a/src/screens/calendar_detail_screen.cpp b/src/screens/calendar_detail_screen.cpp index 990defd..23b0ac1 100644 --- a/src/screens/calendar_detail_screen.cpp +++ b/src/screens/calendar_detail_screen.cpp @@ -1,4 +1,5 @@ #include "calendar_detail_screen.h" +#include "../../include/text_utils.h" #include #include "../../include/theme.h" #include "../icons/icons.h" @@ -50,7 +51,7 @@ void renderCalendarDetailScreen(bool forceRefresh) { M5.Lcd.setTextColor(Theme::TEXT, Theme::BG); M5.Lcd.setTextSize(1); M5.Lcd.setCursor(10, y); - M5.Lcd.print(ev.summary.substring(0, 28)); + M5.Lcd.print(sanitizeGermanText(ev.summary.substring(0, 28))); M5.Lcd.setTextColor(Theme::TEXT_DIM, Theme::BG); M5.Lcd.setCursor(230, y); diff --git a/src/screens/home_screen.cpp b/src/screens/home_screen.cpp index fd516c8..f5dc559 100644 --- a/src/screens/home_screen.cpp +++ b/src/screens/home_screen.cpp @@ -1,4 +1,5 @@ #include "home_screen.h" +#include "../../include/text_utils.h" #include #include "../../include/theme.h" #include "../icons/icons.h" @@ -75,7 +76,7 @@ void renderHomeScreen(bool forceRefresh) { M5.Lcd.setTextSize(2); M5.Lcd.setTextColor(Theme::TEXT_DIM, Theme::BG); M5.Lcd.setCursor(90, 65); - M5.Lcd.print(lastWeather.current.description); + M5.Lcd.print(sanitizeGermanText(lastWeather.current.description)); if (willRainSoon(lastWeather, 8)) { Icons::drawRainWarning(280, 30); @@ -106,7 +107,7 @@ void renderHomeScreen(bool forceRefresh) { M5.Lcd.setTextColor(Theme::TEXT, Theme::BG); M5.Lcd.setTextSize(2); M5.Lcd.setCursor(10, y); - M5.Lcd.print(ev.summary.substring(0, 20)); + M5.Lcd.print(sanitizeGermanText(ev.summary.substring(0, 20))); M5.Lcd.setTextColor(Theme::TEXT_DIM, Theme::BG); M5.Lcd.setTextSize(1); diff --git a/src/screens/mvg_screen.cpp b/src/screens/mvg_screen.cpp index 7e12335..1e90008 100644 --- a/src/screens/mvg_screen.cpp +++ b/src/screens/mvg_screen.cpp @@ -1,4 +1,5 @@ #include "mvg_screen.h" +#include "../../include/text_utils.h" #include #include "../../include/theme.h" #include "../icons/icons.h" @@ -59,7 +60,7 @@ void renderMvgScreen(bool forceRefresh) { M5.Lcd.print(dep.line); M5.Lcd.setCursor(60, y + 3); - M5.Lcd.print(dep.destination.substring(0, 16)); + M5.Lcd.print(sanitizeGermanText(dep.destination.substring(0, 16))); M5.Lcd.setCursor(190, y + 3); if (dep.cancelled) { diff --git a/src/screens/weather_detail_screen.cpp b/src/screens/weather_detail_screen.cpp index e53213e..922fd15 100644 --- a/src/screens/weather_detail_screen.cpp +++ b/src/screens/weather_detail_screen.cpp @@ -1,4 +1,5 @@ #include "weather_detail_screen.h" +#include "../../include/text_utils.h" #include #include "../../include/theme.h" #include "../icons/icons.h" @@ -48,7 +49,7 @@ void renderWeatherDetailScreen(bool forceRefresh) { M5.Lcd.printf("%d C", fe.temperature); M5.Lcd.setCursor(140, y); - M5.Lcd.print(fe.description.substring(0, 12)); + M5.Lcd.print(sanitizeGermanText(fe.description.substring(0, 12))); if (fe.precipitationType == "rain" && fe.precipitationProbability > 0.0f) { M5.Lcd.setTextColor(Theme::ACCENT_RAIN, Theme::BG);