Add Dutch, German, French, Italian, Spanish, Portuguese and Polish with their calendars and Home Assistant's own words

tools/i18n.py gets cldr (day and month names, date orders, numbers and the clock from Node's Intl), ha-words (the
words for states from Home Assistant's own translations, English included) and lint (English left in the firmware's
code). The screens write numbers from Home Assistant in the chosen format, and every text font carries the apostrophe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Max Gramser
2026-09-19 14:35:37 +02:00
parent 520826821f
commit 951dceebf9
19 changed files with 2263 additions and 334 deletions
+29 -26
View File
@@ -3,11 +3,12 @@
#pragma once
#include "components/smart_display/screen_text.h"
static_assert(screen_text::KEYS_HASH == 0x725A92EEu && screen_text::KEY_COUNT == 302,
static_assert(screen_text::KEYS_HASH == 0x8971C0EBu && screen_text::KEY_COUNT == 305,
"screen_text_keys.h does not match screen_manager/translations/en.json: run tools/i18n.py header");
const char *const screen_text::TABLE[] = {
".",
",",
"1",
"Just now",
"{n} min ago",
"1 hour ago | {n} hours ago",
@@ -108,6 +109,8 @@ const char *const screen_text::TABLE[] = {
"Firmware",
"Home Assistant",
"Restart",
"Connected",
"Not connected",
"Tap again to restart",
"{n} sec",
"{n} min",
@@ -231,8 +234,8 @@ const char *const screen_text::TABLE[] = {
"Standby",
"Home",
"Away",
"Above the horizon",
"Below the horizon",
"Above horizon",
"Below horizon",
"Docked",
"Cleaning",
"Paused",
@@ -256,8 +259,8 @@ const char *const screen_text::TABLE[] = {
"Normal",
"Charging",
"Not charging",
"Danger",
"Safe",
"Detected",
"Clear",
"Cold",
"Normal",
"Connected",
@@ -266,21 +269,21 @@ const char *const screen_text::TABLE[] = {
"Closed",
"Open",
"Closed",
"Danger",
"Safe",
"Detected",
"Clear",
"Hot",
"Normal",
"Light",
"Dark",
"Open",
"Light detected",
"No light",
"Unlocked",
"Locked",
"Wet",
"Dry",
"Motion",
"No motion",
"Detected",
"Clear",
"Moving",
"Still",
"Occupied",
"Not moving",
"Detected",
"Clear",
"Open",
"Closed",
@@ -292,20 +295,20 @@ const char *const screen_text::TABLE[] = {
"Away",
"Problem",
"OK",
"Active",
"Inactive",
"Running",
"Not running",
"Unsafe",
"Safe",
"Smoke",
"No smoke",
"Sound",
"Silent",
"Tampering",
"OK",
"Update",
"Up to date",
"Vibration",
"Still",
"Detected",
"Clear",
"Detected",
"Clear",
"Tampering detected",
"Clear",
"Update available",
"Up-to-date",
"Detected",
"Clear",
"Open",
"Closed"
};
+46
View File
@@ -0,0 +1,46 @@
#include "screen_text_en.h"
// The screen's texts (app 0.2.90): lookups, placeholders, plural forms and numbers, with the English table the tests
// build with (tests/screen_text_en.h). A screen's own build writes its language's table instead.
#include <cassert>
#include <cstdio>
#include <string>
using namespace screen_text;
int main() {
assert(std::string(LANGUAGE) == "en");
assert(std::string(tr(txt::settings_title)) == "Settings");
assert(std::string(tr(KEY_COUNT)) == "" && std::string(tr(0xFFFF)) == "");
// A list is its first key plus a count: the month names in order.
assert(txt::date_months_short_count == 12 && std::string(tr(txt::date_months_short + 8)) == "Sep");
assert(txt::date_weekdays_count == 7 && std::string(tr(txt::date_weekdays)) == "Sunday");
// Named placeholders, every occurrence; a translation is never a printf format.
assert(fill(std::string("{n} of {n}"), "n", "3") == "3 of 3");
assert(fill(txt::tile_page, "n", 2) == "Page 2");
assert(fill(std::string("100%"), "n", "1") == "100%");
// Plural forms by the language's rule (English: one for 1, other for the rest); the one form may name the number.
assert(plural(txt::time_hours_ago, 1) == "1 hour ago" && plural(txt::time_hours_ago, 2) == "2 hours ago");
assert(plural(txt::time_hours_ago, 0) == "0 hours ago" && plural(txt::history_times, 1) == "once");
assert(plural(txt::history_times, 21) == "21 times");
// A text without forms is the same for every n.
assert(plural(txt::time_minutes_ago, 5) == "5 min ago");
// Numbers: the language's marks unless Settings -> Language & region chose a format for every screen.
number_style = 0;
assert(localize("1234.5") == "1,234.5" && localize("-3") == "-3" && localize("123") == "123");
assert(localize("1234567") == "1,234,567" && localize("0.25") == "0.25");
for (const char *text : {"on", "1.2.3", "-", ".5", "5.", "12a", "", "1e5"}) assert(localize(text) == text);
assert(decimal(21.54f, 1) == "21.5");
number_style = 2; // 1.234,5
assert(localize("1234.5") == "1.234,5" && localize("-1234") == "-1.234" && decimal(21.54f, 1) == "21,5");
number_style = 3; // 1 234,5
assert(localize("12345.75") == "12 345,75");
number_style = 1; // 1,234.5
assert(localize("1234.5") == "1,234.5");
assert(number_style_of("auto") == 0 && number_style_of("point") == 1 && number_style_of("comma") == 2 &&
number_style_of("space") == 3 && number_style_of("dot") == -1);
number_style = 0;
std::puts("test_screen_text: PASS");
return 0;
}
+3 -2
View File
@@ -184,9 +184,10 @@ int main() {
rows = vacuum_rows(old_robot2, 0);
assert(rows.suction && !rows.water && !choice_action(old_robot2, 'm', "mop").valid());
// Binary sensors (firmware 0.2.53+) in the words of their device class; no class or an unknown one says On and Off.
// Binary sensors (firmware 0.2.53+) in the words of their device class, Home Assistant's own since app 0.2.90 (the
// English table of the tests); no class or an unknown one says On and Off.
assert(!strcmp(binary_state_text("door", true), "Open") && !strcmp(binary_state_text("door", false), "Closed"));
assert(!strcmp(binary_state_text("motion", true), "Motion") && !strcmp(binary_state_text("motion", false), "No motion"));
assert(!strcmp(binary_state_text("motion", true), "Detected") && !strcmp(binary_state_text("motion", false), "Clear"));
assert(!strcmp(binary_state_text("moisture", true), "Wet") && !strcmp(binary_state_text("moisture", false), "Dry"));
assert(!strcmp(binary_state_text("battery_charging", false), "Not charging") && !strcmp(binary_state_text("battery", true), "Low"));
assert(!strcmp(binary_state_text("", true), "On") && !strcmp(binary_state_text("", false), "Off"));