docs(34-06): complete i18n gap closure — routes and components plan summary
This commit is contained in:
136
.planning/phases/34-i18n-foundation/34-06-SUMMARY.md
Normal file
136
.planning/phases/34-i18n-foundation/34-06-SUMMARY.md
Normal file
@@ -0,0 +1,136 @@
|
||||
---
|
||||
phase: 34-i18n-foundation
|
||||
plan: "06"
|
||||
subsystem: client/i18n
|
||||
tags: [i18n, react-i18next, localization, german, components, routes]
|
||||
dependency_graph:
|
||||
requires: ["34-01", "34-02", "34-05"]
|
||||
provides: ["fully-wired-i18n-components", "translated-routes"]
|
||||
affects: ["client/routes/index", "client/routes/profile", "client/routes/settings", "client/components/*"]
|
||||
tech_stack:
|
||||
added: []
|
||||
patterns: ["useTranslation with namespace arrays", "plural keys with count interpolation", "t() with defaultValue fallback"]
|
||||
key_files:
|
||||
created: []
|
||||
modified:
|
||||
- src/client/routes/index.tsx
|
||||
- src/client/routes/profile.tsx
|
||||
- src/client/routes/settings.tsx
|
||||
- src/client/components/ThreadTabs.tsx
|
||||
- src/client/components/PlanningView.tsx
|
||||
- src/client/components/TotalsBar.tsx
|
||||
- src/client/components/ThreadCard.tsx
|
||||
- src/client/components/PublicSetupCard.tsx
|
||||
- src/client/components/SetupImpactSelector.tsx
|
||||
- src/client/components/ClassificationBadge.tsx
|
||||
- src/client/components/ImpactDeltaBadge.tsx
|
||||
- src/client/components/ImageUpload.tsx
|
||||
- src/client/locales/en/common.json
|
||||
- src/client/locales/en/collection.json
|
||||
- src/client/locales/en/setups.json
|
||||
- src/client/locales/en/settings.json
|
||||
- src/client/locales/en/threads.json
|
||||
- src/client/locales/de/common.json
|
||||
- src/client/locales/de/collection.json
|
||||
- src/client/locales/de/setups.json
|
||||
- src/client/locales/de/settings.json
|
||||
- src/client/locales/de/threads.json
|
||||
decisions:
|
||||
- "DashboardCard skipped: component renders only props (title, stats, emptyText) with no hardcoded UI strings — caller is responsible for translation"
|
||||
- "ClassificationBadge uses t() with defaultValue fallback instead of static lookup map — handles unknown classification values gracefully"
|
||||
- "Intl.DateTimeFormat locale changed from hardcoded 'en-US' to undefined in profile.tsx — uses browser locale for member-since date formatting"
|
||||
- "threads.empty.noThreads changed from 'No research threads yet' to 'No threads found' to match PlanningView filtered-results context"
|
||||
metrics:
|
||||
duration: "~30 minutes"
|
||||
completed: "2026-04-17T18:26:54Z"
|
||||
tasks_completed: 2
|
||||
files_modified: 22
|
||||
requirements: [D-01, D-02, D-03]
|
||||
---
|
||||
|
||||
# Phase 34 Plan 06: i18n Gap Closure — Routes and Components Summary
|
||||
|
||||
Wired `useTranslation` into all routes and components that had hardcoded English strings, closing the UAT-identified gap where only the settings page, nav bar, and FAB were translated.
|
||||
|
||||
## What Was Built
|
||||
|
||||
**Task 1 — Routes and settings currency suggestion (commit 755c0ab):**
|
||||
- `routes/index.tsx`: Section headings (Popular Setups, Recently Added, Trending Categories) now use `t("home.*")` from `common` namespace
|
||||
- `routes/profile.tsx`: All sections (Account, Security, Danger Zone) fully translated — email management, password change, account deletion flow
|
||||
- `routes/settings.tsx`: Currency suggestion banner text uses `t("currency.suggestion", { symbol, code })` with interpolation; Switch button and Dismiss aria-label use t()
|
||||
- Added `home`, `profile`, `imageUpload` sections to en/de common.json
|
||||
- Added `currency.suggestion`, `currency.switch`, `showConversions` to en/de settings.json
|
||||
|
||||
**Task 2 — 10 remaining components (commit 480abdd):**
|
||||
- `ThreadTabs.tsx`: Tab labels (My Gear → Gear, Planning, Setups) via `collection` namespace
|
||||
- `PlanningView.tsx`: Section heading, active/resolved tabs, full empty state (title + 3 steps + CTA), "No threads found" — via `threads` namespace
|
||||
- `TotalsBar.tsx`: "Sign in" link via `common.auth.signIn`
|
||||
- `ThreadCard.tsx`: "Resolved" badge and candidate count with plural form (`{{count}} candidates` / `{{count}} candidate`)
|
||||
- `PublicSetupCard.tsx`: "by {{name}}" and "Anonymous" fallback; item count with plural form
|
||||
- `SetupImpactSelector.tsx`: "Compare with setup..." placeholder option
|
||||
- `ClassificationBadge.tsx`: base/worn/consumable labels via `collection.classificationBadge.*` with defaultValue fallback
|
||||
- `ImpactDeltaBadge.tsx`: "(add)" mode label via `setups.impact.adding`
|
||||
- `ImageUpload.tsx`: "Click to add photo", invalid type error, file too large error, upload failed error
|
||||
- `DashboardCard.tsx`: Correctly skipped — all strings are props from caller
|
||||
|
||||
## New Locale Keys Added
|
||||
|
||||
**en/de common.json:** `home.{popularSetups,recentlyAdded,trendingCategories}`, `imageUpload.{clickToAdd,invalidType,tooLarge,uploadFailed}`, `profile.{title,account,accountInfo,email,noEmail,change,newEmailPlaceholder,updating,updateEmail,emailUpdated,memberSince,security,managePassword,currentPassword,newPassword,password,confirmPassword,passwordRequirements,passwordUpdated,changingPassword,changePassword,setPassword,dangerZone,dangerZoneDescription,deleteAccount,deleteConfirmMessage,deleteConfirmPlaceholder}`
|
||||
|
||||
**en/de settings.json:** `currency.{suggestion,switch}`, `showConversions.{title,description}`
|
||||
|
||||
**en/de collection.json:** `tabs.setups`, `totals.{totalWeight,totalCost}`, `classificationBadge.{base,worn,consumable}`
|
||||
|
||||
**en/de setups.json:** `card.{by,anonymous}`, `impact.compareWith`
|
||||
|
||||
**en/de threads.json:** `card.{candidates,candidates_one}`, `planning.{title,emptyTitle,createFirst,step1Title,step1Description,step2Title,step2Description,step3Title,step3Description}`
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 1 - Bug] Fixed hardcoded `en-US` locale in profile.tsx date formatting**
|
||||
- **Found during:** Task 1
|
||||
- **Issue:** `Intl.DateTimeFormat("en-US", ...)` for "Member since" date used hardcoded locale
|
||||
- **Fix:** Changed to `Intl.DateTimeFormat(undefined, ...)` to use browser's locale
|
||||
- **Files modified:** src/client/routes/profile.tsx
|
||||
|
||||
**2. [Rule 2 - Missing] Fixed ASCII fallbacks in de/common.json filter section**
|
||||
- **Found during:** Task 1 locale update
|
||||
- **Issue:** Existing de/common.json had `"Gegenstaenden"` instead of `"Gegenständen"` in filter.showing
|
||||
- **Fix:** Updated to use proper umlauts when touching those strings
|
||||
- **Files modified:** src/client/locales/de/common.json
|
||||
|
||||
## Verification
|
||||
|
||||
- `grep -c "useTranslation" src/client/routes/index.tsx` → 4
|
||||
- `grep -c "useTranslation" src/client/routes/profile.tsx` → 5
|
||||
- `grep -c "useTranslation" src/client/routes/settings.tsx` → 1 (already had it)
|
||||
- All 10 components (minus DashboardCard which has no hardcoded strings) have useTranslation
|
||||
- `bun run build` passes with no errors
|
||||
- `bun test tests/i18n/locales.test.ts` → 19 pass, 0 fail
|
||||
|
||||
## Commits
|
||||
|
||||
| Task | Commit | Description |
|
||||
|------|--------|-------------|
|
||||
| Task 1 | 755c0ab | feat(34-06): wire useTranslation into routes and settings currency suggestion |
|
||||
| Task 2 | 480abdd | feat(34-06): wire useTranslation into 10 remaining components |
|
||||
|
||||
## Known Stubs
|
||||
|
||||
None — all translated strings are wired to real locale data.
|
||||
|
||||
## Threat Flags
|
||||
|
||||
None — translation strings are static bundled content, not user input. React JSX escaping prevents XSS per T-34-07.
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- src/client/routes/index.tsx: exists, contains useTranslation
|
||||
- src/client/routes/profile.tsx: exists, contains useTranslation
|
||||
- src/client/routes/settings.tsx: exists, contains useTranslation
|
||||
- All 10 components modified: confirmed via grep
|
||||
- Commits 755c0ab and 480abdd: confirmed in git log
|
||||
- Build: passed
|
||||
- i18n parity tests: 19/19 passed
|
||||
Reference in New Issue
Block a user