319 lines
44 KiB
Markdown
319 lines
44 KiB
Markdown
# Feature Specification: Platform Localization v1 (DE/EN)
|
|
|
|
**Feature Branch**: `252-platform-localization-v1`
|
|
**Created**: 2026-04-28
|
|
**Status**: Draft
|
|
**Input**: User description: "Prepare the Spec Kit feature for Localization v1 as a narrow repo-grounded slice that introduces locale resolution and EN/DE translation coverage on core governance surfaces, reuses existing translation helpers and current admin/system panels, and stops before website localization or full documentation translation."
|
|
|
|
## Spec Candidate Check *(mandatory — SPEC-GATE-001)*
|
|
|
|
- **Problem**: TenantPilot already contains scattered translation-aware code such as `__()` calls and two domain language files, but it still lacks one central locale resolution path, one supported locale policy, and one bounded definition of which operator-facing surfaces are translated first.
|
|
- **Today's failure**: Users cannot intentionally switch the platform language, many core surfaces still mix extracted translations with raw English strings, relative-time labels stay English-only, and customer-safe review/report flows cannot reliably align to the reader's language without risking raw keys or inconsistent terminology.
|
|
- **User-visible improvement**: Operators can use the product in English or German, new users inherit a workspace default language unless they set their own preference, core governance surfaces render consistent translated copy and locale-aware time labels, and exports, audit records, and machine-readable artifacts remain stable and non-localized.
|
|
- **Smallest enterprise-capable version**: Add one request-time locale foundation where admin and tenant panels use `explicit override -> user preference -> workspace default -> system default`, the system panel uses `explicit override -> system default`, support exactly `en` and `de`, persist only the workspace default plus personal user preference for workspace-bound users, translate the panel shell plus the highest-signal governance surfaces first, and enforce controlled English fallback with no raw translation keys in the UI.
|
|
- **Explicit non-goals**: No `apps/website` localization, no arbitrary locale/plugin system, no public docs translation pipeline, no CSV/JSON/audit artifact localization, no provider/API payload translation, no full outbound email/template program, and no search/sort behavior rewrite beyond verifying locale safety on the current core lists.
|
|
- **Permanent complexity imported**: One bounded locale precedence chain, one supported-locale allowlist, one workspace-owned default locale setting, one workspace-bound user-owned locale preference, additional `lang/en` and `lang/de` catalogs for the selected core surfaces, and focused regression tests for fallback, formatting, and invariant machine-readable outputs.
|
|
- **Why now**: `R1.9 Platform Localization v1 (DE/EN)` is explicitly unspecced in the roadmap, the repo already has partial translation scaffolding (`lang/en/findings.php`, `lang/en/baseline-compare.php`, many `__()` calls), and read-only/customer-safe review maturity now needs a trustworthy locale foundation before more outward-facing product work lands.
|
|
- **Why not local**: Locale choice must affect the same request across Filament shells, auth, Livewire requests, notifications, relative-time rendering, and core governance pages. Translating page by page without a shared resolver contract would hard-code inconsistent language sources immediately.
|
|
- **Approval class**: Core Enterprise
|
|
- **Red flags triggered**: Foundation-sounding theme, cross-surface touchpoint, and one new shared resolver. Defense: the slice is strictly limited to two locales, one precedence chain, one workspace default, one personal preference, and a bounded first-wave translation set on already-real surfaces.
|
|
- **Score**: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexität: 1 | Produktnähe: 2 | Wiederverwendung: 2 | **Gesamt: 11/12**
|
|
- **Decision**: approve
|
|
|
|
## Review Outcome
|
|
|
|
- **Outcome class**: acceptable-special-case
|
|
- **Workflow outcome**: keep
|
|
- **Reason**: The slice is intentionally broad across visible runtime surfaces, but it stays bounded to one shared locale foundation, two supported locales, one user preference path, one workspace default path, and first-wave translation coverage only.
|
|
|
|
## Spec Scope Fields *(mandatory)*
|
|
|
|
- **Scope**: canonical-view
|
|
- **Primary Routes**:
|
|
- current `/admin` and `/system` panel shells, including auth entry surfaces such as `/admin/login`
|
|
- the existing workspace settings surface for a workspace-owned default locale
|
|
- the current self-service user locale preference entry point in the panel shell or profile/user-menu area
|
|
- existing high-signal governance surfaces under `/admin`, including dashboard, Findings, Baseline Compare, Alerts/Monitoring, Operations, and customer-safe review/report consumption surfaces
|
|
- **Data Ownership**: Personal locale preference is user-owned truth for the workspace-bound `User` actor and should persist on that user surface only. Workspace default locale is workspace-owned truth and should reuse the existing workspace settings infrastructure for admin/tenant-plane inheritance only. Explicit override is transient request/session state. System-panel `PlatformUser` actors do not get a separate persisted locale preference in v1. Exports, audit logs, stored report content, raw JSON, and machine-readable identifiers remain unchanged and non-localized.
|
|
- **RBAC**: Authenticated workspace-bound users may set or clear their own personal locale preference and temporary explicit override on admin/tenant surfaces. Workspace owners/managers may change the workspace default locale on the existing workspace settings surface. System-panel actors may use the explicit override only in v1 and otherwise inherit the system default. Existing workspace and tenant membership checks remain authoritative. Wrong-plane and non-member access stays 404, and missing capability on workspace settings stays 403.
|
|
|
|
For canonical-view specs, the spec MUST define:
|
|
|
|
- **Default filter behavior when tenant-context is active**: Locale changes MUST NOT alter existing tenant-context defaults, current filters, query ownership, search scoping, or canonical list routing. The current tenant/workspace context remains authoritative and language selection only affects presentation.
|
|
- **Explicit entitlement checks preventing cross-tenant leakage**: Existing workspace and tenant isolation remain authoritative. Locale selection MUST NOT reveal inaccessible tenants, operations, findings, or global-search hints through translated labels, fallback strings, or locale-specific navigation branches.
|
|
|
|
## Cross-Cutting / Shared Pattern Reuse *(mandatory when the feature touches notifications, status messaging, action links, header actions, dashboard signals/cards, alerts, navigation entry points, evidence/report viewers, or any other existing shared operator interaction family; otherwise write `N/A - no shared interaction family touched`)*
|
|
|
|
- **Cross-cutting feature?**: yes
|
|
- **Interaction class(es)**: navigation, auth copy, status messaging, action labels, notifications, validation/system texts, dashboard signals, evidence/report viewers, relative-time and date labels
|
|
- **Systems touched**: Laravel translator, current `lang/*` catalogs, Filament panel providers, existing auth page copy, workspace settings infrastructure, workspace-bound user model preference storage, system-panel actor handling, Livewire request handling, Filament notifications, and core governance/detail Blade and resource surfaces
|
|
- **Existing pattern(s) to extend**: current `__()` usage, existing domain language files, Filament vendor translation layer, existing workspace settings stack, and the current user/session context path
|
|
- **Shared contract / presenter / builder / renderer to reuse**: existing translation helpers and settings infrastructure remain canonical; this slice adds one bounded locale resolver and one supported-locale allowlist rather than a second presentation framework
|
|
- **Why the existing shared path is sufficient or insufficient**: The current translator and extracted keys are sufficient for rendering translated copy, but they are insufficient because the repo has no single locale resolution contract, no workspace default locale, no workspace-bound user preference path, and no guard against mixed raw English plus translated key usage on the same surfaces.
|
|
- **Allowed deviation and why**: none. No surface may invent a local locale source, inline hard-coded German strings, or page-local fallback behavior.
|
|
- **Consistency impact**: Canonical glossary terms such as Finding, Baseline, Drift, Risk Accepted, Evidence Gap, Alert, and Run must stay semantically aligned across shell navigation, dashboard tiles, findings/detail views, compare surfaces, notifications, and customer-safe report viewers.
|
|
- **Review focus**: Reviewers must verify one shared locale resolver contract, the narrower system-panel source set, no mixed-language operator surface after translation extraction, no raw keys in the rendered UI, and unchanged tenant/workspace authorization semantics.
|
|
|
|
## OperationRun UX Impact *(mandatory when the feature creates, queues, deduplicates, resumes, blocks, completes, or deep-links to an `OperationRun`; otherwise write `N/A - no OperationRun start or link semantics touched`)*
|
|
|
|
N/A - no `OperationRun` start, completion, dedupe, or link semantics are changed by this slice. Existing run-related copy becomes locale-aware, but the run lifecycle contract remains unchanged.
|
|
|
|
## Provider Boundary / Platform Core Check *(mandatory when the feature changes shared provider/platform seams, identity scope, governed-subject taxonomy, compare strategy selection, provider connection descriptors, or operator vocabulary that may leak provider-specific semantics into platform-core truth; otherwise write `N/A - no shared provider/platform boundary touched`)*
|
|
|
|
N/A - no shared provider/platform boundary is changed. Localization must translate platform vocabulary without importing provider-specific aliases into platform-core truth.
|
|
|
|
## UI / Surface Guardrail Impact *(mandatory when operator-facing surfaces are changed; otherwise write `N/A`)*
|
|
|
|
| Surface / Change | Operator-facing surface change? | Native vs Custom | Shared-Family Relevance | State Layers Touched | Exception Needed? | Low-Impact / `N/A` Note |
|
|
|---|---|---|---|---|---|---|
|
|
| Panel shell, auth, and locale controls | yes | Native Filament panels plus existing auth page | navigation, user-menu/profile actions, auth/system texts | shell, detail, URL-query/session | no | No new panel or shell type is introduced |
|
|
| Core governance surfaces | yes | Mixed native Filament resources/pages plus existing Blade views | status messaging, table labels, empty states, glossary terms | page, detail | no | First wave only: dashboard, Findings, Baseline Compare, high-signal tenant/workspace management tables |
|
|
| Monitoring and operational feedback surfaces | yes | Mixed native Filament pages/widgets and shared presenters | notifications, alerts, run/status labels, relative time | page, detail | no | Start/completion semantics stay unchanged; only copy/formatting is localized |
|
|
| Customer-safe review/report consumption surfaces | yes | Native Filament detail/report viewers | report titles, helper text, read-only evidence/report language | page, detail | no | Machine-readable report payloads and downloads remain invariant |
|
|
|
|
## Decision-First Surface Role *(mandatory when operator-facing surfaces are changed)*
|
|
|
|
| Surface | Decision Role | Human-in-the-loop Moment | Immediately Visible for First Decision | On-Demand Detail / Evidence | Why This Is Primary or Why Not | Workflow Alignment | Attention-load Reduction |
|
|
|---|---|---|---|---|---|---|---|
|
|
| Panel shell, auth, and locale controls | Primary Decision Surface | User decides which language the product should use for the current session or their persisted preference | Current language, available language choices, and whether workspace default applies | Workspace-default explanation and reset-to-default detail | Primary because this is the only place where language is intentionally changed | Keeps language choice inside the shell instead of hidden product-by-product | Removes manual browser-translation workarounds and support explanations |
|
|
| Core governance surfaces | Primary Decision Surface | Operator interprets findings, compare results, and tenant/workspace state | Localized headings, state text, actions, empty states, and glossary-consistent labels | Existing raw evidence and detailed diagnostics remain secondary | Primary because these are the actual governance decision surfaces that must be readable first | Preserves the current governance workflow while making the first read understandable in the chosen language | Reduces operator reconstruction of English-only labels and mixed terminology |
|
|
| Monitoring and operational feedback surfaces | Secondary Context Surface | Operator interprets toasts, alerts, validation errors, and relative-time context while working | Localized notification titles/bodies, validation/system copy, and relative-time labels | Existing run detail, technical diagnostics, and raw payloads remain secondary | Not primary because these surfaces support ongoing work rather than replace the main decision pages | Keeps supporting feedback aligned with the main locale choice | Avoids context switching between translated pages and English-only feedback |
|
|
| Customer-safe review/report consumption surfaces | Tertiary Evidence / Diagnostics Surface | Customer or operator reads existing review/report content | Localized viewer shell, labels, and helper text with invariant machine data | Raw evidence and exported artifacts remain non-localized or separately scoped | Not primary because these surfaces answer evidence questions rather than control product configuration | Preserves read-only review/report flows without creating a separate localization program | Avoids mixed-language read-only experiences during customer handoff |
|
|
|
|
## Audience-Aware Disclosure *(mandatory when operator-facing surfaces are changed)*
|
|
|
|
| Surface | Audience Modes In Scope | Decision-First Default-Visible Content | Operator Diagnostics | Support / Raw Evidence | One Dominant Next Action | Hidden / Gated By Default | Duplicate-Truth Prevention |
|
|
|---|---|---|---|---|---|---|---|
|
|
| Panel shell, auth, and locale controls | operator-MSP, support-platform | Current language, override source, and clear change/reset actions | Workspace-default source and personal-preference explanation | No raw settings or session payload by default | `Switch language` or `Use workspace default` | Session mechanics and internal storage details stay hidden | The surface states one resolved language and one source instead of listing multiple conflicting candidates |
|
|
| Core governance surfaces | operator-MSP, support-platform | Localized titles, statuses, actions, and empty-state guidance | Existing diagnostics and technical detail stay secondary | Raw JSON/provider payloads remain hidden or capability-gated as today | Existing primary governance action remains primary | Translation-key details and raw glossary mappings stay hidden | Canonical glossary terms are translated once and reused across related surfaces |
|
|
| Monitoring and operational feedback surfaces | operator-MSP, support-platform | Localized toasts, validation errors, and relative time/context labels | Existing technical diagnostics on run/detail pages | Raw support payloads remain collapsed or gated | Existing remediation or navigation action remains primary | Internal fallback markers and untranslated key debugging stay hidden | The same message family is localized centrally rather than page-local per toast |
|
|
| Customer-safe review/report consumption surfaces | customer-read-only, operator-MSP | Localized shell copy and helper labels around existing review/report content | Existing provenance and review history remain secondary | Machine payloads and exported artifact data stay stable and non-localized | Existing `View` or `Download` action remains primary | Support/raw detail remains gated or omitted | Viewer shell text localizes without creating a second localized export format |
|
|
|
|
## UI/UX Surface Classification *(mandatory when operator-facing surfaces are changed)*
|
|
|
|
| Surface | Action Surface Class | Surface Type | Likely Next Operator Action | Primary Inspect/Open Model | Row Click | Secondary Actions Placement | Destructive Actions Placement | Canonical Collection Route | Canonical Detail Route | Scope Signals | Canonical Noun | Critical Truth Visible by Default | Exception Type / Justification |
|
|
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
| Panel shell, auth, and locale controls | Global context shell | Shell + preference control | Change the current language or reset to inherited default | Shell affordance plus existing settings/profile surface | forbidden | Existing user-menu or settings placement remains secondary to main navigation | none | `/admin` and `/system` shells | existing user/profile or workspace settings surface | Current panel, workspace context, and current locale source | Language / Locale | Current language and override source | Acceptable shell exception because locale is a true global context choice |
|
|
| Core governance surfaces | List / Detail / Dashboard | Native resource/page family | Continue the current governance action using translated labels | Existing row click, detail pages, and dashboard cards stay unchanged | existing | Existing More/detail header actions remain where they already live | unchanged | existing governance collection routes under `/admin` | existing governance detail routes under `/admin` | Active workspace and tenant context remain unchanged | Findings, Baselines, Alerts, Runs | Localized decision copy and canonical glossary terms | No new surface type introduced |
|
|
| Monitoring and operational feedback surfaces | Monitoring / Status / Feedback | Widget/page plus transient notification families | Act on a toast, alert, validation error, or monitoring label | Existing page/widget affordances stay unchanged | existing where already supported | Existing secondary navigation remains secondary | unchanged | existing monitoring and operations routes | existing run/alert detail routes | Active workspace, run, or alert context remains unchanged | Alerts / Operations / Notifications | Localized feedback copy and relative time labels | Feedback-only translation; no action hierarchy change |
|
|
| Customer-safe review/report consumption surfaces | Detail / Report viewer / Download | Read-only viewer family | Read or download the current review/report content | Existing read-only view/download surfaces | existing where already supported | Existing navigation remains secondary | none | existing review/report collections | existing review/report detail routes | Active workspace and tenant context remain unchanged | Review / Report / Evidence | Localized shell labels around stable artifact truth | No new localized export format is introduced |
|
|
|
|
## Operator Surface Contract *(mandatory when operator-facing surfaces are changed)*
|
|
|
|
| Surface | Primary Persona | Decision / Operator Action Supported | Surface Type | Primary Operator Question | Default-visible Information | Diagnostics-only Information | Status Dimensions Used | Mutation Scope | Primary Actions | Dangerous Actions |
|
|
|---|---|---|---|---|---|---|---|---|---|---|
|
|
| Panel shell, auth, and locale controls | Any authenticated operator | Decide which language the product should render now | Global shell and settings detail | Which language should this product view use? | Current language, current source, available choices | Internal source precedence and fallback explanation | locale source, current locale | TenantPilot only | Switch language, clear override, save preference, save workspace default | none |
|
|
| Core governance surfaces | Workspace operator or platform reviewer | Interpret governance state and continue the current action in the chosen language | List/detail/dashboard family | What needs action right now, in a language I can reliably read? | Localized titles, labels, statuses, empty-state guidance, and action labels | Existing raw evidence and diagnostics | governance state, lifecycle/readiness, data completeness | none beyond existing actions | Existing primary governance actions | existing dangerous actions remain unchanged |
|
|
| Monitoring and operational feedback surfaces | Workspace operator or support operator | Understand transient system feedback and supporting context | Feedback/status family | What did the system just tell me, and what should I do next? | Localized notifications, validation messages, and relative-time context | Existing run/alert diagnostic detail | message intent, run status, alert state | none beyond existing actions | Existing follow-up navigation or retry actions | existing dangerous actions remain unchanged |
|
|
| Customer-safe review/report consumption surfaces | Customer-safe reader or workspace operator | Read review/report content with translated viewer chrome | Read-only viewer family | What does this review/report say in my chosen language without changing the underlying evidence? | Localized headings, section labels, helper text, and stable dates/times formatting | Existing provenance and support-only detail | report state, artifact availability | none | Existing view/download actions | none |
|
|
|
|
## Proportionality Review *(mandatory when structural complexity is introduced)*
|
|
|
|
- **New source of truth?**: yes - one resolved locale chain becomes current-release presentation truth, but it derives from existing config plus one user preference and one workspace default rather than a new generic preferences framework
|
|
- **New persisted entity/table/artifact?**: yes - one personal locale preference field and one workspace locale default setting
|
|
- **New abstraction?**: yes - one bounded locale resolver and one request-time application seam
|
|
- **New enum/state/reason family?**: yes - the supported locale set is explicitly bounded to `en` and `de`
|
|
- **New cross-domain UI framework/taxonomy?**: no
|
|
- **Current operator problem**: Operators and customer-safe readers currently encounter a partially translated product with no reliable way to select or inherit a language across shell, actions, notifications, and core governance views.
|
|
- **Existing structure is insufficient because**: Existing `__()` usage and two language files provide raw translation capability, but there is no central locale source, no persisted workspace default, no personal override, and no governed first-wave translation scope.
|
|
- **Narrowest correct implementation**: Keep the locale set at two languages, add one resolver where admin/tenant panels use the full precedence chain and the system panel uses explicit override plus system default, persist only one workspace-bound user preference and one workspace default, translate the highest-signal operator/report surfaces first, and leave exports/audit/machine artifacts untouched.
|
|
- **Ownership cost**: Ongoing maintenance of EN/DE catalogs, translation-key governance for the selected surface families, and regression tests for fallback and invariant machine outputs.
|
|
- **Alternative intentionally rejected**: A generic user-settings registry, multi-locale plugin system, or page-by-page translation without a resolver was rejected because the current release only needs one trustworthy locale chain and a bounded first-wave translation set.
|
|
- **Release truth**: current-release truth. The platform already has outward-facing review/report and governance workflows that need a consistent locale foundation now.
|
|
|
|
### Compatibility posture
|
|
|
|
This feature assumes a pre-production environment.
|
|
|
|
Backward compatibility, legacy aliases, migration shims, historical fixtures, and compatibility-specific tests are out of scope unless explicitly required by this spec.
|
|
|
|
Canonical replacement is preferred over preservation.
|
|
|
|
## Testing / Lane / Runtime Impact *(mandatory for runtime behavior changes)*
|
|
|
|
- **Test purpose / classification**: Unit, Feature
|
|
- **Validation lane(s)**: fast-feedback, confidence
|
|
- **Why this classification and these lanes are sufficient**: Unit coverage proves locale precedence, supported-locale validation, fallback behavior, and invariant machine-format decisions. Focused feature coverage proves request-time application across Filament and auth surfaces, workspace/user preference flows, translated core surfaces, localized notifications/validation, and unchanged export/audit semantics without requiring browser or heavy-governance lanes.
|
|
- **New or expanded test families**: one bounded locale resolver unit family plus focused localization feature coverage for preferences, core governance surfaces, notifications/validation, and fallback/invariant behavior
|
|
- **Fixture / helper cost impact**: low. Add only user, workspace, workspace membership, workspace setting, session override, and representative governance surface fixtures. Avoid browser harness growth and avoid a generic translation-seeding framework.
|
|
- **Heavy-family visibility / justification**: none
|
|
- **Special surface test profile**: global-context-shell, standard-native-filament, shared-detail-family
|
|
- **Standard-native relief or required special coverage**: Standard Filament feature coverage is sufficient for panel shell and settings surfaces. Global-context-shell coverage is required for locale precedence and request/application flow. Shared-detail-family coverage is required for localized review/report viewer chrome without altering machine-readable content.
|
|
- **Reviewer handoff**: Reviewers must confirm the precedence chain is deterministic, unsupported locales fail safely to English, Livewire requests preserve the resolved locale, critical governance surfaces stop mixing English raw strings with translated keys, relative times and validation messages localize correctly, and CSV/JSON/audit artifacts stay stable.
|
|
- **Budget / baseline / trend impact**: low feature-local increase only
|
|
- **Escalation needed**: none
|
|
- **Active feature PR close-out entry**: Guardrail
|
|
- **Planned validation commands**:
|
|
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Localization/LocaleResolverTest.php`
|
|
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Localization/AuthAndSystemSurfaceLocalizationTest.php tests/Feature/Localization/LocalePreferenceFlowTest.php tests/Feature/Localization/WorkspaceDefaultLocaleTest.php tests/Feature/Filament/Localization/CoreGovernanceSurfaceLocalizationTest.php`
|
|
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Localization/LocalizedNotificationFormattingTest.php tests/Feature/Localization/TranslationFallbackGuardTest.php tests/Feature/Localization/MachineFormatInvarianceTest.php`
|
|
|
|
## Scope Boundaries *(required for this slice)*
|
|
|
|
### In Scope
|
|
|
|
- One shared locale resolver contract where admin and tenant panels use `explicit override -> user preference -> workspace default -> system default` and the system panel uses `explicit override -> system default`
|
|
- Exactly two supported locales in v1: `en` and `de`
|
|
- Workspace-owned default locale using the existing workspace settings infrastructure
|
|
- User-owned personal locale preference and a clear reset-to-inherited behavior
|
|
- Request-time locale application across current Filament admin, tenant, and system/auth flows, including Livewire requests, with the system panel limited to explicit override plus system default
|
|
- First-wave translation coverage for panel shell/navigation/auth plus the highest-signal governance surfaces already present in the repo
|
|
- Localized notifications, validation/system messages, and relative-time/date/number formatting for those in-scope surfaces
|
|
- Controlled English fallback with no raw translation keys rendered in the UI
|
|
- Explicit preservation of invariant exports, audit logs, JSON payloads, IDs, and machine-readable report artifacts
|
|
|
|
### Non-Goals
|
|
|
|
- `apps/website` localization or public documentation translation
|
|
- More than two locales in v1
|
|
- A generic user preferences framework or multi-tenant localization framework
|
|
- Provider/API payload translation or localized stored evidence/report artifacts
|
|
- Full outbound email template localization beyond the minimum auth/system texts already on the current panel flow
|
|
- Search ranking, sorting rules, or global-search behavior changes beyond verifying locale safety
|
|
- Pseudolocalization as a full product lane; at most one bounded smoke/guard check may support the initial implementation
|
|
- A separate persisted locale-preference store for `PlatformUser` system actors
|
|
|
|
## Assumptions
|
|
|
|
- `config('app.locale')` and `config('app.fallback_locale')` remain the system-default and fallback anchors, both currently English.
|
|
- English remains the controlled fallback whenever a German translation key is missing.
|
|
- Workspace default locale is a presentation preference only. It does not change authorization, tenant/workspace scope, or machine-readable data.
|
|
- System-panel actors in v1 use explicit override plus system default only; they do not inherit workspace default or a second persisted preference store.
|
|
- Relative time, date, and number formatting should follow the resolved locale on operator-facing surfaces, but stored timestamps, raw payloads, exports, and audit values remain unchanged.
|
|
- The first-wave translation scope is bounded to shell/auth/settings plus existing high-signal governance pages already present in the repo, not every product page.
|
|
|
|
## Risks
|
|
|
|
- Mixed inline `__('Raw English')` usage and keyed translation files can leave surfaces partially translated if extraction rules are not explicit.
|
|
- Livewire and panel-specific middleware may drift if locale application is only added to one request path.
|
|
- Localizing viewer chrome while keeping exports/audit invariant can be confused if teams try to translate machine-readable payloads later.
|
|
- The glossary can drift between `findings`, `baseline-compare`, and generic panel labels if key ownership is not explicit.
|
|
|
|
## Deferred Adjacent Candidates
|
|
|
|
- Full public website localization remains a separate website-track concern.
|
|
- Broad email/template localization, knowledge-base localization, and public documentation translation stay deferred until the operator-facing runtime foundation is stable.
|
|
- Additional locales beyond German and English stay deferred until the two-locale workflow, fallback behavior, and glossary governance are proven.
|
|
|
|
## User Scenarios & Testing *(mandatory)*
|
|
|
|
### User Story 1 - Resolve and persist one trustworthy locale per request (Priority: P1)
|
|
|
|
As an authenticated operator, I want the platform to resolve one language deterministically for the current request so I can work in my chosen language without manually reinterpreting each page.
|
|
|
|
**Why this priority**: Without one shared locale chain, every later translation task remains fragile and page-local.
|
|
|
|
**Independent Test**: Set a workspace default locale, optionally set a personal locale preference, optionally trigger an explicit override, and verify that admin/tenant requests use the full chain while system-panel requests use explicit override plus system default on both normal and Livewire-backed panel pages.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** a user has no personal locale preference and no explicit override, **When** they open the panel inside a workspace with default locale `de`, **Then** the request resolves to `de` and the shell renders German copy.
|
|
2. **Given** the same workspace default is `de` but the user has personal locale preference `en`, **When** they open the panel, **Then** the request resolves to `en`.
|
|
3. **Given** the user currently resolves to `en`, **When** they set an explicit temporary override to `de`, **Then** the current request or session resolves to `de` until the override is cleared.
|
|
4. **Given** an unsupported locale value is supplied through the temporary override or persisted input, **When** the request resolves locale, **Then** the system safely falls back to English and never exposes raw keys.
|
|
5. **Given** a system-panel actor has no explicit override active, **When** they open the system panel, **Then** the request resolves from the system default and does not inherit workspace default or a persisted personal preference in v1.
|
|
|
|
---
|
|
|
|
### User Story 2 - Read core governance surfaces in the chosen language (Priority: P1)
|
|
|
|
As a workspace or platform operator, I want core governance surfaces to render consistent translated copy and glossary terms so I can make decisions without mixed-language UI fragments.
|
|
|
|
**Why this priority**: Dashboard, Findings, Baseline Compare, and the main shell are the highest-signal operating surfaces. If they remain mixed-language, the locale foundation is not credible.
|
|
|
|
**Independent Test**: Open the shell, dashboard, Findings, Baseline Compare, and one representative tenant/workspace management table in both `en` and `de`, and verify that headings, status labels, actions, empty states, and relative-time helper text match the resolved locale.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** the resolved locale is `de`, **When** an operator opens the dashboard and Findings pages, **Then** navigation labels, headings, actions, and empty-state/helper text render in German using the canonical glossary.
|
|
2. **Given** the resolved locale is `en`, **When** the same operator opens Baseline Compare and the representative management tables, **Then** those surfaces render English labels and status text with unchanged workflow semantics.
|
|
3. **Given** a translation key is missing in German for an in-scope surface, **When** the page renders, **Then** the surface falls back to English instead of showing a raw translation key.
|
|
|
|
---
|
|
|
|
### User Story 3 - Keep notifications and machine-readable artifacts truthful at the same time (Priority: P1)
|
|
|
|
As an operator or customer-safe reader, I want notifications and viewer shell copy to follow my language while exports, audit entries, and machine-readable report content remain stable.
|
|
|
|
**Why this priority**: Supportive system feedback and read-only report consumption are part of the real product experience, but they must not compromise machine-format stability or audit truth.
|
|
|
|
**Independent Test**: Trigger representative notifications and validation errors in `de` and `en`, open a customer-safe review/report viewer, and verify that UI shell copy localizes while exported/report payloads and audit records stay invariant.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** the resolved locale is `de`, **When** an operator triggers a representative notification or validation error on an in-scope surface, **Then** the message renders in German.
|
|
2. **Given** the resolved locale is `de`, **When** a customer-safe reader opens an existing review or report surface, **Then** the viewer chrome and helper labels render in German while underlying machine-readable content stays unchanged.
|
|
3. **Given** the same action produces an audit entry, CSV, JSON, or stored machine-readable artifact, **When** the localized UI renders around it, **Then** the artifact content and identifiers remain stable and non-localized.
|
|
|
|
### Edge Cases
|
|
|
|
- Unsupported locale input must never break request rendering or show raw translation keys.
|
|
- Livewire requests must preserve the already-resolved locale instead of silently reverting to the app default.
|
|
- Clearing a personal locale preference must return the user to workspace-default behavior, not leave a stale session override in place.
|
|
- A user outside any active workspace must still resolve locale safely from explicit override, personal preference, or system default.
|
|
- Global-search scope, filter semantics, and authorization outcomes must remain unchanged regardless of locale.
|
|
- Relative time labels must localize correctly without mutating stored timestamps or serialized API/export values.
|
|
|
|
## Requirements *(mandatory)*
|
|
|
|
**Constitution alignment (required):** This feature changes runtime presentation behavior and writes one workspace-bound user-owned preference plus one workspace-owned default, but it introduces no new Microsoft Graph path, no provider dispatch change, and no new queued workflow family.
|
|
|
|
**Constitution alignment (PROP-001 / ABSTR-001 / PERSIST-001 / STATE-001 / BLOAT-001):** The feature introduces one new bounded resolver and two-locale state set because current operator workflows already need a deterministic language source. A narrower page-local translation effort would not solve current-release truth.
|
|
|
|
**Constitution alignment (XCUT-001):** All in-scope panels, notifications, and translated core surfaces must consume the same locale resolver contract. No page may invent a second locale source, and the system panel remains on the explicit-override plus system-default subset in v1.
|
|
|
|
**Constitution alignment (DECIDE-AUD-001 / OPSURF-001):** Localization must improve decision-first readability without exposing support/raw data or changing current disclosure boundaries.
|
|
|
|
**Constitution alignment (PROV-001):** Platform vocabulary remains platform-core. Localization translates the vocabulary but does not rename provider-specific identifiers or alter provider payload truth.
|
|
|
|
**Constitution alignment (TEST-GOV-001):** Proof stays in focused unit plus feature lanes with minimal fixtures and no browser-lane expansion.
|
|
|
|
**Constitution alignment (RBAC-UX):** Language selection MUST NOT alter workspace or tenant access checks, wrong-plane 404 handling, or membership/capability semantics.
|
|
|
|
**Constitution alignment (BADGE-001):** Existing status badges and state labels may be translated, but they must continue to use shared badge/state semantics rather than page-local language mappings.
|
|
|
|
**Constitution alignment (UI-FIL-001):** The slice extends existing Filament pages, resources, widgets, and the current auth surface. It must not create a custom localization panel or second shell.
|
|
|
|
**Constitution alignment (UI-NAMING-001):** Primary operator labels remain domain-specific and translate the same canonical nouns (`Finding`, `Baseline`, `Drift`, `Run`, `Alert`, `Workspace`, `Tenant`) consistently.
|
|
|
|
**Constitution alignment (DECIDE-001):** Locale choice is made once at the shell/settings level; core governance surfaces consume it without becoming configuration pages themselves.
|
|
|
|
**Constitution alignment (UI-CONST-001 / UI-SURF-001 / ACTSURF-001 / UI-HARD-001 / UI-EX-001 / UI-REVIEW-001 / HDR-001):** Existing inspect/open models and action hierarchies remain unchanged. This slice changes copy and preference controls only.
|
|
|
|
**Constitution alignment (UI-SEM-001 / LAYER-001):** One small locale resolver and one supported-locale catalog are justified because current code lacks a single request-level language decision. No generic translation framework or theme layer is allowed.
|
|
|
|
### Functional Requirements
|
|
|
|
- **FR-252-001 Supported locales**: The system MUST support exactly two locales in v1: `en` and `de`.
|
|
- **FR-252-002 Deterministic precedence**: The effective locale for admin and tenant web requests MUST resolve in this order: explicit override, user preference, workspace default, system default. System-panel requests MUST resolve in this order in v1: explicit override, system default.
|
|
- **FR-252-003 Safe validation**: Unsupported or malformed locale values MUST be rejected or normalized safely and MUST fall back to English rather than rendering raw translation keys.
|
|
- **FR-252-004 User-owned preference**: The system MUST allow an authenticated workspace-bound user to save, change, or clear their own personal locale preference without affecting other users.
|
|
- **FR-252-005 Workspace-owned default**: The system MUST allow authorized workspace operators to set or clear a workspace default locale using the existing workspace settings infrastructure for admin and tenant panel inheritance only.
|
|
- **FR-252-006 Reset-to-inherited behavior**: Clearing a user preference MUST cause the locale chain to resume using workspace default or system default.
|
|
- **FR-252-007 Request-time application**: The resolved locale MUST apply consistently to normal web requests, auth flows, and Livewire requests for the in-scope panels, with the system panel using the v1 subset of explicit override plus system default only.
|
|
- **FR-252-008 Shell and auth coverage**: The system MUST localize the panel shell, navigation labels, auth/login copy, and the locale control affordance itself for the supported locales.
|
|
- **FR-252-009 Core surface coverage**: The first implementation slice MUST localize the selected high-signal governance surfaces: dashboard, Findings, Baseline Compare, representative workspace/tenant management tables, monitoring, alerts, operations support labels, and customer-safe review/report viewer shell text.
|
|
- **FR-252-010 Canonical glossary consistency**: The translated surface families MUST use one consistent glossary for core governance terms such as Finding, Baseline, Drift, Risk Accepted, Evidence Gap, Alert, and Run.
|
|
- **FR-252-011 Notification and validation coverage**: In-scope Filament notifications, validation messages, and system helper text MUST render in the resolved locale.
|
|
- **FR-252-012 Locale-aware formatting**: In-scope date, time, number, and relative-time labels shown on operator-facing surfaces MUST respect the resolved locale.
|
|
- **FR-252-013 Controlled fallback**: Missing translations in German MUST fall back to English. Raw translation keys MUST NOT appear on the rendered UI for in-scope surfaces.
|
|
- **FR-252-014 Invariant machine formats**: CSV, JSON, audit logs, stored artifacts, machine-readable report data, IDs, and provider/raw evidence payloads MUST remain stable and non-localized.
|
|
- **FR-252-015 Authorization invariance**: Locale changes MUST NOT alter route access, wrong-plane or non-member 404 behavior, member-but-no-capability 403 behavior, global-search visibility, filter scope, tenant/workspace context, or any other RBAC outcome.
|
|
- **FR-252-016 No parallel locale sources**: In-scope pages, widgets, resources, notifications, and viewers MUST consume the shared resolved locale and MUST NOT implement page-local language sources.
|
|
- **FR-252-017 Bounded v1**: This slice MUST NOT add website localization, more than two locales, a generic preferences framework, or a broad translation program for every product surface.
|
|
|
|
## UI Action Matrix *(mandatory when Filament is changed)*
|
|
|
|
| Surface | Location | Header Actions | Inspect Affordance (List/Table) | Row Actions (max 2 visible) | Bulk Actions (grouped) | Empty-State CTA(s) | View Header Actions | Create/Edit Save+Cancel | Audit log? | Notes / Exemptions |
|
|
|---|---|---|---|---|---|---|---|---|---|---|
|
|
| User locale control | existing panel shell or self-profile surface | none on collection | N/A | none | none | N/A | `Save language`, `Use inherited default`, `Reset override` | existing save/cancel pattern if profile/settings form is used | no | Global shell exception is intentional because locale is a true shell concern |
|
|
| Workspace default locale setting | existing workspace settings surface | existing settings navigation only | N/A | none | none | N/A | existing workspace settings save action includes locale field | existing save/cancel pattern stays authoritative | yes - through existing settings audit path | No destructive action is introduced |
|
|
| Core governance surfaces | existing dashboard, resources, and pages | unchanged | existing inspect affordances remain unchanged | unchanged | unchanged | unchanged | unchanged except translated labels and copy | N/A | no new audit requirement | Translation only; no action hierarchy change |
|
|
| Monitoring and customer-safe review/report surfaces | existing pages, resources, and viewers | unchanged | existing inspect affordances remain unchanged | unchanged | unchanged | unchanged | unchanged except translated labels and copy | N/A | no new audit requirement | Viewer chrome localizes; artifact content stays stable |
|
|
|
|
### Key Entities *(include if feature involves data)*
|
|
|
|
- **Resolved locale context**: Derived request-time value with the selected locale plus source (`explicit_override`, `user_preference`, `workspace_default`, `system_default`); system-panel requests only use the explicit-override or system-default subset in v1
|
|
- **User locale preference**: Workspace-bound user-owned persisted preference for `en` or `de`
|
|
- **Workspace default locale**: Workspace-owned default locale stored through the existing settings infrastructure for admin/tenant inheritance
|
|
- **Translation catalogs**: Bounded EN/DE language files covering the selected first-wave surface families |