Speak the editor in each person's Home Assistant language: every text in the editor section of en.json, the mockup in the screens' language, and one Language & region card for all screens
- vue-i18n 11 with the Composition API: English comes with the page, any other language loads the first time it is needed from screen_manager/translations, and a text a language lacks shows in English. The build keeps only _meta and editor of each file (vite.config.ts), never the screens' or the add-on's texts. - The editor follows the language of the user's Home Assistant profile (<html lang> of Home Assistant's page), else the browser's; plural forms follow the file's _meta.plural, with the screens' rules. - Every request tells the add-on the editor's language (X-ESP-Screens-Language), so its own words can follow it. - The mockup draws the screens' words (Unavailable, Page 2 ›, the date, "5 min ago") in the screens' language, with their clock and number format. - Settings → Language & region: the screen language, time format and number format for every screen, with the user's own profile offered when it differs. The per-screen clock choice goes; the top bar points there. A screen that still needs the new language says so in its update badge. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -67,7 +67,8 @@ describe("TileCard", () => {
|
||||
it("draws the large value, the wide card's toggle and an unavailable entity in grey", () => {
|
||||
state.liveStates["sensor.t"] = { state: "1249", word: null, a: { unit_of_measurement: "W" } };
|
||||
const big = placed({ entity: "sensor.t", name: "Power", slot: 0, options: { display: "watch" } });
|
||||
expect(big.find(".big").text()).toBe("1249W");
|
||||
// Numbers as the screens write them (app 0.2.90): "1,234.5" until the add-on names another format.
|
||||
expect(big.find(".big").text()).toBe("1,249W");
|
||||
state.liveStates["light.a"] = { state: "off", word: "Off", a: {} };
|
||||
const wide = placed({ entity: "light.a", name: "", slot: 2, options: { size: "wide" } });
|
||||
expect(wide.classes()).toContain("wide");
|
||||
@@ -82,12 +83,12 @@ describe("TileCard", () => {
|
||||
const plain = placed({ entity: "sensor.t", name: "Power", slot: 0 });
|
||||
expect(plain.find(".head > .ic").exists()).toBe(true);
|
||||
expect(plain.find(".head > .tx > .nm").text()).toBe("Power");
|
||||
expect(plain.find(".head > .tx > .st").text()).toBe("1249 W");
|
||||
expect(plain.find(".head > .tx > .st").text()).toBe("1,249 W");
|
||||
// A watch card keeps the name next to the icon and puts the big value underneath.
|
||||
const watch = placed({ entity: "sensor.t", name: "Power", slot: 1, options: { display: "watch" } });
|
||||
expect(watch.find(".head").classes()).toContain("top");
|
||||
expect(watch.find(".head .big").exists()).toBe(false);
|
||||
expect(watch.find(".head + .big").text()).toBe("1249W");
|
||||
expect(watch.find(".head + .big").text()).toBe("1,249W");
|
||||
state.liveStates["light.a"] = { state: "on", word: "On", a: { brightness: 255 } };
|
||||
const lamp = placed({ entity: "light.a", name: "", slot: 2, options: { inline: "slider" } });
|
||||
expect(lamp.find(".head + .mini-slider").exists()).toBe(true);
|
||||
|
||||
Reference in New Issue
Block a user