feat(l10n): een poort die Nederlandse doorvoer als vertaling betrapt #1531

Merged
brenno merged 3 commits from feat/l10n-nl-doorvoer into main 2026-08-17 15:34:43 +00:00
Owner

Werkt aan #1526 — de poort. Het opruimen van wat hij vindt volgt in een aparte ronde.

Waarom

l10n_untranslated_test let op Engelse zinnen als vertaling. Een waarde die letterlijk gelijk is aan de Nederlandse bronsleutel glipt er ongemerkt langs. Gevonden bij #1524, waar in het Klingon een compleet LibrePlan-blok in het Nederlands bleek te staan.

De poort

tool/check_l10n_dutch_passthrough.dart + make check-l10n-passthrough. Flutter-vrij, AST-gemeten, in de stijl van de twee poorten ernaast. Vergelijkt twee families: de d()-brontabellen (sleutel == waarde) en de t()-tabel (waarde == de nl-waarde bij dezelfde sleutel).

Drempel van drie woorden, dezelfde afweging als de bestaande wachttest. Zonder drempel ~1.800 treffers, grotendeels ruis (Mermaid, Gantt, Audio, OK). Mét drempel 435. De prijs staat er hardop bij: een onvertaalde bron van één of twee woorden glipt erdoor.

Uitzonderingen per sleutel, niet per taal (14 stuks). Criterium in de code: de bronzin bevat geen enkel vertaalbaar Nederlands woord — een eigennaam, een vastgelegde vakterm, een plaatshouder, of een Engelse uitdrukking die het Nederlands zélf onvertaald leende (Access key ID, DPIA / privacy impact assessment, Sprint review / demo). Per taal uitzonderen zou betekenen dat "tlh mag dit" de vólgende fout in tlh toedekt.

In check-full met ratchet 394, niet in check: het oordeel is een tekstheuristiek, anders dan de pariteitspoort uit #1523 (exacte verzamelingsvergelijking, nul tolerantie, wél in check). Dezelfde ratchet zit in de test, die élke commit meedraait, dus het strengste deel — er mag niets bijkomen — geldt overal.

Wat hij vindt: 394 regels, 38 sleutels, 30 talen

360 daarvan zijn één blok: de LibrePlan-connector, 12 sleutels × 30 talen. Daar zit ook de privacybelofte in — "LibrePlan-connector is optioneel en staat standaard uit…", "Alleen voor servers op het eigen netwerk (LAN)…". Een gebruiker die geen Nederlands leest, krijgt die belofte dus in een taal die hij niet spreekt. Dat is meer dan een schoonheidsfout.

De rest: Alles blijft op dit apparaat in vijf talen, 21 eigen sleutels in het Fries (het auteursrechtenscanblok en editor-labels), en twee Keynote-labels in het Klingon.

Bewust níet uitgezonderd, ook al lijken ze gelijk: Smal (860 px) (Deens/Zweeds kennen "smal" echt), ISO 27001 · Annex A — Organisatorisch (A.5) (Duits kent "Organisatorisch"), Forgejo of Gitea (Fries/Papiaments kennen "of"). Elk draagt een woord dat elders wél vertaald hoort te worden, dus een sleutel-uitzondering zou te breed zijn. De opruimronde beslist per geval.

Tests

12 tests op een mini-repo, twee richtingen: geen alarm op een leenwoord, een korte gelijke waarde, nl zelf of een echte vertaling; wél alarm op een geplante Nederlandse zin in elk van de drie tabellen, en apart geteld per taal.

Poorten

make check groen. make check-secrets groen, make sast groen (0 findings).

Werkt aan #1526 — de poort. Het opruimen van wat hij vindt volgt in een aparte ronde. ## Waarom `l10n_untranslated_test` let op **Engelse** zinnen als vertaling. Een waarde die letterlijk gelijk is aan de **Nederlandse** bronsleutel glipt er ongemerkt langs. Gevonden bij #1524, waar in het Klingon een compleet LibrePlan-blok in het Nederlands bleek te staan. ## De poort `tool/check_l10n_dutch_passthrough.dart` + `make check-l10n-passthrough`. Flutter-vrij, AST-gemeten, in de stijl van de twee poorten ernaast. Vergelijkt twee families: de `d()`-brontabellen (sleutel == waarde) en de `t()`-tabel (waarde == de nl-waarde bij dezelfde sleutel). **Drempel van drie woorden**, dezelfde afweging als de bestaande wachttest. Zonder drempel ~1.800 treffers, grotendeels ruis (`Mermaid`, `Gantt`, `Audio`, `OK`). Mét drempel 435. De prijs staat er hardop bij: een onvertaalde bron van één of twee woorden glipt erdoor. **Uitzonderingen per sleutel, niet per taal** (14 stuks). Criterium in de code: de bronzin bevat geen enkel vertaalbaar Nederlands woord — een eigennaam, een vastgelegde vakterm, een plaatshouder, of een Engelse uitdrukking die het Nederlands zélf onvertaald leende (`Access key ID`, `DPIA / privacy impact assessment`, `Sprint review / demo`). Per taal uitzonderen zou betekenen dat "tlh mag dit" de vólgende fout in tlh toedekt. **In `check-full` met ratchet 394**, niet in `check`: het oordeel is een tekstheuristiek, anders dan de pariteitspoort uit #1523 (exacte verzamelingsvergelijking, nul tolerantie, wél in `check`). Dezelfde ratchet zit in de test, die élke commit meedraait, dus het strengste deel — er mag niets bijkomen — geldt overal. ## Wat hij vindt: 394 regels, 38 sleutels, 30 talen **360 daarvan zijn één blok: de LibrePlan-connector**, 12 sleutels × 30 talen. Daar zit ook de privacybelofte in — "LibrePlan-connector is optioneel en staat standaard uit…", "Alleen voor servers op het eigen netwerk (LAN)…". Een gebruiker die geen Nederlands leest, krijgt die belofte dus in een taal die hij niet spreekt. Dat is meer dan een schoonheidsfout. De rest: `Alles blijft op dit apparaat` in vijf talen, 21 eigen sleutels in het Fries (het auteursrechtenscanblok en editor-labels), en twee Keynote-labels in het Klingon. **Bewust níet uitgezonderd**, ook al lijken ze gelijk: `Smal (860 px)` (Deens/Zweeds kennen "smal" echt), `ISO 27001 · Annex A — Organisatorisch (A.5)` (Duits kent "Organisatorisch"), `Forgejo of Gitea` (Fries/Papiaments kennen "of"). Elk draagt een woord dat elders wél vertaald hoort te worden, dus een sleutel-uitzondering zou te breed zijn. De opruimronde beslist per geval. ## Tests 12 tests op een mini-repo, twee richtingen: geen alarm op een leenwoord, een korte gelijke waarde, `nl` zelf of een echte vertaling; wél alarm op een geplante Nederlandse zin in elk van de drie tabellen, en apart geteld per taal. ## Poorten `make check` groen. `make check-secrets` groen, `make sast` groen (0 findings).
De vertaalpoorten keken alle drie langs hetzelfde gat. `make l10n-check`
vraagt of er een waarde staat, `check-l10n-parity` of de sleutel overal
staat, en `l10n_untranslated_test` of die waarde niet gewoon de ENGELSE
zin is. Niemand vroeg of de waarde de NEDERLANDSE bron is.

Bij #1524 bleek hoe duur dat gat is: tlh.dart droeg 44 sleutels met de
bron als waarde, waaronder een compleet LibrePlan-connectorblok van hele
zinnen. Datzelfde blok staat onvertaald in dertig talen.

De poort telt twee families: de d()-brontabellen (sleutel == waarde) en
de t()-tabel (waarde == de Nederlandse waarde bij dezelfde sleutel), en
alleen vanaf drie woorden — dezelfde drempel en dezelfde afweging als
haar zusterwachter op het Engels, want losse woorden zijn massaal
identiek zonder dat er iets mis is (1.800 treffers zonder drempel, 435
met).

De uitzonderingen gaan per SLEUTEL en niet per taal. Een uitzondering
"tlh mag dit" zegt iets over de vertaler en dekt de volgende fout in die
taal toe; een uitzondering per sleutel zegt dat er in de BRONZIN niets te
vertalen valt, en die uitspraak blijft waar. Criterium in loanKeys, en
wat er bewust NIET in staat staat er ook bij.

De test toetst beide richtingen op een mini-repo: geen alarm op een
leenwoord, een korte gelijke waarde of nl zelf; wél alarm op een
geplante Nederlandse zin, in de basistabel, in de Add-tabel en in de
t()-tabel.

Refs #1526
BEWUSTE KEUZE, en het is niet dezelfde als bij check-l10n-parity.

Die poort vergelijkt twee verzamelingen sleutels op gelijkheid: er valt
niets te interpreteren, dus geen valse melding, geen basislijn, en hij
staat in `check`. Deze poort doet iets anders. (1) Haar oordeel is een
TEKSTHEURISTIEK — gelijkheid vanaf drie woorden. Scherp genoeg om
bruikbaar te zijn, te grof om onfeilbaar te zijn, en dat soort weging
hoort niet in de ronde die élke commit tegenhoudt. (2) Bij invoering
vindt hij er 394. Een poort die meteen rood staat kan niet in `check`
zonder basislijn, en na #1520 en #1523 zetten we een basislijn niet
lichtvaardig terug.

Dus: check-full met een ratchet, precies zoals de wezenpoort. Nul is de
bedoeling; de opruimronde brengt hem daarheen en dán kan hij verhuizen.
Ondertussen raakt het strengste deel wél elke commit: de ratchet zit óók
in test/l10n_dutch_passthrough_test.dart en die draait in de suite mee,
dus een nieuw doorgelaten blok knalt meteen.

passthroughBaseline gaat mee in `make ratchets`, zodat een basislijn die
stil blijft staan zichtbaar wordt in plaats van vergeten.

Refs #1526
docs(checks): de doorlaatpoort in CHECKS.md en het ontwikkellogboek
All checks were successful
scans / scans (pull_request) Successful in 2m59s
static-gate / static-gate (pull_request) Successful in 6m14s
b566fc145f
CHECKS.md is de plek waar een poort uitlegt wat hij weegt en waarom hij
staat waar hij staat. De sectie noemt de drie bestaande vertaalpoorten en
het gat ertussen, de drempel van drie woorden mét de prijs die dat kost,
het criterium voor loanKeys en waarom die per sleutel gaan, en de reden
voor check-full plus ratchet. Ook de tabel onderaan, anders bestaat de
poort daar niet.

Refs #1526
brenno merged commit 365c04040c into main 2026-08-17 15:34:43 +00:00
Sign in to join this conversation.
No description provided.