Wire up all components with useTranslation(), generate translations for all 7 languages + 2 pseudo-locales, and validate with visual QA.
Total scope: ~190 new keys across 17 files.
Problem
The MSP portal shell (sidebar, header, breadcrumbs, banners, quick-create) and dashboard display ~190 hardcoded English strings that are not yet translatable. The shell is visible on every MSP page; the dashboard is the first page users see after login. Together they are the highest-impact untranslated surfaces. Users with non-English locale preferences see a mix of translated page content and English chrome.
Goals
Extract all user-visible hardcoded strings from MSP shell components into msp/core.json
Create msp/dashboard.json namespace with all dashboard strings
Wire all components to consume translations via useTranslation()
Make menuConfig.ts translation-aware so sidebar nav items and section titles use translated labels
Generate accurate translations for all 7 production languages (en, fr, es, de, nl, it, pl)
Update pseudo-locale files (xx, yy) to cover new keys
Register /msp and /msp/dashboard routes in ROUTE_NAMESPACES to load msp/dashboard
Zero regressions — everything works identically with msp-i18n-enabled flag OFF (forced English)
Non-goals
Translating strings inside child components rendered by QuickCreateDialog (QuickAddTicket, QuickAddClient, etc.) — those belong to their respective feature namespaces
Translating the Enterprise Edition RightSidebar chat UI — that's in @enterprise/components
Adding new languages beyond the existing 7
Changing the namespace structure or route mappings (beyond adding dashboard)
Translating the GitHub star button (external widget, not our text)
Refactoring menuConfig.ts to a different data structure
Users and Primary Flows
Primary user: MSP portal operators who have set a non-English locale preference.
Flow: User logs in → sees sidebar, header, breadcrumbs, banners, quick-create menu all in their preferred language instead of hardcoded English.
UX / UI Notes
No visual changes — all strings appear in the same locations, just translated
German/Dutch translations are typically 30-50% longer than English — verify no layout overflow in sidebar (collapsed tooltip), header breadcrumbs, banner badges, dropdown menus, and dashboard feature cards
The sidebar collapsed state shows tooltips — these must also be translated
Tab labels in settings sidebar sections are already covered by existing settings.sections.* and settings.tabs.* keys — verify they're consumed, not hardcoded
Dashboard onboarding cards have progress rings with text like "3 of 5 Steps" — verify interpolation works in all languages
Dashboard feature card descriptions are long sentences — verify no truncation in German/Dutch
Requirements
Functional Requirements
FR1: menuConfig.ts — Translation-aware menu data
The menu config currently exports hardcoded English name and title strings. Two approaches (choose one):
Option A (Recommended): Add translation keys to MenuItem, translate in Sidebar
Add a translationKey field to MenuItem and NavigationSection
Keep name as the English fallback / stable identifier
In Sidebar.tsx, use t(item.translationKey) || item.name for display
Avoids making menuConfig.ts depend on React hooks
Option B: Translate at config level
Create a useTranslatedMenuConfig() hook that returns translated copies
More encapsulated but requires all consumers to be React components
FR2: Sidebar.tsx — Translated labels
String
Key
"Go to dashboard" (aria-label)
sidebar.goToDashboard
"AlgaPSA" (logo text)
Keep hardcoded (brand name)
"AlgaPSA Logo" (alt text)
sidebar.logoAlt
"Back to Main" (button + tooltip, 2 occurrences)
Already exists: sidebar.backToMain
"Expand sidebar"
sidebar.expandSidebar
"Collapse sidebar"
sidebar.collapseSidebar
Sidebar already renders item.name from menuConfig — once FR1 is done, these will be translated.
All new keys follow the established naming convention (see translation-guide.md)
No performance regression — msp/core already loads on every MSP route; msp/dashboard loads only on dashboard route
Feature flag msp-i18n-enabled OFF = forced English (no change in behavior)
Data / API / Integrations
No database changes
No API changes
Translation files: server/public/locales/{lang}/msp/core.json and server/public/locales/{lang}/msp/dashboard.json for all 9 locales
Security / Permissions
No changes — translations are static JSON files served from /public/locales/.
Rollout / Migration
Behind existing msp-i18n-enabled feature flag
Flag OFF: I18nWrapper forces English locale → t() returns English values → identical to current hardcoded strings
Flag ON: User sees their preferred language
No migration needed — purely additive change to translation files + component wiring
Open Questions
menuConfig.ts approach: Option A (translationKey field) vs Option B (hook)? Recommendation: Option A for simplicity — menuConfig stays a plain data file.
Breadcrumb translation: getMenuItemNameByPath() currently returns item.name (English). Should it return the translation key instead, letting the breadcrumb component translate? Or should breadcrumbs show the translated nav label?
GitHubStarButton: The "Star" text and aria-label are part of the GitHub buttons widget — not our text. Skip translation? (Recommendation: yes, skip.)
Onboarding components location: Dashboard onboarding components live in packages/onboarding/, not server/src/. They'll need to import useTranslation from @alga-psa/ui/lib/i18n/client — verify this works from the package context.
stepDefinitions.ts: This file exports plain data (not a React component). Should it export translation keys (like menuConfig Option A) and let the rendering component call t()? (Recommendation: yes, same pattern as menuConfig.)
Acceptance Criteria (Definition of Done)
msp/core (shell)
All ~80 new keys added to en/msp/core.json
All 9 shell component files + menuConfig.ts wired to use useTranslation('msp/core')
With msp-i18n-enabled ON + locale set to xx: sidebar, header, breadcrumbs, banners, quick-create all show 11111
msp/dashboard
New msp/dashboard.json namespace created with ~110 keys
All 4 dashboard component files + stepDefinitions.ts wired to use useTranslation('msp/dashboard')
ROUTE_NAMESPACES updated for /msp and /msp/dashboard to include msp/dashboard
With msp-i18n-enabled ON + locale set to xx: welcome banner, feature cards, onboarding checklist all show 11111
Cross-cutting
All 7 production locale files updated with translations for both namespaces (fr, es, de, nl, it, pl)
Both pseudo-locale files updated for both namespaces (xx, yy)
With msp-i18n-enabled OFF: all text displays in English (no regressions)
With msp-i18n-enabled ON + locale set to pl: shell and dashboard show Polish text
German translations don't overflow sidebar tooltips, header dropdowns, banner badges, or dashboard cards
Italian translations pass accent audit (no missing à, è, ù, ò)
Cross-check: nav item names in msp/core.json match across all languages