diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 8dfbf70..3fafa2e 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -141,7 +141,7 @@ Phases execute in numeric order: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 | 4. RBAC | 3/3 | Complete | 2026-03-24 | | 5. Employee Design | 4/4 | Complete | 2026-03-25 | | 6. Web Chat | 3/3 | Complete | 2026-03-25 | -| 7. Multilanguage | 2/4 | In Progress| | +| 7. Multilanguage | 3/4 | In Progress| | --- diff --git a/.planning/STATE.md b/.planning/STATE.md index 308b239..4e33601 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,14 +3,14 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone status: completed -stopped_at: Completed 07-multilanguage-02-PLAN.md -last_updated: "2026-03-25T22:30:25.808Z" +stopped_at: Completed 07-multilanguage-03-PLAN.md +last_updated: "2026-03-25T23:04:58.017Z" last_activity: 2026-03-23 — Completed 03-02 onboarding wizard, Slack OAuth, BYO API keys progress: total_phases: 7 completed_phases: 6 total_plans: 29 - completed_plans: 27 + completed_plans: 28 percent: 100 --- @@ -79,6 +79,7 @@ Progress: [██████████] 100% | Phase 06-web-chat P03 | verification | 1 tasks | 0 files | | Phase 07-multilanguage P01 | 7min | 2 tasks | 12 files | | Phase 07-multilanguage P02 | 9min | 2 tasks | 14 files | +| Phase 07-multilanguage P03 | 45min | 2 tasks | 48 files | ## Accumulated Context @@ -177,6 +178,8 @@ Recent decisions affecting current work: - [Phase 07-multilanguage]: i18n/locales.ts created to separate client-safe constants from server-only i18n/request.ts (next/headers import) - [Phase 07-multilanguage]: Cookie name konstruct_locale for cookie-based locale with no URL routing - [Phase 07-multilanguage]: LanguageSwitcher isPreAuth prop skips DB PATCH and session.update() on login page +- [Phase 07-multilanguage]: onboarding/page.tsx uses getTranslations() not useTranslations() — Server Component requires next-intl/server import +- [Phase 07-multilanguage]: billing-status.tsx trialEnds key uses only {date} param — boolean ICU params rejected by TypeScript strict mode ### Roadmap Evolution @@ -192,6 +195,6 @@ None — all phases complete. ## Session Continuity -Last session: 2026-03-25T22:30:25.805Z -Stopped at: Completed 07-multilanguage-02-PLAN.md +Last session: 2026-03-25T23:04:58.013Z +Stopped at: Completed 07-multilanguage-03-PLAN.md Resume file: None diff --git a/.planning/phases/07-multilanguage/07-03-SUMMARY.md b/.planning/phases/07-multilanguage/07-03-SUMMARY.md new file mode 100644 index 0000000..3371fa7 --- /dev/null +++ b/.planning/phases/07-multilanguage/07-03-SUMMARY.md @@ -0,0 +1,160 @@ +--- +phase: 07-multilanguage +plan: "03" +subsystem: portal-i18n +tags: + - i18n + - next-intl + - portal + - components + - pages +dependency_graph: + requires: + - 07-01 + - 07-02 + provides: + - fully-translated-portal-ui + affects: + - packages/portal/components + - packages/portal/app + - packages/portal/messages +tech_stack: + added: [] + patterns: + - next-intl useTranslations() in client components + - next-intl getTranslations() in server components + - ICU message format with named params + - useTemplates(locale) locale-aware API call +key_files: + created: [] + modified: + - packages/portal/components/nav.tsx + - packages/portal/components/agent-designer.tsx + - packages/portal/components/billing-status.tsx + - packages/portal/components/budget-alert-badge.tsx + - packages/portal/components/chat-message.tsx + - packages/portal/components/chat-sidebar.tsx + - packages/portal/components/chat-window.tsx + - packages/portal/components/employee-wizard.tsx + - packages/portal/components/impersonation-banner.tsx + - packages/portal/components/message-volume-chart.tsx + - packages/portal/components/onboarding-stepper.tsx + - packages/portal/components/provider-cost-chart.tsx + - packages/portal/components/subscription-card.tsx + - packages/portal/components/template-gallery.tsx + - packages/portal/components/tenant-form.tsx + - packages/portal/components/tenant-switcher.tsx + - packages/portal/components/wizard-steps/step-role.tsx + - packages/portal/components/wizard-steps/step-persona.tsx + - packages/portal/components/wizard-steps/step-tools.tsx + - packages/portal/components/wizard-steps/step-channels.tsx + - packages/portal/components/wizard-steps/step-escalation.tsx + - packages/portal/components/wizard-steps/step-review.tsx + - packages/portal/app/(dashboard)/dashboard/page.tsx + - packages/portal/app/(dashboard)/agents/page.tsx + - packages/portal/app/(dashboard)/agents/[id]/page.tsx + - packages/portal/app/(dashboard)/agents/new/page.tsx + - packages/portal/app/(dashboard)/agents/new/templates/page.tsx + - packages/portal/app/(dashboard)/agents/new/wizard/page.tsx + - packages/portal/app/(dashboard)/agents/new/advanced/page.tsx + - packages/portal/app/(dashboard)/billing/page.tsx + - packages/portal/app/(dashboard)/chat/page.tsx + - packages/portal/app/(dashboard)/usage/page.tsx + - packages/portal/app/(dashboard)/usage/[tenantId]/page.tsx + - packages/portal/app/(dashboard)/settings/api-keys/page.tsx + - packages/portal/app/(dashboard)/users/page.tsx + - packages/portal/app/(dashboard)/admin/users/page.tsx + - packages/portal/app/(dashboard)/tenants/page.tsx + - packages/portal/app/(dashboard)/tenants/new/page.tsx + - packages/portal/app/(dashboard)/tenants/[id]/page.tsx + - packages/portal/app/(dashboard)/onboarding/page.tsx + - packages/portal/app/(dashboard)/onboarding/steps/connect-channel.tsx + - packages/portal/app/(dashboard)/onboarding/steps/configure-agent.tsx + - packages/portal/app/(dashboard)/onboarding/steps/test-message.tsx + - packages/portal/app/invite/[token]/page.tsx + - packages/portal/lib/queries.ts + - packages/portal/messages/en.json + - packages/portal/messages/es.json + - packages/portal/messages/pt.json +decisions: + - "onboarding/page.tsx uses getTranslations() not useTranslations() — Server Component requires next-intl/server import" + - "TIME_RANGE_OPTIONS moved inside component body — module-level constants cannot access t() hook" + - "billing-status.tsx trialEnds key simplified to only {date} param — removed boolean hasDays ICU param that caused TypeScript error" + - "WhatsApp credential step instructions stored as plain-text translation keys — avoids dangerouslySetInnerHTML for HTML-marked-up steps" + - "useTemplates(locale?) accepts optional locale and passes as ?locale= query param — enables locale-aware template API calls" +metrics: + duration: ~45min + completed: 2026-03-25 + tasks_completed: 2 + files_modified: 48 +--- + +# Phase 7 Plan 3: Portal i18n String Extraction Summary + +All 44 portal TSX files now use next-intl `useTranslations()` for every user-visible string — zero hardcoded English in components or pages, with full EN/ES/PT translations for all keys including new namespaces `billingStatus`, `budgetAlert`, `subscriptionCard`, and `invite`. + +## Tasks Completed + +### Task 1: Extract strings from 22 component files + +All component files migrated to `useTranslations()`: + +- **Navigation**: `nav.tsx` — nav labels, sign out +- **Tenant management**: `tenant-form.tsx`, `tenant-switcher.tsx` — form labels, switcher UI +- **Billing**: `billing-status.tsx`, `budget-alert-badge.tsx`, `subscription-card.tsx` — all subscription states, budget thresholds, plan details +- **Templates**: `template-gallery.tsx` — category labels, deploy buttons, preview modal +- **Employee wizard**: `employee-wizard.tsx` + all 6 step components (role, persona, tools, channels, escalation, review) +- **Onboarding**: `onboarding-stepper.tsx`, `impersonation-banner.tsx` +- **Chat**: `chat-sidebar.tsx`, `chat-window.tsx`, `chat-message.tsx`, `message-volume-chart.tsx`, `provider-cost-chart.tsx` +- **Agent designer**: `agent-designer.tsx` + +### Task 2: Extract strings from 22 page files + +All page files migrated to `useTranslations()`: + +- **Core pages**: dashboard, chat, billing, usage (list + detail) +- **Agent pages**: agents list, agent detail, new agent picker, templates, wizard, advanced designer +- **Settings**: api-keys +- **User management**: users, admin/users +- **Tenant management**: tenants list, tenant detail, new tenant +- **Onboarding**: onboarding page (Server Component with `getTranslations`), plus all 3 step components (connect-channel, configure-agent, test-message) +- **Public**: invite accept page + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 1 - Bug] Fixed TypeScript error in billing-status.tsx** +- **Found during:** Task 1 +- **Issue:** `hasDays: days !== null` passed a boolean to an ICU message parameter typed as `string | number | Date` — TypeScript strict mode rejects this +- **Fix:** Removed `hasDays` parameter entirely; simplified `trialEnds` key to `"Trial ends {date}"` using only `{date}` +- **Files modified:** `components/billing-status.tsx`, `messages/en.json`, `messages/es.json`, `messages/pt.json` +- **Commit:** 20f4c5b + +**2. [Rule 2 - Missing functionality] Added onboarding step translations not in plan scope** +- **Found during:** Task 2 +- **Issue:** `onboarding/steps/connect-channel.tsx`, `configure-agent.tsx`, `test-message.tsx` contained hardcoded English; plan listed them in `files_modified` but original task breakdown only mentioned 22 pages without explicitly calling out the step components as separate +- **Fix:** Added ~60 new keys to the `onboarding` namespace in all three message files; rewrote all three step components with `useTranslations("onboarding")` +- **Files modified:** all 3 step files + 3 message files + +**3. [Rule 1 - Bug] TIME_RANGE_OPTIONS moved inside component** +- **Found during:** Task 2 +- **Issue:** `app/(dashboard)/usage/[tenantId]/page.tsx` had `TIME_RANGE_OPTIONS` defined at module level with hardcoded English strings, which cannot access the `t()` hook +- **Fix:** Moved array construction inside the component function body +- **Files modified:** `app/(dashboard)/usage/[tenantId]/page.tsx` + +**4. [Rule 2 - Missing functionality] WhatsApp instructions as plain text** +- **Found during:** Task 1 (connect-channel.tsx) +- **Issue:** Original file used `` HTML inside `
  • ` elements for emphasis in credential instructions; direct translation keys can't hold HTML safely +- **Fix:** Stored instructions as plain-text translation keys (no HTML); bold emphasis replaced with readable text +- **Files modified:** `components/wizard-steps/step-channels.tsx` was already in scope; `onboarding/steps/connect-channel.tsx` instructions simplified + +## Verification + +TypeScript type check (`npx tsc --noEmit`) passes with zero errors after all changes. + +## Self-Check: PASSED + +Files created/modified confirmed present. Commits verified: +- `20f4c5b` — feat(07-03): extract i18n strings from portal components +- `c499029` — feat(07-03): extract i18n strings from portal pages