- app/ui_text/nl.json and app/uitext.py: every page word in Dutch, English fallback per key; the page picks by browser language. Home's sentences move into ui_text `home_words`, so /status?lang=nl builds them in Dutch. - test_ui_text.py: EN/NL key and placeholder parity, STYLE limits, jargon lists for both languages, no inline details, untranslated Dutch caught. Shared rules moved unchanged to tools/style_rules.py. - tools/ux13_screenshots.sh/.py: DOCS screenshots from the demo fixtures in headless Chromium; docs/img/ux13/. Battery modes (P3): no screenshot. - "Other time windows": a list editor (ui.periods) that builds static_profile and names bad times, empty prices, overlaps and gaps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
52 lines
1.6 KiB
Python
52 lines
1.6 KiB
Python
"""UX-13 P5: the page's words, app/ui_text/<lang>.json, in English or Dutch.
|
|
|
|
One file per language with the same keys. A key missing from a language falls
|
|
back to English, key by key, the way the Supervisor's translations do.
|
|
test_ui_text.py holds both files to STYLE.md and to each other.
|
|
"""
|
|
|
|
import copy
|
|
import io
|
|
import json
|
|
import os
|
|
|
|
DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ui_text")
|
|
LANGS = ("en", "nl")
|
|
_CACHE: dict = {}
|
|
|
|
|
|
def lang_of(value) -> str:
|
|
""""nl", "nl-BE" or "nl_NL" -> "nl"; anything else -> "en"."""
|
|
head = str(value or "").strip().lower().replace("_", "-").split("-")[0]
|
|
return head if head in LANGS else "en"
|
|
|
|
|
|
def raw(lang: str) -> dict:
|
|
"""One language file as written, without the English fallback."""
|
|
if lang not in _CACHE:
|
|
with io.open(os.path.join(DIR, f"{lang}.json"), encoding="utf-8") as f:
|
|
_CACHE[lang] = json.load(f)
|
|
return _CACHE[lang]
|
|
|
|
|
|
def _merge(base, over):
|
|
if not (isinstance(base, dict) and isinstance(over, dict)):
|
|
return copy.deepcopy(over)
|
|
out = copy.deepcopy(base)
|
|
for k, v in over.items():
|
|
out[k] = _merge(base.get(k), v) if k in base else copy.deepcopy(v)
|
|
return out
|
|
|
|
|
|
def words(lang="en") -> dict:
|
|
"""Every word in `lang`, English where a key is missing."""
|
|
lang = lang_of(lang)
|
|
return raw("en") if lang == "en" else _merge(raw("en"), raw(lang))
|
|
|
|
|
|
def say(template: str, **values) -> str:
|
|
"""Fill `{name}` placeholders, as settings.js `say()` does."""
|
|
for k, v in values.items():
|
|
template = template.replace("{" + k + "}", str(v))
|
|
return template
|