--- phase: "34" plan: "02" subsystem: "client-i18n" tags: ["i18n", "react-i18next", "locale", "hardcoded-strings"] dependency_graph: requires: ["34-01"] provides: ["all-ui-strings-translated"] affects: ["client/components", "client/routes", "client/locales"] tech_stack: added: ["catalog namespace (en/de)"] patterns: ["useTranslation hook", "multi-namespace pattern", "t() interpolation with variables"] key_files: created: - src/client/locales/en/catalog.json - src/client/locales/de/catalog.json modified: - src/client/components/AddToCollectionModal.tsx - src/client/routes/collection/index.tsx - src/client/routes/threads/$threadId/index.tsx - src/client/routes/items/$itemId.tsx - src/client/routes/setups/$setupId.tsx - src/client/routes/users/$userId.tsx - src/client/routes/global-items/index.tsx - src/client/locales/en/collection.json - src/client/locales/en/threads.json - src/client/locales/en/setups.json - src/client/locales/en/common.json - src/client/locales/de/collection.json - src/client/locales/de/threads.json - src/client/locales/de/setups.json - src/client/locales/de/common.json - src/client/lib/i18n.ts decisions: - "Created catalog namespace for global-items/discover page rather than reusing common" - "Language option labels (English/Deutsch) left as literals — native names are not translated by convention" - "Static data (icon names, CSS classes) kept as module-level constants; only label strings moved inside components" metrics: duration: "~4 hours (multi-session)" completed: "2026-04-18" tasks_completed: 5 files_modified: 25 --- # Phase 34 Plan 02: Extract Hardcoded UI Strings Summary All hardcoded English strings in UI components replaced with react-i18next `t()` calls, with full English and German locale coverage added for all new keys. ## Tasks Completed | Task | Description | Commit | |------|-------------|--------| | 1 | Audit hardcoded strings across all components | (analysis only) | | 2 | i18n collection and item components | c5af124 | | 3 | Extract strings from thread/candidate components | 6fd8874 | | 4 | Extract strings from modals, routes, and catalog | 2aa156a | | 5 | Onboarding and settings (already i18n — no changes needed) | — | ## Scope Components updated in Task 2-3 (from prior session): - CandidateCard, CandidateListItem, CandidateForm, ComparisonTable, StatusBadge - CreateThreadModal, AddToThreadModal - SetupsView, SetupCard, ShareModal Components updated in Task 4 (this session): - AddToCollectionModal - routes/collection/index.tsx (tab labels) - routes/threads/$threadId/index.tsx (thread detail + AddCandidateModal) - routes/items/$itemId.tsx (item detail page) - routes/setups/$setupId.tsx (setup detail page) - routes/users/$userId.tsx (public profile page) - routes/global-items/index.tsx (catalog/discover page) ## Locale Files Extended ### English - `collection.json`: added `addToCollection`, `item` sections - `threads.json`: added `candidateForm.priceLabel`, `detail` section - `setups.json`: added `namePlaceholder`, `creating`, `emptyState`, `detail`, `profile` sections - `common.json`: added `actions.duplicate` - `catalog.json`: created new namespace for global-items page ### German (parity with English) - `collection.json`: added all missing sections to reach parity with English - `threads.json`: added all missing sections (card, candidateCard, candidateForm, comparisonTable, addToThread, statusBadge, planning, detail) - `setups.json`: added namePlaceholder, creating, emptyState, detail, profile, impact.compareWith - `common.json`: added actions.duplicate, home, imageUpload, profile sections - `catalog.json`: created new namespace with German translations ## Deviations from Plan ### Auto-fixed Issues **1. [Rule 2 - Missing functionality] Created catalog.json namespace** - **Found during:** Task 4 (global-items route) - **Issue:** No dedicated namespace existed for the catalog/discover page strings - **Fix:** Created `src/client/locales/en/catalog.json` and `src/client/locales/de/catalog.json`, registered in i18n.ts - **Files modified:** `src/client/lib/i18n.ts`, both catalog.json files - **Commit:** 2aa156a **2. [Rule 2 - Missing functionality] German locale parity** - **Found during:** Task 4 completion - **Issue:** German locale files were missing large sections added to English in this plan - **Fix:** Added all missing German translations for collection, threads, setups, common namespaces - **Files modified:** de/collection.json, de/threads.json, de/setups.json, de/common.json - **Commit:** 2aa156a ### Skipped Items - Task 5 (onboarding + settings): All 5 onboarding components and settings.tsx were already fully i18n-wired with `useTranslation`. Only language option labels (`"English"`, `"Deutsch"`) remain as literals — these are native language names conventionally left untranslated. ## Known Stubs None — all t() calls reference real locale keys that exist in both en and de files. ## Self-Check: PASSED