feat(web): one date standard across the UI — "25 Qer 14:30"

Dates were a mix: catalog-formatted "25 Qershor 20:01" where screens used
formatRelativeDateTime, and browser-locale "7/6/2026, 9:34 AM" in ~20
places that called raw toLocaleString/-Date-/-Time-String. Unified:

- common.monthsShort in both catalogs (Jan/Shk/…/Qer/Korr/…/Dhj);
  formatDate ("25 Qer", year only when not current), formatDateTime
  ("25 Qer 14:30", optional seconds), formatClock ("HH:mm", 24h) in
  lib/format.ts. formatRelativeDateTime keeps Sot/Dje and switches its
  older-dates branch to the same short months.
- Every raw toLocale* DATE call swept: shifts X-report line, plan
  effective dates, sub version labels, drawer today feed, snapshot
  tooltips, device footer checkedAt, event-detail timestamp (keeps
  seconds — chain evidence), tariff composer active-since + version
  sidebar. Number toLocaleString (thousand separators) untouched.

The catalogs in this commit also carry the keys for the two follow-up
commits (fee breakdown, composer increment labels).

Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
2026-07-06 15:41:40 +02:00
parent 6cf3492bff
commit 5e1a885dcb
11 changed files with 96 additions and 22 deletions
+17
View File
@@ -33,6 +33,7 @@ export const en: Catalog = {
"November",
"December",
],
monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
},
auth: {
title: "Parking System",
@@ -330,6 +331,12 @@ export const en: Catalog = {
hoursUnit: "hours",
egHours: "e.g. 2",
pricePerIncrement: "Price / increment (per hour)",
pricePerHour: "Price / hour",
pricePerN: "Price / {{min}} min",
modeFlatN: "Flat price / {{min}} min",
perHourEquiv: "= {{amount}} / hour",
incrementWarning:
"Careful: the billing increment is {{min}} min — every price below is charged per started {{min}} minutes, NOT per hour.",
thereafter: "thereafter (open-ended)",
remove: "Remove",
addBlock: "+ Add block",
@@ -562,6 +569,16 @@ export const en: Catalog = {
graceExpires: "Grace expires",
curve: "Duration curve",
curveHint: "Fee from entry at several durations — see where the daily cap flattens or windows shift.",
bd: {
title: "How the amount is produced",
rounding: "{{raw}} min parked → {{billed}} min billed ({{inc}}-min increments)",
grace: "Free — within the entry grace ({{min}} min)",
package: "window package",
step: "Day {{day}}: stay up to {{hours}}h — total",
stepRepeated: "Day {{day}}: beyond the top tier — full-day total",
cap: "Daily cap {{cap}} applied (day {{day}})",
total: "Total",
},
},
subs: {
title: "Subscriptions",