v0.248.0: i18n slice 1 release A — apps and settings in English, Hungarian byte-identical (R-556)
gates / gates (push) Successful in 20s

Ten pages converted against fixtures captured from unconverted templates (6be55a0); marker
coverage test; English page mask narrowed; English retrieval-promise stems; common keys;
title keys and infraMeta from the bundle; old wording tests read the Hungarian expansion.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-09-17 17:36:08 +02:00
parent 6be55a0eb3
commit ff68b0b433
30 changed files with 1690 additions and 651 deletions
+18 -3
View File
@@ -35,6 +35,7 @@ import (
// TestI18nParity fails naming the page and the first differing line.
var updateI18nGolden = flag.Bool("update-i18n-golden", false, "write MISSING testdata/i18n_parity fixtures from the current templates (an existing fixture is never overwritten)")
var i18nDumpDir = flag.String("i18n-dump-dir", "", "TestI18nEnglishPages: also write every case's hu and en render to this directory (evidence, per-page review)")
var i18nGoldenOnly = flag.String("i18n-golden-only", "", "with -update-i18n-golden: only cases whose name matches this regexp")
var relativeAgeRe = regexp.MustCompile(`\d+ (napja|órája|perce)`)
@@ -52,6 +53,12 @@ func i18nFixtureTime() time.Time { return time.Date(2026, 9, 14, 3, 12, 0, 0, ti
var i18nTitleKeys = map[string]string{
"Indítópult": "page.title.launcher",
"Biztonsági mentés": "page.title.backups",
"Vezérlőpult": "page.title.dashboard",
"Alkalmazások": "page.title.stacks",
"Rendszermonitor": "page.title.monitoring",
"Beállítások": "page.title.settings",
"Értesítések": "page.title.settings_notifications",
"Biztonság és hozzáférés": "page.title.settings_security",
}
func i18nLayoutData(page, title string) map[string]interface{} {
@@ -376,7 +383,7 @@ func fixtureStrings(v reflect.Value, out map[string]bool) {
}
}
var i18nKeyLikeRe = regexp.MustCompile(`\b(launcher|backups|backups_shared|app_info|layout|func)\.[a-z0-9_]+\b`)
var i18nKeyLikeRe = regexp.MustCompile(`\b[a-z][a-z_]*\.[a-z0-9_.]+\b`)
var emptyElemRe = regexp.MustCompile(`<(h[1-6]|button|label|li|strong|option|p)(\s[^>]*)?>\s*</(h[1-6]|button|label|li|strong|option|p)>`)
// TestI18nEnglishPages — the three pages in English: no Hungarian letter from the TEMPLATE copy, no
@@ -395,14 +402,22 @@ func TestI18nEnglishPages(t *testing.T) {
for _, c := range i18nCases() {
hu := renderI18nCase(t, s, "hu", c)
en := renderI18nCase(t, s, "en", c)
if *i18nDumpDir != "" {
_ = os.MkdirAll(*i18nDumpDir, 0o755)
_ = os.WriteFile(filepath.Join(*i18nDumpDir, c.name+".hu.html"), []byte(hu), 0o644)
_ = os.WriteFile(filepath.Join(*i18nDumpDir, c.name+".en.html"), []byte(en), 0o644)
}
if !huLetter(hu) {
t.Fatalf("%s: positive control failed — the Hungarian render carries no Hungarian letter", c.name)
}
if strings.Contains(en, `{{T `) {
t.Errorf("%s: an unexpanded marker reached the English page", c.name)
}
if m := i18nKeyLikeRe.FindString(en); m != "" && s.i18n.Has(i18n.Default, m) {
t.Errorf("%s: a raw bundle key reached the English page: %q", c.name, m)
for _, m := range i18nKeyLikeRe.FindAllString(en, -1) {
if s.i18n.Has(i18n.Default, m) {
t.Errorf("%s: a raw bundle key reached the English page: %q", c.name, m)
break
}
}
if a, b := len(emptyElemRe.FindAllString(hu, -1)), len(emptyElemRe.FindAllString(en, -1)); b > a {
t.Errorf("%s: English has %d empty elements, Hungarian %d — a translation rendered blank", c.name, b, a)