#119-i18n (alt) — Automatische Spracherkennung + vollständige Internationalisierung (DE/EN) #122

Closed
opened 2026-08-18 13:14:17 +02:00 by lena · 3 comments
lena commented 2026-08-18 13:14:17 +02:00 (Migrated from git.butzei.de)

Story: Automatische Spracherkennung + vollständige Internationalisierung (DE/EN)

As a Nutzer,
I want to die App automatisch in der Sprache meines Geräts sehen (Deutsch, sonst Englisch als Fallback),
so that ich nicht zwischen Sprachen wechseln oder mit einer für mich fremden Sprache klarkommen muss.

Background

Verifiziert im Code: Es existiert aktuell kein i18n-Framework (keine Treffer für i18n,
useTranslation, LanguageProvider o. ä. in ReactUi/src). Die UI-Strings sind eine unkoordinierte
Mischung aus Englisch und Deutsch, z. B.:

  • ListActionsMenu.tsx, TodoListItem.tsx: durchgängig Englisch ("Delete", "Rename", "Invite",
    "Archive", "Transfer ownership", "Export as CSV" …)
  • PriorityMatrixPage.tsx: durchgängig Deutsch ("Ändern", "Dringend / Wichtig", "Faktor", "Neuer
    Eintrag", "Liste"/"Karte", "Alle Labels" …)

PO-Entscheidung (2026-08-17, per Rückfrage bestätigt): Vollständige Internationalisierung — nicht
nur Spracherkennung oder ein Teilbereich. Größter Umfang der drei zur Wahl gestellten Optionen, dafür
langfristig sauber statt eines weiteren Flickenteppichs.

AC

  • i18n-Framework eingeführt (z. B. react-i18next o. äquivalent — technische Wahl liegt beim
    Architekten), mit zwei Sprachpaketen: Deutsch und Englisch.
  • Beim ersten Laden wird die Gerätesprache (navigator.language/navigator.languages) ausgewertet:
    Deutsch (de*) → deutsche UI, alles andere → englische UI als Fallback.
  • Die erkannte/gewählte Sprache wird persistiert (analog zum bestehenden Theme-Präferenz-Muster,
    siehe Theme/GetThemePreferenceQuery/UpdateThemePreferenceCommand), sodass ein eingeloggter
    Nutzer sie geräteübergreifend behält.
  • Manuelles Umschalten der Sprache ist über die Settings möglich (analog zum bestehenden
    Dark-Mode-Schalter).
  • Alle bestehenden UI-Strings (aktuell die o. g. Englisch/Deutsch-Mischung) werden durch den neuen
    Mechanismus ersetzt — keine hartkodierten Strings mehr in Komponenten.
  • Neu hinzukommende Features müssen künftig ebenfalls beide Sprachpakete pflegen (in
    ai/roles/00_team_overview.md bzw. der Frontend-Rolle als Konvention ergänzen).

Out of scope

  • Weitere Sprachen über Deutsch/Englisch hinaus.
  • Übersetzung von nutzergenerierten Inhalten (Todo-Texte, Kommentare etc.) — nur die UI selbst.
  • Server-seitige Inhalte wie E-Mail-Templates (separate Story, falls gewünscht).
# Story: Automatische Spracherkennung + vollständige Internationalisierung (DE/EN) **As a** Nutzer, **I want to** die App automatisch in der Sprache meines Geräts sehen (Deutsch, sonst Englisch als Fallback), **so that** ich nicht zwischen Sprachen wechseln oder mit einer für mich fremden Sprache klarkommen muss. ## Background Verifiziert im Code: Es existiert aktuell **kein i18n-Framework** (keine Treffer für `i18n`, `useTranslation`, `LanguageProvider` o. ä. in `ReactUi/src`). Die UI-Strings sind eine unkoordinierte Mischung aus Englisch und Deutsch, z. B.: - `ListActionsMenu.tsx`, `TodoListItem.tsx`: durchgängig Englisch ("Delete", "Rename", "Invite", "Archive", "Transfer ownership", "Export as CSV" …) - `PriorityMatrixPage.tsx`: durchgängig Deutsch ("Ändern", "Dringend / Wichtig", "Faktor", "Neuer Eintrag", "Liste"/"Karte", "Alle Labels" …) PO-Entscheidung (2026-08-17, per Rückfrage bestätigt): **Vollständige Internationalisierung** — nicht nur Spracherkennung oder ein Teilbereich. Größter Umfang der drei zur Wahl gestellten Optionen, dafür langfristig sauber statt eines weiteren Flickenteppichs. ## AC - i18n-Framework eingeführt (z. B. `react-i18next` o. äquivalent — technische Wahl liegt beim Architekten), mit zwei Sprachpaketen: Deutsch und Englisch. - Beim ersten Laden wird die Gerätesprache (`navigator.language`/`navigator.languages`) ausgewertet: Deutsch (`de*`) → deutsche UI, alles andere → englische UI als Fallback. - Die erkannte/gewählte Sprache wird persistiert (analog zum bestehenden Theme-Präferenz-Muster, siehe `Theme`/`GetThemePreferenceQuery`/`UpdateThemePreferenceCommand`), sodass ein eingeloggter Nutzer sie geräteübergreifend behält. - Manuelles Umschalten der Sprache ist über die Settings möglich (analog zum bestehenden Dark-Mode-Schalter). - **Alle** bestehenden UI-Strings (aktuell die o. g. Englisch/Deutsch-Mischung) werden durch den neuen Mechanismus ersetzt — keine hartkodierten Strings mehr in Komponenten. - Neu hinzukommende Features müssen künftig ebenfalls beide Sprachpakete pflegen (in `ai/roles/00_team_overview.md` bzw. der Frontend-Rolle als Konvention ergänzen). ## Out of scope - Weitere Sprachen über Deutsch/Englisch hinaus. - Übersetzung von nutzergenerierten Inhalten (Todo-Texte, Kommentare etc.) — nur die UI selbst. - Server-seitige Inhalte wie E-Mail-Templates (separate Story, falls gewünscht).
lena commented 2026-08-23 21:07:17 +02:00 (Migrated from git.butzei.de)

Claimed for this go-cycle (2026-08-23).

Architect plan:

  • Library: react-i18next + i18next-browser-languagedetector (the standard React i18n stack, actively maintained, supports lazy namespace loading if the bundle grows).
  • Structure: ReactUi/src/i18n/locales/{de,en}/common.json (single namespace to start given the app's current size - can split later if it grows unwieldy). Keys grouped by component/feature area.
  • Detection: i18next-browser-languagedetector's navigator detector, restricted to the de* vs everything-else fallback the AC specifies (not the library's full locale-matching default, which would need to be constrained explicitly).
  • Persistence: mirrors the existing Theme pattern exactly - new Language plain enum (German/English, not a Vogen VO, same precedent as Theme/TodoListColor/TodoPriority), GetLanguagePreferenceQuery/UpdateLanguagePreferenceCommand, single-field addition to the user settings shape (4th one after IsEmailVerified/SessionsRevokedBeforeUtc/avatar/Theme - still not worth a consolidated preferences object per the #31 decision precedent).
  • Settings UI: new toggle next to the existing dark-mode switch in SettingsModal.tsx.
  • String migration: full sweep of ReactUi/src/components (~100+ files) replacing hardcoded strings with t('key') calls and populating both locale files as I go. Given the size, this lands as a sequence of small, reviewable commits (framework+backend+detection+settings first, then component groups) rather than one mega-diff, per this repo's commit-discipline convention - the AC's 100% coverage requirement stays the actual completion bar, tracked here until every component is migrated.

Security/scope: no new attack surface (same pattern as Theme, a simple per-user string preference); no server-side content translated (emails etc. explicitly out of scope per the story).

Claimed for this go-cycle (2026-08-23). Architect plan: - Library: react-i18next + i18next-browser-languagedetector (the standard React i18n stack, actively maintained, supports lazy namespace loading if the bundle grows). - Structure: `ReactUi/src/i18n/locales/{de,en}/common.json` (single namespace to start given the app's current size - can split later if it grows unwieldy). Keys grouped by component/feature area. - Detection: i18next-browser-languagedetector's navigator detector, restricted to the `de*` vs everything-else fallback the AC specifies (not the library's full locale-matching default, which would need to be constrained explicitly). - Persistence: mirrors the existing Theme pattern exactly - new `Language` plain enum (German/English, not a Vogen VO, same precedent as Theme/TodoListColor/TodoPriority), `GetLanguagePreferenceQuery`/`UpdateLanguagePreferenceCommand`, single-field addition to the user settings shape (4th one after IsEmailVerified/SessionsRevokedBeforeUtc/avatar/Theme - still not worth a consolidated preferences object per the #31 decision precedent). - Settings UI: new toggle next to the existing dark-mode switch in SettingsModal.tsx. - String migration: full sweep of ReactUi/src/components (~100+ files) replacing hardcoded strings with `t('key')` calls and populating both locale files as I go. Given the size, this lands as a sequence of small, reviewable commits (framework+backend+detection+settings first, then component groups) rather than one mega-diff, per this repo's commit-discipline convention - the AC's 100% coverage requirement stays the actual completion bar, tracked here until every component is migrated. Security/scope: no new attack surface (same pattern as Theme, a simple per-user string preference); no server-side content translated (emails etc. explicitly out of scope per the story).
lena commented 2026-08-23 22:27:00 +02:00 (Migrated from git.butzei.de)

Progress update + scope split decision.

Delivered so far (2 commits): the full i18n mechanism end-to-end - react-i18next, persisted Language preference (backend GetLanguagePreferenceQuery/UpdateLanguagePreferenceCommand mirroring the existing Theme pattern exactly, migration AddLanguageToUser), device detection on first load, the Settings toggle, and a representative migrated batch (Login, Register, AcceptInvitePage, ForgotPasswordPage, ResetPasswordPage, VerifyEmailPage, UnsubscribePage, EmailVerificationBanner, LogoutButton, BackendUnreachableBanner, OfflineBanner, SettingsModal's Appearance tab).

Remaining scope: ~78 components still have hardcoded strings (Todo list core, Shopping, Pantry, Priority Matrix, Master Packing List, account/notifications). That's real, substantial work on its own - splitting it into 5 follow-up stories (#122b-f, same pattern as #101's split into #101b-e) rather than one unreviewable mega-diff, per this repo's commit-discipline convention. This issue (#122) stays open and tracks the umbrella - its own AC (100% string coverage) is only satisfied once #122b-f are all done and a final repo-wide grep sweep (per #122f) confirms nothing was missed.

Progress update + scope split decision. Delivered so far (2 commits): the full i18n mechanism end-to-end - react-i18next, persisted Language preference (backend GetLanguagePreferenceQuery/UpdateLanguagePreferenceCommand mirroring the existing Theme pattern exactly, migration AddLanguageToUser), device detection on first load, the Settings toggle, and a representative migrated batch (Login, Register, AcceptInvitePage, ForgotPasswordPage, ResetPasswordPage, VerifyEmailPage, UnsubscribePage, EmailVerificationBanner, LogoutButton, BackendUnreachableBanner, OfflineBanner, SettingsModal's Appearance tab). Remaining scope: ~78 components still have hardcoded strings (Todo list core, Shopping, Pantry, Priority Matrix, Master Packing List, account/notifications). That's real, substantial work on its own - splitting it into 5 follow-up stories (#122b-f, same pattern as #101's split into #101b-e) rather than one unreviewable mega-diff, per this repo's commit-discipline convention. This issue (#122) stays open and tracks the umbrella - its own AC (100% string coverage) is only satisfied once #122b-f are all done and a final repo-wide grep sweep (per #122f) confirms nothing was missed.
lena commented 2026-08-31 07:56:17 +02:00 (Migrated from git.butzei.de)

Closing out #122 - full i18n migration to react-i18next now complete across the entire ReactUi frontend.

Summary

  • ~90+ components across todo/shopping/pantry/priority-matrix/master-packing/account/settings/notifications migrated from hardcoded English strings to useTranslation()/t(...) keys, in sub-issues #122b through #122f plus this final close-out gap-fill (SettingsModal.tsx's remaining Profile/Security/Notifications tabs, which had only been partially migrated).

Final verification sweep (repo-wide grep across every .tsx under src/, not just components/):

  • Found and fixed 2 remaining hardcoded strings that every prior per-component batch had no reason to catch, since both live outside components/: App.tsx's top-level loading fallback, and the shared ui/dialog.tsx DialogContent close-button's screen-reader-only label.
  • Confirmed zero hardcoded UI strings remain anywhere in the frontend.
  • Confirmed EN/DE locale key parity: 758 keys each, zero orphaned in either direction.

Code review

  • This migration series repeatedly hit the same anti-pattern (a freshly-added translation key duplicating an existing one, byte-identical in both locales) - caught and fixed 5 separate times across the series (see ai/roles/memory/04_frontend_engineer_memory.md's Learned Patterns for the full progression of the rule). The 5th recurrence (in this close-out cycle's SettingsModal work) was fixed: settings.profile.email/username -> reused auth.register.email/username, settings.profile.remove/.removing -> reused shopping.cartCheck.remove/.removing, settings.security.copy -> reused invitePanel.copy.
  • Full npm run build + npx tsc -b + npm run coverage (1050 tests, 114 files) green after every fix.

Known limitation: Docker is not available in this environment, so the local review container (docker-compose.dev.yml) could not be rebuilt this cycle - noted explicitly per the loop's step 6 rather than silently skipped.

Closing out #122 - full i18n migration to react-i18next now complete across the entire ReactUi frontend. **Summary** - ~90+ components across todo/shopping/pantry/priority-matrix/master-packing/account/settings/notifications migrated from hardcoded English strings to `useTranslation()`/`t(...)` keys, in sub-issues #122b through #122f plus this final close-out gap-fill (SettingsModal.tsx's remaining Profile/Security/Notifications tabs, which had only been partially migrated). **Final verification sweep** (repo-wide grep across every `.tsx` under `src/`, not just `components/`): - Found and fixed 2 remaining hardcoded strings that every prior per-component batch had no reason to catch, since both live outside `components/`: `App.tsx`'s top-level loading fallback, and the shared `ui/dialog.tsx` `DialogContent` close-button's screen-reader-only label. - Confirmed zero hardcoded UI strings remain anywhere in the frontend. - Confirmed EN/DE locale key parity: 758 keys each, zero orphaned in either direction. **Code review** - This migration series repeatedly hit the same anti-pattern (a freshly-added translation key duplicating an existing one, byte-identical in both locales) - caught and fixed 5 separate times across the series (see `ai/roles/memory/04_frontend_engineer_memory.md`'s Learned Patterns for the full progression of the rule). The 5th recurrence (in this close-out cycle's SettingsModal work) was fixed: `settings.profile.email/username` -> reused `auth.register.email/username`, `settings.profile.remove/.removing` -> reused `shopping.cartCheck.remove/.removing`, `settings.security.copy` -> reused `invitePanel.copy`. - Full `npm run build` + `npx tsc -b` + `npm run coverage` (1050 tests, 114 files) green after every fix. **Known limitation**: Docker is not available in this environment, so the local review container (docker-compose.dev.yml) could not be rebuilt this cycle - noted explicitly per the loop's step 6 rather than silently skipped.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
robert/todo#122
No description provided.