fix(i18n): translate viewer + Transcribe panel controls for EN/ES locales #626
Reference in New Issue
Block a user
Delete Branch "feat/issue-319-i18n-viewer-transcribe-controls"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #319
Summary
viewer_previous_page,viewer_next_page,viewer_zoom_out,viewer_zoom_in,transcribe_mark_for_training,layout_menu_open,layout_menu_close) tode/en/es.jsonPdfControls.svelte— 4 icon-button aria-labels (Zurück,Weiter,Verkleinern,Vergrößern) now go throughm.viewer_*()AppNav.svelte— hamburger button aria-label (Menü öffnen/Menü schließen) now goes throughm.layout_menu_open()/m.layout_menu_close()TranscriptionEditView.svelte— visible labelFür Training vormerkennow goes throughm.transcribe_mark_for_training()src/lib/messages.spec.ts— key-parity test asserting de/en/es always have identical key sets; specific assertions for all 7 new keyslang.spec.ts— mobile-viewport EN locale assertion that the hamburger button has accessible nameOpen menuTest plan
npm run test— all unit tests green (key parity + existing viewer/transcription suites)npm run check— no new type errors introduced🤖 Generated with Claude Code
👨💻 Felix Brandt — Senior Fullstack Developer
Verdict: ⚠️ Approved with concerns
The mechanical substitution is correct and clean throughout. TDD cycle was followed — messages.spec.ts went red before the JSON keys were added, then green. Existing viewer and transcription test suites still pass.
Suggestion
PdfControls.svelte.spec.ts— tests pass coincidentally, not intentionallyLines 89, 155, and 167 filter icon-only buttons using hardcoded German strings:
After this PR the component uses
m.viewer_previous_page()etc., which in DE locale still returns"Zurück","Weiter", etc. — so the tests pass. But they're testing the locale-resolved string value by coincidence, not the i18n contract. If someone changes the DE translation ofviewer_previous_pageto"Zurückblättern", these tests will silently break in a confusing way (four buttons → zero buttons found, length assertion fails with no clear message).Suggested fix — replace the hardcoded array with the message functions:
Same for the
PdfViewer.svelte.test.tsdescriptions that mention the DE strings inline (lines 25, 33–36 — test description string"Zurück/Weiter/Vergrößern/Verkleinern"can stay as a description, but the assertions on lines 33–36 could also usem.*()for clarity).This is a suggestion, not a blocker — the tests do pass and the production code is correct.
🏛️ Markus Keller — Senior Application Architect
Verdict: ✅ Approved
Pure frontend change. Checked against the full doc-update matrix in
CLAUDE.md:+page.sveltefilesErrorCodeorPermissionvalueThe key namespace conventions (
viewer_*,layout_*,transcribe_*) are consistent with the established prefix pattern (nav_*,btn_*,pdf_*,training_*) and scale correctly. No architecture boundary is crossed.The
messages.spec.tsparity test belongs where it was placed —src/lib/is the right home for a spec that imports the three JSON files directly as modules.Nothing to flag from an architecture perspective.
🚀 Tobias Wendt — DevOps & Platform Engineer
Verdict: ✅ Approved
No infrastructure changes in this PR. Checked:
E2E test pattern note (not a blocker)
The new test in
e2e/lang.spec.tsusesbrowser.newContext()to spin up a mobile viewport context, which mirrors the pattern already established ine2e/accessibility.spec.ts(dark mode context). That's consistent.One thing to be aware of: E2E tests are not currently wired into CI (
e2e/CLAUDE.mdstates they stop at unit/component tests). The new test will only run when someone runsnpm run test:e2elocally or if the CI pipeline is extended. That's fine for now — just means the mobile hamburger aria-label won't be automatically verified on every PR until CI is extended.No platform concerns. Clean.
📋 Elicit — Requirements Engineer
Verdict: 🚫 Changes requested
Checked the PR against the acceptance criteria from issue #319.
messages.spec.tsenforces thisBlockers
1. E2E coverage for viewer and Transcribe panel is absent
The only new E2E test added checks the hamburger button in EN on a mobile viewport. The issue's acceptance criteria explicitly require verifying that no German strings appear in the viewer controls and Transcribe panel under EN and ES locales. Those tests are not here.
The issue itself raised the concern that fixture availability needs to be confirmed (Sara noted this in the review comments on #319 — a document with an attached PDF is needed). If a fixture exists (the viewer directory contains
minimal.pdf), the test should be added. If no fixture is available in the E2E test data, this needs to be either documented as a known gap with a follow-up issue, or the fixture needs to be created.2. axe-core WCAG 3.1.2 check not added
Criterion 5 requires an axe-core scan in EN and ES locales verifying no "language of parts" violations. The existing
e2e/accessibility.spec.tsscanshome,persons,aktivitaeten,admin, andadmin-system— it does not cover the document detail page or the Transcribe panel.Recommendation
Either:
The core fix (all 7 strings wired, parity test) is correct. The gap is in verification, not in implementation.
🔒 Nora "NullX" Steiner — Application Security Engineer
Verdict: ✅ Approved
Reviewed with an adversarial lens. This PR is a pure i18n wiring change — it modifies message JSON files, Svelte template strings, and adds test coverage. Checked:
WCAG 3.1.2 (Language of Parts) — positive security outcome
The fix directly addresses the accessibility conformance failure raised in the issue. When AT users receive screen reader output in the wrong language, it degrades their ability to understand what actions do — which has a security dimension (confirming an action you didn't understand). This PR resolves that.
Message injection — not a concern
The Paraglide message functions (
m.viewer_previous_page()etc.) return statically compiled strings from the JSON files. They do not accept user input and cannot be influenced at runtime by external data. No injection vector here.No security concerns. Clean merge.
🧪 Sara Holt — Senior QA Engineer
Verdict: ⚠️ Approved with concerns
What's good
messages.spec.tsis well-structured: four focused tests, each with a single logical assertion, descriptive names, and no shared state. The key-parity test will catch the most common i18n regression (adding a key to one locale and forgetting the others). This is permanent value added to the test suite.Concerns
1.
PdfControls.svelte.spec.ts— silent pass via coincidence (lines 89, 155, 167)Three test cases filter buttons by hardcoded lowercase German strings:
After this PR the component uses
m.viewer_*(), which in the DE test locale still returns those exact strings. The tests pass — but for the wrong reason. Ifviewer_previous_page's DE translation ever changes, these tests fail with a confusing "expected 4 buttons, got 0" rather than a meaningful message. This is a test reliability issue, not just a style issue.2. E2E coverage gap against the acceptance criteria
The issue requires E2E verification that no German appears in the EN and ES viewer/Transcribe panel. The only new E2E test covers the mobile hamburger in EN. Missing:
Previous page,Next page,Zoom out,Zoom in)Mark for OCR training)Abrir menú)The unit + parity tests prove the keys exist and are wired. Only E2E can prove no German leaks through in a real browser render under a specific locale.
3. E2E test is not in CI
e2e/CLAUDE.mddocuments that E2E tests don't run in CI. The new test will only catch regressions when someone runsnpm run test:e2emanually.Blockers
None — the production implementation is correct and the unit tests pass. The E2E gaps are test coverage concerns, not implementation bugs. I'd flag them as suggestions that should be addressed before claiming the acceptance criteria fully met.
🎨 Leonie Voss — Senior UX Designer & Accessibility Strategist
Verdict: ✅ Approved
The fix directly addresses the WCAG 3.1.2 "Language of Parts" failure. Reviewed all 7 translations:
viewer_previous_pageviewer_next_pageviewer_zoom_outviewer_zoom_intranscribe_mark_for_traininglayout_menu_openlayout_menu_closeAll four icon-only PDF viewer buttons (
Previous page,Next page,Zoom out,Zoom in) now have AT-readable labels in all three locales. The mobile hamburger button correctly announces its state in both directions. The visible "Für Training vormerken" label in the Transcribe footer is now fully localized.Suggestion (non-blocking)
The existing
e2e/accessibility.spec.tsscans five pages (home, persons, aktivitaeten, admin, admin-system) with axe-core for wcag2a/wcag2aa. The document detail page — where the viewer and Transcribe panel live — is not included. Even after this fix, WCAG 3.1.2 regressions on that page would not be caught automatically.Extending the
AUTHENTICATED_PAGESarray to include a document detail path would close this gap:This needs a stable document ID in the E2E test data. Worth a follow-up issue if not done here.
Overall the translation quality is good and the implementation is clean.