14 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 07-multilanguage | 02 | execute | 1 |
|
true |
|
|
Purpose: Establishes the i18n framework so all portal components can use useTranslations(). Creates the complete en/es/pt message files with all translation keys for every page and component. This plan does the infrastructure setup AND the translation file authoring, while Plan 03 does the actual string extraction (replacing hardcoded strings with t() calls).
Output: Working next-intl setup, complete message files in 3 languages, language switcher in sidebar and login page.
<execution_context> @/home/adelorenzo/.claude/get-shit-done/workflows/execute-plan.md @/home/adelorenzo/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/07-multilanguage/07-CONTEXT.md @.planning/phases/07-multilanguage/07-RESEARCH.md From packages/portal/app/layout.tsx: ```typescript // Currently: static html lang="en", no i18n provider export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en" className="..."> {children} </html> ); } ```From packages/portal/components/nav.tsx:
'use client';
// navItems array has hardcoded labels: "Dashboard", "Employees", "Chat", etc.
// User section at bottom with sign out button
export function Nav() { ... }
From packages/portal/lib/auth.ts:
// JWT callback with trigger="update" pattern used for active_tenant_id
// Same pattern needed for language field
From packages/portal/next.config.ts:
const nextConfig: NextConfig = { output: "standalone" };
export default nextConfig;
// MUST become: export default withNextIntl(nextConfig);
From packages/portal/app/(auth)/login/page.tsx — Client Component with email/password form
From packages/portal/components/session-sync.tsx
Task 1: Install next-intl, configure i18n infrastructure, create complete message files packages/portal/package.json packages/portal/next.config.ts packages/portal/i18n/request.ts packages/portal/messages/en.json packages/portal/messages/es.json packages/portal/messages/pt.json packages/portal/app/layout.tsx 1. Install dependencies in packages/portal/: ```bash cd packages/portal && npm install next-intl @formatjs/intl-localematcher negotiator && npm install --save-dev @types/negotiator ```2. Create i18n/request.ts (next-intl server config WITHOUT URL routing):
- Define SUPPORTED_LOCALES = ['en', 'es', 'pt'] as const
- Export type Locale, isValidLocale helper, LOCALE_COOKIE constant ('konstruct_locale')
- getRequestConfig reads locale from cookie (LOCALE_COOKIE), falls back to 'en'
- Dynamic import of messages/{locale}.json
- Follow Pattern 1 from RESEARCH.md exactly
3. Update next.config.ts:
- Import createNextIntlPlugin from 'next-intl/plugin'
- Wrap config: const withNextIntl = createNextIntlPlugin('./i18n/request.ts')
- export default withNextIntl({ output: 'standalone' })
4. Create complete messages/en.json with ALL translation keys for every page and component:
- nav: dashboard, employees, chat, usage, billing, apiKeys, users, platform, signOut
- login: title, subtitle, emailLabel, passwordLabel, submitButton, invalidCredentials, signingIn
- dashboard: title, welcome, agentCount, tenantCount, recentActivity, noActivity
- agents: pageTitle, newEmployee, noAgents, noAgentsDescription, createFirst, active, inactive, editButton, deleteButton, confirmDelete, agent fields (name, role, persona, systemPrompt, modelPreference, tools, escalation)
- agentDesigner: title, fields (jobDescription, statementOfWork, persona, systemPrompt, toolAssignments, escalationRules), saveButton, addTool, addRule, condition, action
- agentNew: title, subtitle, options (template, wizard, advanced), descriptions for each
- templates: title, subtitle, deploy, deploying, deployed, recommended, noTemplates, category labels
- wizard: steps (role, persona, tools, channels, escalation, review), labels for each field, next, back, deploy, deployingAgent
- onboarding: title, steps (connectChannel, configureAgent, testMessage), descriptions, buttons, completion message
- chat: title, newConversation, noConversations, noMessages, typeMessage, send, selectAgent, conversations
- billing: title, currentPlan, subscribe, manage, cancelSubscription, upgrade, invoiceHistory
- usage: title, selectTenant, tokenUsage, costBreakdown, timeRange, day, week, month, noBudget
- apiKeys: title, addKey, provider, keyHint, deleteKey, confirmDelete, noKeys
- users: title, inviteUser, name, email, role, status, actions, pending, accepted, revokeInvite
- adminUsers: title, allUsers, platformUsers
- tenants: title, newTenant, name, slug, plan, actions, editTenant, deleteTenant, confirmDelete, noTenants
- tenantForm: nameLabel, slugLabel, planLabel, createButton, updateButton, creating, updating
- common: loading, error, save, cancel, delete, confirm, search, noResults, retry, back, close
- impersonation: banner text, stopButton
- tenantSwitcher: selectTenant, allTenants, currentTenant
- validation: required, invalidEmail, minLength, maxLength, invalidFormat
- language: switcherLabel, en, es, pt
5. Create messages/es.json — complete Spanish translation of ALL keys from en.json. Use proper Latin American Spanish business terminology. Not literal translations — natural phrasing. Example: "Employees" -> "Empleados", "Dashboard" -> "Panel", "Sign out" -> "Cerrar sesion", "AI Workforce" -> "Fuerza laboral IA".
6. Create messages/pt.json — complete Brazilian Portuguese translation of ALL keys from en.json. Use proper Brazilian Portuguese business terminology. Example: "Employees" -> "Funcionarios", "Dashboard" -> "Painel", "Sign out" -> "Sair", "AI Workforce" -> "Forca de trabalho IA".
7. Update app/layout.tsx:
- Keep as Server Component (NO 'use client')
- Import NextIntlClientProvider from 'next-intl'
- Import getLocale, getMessages from 'next-intl/server'
- Make function async
- Call const locale = await getLocale(); const messages = await getMessages();
- Set html lang={locale} (dynamic, not hardcoded "en")
- Wrap body children with <NextIntlClientProvider messages={messages}>
- Keep all existing font and class logic unchanged
cd /home/adelorenzo/repos/konstruct/packages/portal && npx next build 2>&1 | tail -20
- next-intl installed and configured
- i18n/request.ts reads locale from cookie
- next.config.ts wrapped with withNextIntl
- Complete en.json, es.json, pt.json message files with keys for every page/component
- Root layout wraps app with NextIntlClientProvider
- Portal builds successfully
Task 2: Language switcher component + Auth.js JWT language sync + login page locale detection
packages/portal/components/language-switcher.tsx
packages/portal/components/nav.tsx
packages/portal/lib/auth.ts
packages/portal/lib/auth-types.ts
packages/portal/components/session-sync.tsx
packages/portal/app/(auth)/login/page.tsx
1. Create components/language-switcher.tsx:
- 'use client' component
- Three clickable buttons: EN / ES / PT (compact, inline)
- Current locale highlighted (derived from cookie or session)
- On click: (a) set document.cookie with konstruct_locale={locale}, path=/, max-age=31536000; (b) if authenticated, PATCH /api/portal/users/me/language with the locale; (c) call update({ language: locale }) on Auth.js session; (d) router.refresh() to re-render with new locale
- Style: compact row of 3 buttons, fits in sidebar user section. Use sidebar color tokens. Active locale has subtle highlight.
- Accept optional `isPreAuth` prop — when true, skip the DB PATCH and session update (for login page)
2. Add LanguageSwitcher to nav.tsx:
- Import and render <LanguageSwitcher /> between the user info section and the sign-out button
- Keep existing nav structure and styling intact
3. Update Auth.js config in lib/auth.ts:
- In the JWT callback: read user.language from the verify endpoint response and add to token
- Handle trigger="update" case for language: if (trigger === "update" && session?.language) token.language = session.language
- In the session callback: expose token.language on session.user.language
- Follow the exact same pattern already used for active_tenant_id
4. Update auth-types.ts if needed to include language in the session/token types.
5. Update session-sync.tsx:
- After login, sync the locale cookie from session.user.language (if the cookie differs from the session value, update the cookie so i18n/request.ts reads the DB-authoritative value)
6. Update login page (app/(auth)/login/page.tsx):
- On mount (useEffect), detect browser locale via navigator.language.slice(0, 2), check if supported ['en', 'es', 'pt'], set konstruct_locale cookie if no cookie exists yet
- Add <LanguageSwitcher isPreAuth /> near the form (below the sign-in button or in the page header)
- Use useTranslations('login') for all login form strings (title, labels, button, error message)
cd /home/adelorenzo/repos/konstruct/packages/portal && npx next build 2>&1 | tail -20
- LanguageSwitcher component renders EN/ES/PT buttons with active highlight
- Sidebar shows language switcher near user avatar
- Changing language updates cookie + DB + JWT + triggers re-render
- Login page detects browser locale and shows language switcher
- Login form strings use useTranslations('login')
- Portal builds successfully
- Portal builds: `cd packages/portal && npx next build`
- next-intl configured: i18n/request.ts exists, next.config.ts uses withNextIntl
- Message files exist: en.json, es.json, pt.json all have matching key structures
- LanguageSwitcher component exists and is rendered in Nav
- Login page uses useTranslations
<success_criteria>
- next-intl v4 installed and configured without URL-based routing
- Complete en/es/pt message files covering all pages and components
- Language switcher in sidebar (post-auth) and login page (pre-auth)
- Language preference persists via cookie + DB + JWT
- Browser locale auto-detected on first visit
- Portal builds without errors </success_criteria>