polish: rebrand to Fleet Ops, add trilingual i18n, adaptive demo guide, and UX overhaul

Rebrands the product from MobilityOps to Fleet Ops across the UI, backend defaults and
knowledge base, and makes nl-BE/en-GB/fr-BE full first-class languages: i18next with
eager-bundled per-namespace resources, a persisted accessible language switcher (topbar
and mobile drawer), locale-aware date/number formatting, and a coverage test that fails
the build on any missing or empty translation key.

Backend dynamic content (demo scenarios, blocked-reason text, integration status) moves
from fixed English/Dutch prose to stable message codes + params so the frontend can
localize it; the demo knowledge base gains a fully translated NL/EN/FR procedure corpus
(11 documents each) with per-language retrieval and localized evidence-state messages.

The Demo Guide becomes breakpoint-adaptive: a docked rail on extra-wide desktop, a
floating panel that auto-collapses to a persistent, closable progress chip on standard
desktop/tablet, and a collapsed/half/full bottom sheet on mobile -- with scroll+focus+
highlight on "go to this step", Escape handling, and reduced-motion support.

The Data Quality Workbench gets accessible choice-card decisions with a clear primary/
secondary/tertiary action hierarchy; the Automation ledger groups repeated successes and
uses meaningful short refs; the Audit trail groups events by correlation id with human
action labels and readable before/after diffs. Attention Queue, Today's movements,
Vehicles, Bookings and Data Quality rows are fully clickable (stretched-link pattern)
with independent secondary links, keyboard support and mobile touch targets.

Fixes a topbar overflow on mobile caused by the new language switcher (moved into the
mobile drawer at <=960px) and two dangling aria-labelledby references introduced this
session. Updates all affected Playwright specs for the new nl-BE default and the new
Audit/DemoGuide DOM structure, and adds new i18n-coverage, demo-guide-adaptive and
clickable-rows specs. 131 backend tests, Ruff and mypy, and 71 Playwright tests pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
NuklearRabbit
2026-08-03 18:33:22 +02:00
co-authored by Claude Sonnet 5
parent 257a4cf6c0
commit 337f8716bb
127 changed files with 5529 additions and 1287 deletions
@@ -0,0 +1,192 @@
{
"list": {
"eyebrow": "Assure / Workbench",
"title": "Data quality",
"description": "Resolve evidence-backed exceptions before they disrupt operations.",
"runScan": "Run quality scan",
"confirmScanTitle": "Confirm quality scan",
"confirmScanBody": "Run the deterministic scan across all five rule types now?",
"scanning": "Scanning…",
"confirmScanYes": "Yes, run scan",
"cancel": "Cancel",
"scanComplete": "Scan complete: {{summary}}",
"scanNoNew": "no new issues found (existing open issues are not recreated).",
"scanFailed": "Could not run the quality scan.",
"statusLabel": "Status",
"statusAll": "All statuses",
"statusOpen": "Open",
"statusDeferred": "Deferred",
"statusResolved": "Resolved",
"statusRejected": "Rejected",
"ruleTypeLabel": "Rule type",
"ruleTypeAll": "All rule types",
"demoScenariosOnly": "Demo scenarios only",
"loading": "Loading quality workbench…",
"queueClear": "Queue is clear",
"noIssuesMatch": "No issues match the current filters.",
"noDemoIssuesMatch": "No demo-scenario issues match",
"noDemoIssuesMatchDetail": "Uncheck 'Demo scenarios only' to see the full queue.",
"unavailable": "Data-quality issues are unavailable right now.",
"count": "{{count}} issues",
"evidenceBacked": "Evidence-backed detection",
"columns": {
"reference": "Reference",
"rule": "Rule",
"entity": "Entity",
"severity": "Severity",
"status": "Status"
}
},
"ruleTypes": {
"possible_duplicate_customer": "Possible duplicate customer",
"missing_required_field": "Missing required field",
"odometer_regression": "Odometer regression",
"booking_overlap": "Booking overlap",
"vehicle_status_conflict": "Vehicle status conflict"
},
"severities": {
"high": "Critical",
"medium": "Warning",
"low": "Info"
},
"detail": {
"backLink": "Quality workbench",
"eyebrow": "Quality / {{rule}}",
"title": "Review persisted evidence and record an audited resolution.",
"notFound": "This issue could not be found.",
"loading": "Loading issue evidence…",
"managerOnly": "The quality workbench is visible to Operations Managers only.",
"managerOnlyDetail": "Data-quality evidence and resolutions are visible to Operations Managers only.",
"summary": {
"rule": "Rule",
"entity": "Entity",
"evidenceSummary": "Evidence summary"
},
"resolved": {
"title": "Issue {{ref}} resolved",
"body": "The change has been applied and is recorded in the audit trail.",
"viewAudit": "View audit trail",
"viewVehicle": "View vehicle",
"continueDemo": "Continue the demo"
},
"deferOrReject": {
"heading": "Defer or reject",
"description": "Defer to review later, or reject if this is not a real issue.",
"defer": "Defer",
"reject": "Reject",
"deferFailed": "Could not defer this issue.",
"rejectFailed": "Could not reject this issue."
},
"explainer": {
"whatIsWrong": "What's wrong",
"whyItMatters": "Why it matters",
"possible_duplicate_customer": {
"whatIsWrong": "Two customer profiles share identifying details (email, phone or a very similar name) strongly enough that they are likely the same person, registered twice.",
"whyItMatters": "Duplicate customers split booking history across two records, risk duplicate billing, and confuse support conversations."
},
"missing_required_field": {
"whatIsWrong": "This record is missing information that's required for normal operation (for example, a customer with neither an email nor a phone number on file).",
"whyItMatters": "Without this data, the business can't reach the customer, or can't reliably identify the vehicle for compliance and hand-off checks."
},
"odometer_regression": {
"whatIsWrong": "A submitted odometer reading is lower than the vehicle's last known (canonical) reading.",
"whyItMatters": "A falling odometer usually means a data-entry mistake or that readings were recorded against the wrong vehicle. Letting it through silently would corrupt maintenance scheduling and resale mileage history."
},
"booking_overlap": {
"whatIsWrong": "The same vehicle is committed to two bookings whose date ranges overlap.",
"whyItMatters": "Only one of these bookings can actually be honoured. Left unresolved, a customer would arrive to find their vehicle already out with someone else."
},
"vehicle_status_conflict": {
"whatIsWrong": "This vehicle's stored operational status doesn't match what its own booking and inspection history implies it should be.",
"whyItMatters": "An incorrect status can make an unavailable vehicle appear bookable, or keep an available vehicle hidden from the fleet."
}
},
"duplicateCustomer": {
"heading": "Compare and merge",
"description": "Choose the canonical customer and review each conflicting field.",
"keepAsSurvivor": "Keep as survivor",
"differs": "Differs",
"match": "Match",
"mergePreview": "{{loser}} will become a tombstone linked to {{survivor}}; its bookings will be rewired.",
"mergeInto": "Merge into {{ref}}",
"confirmMergeTitle": "Confirm merge",
"confirmMergeBody": "Merge {{loser}} into {{survivor}}? This cannot be undone.",
"merging": "Merging…",
"confirmMergeYes": "Yes, merge",
"mergeFailed": "Could not merge these customers.",
"bothMissing": "Both customers in this comparison could not be loaded.",
"fieldColumn": "Field",
"fields": {
"first_name": "First name",
"last_name": "Last name",
"email": "Email",
"phone": "Phone",
"postal_code": "Postal code",
"city": "City"
}
},
"missingField": {
"heading": "Provide the missing fields",
"description": "Complete the record for {{ref}}. The issue resolves automatically once nothing required is missing.",
"atLeastOne": "At least one of email or phone is required.",
"saveAndRecheck": "Save and re-check",
"saving": "Saving…",
"saveFailed": "Could not save these fields.",
"fields": {
"first_name": "First name",
"last_name": "Last name",
"email": "Email",
"phone": "Phone",
"registration_number": "Registration number",
"make": "Make",
"model": "Model",
"location": "Location"
}
},
"odometerRegression": {
"heading": "Resolve the odometer regression",
"description": "The canonical odometer is never lowered automatically -- choose how to reconcile it.",
"canonicalOdometer": "Canonical odometer",
"decisionLegend": "Decision",
"retainCanonical": "Retain canonical reading",
"retainCanonicalDetail": "Treat the submitted reading as erroneous; nothing changes on the vehicle record.",
"correctReading": "Correct the reading",
"correctReadingDetail": "Update both the booking and the canonical odometer with the correct value.",
"noBookingAttached": "No related booking is attached to this issue, so only 'retain canonical' is available.",
"booking": "Booking",
"correctedOdometer": "Corrected odometer (km)",
"note": "Note",
"resolving": "Resolving…",
"resolveIssue": "Resolve issue",
"resolveFailed": "Could not resolve this issue."
},
"bookingOverlap": {
"heading": "Resolve the booking overlap",
"description": "Block one of the two overlapping commitments. The other keeps its current status.",
"columns": {
"booking": "Booking",
"window": "Window",
"status": "Status",
"blockThis": "Block this one"
},
"blockLabel": "Block {{ref}}",
"note": "Note",
"resolving": "Resolving…",
"blockButton": "Block {{ref}}",
"blockButtonFallback": "Block booking",
"resolveFailed": "Could not resolve this overlap."
},
"vehicleStatusConflict": {
"heading": "Resolve the status conflict",
"description": "One authoritative rule recommends a corrected operational status for this vehicle.",
"currentStatus": "Current status",
"calculateAndApply": "Calculate and apply recommended status",
"confirmTitle": "Confirm status change",
"confirmBody": "Apply the authoritative recommended status for this vehicle?",
"applying": "Applying…",
"confirmYes": "Yes, apply",
"applied": "Applied {{status}} — {{reason}}",
"applyFailed": "Could not apply a recommended status."
}
}
}