v0.247.0: i18n spike — the dashboard can speak English, Hungarian byte-identical
gates / gates (push) Successful in 19s
gates / gates (push) Successful in 19s
Message bundles (internal/i18n) expanded into templates before parsing, one template set per language. Launcher, /backups, /apps/<slug> and the layout converted; household language setting, POST /settings/language, ?lang= override, report field. Parity test against fixtures captured from unconverted templates; copy gates read templates expanded; new i18n_missing_gate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""i18n_bundle.py -- read a dashboard template the way the controller renders it.
|
||||
|
||||
Since v0.247.0 a template's copy lives in internal/i18n/locales/<lang>.json and the template carries
|
||||
`{{T "key"}}` markers, expanded before parsing (internal/i18n/i18n.go). A gate that reads the raw
|
||||
template no longer sees that copy -- the retrieval-promise gate went STALE the moment the first page
|
||||
was converted, which is how this module was found to be needed. Gates that judge copy, markup or
|
||||
template actions call expand()/read_template() so they judge what a household actually receives, in
|
||||
every language.
|
||||
|
||||
The marker pattern is the Go one, character for character (markerRe); an undefined key is left in
|
||||
place, exactly as the loader leaves it.
|
||||
"""
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
|
||||
_HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
LOCALES = os.path.join(_HERE, "..", "internal", "i18n", "locales")
|
||||
LANGS = ("hu", "en")
|
||||
MARKER = re.compile(r'\{\{\s*T\s+"([A-Za-z0-9_.\-]+)"\s*\}\}')
|
||||
|
||||
_cache = {}
|
||||
|
||||
|
||||
def load(lang):
|
||||
if lang not in _cache:
|
||||
p = os.path.join(LOCALES, lang + ".json")
|
||||
_cache[lang] = json.load(io.open(p, encoding="utf-8")) if os.path.exists(p) else {}
|
||||
return _cache[lang]
|
||||
|
||||
|
||||
def expand(text, lang):
|
||||
hu, own = load("hu"), load(lang)
|
||||
|
||||
def rep(m):
|
||||
k = m.group(1)
|
||||
if k in own:
|
||||
return own[k]
|
||||
if k in hu:
|
||||
return hu[k]
|
||||
return m.group(0)
|
||||
return MARKER.sub(rep, text)
|
||||
|
||||
|
||||
def read_template(path, lang="hu"):
|
||||
return expand(io.open(path, encoding="utf-8").read(), lang)
|
||||
Reference in New Issue
Block a user