Files
2026-05-27 23:29:53 +01:00

5.7 KiB

Tasks — react-ui i18n deferred tooling

Three independent workstreams. Stories (Phase 1) is the largest; the two scripts (Phases 2, 3) are smaller and can run in parallel.

Phase 1 — Stories for the new i18n surface

  • 1.1 src/i18n/formatted-number/formatted-number.stories.tsx — default + playground + variants (Latin / Arabic-Indic / percent / unit notation, as polymorphism). Wrapped in <TranslationProvider> + <RegistryProvider> + <ReactUiI18nBridge>.
  • 1.2 src/i18n/formatted-currency/formatted-currency.stories.tsx — USD / EUR / GBP / JPY across en-GB / fr-FR / zh-CN, display modes (symbol / narrowSymbol / code / name).
  • 1.3 src/i18n/formatted-date/formatted-date.stories.tsx — Date / ISO / epoch ms inputs; preset names + raw Intl.DateTimeFormatOptions; invalid-input renders empty.
  • 1.4 src/i18n/formatted-list/formatted-list.stories.tsx — conjunction / disjunction / unit; long / short / narrow.
  • 1.5 src/i18n/formatted-relative-time/formatted-relative-time.stories.tsx — auto-mode (with fakeClock for deterministic story snapshots), explicit unit, future / past.
  • 1.6 src/i18n/plural/plural.stories.tsx — en-GB / ar-AE / ru-RU showing different category buckets.
  • 1.7 src/i18n/formatted-message/formatted-message.stories.tsx — rich-text tag interpolation, plural via count.
  • 1.8 src/i18n/react-ui-i18n-bridge/react-ui-i18n-bridge.stories.tsx — Radix <DirectionProvider> propagation demo (popover, dropdown-menu, dialog, tooltip rendered side-by-side under en-GB and ar-AE).
  • 1.9 src/i18n/formatted-cell/formatted-cell.stories.tsx — composed inside <DataTable> columns for each formatter kind.
  • 1.10 src/i18n/validation-message-bridge/validation-message-bridge.stories.tsx — bridge inside <Alert> and <Toast>.
  • 1.11 src/components/input/input-number/input-number.stories.tsx — en-GB / de-DE / ar-AE locales, controlled / uncontrolled, percent / currency display options.
  • 1.12 Story-snapshot test (mirroring existing *.stories.test.tsx pattern in react-ui) for every new story.

Phase 2 — check:i18n-keys translation key drift gate

  • 2.1 Pick the AST parser already used elsewhere in the repo for source walks (@babel/parser is the typical choice; verify the catalog).
  • 2.2 Author scripts/check-i18n-keys.ts. Walk src/components/**/*.{ts,tsx} and src/i18n/**/*.{ts,tsx}. Detect:
    • t("react-ui.…") / t("react-ui.…", …)
    • tDynamic("react-ui.…")
    • <FormattedMessage i18nKey="react-ui.…" />
    • <Trans i18nKey="react-ui.…" />
  • 2.3 Diff discovered keys against src/locales/en-GB.json. Build the orphan list and the missing list.
  • 2.4 Author scripts/check-i18n-keys.test.ts — fixture directory exercises both diagnostics + the happy path.
  • 2.5 Add "check:i18n-keys": "bun scripts/check-i18n-keys.ts" to package.json::scripts.
  • 2.6 Wire check:i18n-keys into turbo.json's lint pipeline so CI fails on drift.
  • 2.7 Run the script against the current source — expect zero diagnostics. If diagnostics appear, file each as a separate fix in this change.

Phase 3 — check:registry-eject shadcn ejection compile gate

  • 3.1 Confirm the registry transform's exact rewriting rules (which import specifiers are rewritten, which preserved). Document at the top of the script.
  • 3.2 Author scripts/check-registry-eject.ts:
    • Read every registry/r/<name>.json.
    • For each entry: copy listed source files into mkdtemp directory.
    • Apply registry transform.
    • Synthesize a consumer tsconfig.json (extends @suaveplan/typescript-config/library.json, declares paths for @suaveplan/react-i18n + React peers).
    • Run tsc --noEmit over the transformed tree.
    • On failure, surface the underlying tsc diagnostics with the registry-entry name as context.
  • 3.3 Detect missing registry entries — for every directory in src/components/**/ and src/i18n/**/ that has a public default-exporting *.tsx, assert the matching registry/r/<name>.json exists.
  • 3.4 Author scripts/check-registry-eject.test.ts — happy-path test (pick one trivial component + verify ejection compiles); failure-path tests (corrupt transform output, drop a registry entry).
  • 3.5 Add "check:registry-eject": "bun scripts/check-registry-eject.ts" to package.json::scripts.
  • 3.6 Wire check:registry-eject into turbo.json's lint pipeline.
  • 3.7 Run the script against the current registry — expect zero diagnostics.

Phase 4 — Pre-publish gate + spec fold

  • 4.1 bunx turbo lint typecheck test --filter=@suaveplan/react-ui green.
  • 4.2 bunx turbo test:coverage --filter=@suaveplan/react-ui ≥ 100 / 100 / 100 / 100 (story-snapshot + script tests must contribute to coverage).
  • 4.3 bunx turbo build --filter=@suaveplan/react-ui green.
  • 4.4 bun run check:i18n-keys zero-defect.
  • 4.5 bun run check:registry-eject zero-defect.
  • 4.6 §13 banned-pattern / missing-.md / barrel-shape / runner-import scans clean.
  • 4.7 Downstream sweep bunx turbo test --filter=...@suaveplan/react-ui green (sanity check; no runtime surface change expected).
  • 4.8 Fold spec deltas into openspec/specs/react-ui-i18n/spec.md. The two new scripts get their own Requirements with verification scenarios; stories are an artifact-presence requirement (one Scenario per primitive: <feature>.stories.tsx exists).
  • 4.9 Update STATUS.md to reflect the closure of the deferred items.
  • 4.10 Run bunx markdownlint-cli2 --fix across touched markdown.
  • 4.11 Move openspec/changes/react-ui-i18n-deferred-tooling/ → openspec/archive/<yyyy-mm-dd>-react-ui-i18n-deferred-tooling/.