@usequeek/theme-kit 0.1.20 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/utils/locale.ts CHANGED
@@ -19,6 +19,58 @@
19
19
  * byte-identical to before.
20
20
  */
21
21
 
22
+ /**
23
+ * English display locale — the ONE Intl tag every English shopper sees dates,
24
+ * numbers and money in. `en-NG`, not `en-GB`: both print dates identically
25
+ * ("2 October 2026", "14 Feb 2026"), but only `en-NG` renders NGN with the
26
+ * naira sign the stores already show (`₦12,500` vs `en-GB`'s `NGN 12,500` —
27
+ * verified on Node 22, full ICU, 2/10/26). `DISPLAY_LOCALE` in
28
+ * `utils/format.ts` aliases this, so the value lives in exactly one place.
29
+ */
30
+ export const ENGLISH_DISPLAY_LOCALE = 'en-NG';
31
+
32
+ /**
33
+ * THE single canonical mapping from a storefront locale code to the Intl
34
+ * locale dates/numbers/relative time are formatted in (founder 2/10/26:
35
+ * shopper's locale, English in the British/Nigerian style so English stores
36
+ * do not change visibly — "2 October 2026", never US "October 2, 2026").
37
+ *
38
+ * - Missing/invalid/unknown-structure codes and EVERY English variant (`en`,
39
+ * `en-GB`, `en-NG`, `en-US`, …) become `ENGLISH_DISPLAY_LOCALE`. In
40
+ * particular bare `en` must never reach Intl directly: `en` formats US
41
+ * order ("October 2, 2026").
42
+ * - Every other well-formed code passes through unchanged (`fr`, `ar`,
43
+ * `pt-BR`, `zh-CN`, `yo`, `ha`, `sw`, …).
44
+ *
45
+ * Pure (no `next/*`, no React) like the rest of this module. Never throws.
46
+ * Pair with `resolveSupportedLocale` when the runtime's ICU may lack the
47
+ * locale — this function maps, it does not probe.
48
+ */
49
+ export function resolveIntlLocale(locale: string | null | undefined): string {
50
+ const code = parseLocaleCode(locale);
51
+ if (!code) return ENGLISH_DISPLAY_LOCALE;
52
+ if ((code.split('-')[0] ?? '').toLowerCase() === 'en') return ENGLISH_DISPLAY_LOCALE;
53
+ return code;
54
+ }
55
+
56
+ /**
57
+ * Graceful ICU fallback for one formatting call: the candidate when this
58
+ * Node's ICU formats it natively, `ENGLISH_DISPLAY_LOCALE` otherwise (a
59
+ * minimal-ICU build with no French data still renders English, never an
60
+ * exception). Never throws — pass any Intl constructor's
61
+ * `supportedLocalesOf`, e.g. `(l) => Intl.DateTimeFormat.supportedLocalesOf(l)`.
62
+ */
63
+ export function resolveSupportedLocale(
64
+ candidate: string,
65
+ supportedLocalesOf: (locales: string[]) => readonly string[],
66
+ ): string {
67
+ try {
68
+ return supportedLocalesOf([candidate]).length > 0 ? candidate : ENGLISH_DISPLAY_LOCALE;
69
+ } catch {
70
+ return ENGLISH_DISPLAY_LOCALE;
71
+ }
72
+ }
73
+
22
74
  /** Request header the proxy sets for published non-primary locales. */
23
75
  export const LOCALE_CODE_HEADER = 'x-queek-locale';
24
76