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:
co-authored by
Claude Sonnet 5
parent
257a4cf6c0
commit
337f8716bb
@@ -0,0 +1,192 @@
|
||||
{
|
||||
"list": {
|
||||
"eyebrow": "Bewaken / Werkbank",
|
||||
"title": "Datakwaliteit",
|
||||
"description": "Los evidentie-onderbouwde uitzonderingen op voor ze de werking verstoren.",
|
||||
"runScan": "Kwaliteitscontrole uitvoeren",
|
||||
"confirmScanTitle": "Kwaliteitscontrole bevestigen",
|
||||
"confirmScanBody": "Nu de deterministische controle over alle vijf regeltypes uitvoeren?",
|
||||
"scanning": "Bezig met controleren…",
|
||||
"confirmScanYes": "Ja, uitvoeren",
|
||||
"cancel": "Annuleren",
|
||||
"scanComplete": "Controle voltooid: {{summary}}",
|
||||
"scanNoNew": "geen nieuwe problemen gevonden (bestaande open problemen worden niet opnieuw aangemaakt).",
|
||||
"scanFailed": "Kwaliteitscontrole kon niet uitgevoerd worden.",
|
||||
"statusLabel": "Status",
|
||||
"statusAll": "Alle statussen",
|
||||
"statusOpen": "Open",
|
||||
"statusDeferred": "Uitgesteld",
|
||||
"statusResolved": "Opgelost",
|
||||
"statusRejected": "Verworpen",
|
||||
"ruleTypeLabel": "Regeltype",
|
||||
"ruleTypeAll": "Alle regeltypes",
|
||||
"demoScenariosOnly": "Enkel demoscenario's",
|
||||
"loading": "Kwaliteitswerkbank laden…",
|
||||
"queueClear": "Wachtrij is leeg",
|
||||
"noIssuesMatch": "Geen problemen komen overeen met de huidige filters.",
|
||||
"noDemoIssuesMatch": "Geen demoscenario-problemen komen overeen",
|
||||
"noDemoIssuesMatchDetail": "Vink 'Enkel demoscenario's' uit om de volledige wachtrij te zien.",
|
||||
"unavailable": "Datakwaliteitsproblemen zijn momenteel niet beschikbaar.",
|
||||
"count": "{{count}} problemen",
|
||||
"evidenceBacked": "Evidentie-onderbouwde detectie",
|
||||
"columns": {
|
||||
"reference": "Referentie",
|
||||
"rule": "Regel",
|
||||
"entity": "Entiteit",
|
||||
"severity": "Ernst",
|
||||
"status": "Status"
|
||||
}
|
||||
},
|
||||
"ruleTypes": {
|
||||
"possible_duplicate_customer": "Mogelijke dubbele klant",
|
||||
"missing_required_field": "Ontbrekend verplicht veld",
|
||||
"odometer_regression": "Afwijkende kilometerstand",
|
||||
"booking_overlap": "Overlappende boeking",
|
||||
"vehicle_status_conflict": "Statusconflict voertuig"
|
||||
},
|
||||
"severities": {
|
||||
"high": "Kritiek",
|
||||
"medium": "Waarschuwing",
|
||||
"low": "Info"
|
||||
},
|
||||
"detail": {
|
||||
"backLink": "Kwaliteitswerkbank",
|
||||
"eyebrow": "Kwaliteit / {{rule}}",
|
||||
"title": "Bekijk vastgelegde evidentie en registreer een geauditeerde oplossing.",
|
||||
"notFound": "Dit probleem kon niet gevonden worden.",
|
||||
"loading": "Probleemevidentie laden…",
|
||||
"managerOnly": "De kwaliteitswerkbank is enkel zichtbaar voor Operations Managers.",
|
||||
"managerOnlyDetail": "Datakwaliteitsevidentie en -oplossingen zijn enkel zichtbaar voor Operations Managers.",
|
||||
"summary": {
|
||||
"rule": "Regel",
|
||||
"entity": "Entiteit",
|
||||
"evidenceSummary": "Evidentiesamenvatting"
|
||||
},
|
||||
"resolved": {
|
||||
"title": "Probleem {{ref}} opgelost",
|
||||
"body": "De wijziging is doorgevoerd en vastgelegd in de audit trail.",
|
||||
"viewAudit": "Audit trail bekijken",
|
||||
"viewVehicle": "Voertuig bekijken",
|
||||
"continueDemo": "Ga verder met de demo"
|
||||
},
|
||||
"deferOrReject": {
|
||||
"heading": "Uitstellen of verwerpen",
|
||||
"description": "Stel uit om later opnieuw te bekijken, of verwerp als dit geen echt probleem is.",
|
||||
"defer": "Uitstellen",
|
||||
"reject": "Verwerpen",
|
||||
"deferFailed": "Kon dit probleem niet uitstellen.",
|
||||
"rejectFailed": "Kon dit probleem niet verwerpen."
|
||||
},
|
||||
"explainer": {
|
||||
"whatIsWrong": "Wat is er mis",
|
||||
"whyItMatters": "Waarom dit belangrijk is",
|
||||
"possible_duplicate_customer": {
|
||||
"whatIsWrong": "Twee klantprofielen delen identificerende gegevens (e-mail, telefoon of een erg gelijkende naam) sterk genoeg om waarschijnlijk dezelfde persoon te zijn, twee keer geregistreerd.",
|
||||
"whyItMatters": "Dubbele klanten verdelen de boekingsgeschiedenis over twee records, riskeren dubbele facturatie en verwarren klantcontacten."
|
||||
},
|
||||
"missing_required_field": {
|
||||
"whatIsWrong": "Dit record mist gegevens die vereist zijn voor normale werking (bijvoorbeeld een klant zonder e-mail of telefoonnummer).",
|
||||
"whyItMatters": "Zonder deze gegevens kan het bedrijf de klant niet bereiken, of het voertuig niet betrouwbaar identificeren voor compliance- en overdrachtscontroles."
|
||||
},
|
||||
"odometer_regression": {
|
||||
"whatIsWrong": "Een ingevoerde kilometerstand ligt lager dan de laatst bevestigde (canonieke) stand van het voertuig.",
|
||||
"whyItMatters": "Een dalende kilometerstand wijst meestal op een invoerfout of een verwisseld voertuig. Dit stilzwijgend doorlaten zou de onderhoudsplanning en de kilometerhistoriek bij wederverkoop verstoren."
|
||||
},
|
||||
"booking_overlap": {
|
||||
"whatIsWrong": "Hetzelfde voertuig is toegewezen aan twee boekingen met overlappende periodes.",
|
||||
"whyItMatters": "Slechts één van deze boekingen kan effectief worden nagekomen. Onopgelost zou een klant aankomen en merken dat zijn voertuig al bij iemand anders is."
|
||||
},
|
||||
"vehicle_status_conflict": {
|
||||
"whatIsWrong": "De opgeslagen operationele status van dit voertuig komt niet overeen met wat de eigen boekings- en inspectiegeschiedenis impliceert.",
|
||||
"whyItMatters": "Een foutieve status kan een niet-beschikbaar voertuig boekbaar laten lijken, of een beschikbaar voertuig verbergen voor het wagenpark."
|
||||
}
|
||||
},
|
||||
"duplicateCustomer": {
|
||||
"heading": "Vergelijken en samenvoegen",
|
||||
"description": "Kies de klant die behouden blijft en bekijk elk afwijkend veld.",
|
||||
"keepAsSurvivor": "Behouden als hoofdprofiel",
|
||||
"differs": "Verschilt",
|
||||
"match": "Gelijk",
|
||||
"mergePreview": "{{loser}} wordt een tombstone gekoppeld aan {{survivor}}; de boekingen worden herverbonden.",
|
||||
"mergeInto": "Samenvoegen met {{ref}}",
|
||||
"confirmMergeTitle": "Samenvoegen bevestigen",
|
||||
"confirmMergeBody": "{{loser}} samenvoegen met {{survivor}}? Dit kan niet ongedaan gemaakt worden.",
|
||||
"merging": "Bezig met samenvoegen…",
|
||||
"confirmMergeYes": "Ja, samenvoegen",
|
||||
"mergeFailed": "Kon deze klanten niet samenvoegen.",
|
||||
"bothMissing": "Beide klanten in deze vergelijking konden niet geladen worden.",
|
||||
"fieldColumn": "Veld",
|
||||
"fields": {
|
||||
"first_name": "Voornaam",
|
||||
"last_name": "Achternaam",
|
||||
"email": "E-mail",
|
||||
"phone": "Telefoon",
|
||||
"postal_code": "Postcode",
|
||||
"city": "Stad"
|
||||
}
|
||||
},
|
||||
"missingField": {
|
||||
"heading": "Ontbrekende velden invullen",
|
||||
"description": "Vervolledig het record voor {{ref}}. Het probleem wordt automatisch opgelost zodra niets verplichts meer ontbreekt.",
|
||||
"atLeastOne": "Minstens één van e-mail of telefoon is vereist.",
|
||||
"saveAndRecheck": "Opslaan en herchecken",
|
||||
"saving": "Opslaan…",
|
||||
"saveFailed": "Kon deze velden niet opslaan.",
|
||||
"fields": {
|
||||
"first_name": "Voornaam",
|
||||
"last_name": "Achternaam",
|
||||
"email": "E-mail",
|
||||
"phone": "Telefoon",
|
||||
"registration_number": "Kenteken",
|
||||
"make": "Merk",
|
||||
"model": "Model",
|
||||
"location": "Locatie"
|
||||
}
|
||||
},
|
||||
"odometerRegression": {
|
||||
"heading": "Kilometerafwijking oplossen",
|
||||
"description": "De laatst bevestigde kilometerstand wordt nooit automatisch verlaagd — kies hoe dit te verwerken.",
|
||||
"canonicalOdometer": "Laatst bevestigde kilometerstand",
|
||||
"decisionLegend": "Beslissing",
|
||||
"retainCanonical": "Laatst bevestigde stand behouden",
|
||||
"retainCanonicalDetail": "Behandel de ingevoerde stand als foutief; er verandert niets aan het voertuigrecord.",
|
||||
"correctReading": "Stand corrigeren",
|
||||
"correctReadingDetail": "Werk zowel de boeking als de laatst bevestigde kilometerstand bij met de juiste waarde.",
|
||||
"noBookingAttached": "Geen gekoppelde boeking bij dit probleem, dus enkel 'laatst bevestigde stand behouden' is beschikbaar.",
|
||||
"booking": "Boeking",
|
||||
"correctedOdometer": "Gecorrigeerde kilometerstand (km)",
|
||||
"note": "Notitie",
|
||||
"resolving": "Bezig met oplossen…",
|
||||
"resolveIssue": "Probleem oplossen",
|
||||
"resolveFailed": "Kon dit probleem niet oplossen."
|
||||
},
|
||||
"bookingOverlap": {
|
||||
"heading": "Boekingsoverlap oplossen",
|
||||
"description": "Blokkeer één van de twee overlappende verbintenissen. De andere behoudt zijn huidige status.",
|
||||
"columns": {
|
||||
"booking": "Boeking",
|
||||
"window": "Periode",
|
||||
"status": "Status",
|
||||
"blockThis": "Deze blokkeren"
|
||||
},
|
||||
"blockLabel": "{{ref}} blokkeren",
|
||||
"note": "Notitie",
|
||||
"resolving": "Bezig met oplossen…",
|
||||
"blockButton": "{{ref}} blokkeren",
|
||||
"blockButtonFallback": "Boeking blokkeren",
|
||||
"resolveFailed": "Kon deze overlap niet oplossen."
|
||||
},
|
||||
"vehicleStatusConflict": {
|
||||
"heading": "Statusconflict oplossen",
|
||||
"description": "Eén gezaghebbende regel beveelt een gecorrigeerde operationele status voor dit voertuig aan.",
|
||||
"currentStatus": "Huidige status",
|
||||
"calculateAndApply": "Aanbevolen status berekenen en toepassen",
|
||||
"confirmTitle": "Statuswijziging bevestigen",
|
||||
"confirmBody": "De gezaghebbende aanbevolen status voor dit voertuig toepassen?",
|
||||
"applying": "Bezig met toepassen…",
|
||||
"confirmYes": "Ja, toepassen",
|
||||
"applied": "Toegepast {{status}} — {{reason}}",
|
||||
"applyFailed": "Kon geen aanbevolen status toepassen."
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user