docs(34-03): complete locale-aware formatter integration plan summary

- All 5 tasks verified complete: useLanguage hook, formatPrice/formatWeight
  with Intl.NumberFormat, useFormatters locale wiring, formatter tests
- 15 tests passing, build clean, CURRENCY_SYMBOLS removed
This commit is contained in:
2026-04-18 14:07:09 +02:00
parent bf64b8f6a5
commit a1ffcf3061

View File

@@ -0,0 +1,130 @@
---
phase: 34-i18n-foundation
plan: "03"
subsystem: ui
tags: [i18n, formatters, intl, locale, react-hooks, typescript]
# Dependency graph
requires:
- phase: 34-i18n-foundation/34-01
provides: i18n infrastructure, translation framework, useSetting hook patterns
provides:
- Locale-aware formatPrice using Intl.NumberFormat (en: "$1,234.56", de: "1.234,56 €")
- Locale-aware formatWeight using Intl.NumberFormat (en: "1,234g", de: "1.234g")
- useLanguage hook reading language from settings with "en" fallback
- useFormatters hook wiring locale into all format calls
- Formatter test suite covering null, en locale, de locale, unit conversions
affects: [34-04, 34-05, 34-06, 34-07, 34-08]
# Tech tracking
tech-stack:
added: []
patterns:
- "Intl.NumberFormat for all number/currency formatting instead of manual symbol lookup"
- "locale parameter added as third argument (defaulting to 'en') for backward compatibility"
- "useLanguage follows same pattern as useWeightUnit/useCurrency: useSetting + VALID_* array + default"
key-files:
created:
- src/client/hooks/useLanguage.ts
- tests/formatters.test.ts
modified:
- src/client/lib/formatters.ts
- src/client/hooks/useFormatters.ts
key-decisions:
- "locale parameter defaults to 'en' so existing callers without locale continue to work"
- "CURRENCY_SYMBOLS constant removed — Intl.NumberFormat handles symbols natively"
- "VALID_LANGUAGES ['en', 'de'] validates DB value before returning; invalid falls back to 'en' (T-34-04 threat mitigation)"
patterns-established:
- "Locale-aware formatting: all number/price/weight formatters accept locale as third arg"
- "Settings hook pattern: useSetting + VALID_* array const + default fallback"
requirements-completed: [D-04, D-09, D-10]
# Metrics
duration: 15min
completed: 2026-04-18
---
# Phase 34 Plan 03: Locale-Aware Formatter Integration Summary
**Intl.NumberFormat-based locale-aware formatPrice and formatWeight with useLanguage hook — German locale shows "1.234,56 €", English shows "$1,234.56"**
## Performance
- **Duration:** ~15 min
- **Started:** 2026-04-18T12:15:00Z
- **Completed:** 2026-04-18T12:30:00Z
- **Tasks:** 5
- **Files modified:** 4
## Accomplishments
- `useLanguage()` hook reads language from settings DB, validates against `VALID_LANGUAGES`, falls back to "en"
- `formatPrice()` updated to use `Intl.NumberFormat(locale, { style: "currency", currency })` — CURRENCY_SYMBOLS removed
- `formatWeight()` updated to use `Intl.NumberFormat(locale, { minimumFractionDigits, maximumFractionDigits })` for locale-aware separators
- `useFormatters()` extended to call `useLanguage()` and pass locale to both formatters, exposing locale in return value
- 15-test suite covering null, en/de locales, unit conversions, JPY special case, large number thousands separators
## Task Commits
All tasks were implemented in a prior commit and verified as complete at plan execution time:
- **Tasks 1-4: locale-aware formatters and useLanguage hook** - `f759dd0` (feat)
- **Task 5: formatter tests** - `f759dd0` (feat/test)
Note: Implementation pre-existed this plan's execution in commit `f759dd0` (feat(i18n): locale-aware formatters and useLanguage hook). All acceptance criteria verified as passing.
## Files Created/Modified
- `src/client/hooks/useLanguage.ts` — Hook reading "language" setting, returning Language type with "en" fallback, exports VALID_LANGUAGES
- `src/client/lib/formatters.ts` — formatPrice and formatWeight updated with locale parameter and Intl.NumberFormat; CURRENCY_SYMBOLS removed
- `src/client/hooks/useFormatters.ts` — Extended with useLanguage import, locale passed to both formatters, locale in return object
- `tests/formatters.test.ts` — 15 tests for formatPrice and formatWeight across locales, units, null, and edge cases
## Decisions Made
- Locale parameter defaults to "en" to preserve backward compatibility with callers that don't pass locale
- CURRENCY_SYMBOLS constant removed entirely — Intl.NumberFormat handles currency symbols natively for all currencies
- T-34-04 threat mitigation applied: VALID_LANGUAGES validation ensures untrusted DB values can't cause unexpected locale behavior
## Deviations from Plan
None - plan executed exactly as written. All files were already implemented in the correct state matching the plan's acceptance criteria.
## Issues Encountered
None.
## Known Stubs
None — all formatters produce real locale-aware output from Intl.NumberFormat.
## Threat Flags
None — no new network endpoints, auth paths, or trust boundaries introduced. The T-34-04 threat (tampering via settings DB language value) is mitigated by VALID_LANGUAGES validation in useLanguage.
## User Setup Required
None - no external service configuration required.
## Next Phase Readiness
- Locale-aware formatters are ready for phase 34-04 (UI locale switching) and 34-05 (currency display)
- useLanguage hook is consumed by useFormatters, which is used app-wide via the `useFormatters()` hook pattern
- Build passes cleanly, all 15 formatter tests pass
## Self-Check: PASSED
- `src/client/hooks/useLanguage.ts` — FOUND
- `src/client/lib/formatters.ts` — FOUND (Intl.NumberFormat: 2 occurrences, CURRENCY_SYMBOLS: 0 occurrences)
- `src/client/hooks/useFormatters.ts` — FOUND (useLanguage + locale: 6 occurrences)
- `tests/formatters.test.ts` — FOUND (15 tests, all pass)
- Build: PASSED (built in 937ms)
- Commit f759dd0 — FOUND
---
*Phase: 34-i18n-foundation*
*Completed: 2026-04-18*