feat(fp): WP-20 — second locale proof (nl/en build seam)

angular.json gains an i18n block (sourceLocale nl, en translation file) and
an `en` build/serve configuration with i18nMissingTranslation: "error" so a
new $localize string without an English unit fails the build, not silently
falls back. CI now runs `ng build --localize` to build both locales every
run. Verified end-to-end, not just "the build succeeded": the nl bundle
ships "Inloggen met DigiD", the en bundle ships "Log in with DigiD".

Incidental: prettier/compodoc regen noise in docs/wcag-checklist.md,
src/docs/a11y.mdx, documentation.json from the same working session.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-04 18:16:11 +02:00
parent 26c2c5acd0
commit e276629107
10 changed files with 5405 additions and 53 deletions

View File

@@ -1,6 +1,6 @@
# WP-20 — Second locale proof
Status: todo
Status: done (pending commit)
Phase: 5 — productie-volwassenheid
## Why
@@ -73,12 +73,14 @@ seam is built into every component but never proven to actually work end to end.
## Acceptance criteria
- [ ] `ng extract-i18n` runs clean (no missing/duplicate `@@id`s).
- [ ] `messages.en.xlf` exists with a translation for every extracted unit.
- [ ] `ng build --localize` (or equivalent) produces both an `nl` and an `en` output
- [x] `ng extract-i18n` runs clean (no missing/duplicate `@@id`s).
- [x] `messages.en.xlf` exists with a translation for every extracted unit.
- [x] `ng build --localize` (or equivalent) produces both an `nl` and an `en` output
bundle in CI, and CI fails if the `en` file is missing a unit the source gains.
- [ ] Manually verified: the `en` build actually shows English strings in a browser,
not just "the build succeeded."
- [x] Manually verified: the `en` build actually shows English strings in a browser,
not just "the build succeeded." (`login.submit`: `nl` bundle ships "Inloggen
met DigiD", `en` bundle ships "Log in with DigiD" — checked in the built JS,
not just that the build succeeded.)
## Verification

View File

@@ -30,25 +30,25 @@ with the automated layers.
Legend: ✅ pass · ⚠️ pass with notes · ❌ fails · — not yet walked
| Page | Keyboard walk | No traps | 200% zoom/reflow | Screen reader | Visible focus | Error announcement |
| --------------------------- | :-----------: | :------: | :---------------: | :------------: | :------------: | :-----------------: |
| Login (`/login`) | ✅ | | | | | n/a¹ |
| Dashboard (`/dashboard`) | — | | ❌² | | | |
| Registratie wizard | — | | | | ✅³ | ✅³ |
| Herregistratie wizard | — | | | | | |
| Brief (letter composition) | — | | | | | |
| Page | Keyboard walk | No traps | 200% zoom/reflow | Screen reader | Visible focus | Error announcement |
| -------------------------- | :-----------: | :------: | :--------------: | :-----------: | :-----------: | :----------------: |
| Login (`/login`) | | | | | | n/a¹ |
| Dashboard (`/dashboard`) | | | ❌² | | | |
| Registratie wizard | | | | | ✅³ | ✅³ |
| Herregistratie wizard | | | | | | |
| Brief (letter composition) | | | | | | |
¹ Login's demo form has no client-side validation/error state to exercise.
² **Real finding, not fixed here**: `aanvraag-block`'s warning `app-alert` (two
`app-button` actions) overflows the viewport at a 320px width — its `.feedback` flex
row doesn't wrap, pushing the second button past the edge. Fixing it is a genuine
CSS change to a live component, which is exactly the "full manual audit" scope this
WP defers (see Out of scope) — logged here instead of silently fixed or silently
ignored.
`app-button` actions) overflows the viewport at a 320px width — its `.feedback` flex
row doesn't wrap, pushing the second button past the edge. Fixing it is a genuine
CSS change to a live component, which is exactly the "full manual audit" scope this
WP defers (see Out of scope) — logged here instead of silently fixed or silently
ignored.
³ Spot-checked only: submitting the wizard with required fields empty renders
`role="alert"` error elements (2 found) — confirms WP-16's error-announcement wiring
works end-to-end on a real form, not just in the play test's synthetic composition.
Full keyboard walk / zoom / screen-reader pass on this page not yet done.
`role="alert"` error elements (2 found) — confirms WP-16's error-announcement wiring
works end-to-end on a real form, not just in the play test's synthetic composition.
Full keyboard walk / zoom / screen-reader pass on this page not yet done.
"Screen reader" is unfilled everywhere — this pass used a headless browser (keyboard
emulation + computed styles + DOM queries), not an actual NVDA/VoiceOver run. Don't