Files
Max Gramser 94b320074d Draw the mockup with the screens' own words, compile every text while building, and send the language with the live updates
- The page takes the screens' words its mockup draws from their own texts: screen.ha (Home Assistant's words, filled
  from Home Assistant), screen.time, screen.date, screen.number and screen.tile.page, per language next to _meta and
  editor. The copies under editor.mockup go; the rest of `screen` and all of `addon` stay out of the build.
- Numbers in the mockup follow the screens' language (screen.number, with its minimum grouping) or the chosen style,
  as the firmware writes them.
- @intlify/unplugin-vue-i18n compiles every text at build time, so the page runs vue-i18n's runtime-only build
  without the message compiler; every language's _meta comes with the page. Empty texts stay out while building.
- The live updates carry the editor's language (api/events?language=), as an EventSource sends no headers.
- web/ needs Node 22.13 or newer: vue-i18n 11.4, Vite 7 and the unplugin ask for it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 14:59:02 +02:00

26 lines
1.7 KiB
TypeScript

// What the page takes from the translations (app 0.2.90), for vite.config.ts and the tests. Every language is one file
// in screen_manager/translations, shared with the firmware and the add-on.
import { join } from "node:path";
export const TRANSLATIONS = join(__dirname, "..", "screen_manager", "translations");
// Of the screens' texts the page takes the ones its mockup draws: Home Assistant's words, times, dates, numbers and the
// page label. The rest of `screen` and all of `addon` stay out.
const SCREEN_PARTS = ["ha", "time", "date", "number"];
// An empty text is one the language doesn't have yet: it stays out, so English shows, as on the screens. A space is
// a text (French writes 1 234,5).
function filled(node: unknown): unknown {
if (typeof node === "string") return node === "" ? undefined : node;
if (Array.isArray(node)) return node.every((item) => typeof item === "string" && item !== "") ? node : undefined;
if (!node || typeof node !== "object") return undefined;
const kept = Object.entries(node).map(([key, value]) => [key, filled(value)]).filter(([, value]) => value !== undefined);
return kept.length ? Object.fromEntries(kept) : undefined;
}
/** The part of a language's file the page takes: the editor's texts and the screens' words its mockup draws. */
export function pageTexts(data: any) {
const screen = data?.screen || {};
const words: Record<string, unknown> = Object.fromEntries(SCREEN_PARTS.filter((part) => part in screen).map((part) => [part, screen[part]]));
if (screen.tile?.page !== undefined) words.tile = { page: screen.tile.page };
return (filled({ editor: data?.editor, screen: words }) || {}) as Record<string, unknown>;
}