Build each screen in one language: the screen texts from the translations, European letters in the fonts, and Language & region in the app

The firmware takes its texts from screen_manager/translations/<code>.json at build time (components/smart_display:
one table in main.cpp, keys in screen_text_keys.h), and the fonts carry every letter European languages write with.
The app keeps Settings -> Language & region (language, clock, numbers) for every screen, writes LANGUAGE into the
screens' YAML and sends the clock and the number format in the layout message; the per-screen 24-hour clock goes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Max Gramser
2026-09-19 14:24:19 +02:00
parent 9362a5f1db
commit 378d0b3e61
51 changed files with 2321 additions and 383 deletions
+313
View File
@@ -0,0 +1,313 @@
// GENERATED by tools/i18n.py (`python3 tools/i18n.py header`): the English texts for the C++ tests, which
// build a header without ESPHome and so without the table a screen's build writes into main.cpp.
#pragma once
#include "components/smart_display/screen_text.h"
static_assert(screen_text::KEYS_HASH == 0x725A92EEu && screen_text::KEY_COUNT == 302,
"screen_text_keys.h does not match screen_manager/translations/en.json: run tools/i18n.py header");
const char *const screen_text::TABLE[] = {
".",
",",
"Just now",
"{n} min ago",
"1 hour ago | {n} hours ago",
"Yesterday",
"1 day ago | {n} days ago",
"1 week ago | {n} weeks ago",
"1 month ago | {n} months ago",
"1 year ago | {n} years ago",
"In {n} min",
"In 1 hour | In {n} hours",
"Tomorrow",
"In 1 day | In {n} days",
"AM",
"PM",
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat",
"Su",
"Mo",
"Tu",
"We",
"Th",
"Fr",
"Sa",
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
"{weekday} {day} {month}",
"{weekday} {day} {month}",
"{day} {month}",
"{weekday} {time}",
"{n} s",
"{n} min",
"{n} h",
"{h} h {m} min",
"{n} d",
"{d} d {h} h",
"Connecting to Home Assistant",
"Waiting for ESP Screens",
"Loading tiles...",
"HA not connected",
"ESP Screens not active",
"Choose tiles in HA",
"Home",
"No network",
"Settings",
"Brightness",
"Night",
"Screen",
"This screen",
"Dark mode",
"Auto standby",
"Standby after",
"Standby brightness",
"Night mode",
"Starts",
"Ends",
"Night brightness",
"Back to page 1",
"After",
"Also on standby",
"Swipe between pages",
"Page buttons",
"Rotation",
"Address",
"Firmware",
"Home Assistant",
"Restart",
"Tap again to restart",
"{n} sec",
"{n} min",
"{n} h",
"{h} h {m}",
"Tap to open",
"Page {n}",
"Unavailable",
"Refused",
"Command sent...",
"Confirmed by Home Assistant",
"Notification",
"OK",
"Color",
"Color temperature",
"Brightness",
"Waiting...",
"Effect",
"Nothing to choose",
"Loading...",
"Not connected",
"Target",
"Mode",
"Fan",
"Swing",
"Now {value}",
"Check the robot in HA",
"Automatic suction power",
"The robot chooses suction and water",
"Suction and water as set per room",
"Quiet",
"Normal",
"Turbo",
"Max",
"Pause cleaning",
"Pause",
"Resume",
"Start cleaning",
"Clean",
"Dock",
"Position",
"Tilt",
"Tilt {n}%",
"Feels like {n}\302\260",
"No daily forecast from Home Assistant",
"Coming days",
"No data",
"average",
"average of {duration}",
"Now",
"1 hour",
"24 hours",
"1 week",
"High {value}",
"Low {value}",
"once | {n} times",
"Loading history...",
"No history in this period",
"No history available",
"Muted",
"Not playing",
"Loading",
"Running",
"Paused",
"Stopped",
"Pause",
"Start",
"Cancel",
"Paused {time}",
"Sun",
"Sunrise {time}",
"Sunset {time}",
"rise {time}",
"set {time}",
"Running...",
"Never run",
"Last {time}",
"Yesterday {time}",
"Last {date}",
"No image from this camera",
"Loading image",
"Live",
"Recording",
"Tap to view",
"No image yet",
"Activate",
"Run",
"Press",
"Follow the calibration wizard",
"GT911 touch check",
"Hold each tap for a moment",
"Tap the crosshair\012Point {point}/5 - tap {tap}/3",
"Tap gently, a bit longer",
"Tap the same crosshair 3 times",
"Measurement rejected; try again",
"Save failed; try again",
"On",
"Off",
"Off",
"Heat",
"Cool",
"Heat/Cool",
"Auto",
"Dry",
"Fan only",
"Heating",
"Cooling",
"Idle",
"Off",
"Drying",
"Fan",
"Preheating",
"Defrosting",
"Open",
"Closed",
"Opening",
"Closing",
"Playing",
"Paused",
"Idle",
"Standby",
"Home",
"Away",
"Above the horizon",
"Below the horizon",
"Docked",
"Cleaning",
"Paused",
"Returning to dock",
"Idle",
"Sunny",
"Clear, night",
"Cloudy",
"Partly cloudy",
"Rainy",
"Pouring",
"Snowy",
"Snowy, rainy",
"Fog",
"Hail",
"Lightning",
"Lightning, rainy",
"Windy",
"Exceptional",
"Low",
"Normal",
"Charging",
"Not charging",
"Danger",
"Safe",
"Cold",
"Normal",
"Connected",
"Disconnected",
"Open",
"Closed",
"Open",
"Closed",
"Danger",
"Safe",
"Hot",
"Normal",
"Light",
"Dark",
"Open",
"Locked",
"Wet",
"Dry",
"Motion",
"No motion",
"Moving",
"Still",
"Occupied",
"Clear",
"Open",
"Closed",
"Plugged in",
"Unplugged",
"On",
"Off",
"Home",
"Away",
"Problem",
"OK",
"Active",
"Inactive",
"Unsafe",
"Safe",
"Smoke",
"No smoke",
"Sound",
"Silent",
"Tampering",
"OK",
"Update",
"Up to date",
"Vibration",
"Still",
"Open",
"Closed"
};
const char *const screen_text::LANGUAGE = "en";
int screen_text::plural_index(int n) { return n == 1 ? 0 : 1; }