3.8 KiB
3.8 KiB
i18n formatting (dates, times, numbers)
Use when adding or changing user-visible dates/times/numbers, RTL layout, or locale-specific pickers.
Display formatting
- Module:
frontend/src/lib/i18n/format.ts - Hook:
frontend/src/lib/hooks/useAppFormatters.ts(useLocale()inside) - Never use raw
toLocaleDateString/toLocaleTimeString/ bareIntl.DateTimeFormat(undefined, …)in UI.
| Helper | Use for |
|---|---|
formatAppDate |
Date-only labels |
formatAppTime |
Time-only labels |
formatAppDateTime |
Combined stamp |
formatAppTimeRange |
Appointment ranges |
formatAppTableDate |
Table cells |
formatAppNumber |
Counts, amounts (grouped) |
formatAppInteger |
Calendar year/day — no comma grouping |
formatAppPickerDateLabel |
Calendar trigger button label |
APP_DATE.* |
Shared preset option objects |
Form controls (dates & selects)
| Piece | Location / use |
|---|---|
AppDateInput |
All form/filter date fields — every locale; masked typing + calendar popup; wire value YYYY-MM-DD or empty |
FORM_DATE_INPUT_CLASS |
Visual shell for date input (same padding/inset as selects; no CSS chevron) |
FORM_SELECT_CLASS |
Native <select> filters/fields — ps-3 pe-10, chevron from globals.css |
FORM_SELECT_COMPACT_CLASS |
Tiny selects (e.g. sort direction ↓/↑) — symmetric px-2, no chevron gutter |
Dropdown |
Labeled form select — only where already used; prefer FORM_SELECT_CLASS for new filters |
CompactSelect |
Year/month/day sub-selects inside calendar panels |
AppDateInput behavior
fa: Jalali displayYYYY/MM/DD(Persian digits), parse/mask inpersianCalendar.tsen/nl: Gregorian displayYYYY-MM-DD, parse/mask indateInputFormat.ts- Calendar icon at
end-3(matches select chevron inset); text usestext-start(logical — right in RTL, left in LTR) - Popup:
CalendarDayPartsPanel(shared with schedule picker) - Do not add native
<input type="date">— one component for all locales
Select chevron
- Defined once in
frontend/src/styles/globals.csson.form-select:not(.form-select-no-chevron) - RTL:
background-position: left 0.75rem center; LTR:right 0.75rem center text-align: starton selects
Calendar / appointment pickers
| Component | Use for |
|---|---|
ScheduleDayPicker |
Appointments strip — nav arrows + today toggle + expandable panel |
CalendarDaySelect |
Navigator wrapper (arrows + panel) |
CalendarDayPartsPanel |
Year / month / day row — used by schedule picker and AppDateInput |
Persian (fa): Jalali calendar + arabext digits via Intl (usesPersianCalendar). Internal model stays Date at local midnight (Gregorian) — APIs unchanged.
- Conversion:
frontend/src/lib/i18n/persianCalendar.ts - Gregorian typing:
frontend/src/lib/i18n/dateInputFormat.ts - Gregorian month labels:
schedule.monthJanuary… message keys
RTL
dir/langon<html>fromapp/[locale]/layout.tsxisRtlLocaleinfrontend/src/i18n/routing.ts- Use logical CSS:
text-start,text-end,ps-*,pe-*,ms-*,me-* Table: default[&_th]:text-start [&_td]:text-start; override withtext-centerortext-endon cells — nevertext-left/text-righton headers (causes header/body column drift in RTL)- Minimal overrides in
globals.css— avoid double-mirroring (no extrarow-reverseon shells that already inheritdirection: rtl)
i18n strings
- User-facing copy:
frontend/messages/{en,fa,nl}.json— all three locales.
Verify
cd frontend && npx tsc --noEmit
Manual: switch to Persian — Cases date filters, Tasks filter row (single line + sort visible), Staff/Orgs table columns aligned; switch to English — date fields match adjacent dropdown alignment.