UX-13 P5 review: every STYLE rule has a mutation check, fuller jargon lists, Dutch wording, overlap partner test
checks / unit (pull_request) Successful in 10m44s
infra-pin / fresh (pull_request) Successful in 1s

- test_ui_text.py: key parity, placeholder parity, English-left-in-Dutch,
  semicolon, 25-word description and 2-sentence line each now fail on a
  spoiled input (the English-left check was not a real mutation).
- Jargon lists now cover the whole 'Not' column of STYLE.md section 4, in
  English, with the Dutch equivalents.
- nl.json: 'gewijzigd worden' where 'wijzigen' read as intransitive,
  'Bezig met bewaren' for the saving state, 'Metingen kloppen niet'.
- test_uimodel.py: an overlap that changes partners is named piece by piece
  (a surviving mutant of _tiling's partner check).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
review-agent
2026-09-28 16:54:45 +02:00
parent 667b8e9145
commit ede01b8a04
3 changed files with 71 additions and 23 deletions
+58 -17
View File
@@ -68,18 +68,30 @@ def where(lang, path):
# ============================================================================ #
print("1. English and Dutch have the same keys and placeholders")
_en, _nl = dict(leaves(EN)), dict(leaves(NL))
_only_en = sorted(where("en", p) for p in _en if p not in _nl)
_only_nl = sorted(where("nl", p) for p in _nl if p not in _en)
def missing(en, nl):
"""The keys only one language has."""
return (sorted(where("en", p) for p in en if p not in nl),
sorted(where("nl", p) for p in nl if p not in en))
def holes(en, nl):
"""The Dutch strings whose {placeholders} differ from the English."""
return sorted(
f"{where('nl', p)}: {sorted(PLACEHOLDER.findall(str(en[p])))} vs "
f"{sorted(PLACEHOLDER.findall(str(t)))}"
for p, t in nl.items() if p in en
and sorted(PLACEHOLDER.findall(str(t)))
!= sorted(PLACEHOLDER.findall(str(en[p]))))
_only_en, _only_nl = missing(_en, _nl)
for x in _only_en + _only_nl:
print(f" MISSING in the other language: {x}")
check(f"every one of the {len(_en)} English strings has a Dutch one, and no "
"Dutch string is extra", not _only_en and not _only_nl and len(_en) > 300)
_holes = sorted(
f"{where('nl', p)}: {sorted(PLACEHOLDER.findall(str(_en[p])))} vs "
f"{sorted(PLACEHOLDER.findall(str(t)))}"
for p, t in _nl.items() if p in _en
and sorted(PLACEHOLDER.findall(str(t)))
!= sorted(PLACEHOLDER.findall(str(_en[p]))))
_holes = holes(_en, _nl)
for x in _holes:
print(f" PLACEHOLDERS differ: {x}")
check("every Dutch string fills the same {placeholders} as its English one",
@@ -94,10 +106,14 @@ print("\n2. every string follows STYLE.md, in both languages")
JARGON = {
"en": r"controllers?|control loop|setpoints?|SoC|state of charge|BMS|PV|"
r"failsafe|trip(?:ped)?|parked|discharg\w*|P1 feed|quarter-hour|"
r"payload|endpoint|JSON|API|timeout|boolean|config",
"nl": r"setpoints?|SoC|BMS|PV|failsafe|regelaar|regellus|"
r"latch|ontlad\w*|payload|endpoint|JSON|API|time-?out|boolean|"
r"config|kwartuur\w*",
r"payload|endpoint|JSON|API|timeout|boolean|config|commands?|"
r"charge level|ceiling|billed quarter|quarters?|banked|soft limit|"
r"open block|actuator|ESP32|master|meter source|circulating|"
r"sign disagreement|rail",
"nl": r"setpoints?|setpunt\w*|SoC|laadtoestand|BMS|PV|failsafe|regelaar|"
r"regellus|controller|latch|ontlad\w*|payload|endpoint|JSON|API|"
r"time-?out|boolean|config|kwartuur\w*|commando\w*|geparkeerd|"
r"ESP32|master",
}
JARGON = {k: re.compile(r"\b(?:" + v + r")\b", re.I) for k, v in JARGON.items()}
# Details belong behind the page's DOCS link, never in the string itself.
@@ -167,6 +183,22 @@ check("a link or section in a string is caught",
"See https://example.org for the rest."))
check("a snake_case option key is caught",
problems("nl", ("x",), "Zet peak_cap_w hoger"))
check("a semicolon is caught",
problems("en", ("x",), "Saved; restart to apply"))
check("a 26-word description is caught, and 25 words pass",
problems("en", ("x", "description"), " ".join(["word"] * 26) + ".")
and not problems("en", ("x", "description"),
" ".join(["word"] * 25) + "."))
check("a 3-sentence line is caught",
problems("en", ("x",), "One. Two. Three."))
check("a key only one language has is caught, both ways",
missing({("a",): "x", ("b",): "y"}, {("a",): "x"}) == (["en.json:b"], [])
and missing({("a",): "x"}, {("a",): "x", ("c",): "z"})
== ([], ["nl.json:c"]))
check("a placeholder dropped or renamed in Dutch is caught",
holes({("a",): "Window {row}"}, {("a",): "Tijdvak"})
and holes({("a",): "{w} now"}, {("a",): "nu {d}"})
and not holes({("a",): "{a} {b}"}, {("a",): "{b} {a}"}))
# ============================================================================ #
@@ -219,14 +251,23 @@ print("\n5. no Dutch string is left in English")
# Words that are the same in both, or names. Anything else equal is untranslated.
SAME = {"Meter", "Timing", "Support", "Details", "Alarm", "Info", "per kWh",
"{hour}:00 UTC", "Flanders, Fluvius Antwerpen", "Modus", "Status"}
_same = sorted(f"{where('nl', p)} = {t!r}" for p, t in _nl.items()
if p in _en and t == _en[p] and t not in SAME
and PLACEHOLDER.sub("", t).strip(" .:,"))
def english(en, nl):
return sorted(f"{where('nl', p)} = {t!r}" for p, t in nl.items()
if p in en and t == en[p] and t not in SAME
and PLACEHOLDER.sub("", t).strip(" .:,"))
_same = english(_en, _nl)
for x in _same:
print(f" ENGLISH {x}")
check(f"every Dutch string is Dutch ({len(_same)} still English)", not _same)
check("mutation: an English string in nl.json is caught",
"Save" != NL["settings"]["savebar"]["save"] and "Save" not in SAME)
_spoiled = dict(_nl)
_spoiled[("settings", "savebar", "save")] = _en[("settings", "savebar",
"save")]
check("mutation: an English string left in nl.json is caught",
english(_en, _spoiled) == ["nl.json:settings.savebar.save = 'Save'"])
# ============================================================================ #