Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
16 KiB
16 KiB
Scratchpad — MSP i18n Batches 2b-1 + 2b-2: Core + Dashboard
- Plan slug:
2026-03-19-msp-i18n-batch-2b1-core - Created:
2026-03-19
Decisions
- (2026-03-19) menuConfig.ts approach: Option A — add
translationKeyfield toMenuItemandNavigationSection. Keepnameas stable identifier / English fallback. Sidebar.tsx usest(item.translationKey) || item.namefor display. This avoids making menuConfig depend on React hooks and keeps it as a plain data export. - (2026-03-19) GitHubStarButton: Skip translation — "Star" text and aria-label are injected by the external GitHub buttons widget script, not our code.
- (2026-03-19) "AlgaPSA" brand name: Keep hardcoded — brand names are not translated. Only the alt text ("AlgaPSA Logo") gets a key.
- (2026-03-19) Breadcrumb translation:
getMenuItemNameByPath()returnsitem.name(English). Once Sidebar translates viatranslationKey, breadcrumbs should also translate. Two options: (a) move translation lookup intogetMenuItemNameByPathby passingtfunction, or (b) return the translationKey and let breadcrumb component callt(). Decision: option (a) — passtto the function or move it into Header component wheretis available. - (2026-03-19) TIER_LABELS: TrialBanner uses
TIER_LABELS[tier]from@alga-psa/typesfor tier display names ("Pro", "Premium"). These are product tier names and should likely stay in English. Only the surrounding text ("Trial:", "days left", "confirm to keep") gets translated. - (2026-03-19) Billing key collision:
nav.billingcould not remain a plain string once the billing sidebar section and item keys moved undernav.billing.*. The top-level billing nav label now usesnav.billing.label, while section/item keys stay undernav.billing.sections.*andnav.billing.<item>.
Discoveries / Constraints
Core (msp/core)
- (2026-03-19)
msp/core.jsonalready has 72 keys covering: nav.* (27), sidebar.* (4), settings.sections.* (6), settings.tabs.* (17+), header.* (5). Many sidebar/header strings are NOT yet wired up — the keys exist but components still use hardcoded English. - (2026-03-19) Sidebar.tsx does NOT use
useTranslationcurrently. It readsitem.namedirectly from menuConfig. Thesidebar.backToMainkey exists in core.json but is not consumed. - (2026-03-19) Header.tsx does NOT use
useTranslationcurrently. Theheader.*keys exist in core.json but are not consumed. - (2026-03-19)
settingsNavigationSectionshas a "Language" item that's conditionally filtered out whenmsp-i18n-enabledis OFF. This filter usesitem.name !== 'Language'— if we change how names work, this filter needs to usetranslationKeyor a stable id instead. - (2026-03-19)
billingNavigationSectionshas 4 section titles + 12 items = 16 new strings. These are NOT in the current core.json. - (2026-03-19)
QuickCreateDialog.tsxdelegates to child components (QuickAddTicket, QuickAddClient, etc.) which have their own internal strings — those are OUT OF SCOPE for this batch. Only the wrapper's toast messages, dialog titles, and error messages are in scope. - (2026-03-19)
RightSidebar.tsxCE fallback has only 2 strings. The enterprise version (@enterprise/components/layout/RightSidebar) is separate and out of scope. - (2026-03-19)
PlatformNotificationBanner.tsxrendersbanner_contentviadangerouslySetInnerHTML— this content comes from the database and is NOT translatable via i18n keys. Only the "Learn More" and "Dismiss" buttons are in scope.
Dashboard (msp/dashboard)
- (2026-03-19) Dashboard has NO existing translations —
msp/dashboard.jsondoesn't exist yet. This is a new namespace. - (2026-03-19) Onboarding components live in
packages/onboarding/src/components/dashboard/, NOT inserver/src/. They import from@alga-psa/onboarding. Need to verifyuseTranslationworks from package context (it should —@alga-psa/ui/lib/i18n/clientis the shared import path). - (2026-03-19)
stepDefinitions.tsis a plain data file (not a React component) — same pattern as menuConfig. Should exporttranslationKeyfields, rendering component callst(). - (2026-03-19)
DashboardContainer.tsxshows different welcome banners for Enterprise vs Community editions — both need translation. - (2026-03-19) Onboarding progress ring has interpolated text: "3 of 5 Steps" — needs
{{completed}}and{{total}}variables. - (2026-03-19) Feature cards have a "Coming soon!" toast — this fires on click for cards without an href. Simple string, one key.
- (2026-03-19)
ROUTE_NAMESPACEScurrently maps/mspto['common', 'msp/core']. Need to add'msp/dashboard'to both/mspand/msp/dashboardroutes. - (2026-03-19)
DashboardOnboardingSlot.tsxandDashboardOnboardingSkeleton.tsxhave no user-visible text — just layout/loading components. No translation needed. - (2026-03-19)
DashboardOnboardingSection.tsxhad a hidden rerender-loop bug: itsinitialDismissedStepIds = []default created a fresh array every render, retriggering theuseEffectdependency and causing an infinite update loop when the prop was omitted. Fixed by hoisting a stable empty constant (F071/T101). - (2026-03-19)
DashboardOnboardingSection.tsxhad two additional user-visible hardcoded error fallbacks (Failed to dismiss onboarding step.,Failed to restore onboarding step.) not enumerated in the PRD tables. Added them tomsp/dashboard.jsonunderonboarding.errors.*because they are user-facing dashboard strings. - (2026-03-19)
DashboardContainer.tsxneeded an explicitFeatureCardDefinitiontype; otherwise the translated feature-card array widened into a union wherehrefwas not guaranteed andnext buildfailed during TypeScript.
Progress Log
- (2026-03-19) Completed
F001-F006andT001-T009together in the shared menu config layer. Added optionaltranslationKeymetadata toMenuItemandNavigationSection, populated every main/bottom/settings/billing/extensions nav item with stable i18n keys, and addedserver/src/test/unit/layout/menuConfig.i18n.test.tsto lock the mapping in place before Sidebar/Header consume it. - (2026-03-19) New core keys implied by the menu config and still pending locale-file work:
nav.documentsAll,nav.knowledgeBase,nav.controlPanel,nav.workflowEditor,nav.systemMonitoring,nav.jobMonitoring,settings.tabs.language,settings.tabs.sla, and allnav.billing.*entries. - (2026-03-19) Completed
F007-F012andT010-T018inSidebar.tsx. Sidebar now translates menu item labels by cloning config items witht(item.translationKey), translates the dashboard link/logo/toggle/back-to-main chrome, and filters the hidden Language settings entry bytranslationKeyinstead of English text so locale changes do not break the feature-flag behavior. - (2026-03-19) Added
server/src/test/unit/layout/Sidebar.i18n.test.tsxwith a lightweight tooltip/collapse mock to verify translated open-state labels, collapsed tooltip labels, section titles in settings and billing modes, and the English fallback path when translations are unavailable. - (2026-03-19) Completed
F013-F019andT019-T029inHeader.tsx. Quick Create, Job Activity, breadcrumb root/current label lookup, tenant badge interpolation, and existing user-menu fallback strings now all read throughuseTranslation('msp/core')with English defaults so the pre-i18n flag-off path stays stable. - (2026-03-19) Added
server/src/test/unit/layout/Header.i18n.test.tsxand updatedserver/vitest.config.tsaliases to cover@alga-psa/jobs. The header tests verify translated quick-create labels/descriptions, job activity strings, breadcrumb translation from menu translation keys, and the tenant badge{{tenant}}interpolation path. - (2026-03-19) Completed
F020andT030-T032inDefaultLayout.tsxby translating both AI interruption dialog variants throughmsp/corekeys with English defaults. Reusedserver/src/test/unit/layout/DefaultLayout.chatInterruptGuard.test.tsxfor translated title/confirm/cancel assertions instead of creating a duplicate harness. - (2026-03-19) Extended the DefaultLayout test harness with a direct mock for
@alga-psa/msp-composition/scheduling/MspSchedulingCrossFeatureProviderso the unit test stays isolated from deeper ticket/document cross-feature imports while still exercising the interrupt guard behavior. - (2026-03-19) Completed
F021-F024andT033-T037inTrialBanner.tsx. Trial copy now usesmsp/corekeys with explicit English defaults, and the singular/plural day label is built once and interpolated into both premium and Stripe trial wrapper strings while keepingTIER_LABELSproduct names untranslated. - (2026-03-19) Added
server/src/test/unit/layout/TrialBanner.i18n.test.tsxto cover premium-confirmed, premium singular-day, Stripe plural-day, and tier-name interpolation branches. This gives direct verification that{{count}},{{daysLabel}}, and{{tier}}survive the component wiring.
Commands / Runbooks
- Validate translations:
node scripts/validate-translations.cjs - Generate pseudo-locales:
npx ts-node scripts/generate-pseudo-locale.ts --locale xx --fill "1111" - Italian accent audit:
grep -n ' e [a-z]\| puo \| gia \| verra \| funzionalita\| necessario' server/public/locales/it/msp/core.json - Count keys:
node -e "const o=JSON.parse(require('fs').readFileSync('server/public/locales/en/msp/core.json'));const c=(o,p='')=>{let n=0;for(const[k,v]of Object.entries(o)){if(typeof v==='object'&&v!==null)n+=c(v,p+k+'.');else n++}return n};console.log(c(o))" - Visual QA: Enable
msp-i18n-enabledflag locally, switch toxxlocale, navigate sidebar/header/settings/billing modes - Dashboard component suite:
cd server && npx vitest run --config vitest.config.ts src/test/unit/i18n/mspDashboardBatch2b1.test.ts src/test/unit/dashboard/DashboardContainer.i18n.test.tsx src/test/unit/onboarding/DashboardOnboardingSection.i18n.test.tsx src/test/unit/onboarding/OnboardingChecklist.i18n.test.tsx - Full build verification:
npm run build
Progress Log
- (2026-03-19) Completed
F025-F030andT038-T051.PaymentFailedBanner.tsxnow readsbanners.paymentFailed.messageandbanners.paymentFailed.portalErrorfrommsp/core.QuickCreateDialog.tsxnow translates all success toasts, loading dialog titles, and client/service-type load errors throughmsp/core, preserving interpolation for ticket numbers and entity names.RightSidebar.tsxnow translates the CE fallback title/message viarightSidebar.*.PlatformNotificationBanner.tsxnow translates the Learn More CTA and dismiss aria-label viabanners.platformNotification.*.- Validation:
cd server && npx vitest run --config vitest.config.ts src/test/unit/layout/PaymentFailedBanner.i18n.test.tsx src/test/unit/layout/RightSidebar.i18n.test.tsx src/test/unit/layout/PlatformNotificationBanner.i18n.test.tsx src/test/unit/layout/QuickCreateDialog.i18n.test.tsx - Gotcha: the platform notification test emits a React warning because the local
next/linkmock forwardsprefetch={false}to a DOM anchor; behavior is otherwise correct and assertions pass.
- (2026-03-19) Completed
F031-F043andT052-T062,T064-T066.- Rebuilt
server/public/locales/*/msp/core.jsonfor all 7 production locales plusxxandyy, adding the new shell/sidebar/header/dialog/banner/quick-create/right-sidebar keys and the nested billing navigation structure. - Added
settings.tabs.languageandsettings.tabs.slaacross all locales and introducednav.billing.labelto avoid the string-vs-object collision with nestednav.billing.sections.*andnav.billing.<item>keys. - Added
server/src/test/unit/i18n/mspCoreBatch2b1.test.tsto verify the English key inventory, production-locale alignment, pseudo-locale fills, variable preservation, Italian accents, representativexxQA coverage, and German overflow-sensitive label lengths. - Extended
Sidebar.i18n.test.tsxwith a feature-flag check that hides the Language item whenmsp-i18n-enabledis off. - Validation:
node scripts/validate-translations.cjscd server && npx vitest run --config vitest.config.ts src/test/unit/i18n/mspCoreBatch2b1.test.ts src/test/unit/layout/Sidebar.i18n.test.tsx src/test/unit/layout/menuConfig.i18n.test.ts
- Gotcha: the old
npx ts-node scripts/validate-translations.tsrunbook in this plan is stale; the repository validator lives atscripts/validate-translations.cjs.
- Rebuilt
Links / References
- Translation plan:
.ai/translation/MSP_i18n_plan.md - Translation guide:
.ai/translation/translation-guide.md - File structure:
.ai/translation/translation_files_structure.md - Phase 1 plan:
docs/plans/2026-02-12-msp-i18n-phase1/ - Infra sprint plan:
docs/plans/2026-02-19-msp-i18n-infrastructure-sprint/
Key file paths
| File | Role |
|---|---|
server/src/config/menuConfig.ts |
Menu data — needs translationKey fields |
server/src/components/layout/Sidebar.tsx |
Main sidebar — needs useTranslation |
server/src/components/layout/Header.tsx |
Top bar — needs useTranslation |
server/src/components/layout/DefaultLayout.tsx |
Layout wrapper — AI interrupt dialogs |
server/src/components/layout/TrialBanner.tsx |
Trial status badge |
server/src/components/layout/PaymentFailedBanner.tsx |
Payment failure badge |
server/src/components/layout/QuickCreateDialog.tsx |
Quick-create modal + toasts |
server/src/components/layout/RightSidebar.tsx |
CE chat fallback |
server/src/components/layout/PlatformNotificationBanner.tsx |
Platform notifications |
server/public/locales/en/msp/core.json |
English core translation file |
server/public/locales/en/msp/dashboard.json |
English dashboard translation file (TO CREATE) |
server/src/components/dashboard/DashboardContainer.tsx |
Main dashboard component |
packages/onboarding/src/components/dashboard/DashboardOnboardingSection.tsx |
Onboarding progress cards |
packages/onboarding/src/components/dashboard/OnboardingChecklist.tsx |
Alternative checklist view |
packages/onboarding/src/lib/stepDefinitions.ts |
Onboarding step data |
packages/core/src/lib/i18n/config.ts |
ROUTE_NAMESPACES config |
Progress Log
- (2026-03-19) Completed dashboard namespace batch (
F050-F070): createdmsp/dashboard.jsonfor all production locales + pseudo-locales, translatedDashboardContainer.tsx,DashboardOnboardingSection.tsx,OnboardingChecklist.tsx, andstepDefinitions.ts, and updatedROUTE_NAMESPACESto loadmsp/dashboardon/mspand/msp/dashboard. - (2026-03-19) Added dashboard i18n verification coverage:
server/src/test/unit/i18n/mspDashboardBatch2b1.test.ts,server/src/test/unit/dashboard/DashboardContainer.i18n.test.tsx,server/src/test/unit/onboarding/DashboardOnboardingSection.i18n.test.tsx, andserver/src/test/unit/onboarding/OnboardingChecklist.i18n.test.tsx. These now coverT070-T101. - (2026-03-19) Ran
node scripts/validate-translations.cjsafter adding dashboard locales — passed with 0 errors / 0 warnings. - (2026-03-19) Ran the dashboard component and locale suite — all 19 dashboard tests passed.
- (2026-03-19) Ran
npm run buildsuccessfully. Build still emits pre-existing webpack warnings (scheduling star-export conflict, handlebarsrequire.extensions, knex/fluent-ffmpeg/Temporal dynamic dependency warnings), but the build completed and closedT063.
Open Questions
- Breadcrumb name source: Currently
getMenuItemNameByPath()returns Englishitem.name. Need to decide how to passt()function to it (it's called inside the Header component, sotis available — could change the function signature to accept a translator, or move the logic inline). - Language filter in Sidebar: The
item.name !== 'Language'check needs updating once translationKeys are used. Should useitem.translationKey !== 'settings.tabs.language'or add a stableidfield. - Onboarding package imports: Verify that
useTranslationfrom@alga-psa/ui/lib/i18n/clientworks correctly when called from components inpackages/onboarding/. The i18n context is provided at the layout level, so it should work — but test early. - stepDefinitions.ts pattern: Should it use the same
translationKeypattern as menuConfig? Or should the rendering components just use hardcoded key paths liket('onboarding.steps.identity.title')? The latter is simpler since step IDs are stable.