295 lines
14 KiB
Markdown
295 lines
14 KiB
Markdown
---
|
|
phase: 07-multilanguage
|
|
plan: 03
|
|
type: execute
|
|
wave: 2
|
|
depends_on:
|
|
- "07-01"
|
|
- "07-02"
|
|
files_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/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)/chat/page.tsx
|
|
- packages/portal/app/(dashboard)/billing/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/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
|
|
autonomous: true
|
|
requirements:
|
|
- I18N-01
|
|
- I18N-04
|
|
- I18N-05
|
|
|
|
must_haves:
|
|
truths:
|
|
- "Every user-visible string in the portal uses useTranslations() instead of hardcoded English"
|
|
- "Navigation labels render in the selected language"
|
|
- "Agent designer, wizard, and template gallery are fully translated"
|
|
- "Onboarding flow steps are fully translated"
|
|
- "Error messages and validation text render in the selected language"
|
|
- "Chat UI, billing, usage, and all other pages are translated"
|
|
artifacts:
|
|
- path: "packages/portal/components/nav.tsx"
|
|
provides: "Translated navigation labels"
|
|
contains: "useTranslations"
|
|
- path: "packages/portal/components/employee-wizard.tsx"
|
|
provides: "Translated wizard UI"
|
|
contains: "useTranslations"
|
|
- path: "packages/portal/components/template-gallery.tsx"
|
|
provides: "Translated template cards with locale-aware API calls"
|
|
contains: "useTranslations"
|
|
- path: "packages/portal/app/(dashboard)/chat/page.tsx"
|
|
provides: "Translated chat interface"
|
|
contains: "useTranslations"
|
|
key_links:
|
|
- from: "All portal components"
|
|
to: "packages/portal/messages/{locale}.json"
|
|
via: "useTranslations() hook reading from NextIntlClientProvider context"
|
|
pattern: "useTranslations"
|
|
- from: "packages/portal/components/template-gallery.tsx"
|
|
to: "/api/portal/templates?locale="
|
|
via: "Locale query param passed to templates API"
|
|
pattern: "locale"
|
|
---
|
|
|
|
<objective>
|
|
Extract all hardcoded English strings from every portal page and component, replacing them with `useTranslations()` calls that read from the en/es/pt message files created in Plan 02.
|
|
|
|
Purpose: This is the core localization work. Every user-visible string in every TSX file must be replaced with a `t('key')` call. Without this, the message files and i18n infrastructure from Plan 02 have no effect.
|
|
Output: All 40+ portal TSX files updated with useTranslations() calls. Zero hardcoded English strings remain in user-visible UI.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@/home/adelorenzo/.claude/get-shit-done/workflows/execute-plan.md
|
|
@/home/adelorenzo/.claude/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@.planning/STATE.md
|
|
@.planning/phases/07-multilanguage/07-CONTEXT.md
|
|
@.planning/phases/07-multilanguage/07-RESEARCH.md
|
|
@.planning/phases/07-multilanguage/07-01-SUMMARY.md
|
|
@.planning/phases/07-multilanguage/07-02-SUMMARY.md
|
|
|
|
<interfaces>
|
|
<!-- next-intl usage pattern (from Plan 02) -->
|
|
```typescript
|
|
// In Client Components ('use client'):
|
|
import { useTranslations } from 'next-intl';
|
|
const t = useTranslations('namespace');
|
|
// Then: <h1>{t('title')}</h1>
|
|
|
|
// In Server Components:
|
|
import { useTranslations } from 'next-intl';
|
|
const t = useTranslations('namespace');
|
|
// Same API — works in both
|
|
|
|
// Message file structure (from Plan 02):
|
|
// messages/en.json has nested keys: nav.dashboard, agents.pageTitle, etc.
|
|
// useTranslations('nav') gives t('dashboard') -> "Dashboard"
|
|
```
|
|
|
|
<!-- Template gallery needs locale-aware API call -->
|
|
```typescript
|
|
// Plan 01 adds ?locale= param to templates API
|
|
// Template gallery must pass current locale when fetching:
|
|
// GET /api/portal/templates?locale=es
|
|
```
|
|
</interfaces>
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Extract strings from all components (nav, sidebar, forms, wizards, chat)</name>
|
|
<files>
|
|
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
|
|
</files>
|
|
<action>
|
|
For EVERY component listed, apply this transformation:
|
|
|
|
1. Add `import { useTranslations } from 'next-intl';` (for 'use client' components)
|
|
2. At the top of the component function, add `const t = useTranslations('namespace');` where namespace matches the message file key group (e.g., 'nav' for nav.tsx, 'wizard' for wizard steps, 'chat' for chat components)
|
|
3. Replace every hardcoded English string with `t('keyName')` — use the exact keys from the en.json message file created in Plan 02
|
|
4. For strings with interpolation (e.g., "Welcome, {name}"), use `t('welcome', { name })` and ensure the message file uses ICU format: "Welcome, {name}"
|
|
5. For nav.tsx specifically: replace the hardcoded label strings in the navItems array with t() calls. Since navItems is defined outside the component, move the labels inside the component function or use a computed items pattern.
|
|
|
|
Specific component notes:
|
|
- nav.tsx: navItems labels ("Dashboard", "Employees", etc.) -> t('dashboard'), t('employees'), etc. "Sign out" -> t('signOut')
|
|
- template-gallery.tsx: Pass locale to templates API call: fetch(`/api/portal/templates?locale=${currentLocale}`). Get current locale from cookie or useLocale() from next-intl.
|
|
- employee-wizard.tsx: All step labels, button text, form labels
|
|
- onboarding-stepper.tsx: Step titles and descriptions
|
|
- agent-designer.tsx: Field labels, button text, placeholders
|
|
- chat-window.tsx: "Type a message", "Send", placeholder text
|
|
- chat-sidebar.tsx: "New Conversation", "No conversations"
|
|
- billing-status.tsx: Status labels, button text
|
|
- subscription-card.tsx: Plan names, subscribe/manage buttons
|
|
- tenant-form.tsx: Form labels, submit buttons
|
|
- tenant-switcher.tsx: "Select tenant", "All tenants"
|
|
- impersonation-banner.tsx: Banner text, stop button
|
|
- budget-alert-badge.tsx: "No limit set", budget alert text
|
|
|
|
Do NOT translate:
|
|
- Component prop names or internal variable names
|
|
- CSS class strings
|
|
- API endpoint URLs
|
|
- Console.log messages
|
|
- aria-label values that are already descriptive (but DO translate user-visible aria-labels)
|
|
</action>
|
|
<verify>
|
|
<automated>cd /home/adelorenzo/repos/konstruct/packages/portal && npx next build 2>&1 | tail -20</automated>
|
|
</verify>
|
|
<done>
|
|
- All 22 component files use useTranslations() for every user-visible string
|
|
- No hardcoded English strings remain in component files (except technical strings like URLs, class names)
|
|
- Template gallery passes locale to API
|
|
- Portal builds successfully
|
|
</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Extract strings from all page files (dashboard, agents, chat, billing, usage, etc.)</name>
|
|
<files>
|
|
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)/chat/page.tsx
|
|
packages/portal/app/(dashboard)/billing/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
|
|
</files>
|
|
<action>
|
|
For EVERY page file listed, apply the same transformation pattern as Task 1:
|
|
|
|
1. Add `import { useTranslations } from 'next-intl';`
|
|
2. Add `const t = useTranslations('namespace');` using the appropriate namespace
|
|
3. Replace all hardcoded English strings with `t('key')` calls
|
|
|
|
Page-specific notes:
|
|
- dashboard/page.tsx: "Dashboard", "Welcome back", stats labels -> t('dashboard.*')
|
|
- agents/page.tsx: "AI Employees", "New Employee", empty state text -> t('agents.*')
|
|
- agents/[id]/page.tsx: Agent detail labels, edit/delete buttons -> t('agentDesigner.*')
|
|
- agents/new/page.tsx: Three creation options text -> t('agentNew.*')
|
|
- agents/new/templates/page.tsx: Template gallery page title -> t('templates.*')
|
|
- agents/new/wizard/page.tsx: Wizard page wrapper -> t('wizard.*')
|
|
- agents/new/advanced/page.tsx: Advanced mode labels -> t('agentDesigner.*')
|
|
- chat/page.tsx: Chat page labels -> t('chat.*')
|
|
- billing/page.tsx: Billing page labels, plan info -> t('billing.*')
|
|
- usage/page.tsx & usage/[tenantId]/page.tsx: Usage labels, chart titles -> t('usage.*')
|
|
- settings/api-keys/page.tsx: API key management labels -> t('apiKeys.*')
|
|
- users/page.tsx: User management, invite labels -> t('users.*')
|
|
- admin/users/page.tsx: Platform admin user list -> t('adminUsers.*')
|
|
- tenants pages: Tenant management labels -> t('tenants.*')
|
|
- onboarding pages + steps: All onboarding UI -> t('onboarding.*')
|
|
- invite/[token]/page.tsx: Invitation acceptance page -> t('invite.*') (add invite namespace to message files if not already present)
|
|
|
|
After all string extraction is complete, do a final review of messages/en.json, messages/es.json, and messages/pt.json to ensure every key used by t() exists in all three files. Add any missing keys discovered during extraction.
|
|
|
|
IMPORTANT: If any page is a Server Component (no 'use client'), useTranslations still works the same way in next-intl v4 — it reads from the server context set up by i18n/request.ts. No change needed.
|
|
</action>
|
|
<verify>
|
|
<automated>cd /home/adelorenzo/repos/konstruct/packages/portal && npx next build 2>&1 | tail -20</automated>
|
|
</verify>
|
|
<done>
|
|
- All 22 page files use useTranslations() for every user-visible string
|
|
- No hardcoded English strings remain in any page file
|
|
- All translation keys used in t() calls exist in en.json, es.json, and pt.json
|
|
- Portal builds successfully with zero errors
|
|
</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
- Portal builds: `cd packages/portal && npx next build`
|
|
- Grep for remaining hardcoded strings: search for obvious English strings that should be translated
|
|
- All message file keys are consistent across en.json, es.json, pt.json
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- Every user-visible string in the portal uses useTranslations()
|
|
- All three message files (en/es/pt) have matching key structures
|
|
- Template gallery passes locale to API for translated template content
|
|
- Portal builds without errors
|
|
- Zero hardcoded English strings remain in user-facing UI
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/07-multilanguage/07-03-SUMMARY.md`
|
|
</output>
|