@@ -48,6 +48,7 @@ import { formatCHF, slugify, clamp } from '@mikespa/kit';
4848| ` formatDate(input) ` | Date as DD.MM.YYYY | "19.06.2026" |
4949| ` formatTime(input) ` | Time (24h) | "15:30" |
5050| ` formatDateTime(input) ` | Date + time (locale-formatted) | "19 juin 2026, 15:30" |
51+ | ` formatDateRange(start, end) ` | Compact date range (locale-formatted) | "01.06.2026 – 15.06.2026" |
5152| ` formatRelative(input) ` | Relative to now (locale-formatted) | "il y a 3 heures" |
5253| ` isToday(input) ` | Whether date is today | ` true ` |
5354| ` isPast(input) ` | Whether date is in the past | ` true ` |
@@ -59,10 +60,22 @@ import { formatCHF, slugify, clamp } from '@mikespa/kit';
5960| ` formatCHF(amount) ` | Swiss CHF, apostrophe sep. | "1'234.50 CHF" |
6061| ` formatCurrency(value) ` | Intl currency (CHF default) | "1 234.50 CHF" |
6162| ` formatCompact(value) ` | Compact notation | "1,2 k" |
63+ | ` parseCHF(input) ` | Parse Swiss amount → number | ` 1234.5 ` |
6264| ` formatPercent(value) ` | Percentage | "45,6%" |
6365| ` formatBytes(bytes) ` | Human-readable file size | "1.5 KB" |
6466| ` formatPhone(input) ` | Swiss phone number | "+41 79 123 45 67" |
67+ | ` isValidPhone(input) ` | Validate Swiss phone number shape | ` true ` |
6568| ` formatIBAN(input) ` | IBAN with spaces | "CH56 0483 5012 3456 7800 9" |
69+ | ` isValidIBAN(input) ` | Validate IBAN check digits (any country) | ` true ` |
70+ | ` maskIBAN(input) ` | Mask IBAN for safe display | "CH56 *** * *** * *** * *** * 9" |
71+ | ` formatAHV(input) ` | AHV/OASI number, grouped | "756.9217.0769.85" |
72+ | ` isValidAHV(input) ` | Validate AHV/OASI check digit | ` true ` |
73+ | ` maskAHV(input) ` | Mask AHV number for safe display | "756.**** .**** .85" |
74+ | ` formatQRReference(input) ` | QR-bill/ISR reference, grouped | "21 00000 00003 13947 14300 09017" |
75+ | ` isValidQRReference(input) ` | Validate QR-bill/ISR check digit | ` true ` |
76+ | ` formatUID(input) ` | UID/VAT number, grouped | "CHE-116.281.710" |
77+ | ` isValidUID(input) ` | Validate UID/VAT check digit | ` true ` |
78+ | ` isValidSwissPostalCode(input) ` | Validate 4-digit postal code range | ` true ` |
6679| ` formatSecs(seconds, step?) ` | Duration from seconds | "2h30" / "45min" |
6780| ` formatMinutes(minutes, step?) ` | Duration from minutes | "2h30" / "45min" |
6881| ` formatHours(hours, step?) ` | Duration from decimal hours | "2h30" / "45min" |
@@ -74,6 +87,22 @@ import { formatCHF, slugify, clamp } from '@mikespa/kit';
7487All ` format* ` functions that wrap ` Intl ` accept an optional ` locale ` parameter
7588(defaults to ` 'fr-CH' ` ) so consuming projects can override per-call.
7689
90+ For apps with a variable/per-request locale (e.g. a language switcher, or SSR with
91+ per-request locale), ` createFormatters(locale) ` returns those same functions
92+ pre-bound to one locale, so call sites don't repeat ` { locale } ` everywhere. It's
93+ a plain factory — no shared/global state, safe under concurrent requests:
94+
95+ ``` ts
96+ import { createFormatters } from ' @mikespa/kit/format' ;
97+
98+ const fmt = createFormatters (' de-CH' );
99+ fmt .formatDate (order .date );
100+ fmt .formatCurrency (order .total );
101+ ```
102+
103+ ` createFormatters ` binds: ` formatDate ` , ` formatTime ` , ` formatDateTime ` ,
104+ ` formatRelative ` , ` formatNumber ` , ` formatCompact ` , ` formatCurrency ` , ` formatPercent ` .
105+
77106### ` ./string `
78107
79108| Function | Description |
0 commit comments