@vocoder/core 0.2.0 → 0.3.0

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/dist/index.d.mts CHANGED
@@ -100,6 +100,32 @@ declare function formatValue(value: string | number | Date, format: FormatMode,
100
100
  */
101
101
  declare function generateMessageHash(text: string, context?: string, formality?: string): string;
102
102
 
103
+ declare const PLURAL_CLDR: Set<string>;
104
+ declare const ALL_CLDR: Set<string>;
105
+ /**
106
+ * Default ordinal ICU — locale-neutral structural placeholder used as the extraction
107
+ * key and bundle lookup key for `<T value={rank} ordinal />` components.
108
+ *
109
+ * Uses a minimal single-branch form so the stored ICU carries no source-language
110
+ * ordinal suffixes. The actual ordinal form is resolved at runtime:
111
+ * Tier 1 — ordinalForms.suffixes/words from the compiled bundle (covers 93+ languages)
112
+ * Tier 2 — this key's bundle translation (provider returns `other {#}` unchanged;
113
+ * formatICU evaluates it to String(rank), same as Tier 3)
114
+ * Tier 3 — String(rank) fallback
115
+ */
116
+ declare const DEFAULT_ORDINAL_ICU = "{count, selectordinal, other {#}}";
117
+ /**
118
+ * Build a plural or ordinal ICU string from plural prop key/value pairs.
119
+ * Exact matches (_0, _1) come before CLDR categories (one, other, etc.).
120
+ * Internal variable name is always "count" for consistent lookup keys.
121
+ */
122
+ declare function buildPluralICU(props: Record<string, string>, ordinal?: boolean): string;
123
+ /**
124
+ * Build a select ICU string from select prop key/value pairs.
125
+ * Internal variable name is always "value" for consistent lookup keys.
126
+ */
127
+ declare function buildSelectICU(props: Record<string, string>): string;
128
+
103
129
  /**
104
130
  * Format an ICU MessageFormat string with the given values and locale.
105
131
  * Returns the raw `text` unchanged if parsing or formatting throws — the
@@ -120,5 +146,15 @@ declare function formatICU(text: string, values: Record<string, any>, locale?: s
120
146
  * @param values - Runtime interpolation values (needed for word-based rank lookup)
121
147
  */
122
148
  declare function rewriteSelectordinalInICU(icu: string, ordinalForms: OrdinalForms, values: Record<string, any>): string;
149
+ /**
150
+ * Apply ordinal forms data to produce a locale-correct ordinal string.
151
+ *
152
+ * Returns the formatted ordinal when ordinalForms covers the value, or
153
+ * `String(value)` for word-based locales when the rank is outside the
154
+ * compiled word map (e.g. ranks > 100). Returns `null` only when the
155
+ * forms type is unrecognised — callers should fall through to their ICU
156
+ * bundle or String(value) in that case.
157
+ */
158
+ declare function applyOrdinalForms(value: number, locale: string, forms: OrdinalForms, gender?: string): string | null;
123
159
 
124
- export { type FormatMode, type FormatValueOptions, type LocaleInfo, type LocalesMap, type OrdinalForms, type OrdinalSuffixes, type TOptions, type TranslationsMap, type VocoderTranslationData, formatICU, formatValue, generateMessageHash, getBestMatchingLocale, getCookie, rewriteSelectordinalInICU, setCookie };
160
+ export { ALL_CLDR, DEFAULT_ORDINAL_ICU, type FormatMode, type FormatValueOptions, type LocaleInfo, type LocalesMap, type OrdinalForms, type OrdinalSuffixes, PLURAL_CLDR, type TOptions, type TranslationsMap, type VocoderTranslationData, applyOrdinalForms, buildPluralICU, buildSelectICU, formatICU, formatValue, generateMessageHash, getBestMatchingLocale, getCookie, rewriteSelectordinalInICU, setCookie };
package/dist/index.d.ts CHANGED
@@ -100,6 +100,32 @@ declare function formatValue(value: string | number | Date, format: FormatMode,
100
100
  */
101
101
  declare function generateMessageHash(text: string, context?: string, formality?: string): string;
102
102
 
103
+ declare const PLURAL_CLDR: Set<string>;
104
+ declare const ALL_CLDR: Set<string>;
105
+ /**
106
+ * Default ordinal ICU — locale-neutral structural placeholder used as the extraction
107
+ * key and bundle lookup key for `<T value={rank} ordinal />` components.
108
+ *
109
+ * Uses a minimal single-branch form so the stored ICU carries no source-language
110
+ * ordinal suffixes. The actual ordinal form is resolved at runtime:
111
+ * Tier 1 — ordinalForms.suffixes/words from the compiled bundle (covers 93+ languages)
112
+ * Tier 2 — this key's bundle translation (provider returns `other {#}` unchanged;
113
+ * formatICU evaluates it to String(rank), same as Tier 3)
114
+ * Tier 3 — String(rank) fallback
115
+ */
116
+ declare const DEFAULT_ORDINAL_ICU = "{count, selectordinal, other {#}}";
117
+ /**
118
+ * Build a plural or ordinal ICU string from plural prop key/value pairs.
119
+ * Exact matches (_0, _1) come before CLDR categories (one, other, etc.).
120
+ * Internal variable name is always "count" for consistent lookup keys.
121
+ */
122
+ declare function buildPluralICU(props: Record<string, string>, ordinal?: boolean): string;
123
+ /**
124
+ * Build a select ICU string from select prop key/value pairs.
125
+ * Internal variable name is always "value" for consistent lookup keys.
126
+ */
127
+ declare function buildSelectICU(props: Record<string, string>): string;
128
+
103
129
  /**
104
130
  * Format an ICU MessageFormat string with the given values and locale.
105
131
  * Returns the raw `text` unchanged if parsing or formatting throws — the
@@ -120,5 +146,15 @@ declare function formatICU(text: string, values: Record<string, any>, locale?: s
120
146
  * @param values - Runtime interpolation values (needed for word-based rank lookup)
121
147
  */
122
148
  declare function rewriteSelectordinalInICU(icu: string, ordinalForms: OrdinalForms, values: Record<string, any>): string;
149
+ /**
150
+ * Apply ordinal forms data to produce a locale-correct ordinal string.
151
+ *
152
+ * Returns the formatted ordinal when ordinalForms covers the value, or
153
+ * `String(value)` for word-based locales when the rank is outside the
154
+ * compiled word map (e.g. ranks > 100). Returns `null` only when the
155
+ * forms type is unrecognised — callers should fall through to their ICU
156
+ * bundle or String(value) in that case.
157
+ */
158
+ declare function applyOrdinalForms(value: number, locale: string, forms: OrdinalForms, gender?: string): string | null;
123
159
 
124
- export { type FormatMode, type FormatValueOptions, type LocaleInfo, type LocalesMap, type OrdinalForms, type OrdinalSuffixes, type TOptions, type TranslationsMap, type VocoderTranslationData, formatICU, formatValue, generateMessageHash, getBestMatchingLocale, getCookie, rewriteSelectordinalInICU, setCookie };
160
+ export { ALL_CLDR, DEFAULT_ORDINAL_ICU, type FormatMode, type FormatValueOptions, type LocaleInfo, type LocalesMap, type OrdinalForms, type OrdinalSuffixes, PLURAL_CLDR, type TOptions, type TranslationsMap, type VocoderTranslationData, applyOrdinalForms, buildPluralICU, buildSelectICU, formatICU, formatValue, generateMessageHash, getBestMatchingLocale, getCookie, rewriteSelectordinalInICU, setCookie };
package/dist/index.js CHANGED
@@ -47,6 +47,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
47
47
  // src/index.ts
48
48
  var src_exports = {};
49
49
  __export(src_exports, {
50
+ ALL_CLDR: () => ALL_CLDR,
51
+ DEFAULT_ORDINAL_ICU: () => DEFAULT_ORDINAL_ICU,
52
+ PLURAL_CLDR: () => PLURAL_CLDR,
53
+ applyOrdinalForms: () => applyOrdinalForms,
54
+ buildPluralICU: () => buildPluralICU,
55
+ buildSelectICU: () => buildSelectICU,
50
56
  formatICU: () => formatICU,
51
57
  formatValue: () => formatValue,
52
58
  generateMessageHash: () => generateMessageHash,
@@ -181,6 +187,40 @@ function generateMessageHash(text, context, formality) {
181
187
  return h.toString(36).padStart(7, "0");
182
188
  }
183
189
 
190
+ // src/icu-builders.ts
191
+ var PLURAL_CLDR = /* @__PURE__ */ new Set(["zero", "one", "two", "few", "many"]);
192
+ var ALL_CLDR = /* @__PURE__ */ new Set(["zero", "one", "two", "few", "many", "other"]);
193
+ var DEFAULT_ORDINAL_ICU = "{count, selectordinal, other {#}}";
194
+ function buildPluralICU(props, ordinal = false) {
195
+ const type = ordinal ? "selectordinal" : "plural";
196
+ const exactParts = [];
197
+ const cldrParts = [];
198
+ for (const [key, text] of Object.entries(props)) {
199
+ const exactMatch = key.match(/^_(\d+)$/);
200
+ if (exactMatch) {
201
+ exactParts.push(`=${exactMatch[1]} {${text}}`);
202
+ } else if (ALL_CLDR.has(key)) {
203
+ cldrParts.push(`${key} {${text}}`);
204
+ }
205
+ }
206
+ return `{count, ${type}, ${[...exactParts, ...cldrParts].join(" ")}}`;
207
+ }
208
+ function buildSelectICU(props) {
209
+ const cases = [];
210
+ let hasOther = false;
211
+ for (const [key, text] of Object.entries(props)) {
212
+ if (key === "other") {
213
+ hasOther = true;
214
+ cases.push(`other {${text}}`);
215
+ } else {
216
+ const wordCase = key.match(/^_([a-zA-Z].*)$/);
217
+ if (wordCase) cases.push(`${wordCase[1]} {${text}}`);
218
+ }
219
+ }
220
+ if (!hasOther) cases.push("other {other}");
221
+ return `{value, select, ${cases.join(" ")}}`;
222
+ }
223
+
184
224
  // src/icu.ts
185
225
  var import_intl_messageformat = __toESM(require("intl-messageformat"));
186
226
  var import_icu_messageformat_parser = require("@formatjs/icu-messageformat-parser");
@@ -354,4 +394,21 @@ function rewriteSelectordinalInICU(icu, ordinalForms, values) {
354
394
  return icu;
355
395
  }
356
396
  }
397
+ function applyOrdinalForms(value, locale, forms, gender) {
398
+ var _a, _b, _c;
399
+ if (forms.type === "suffix") {
400
+ const pr = new Intl.PluralRules(locale, { type: "ordinal" });
401
+ const category = pr.select(value);
402
+ const pattern = (_a = forms.suffixes[category]) != null ? _a : forms.suffixes.other;
403
+ return pattern ? pattern.replace("#", String(value)) : null;
404
+ }
405
+ if (forms.type === "word") {
406
+ const genderKey = gender != null ? gender : "masculine";
407
+ const genderMap = (_c = (_b = forms.words[genderKey]) != null ? _b : forms.words["masculine"]) != null ? _c : Object.values(forms.words)[0];
408
+ const word = genderMap == null ? void 0 : genderMap[value];
409
+ if (word) return word;
410
+ return String(value);
411
+ }
412
+ return null;
413
+ }
357
414
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/cookies.ts","../src/format-value.ts","../src/hash.ts","../src/icu.ts"],"sourcesContent":["export { getCookie, getBestMatchingLocale, setCookie } from \"./cookies\";\nexport { formatValue } from \"./format-value\";\nexport type { FormatValueOptions } from \"./format-value\";\nexport { generateMessageHash } from \"./hash\";\nexport { formatICU, rewriteSelectordinalInICU } from \"./icu\";\nexport type {\n\tFormatMode,\n\tLocaleInfo,\n\tLocalesMap,\n\tOrdinalForms,\n\tOrdinalSuffixes,\n\tTOptions,\n\tTranslationsMap,\n\tVocoderTranslationData,\n} from \"./types\";\n","export function getCookie(name: string, cookieString?: string): string | null {\n\tconst cookies =\n\t\tcookieString || (typeof document !== \"undefined\" ? document.cookie : \"\");\n\n\tif (!cookies) {\n\t\treturn null;\n\t}\n\n\tconst value = cookies\n\t\t.split(\"; \")\n\t\t.find((row: string) => row.startsWith(`${name}=`))\n\t\t?.split(\"=\")[1];\n\n\treturn value ? decodeURIComponent(value) : null;\n}\n\nexport function setCookie(\n\tname: string,\n\tvalue: string,\n\toptions: {\n\t\tmaxAge?: number;\n\t\tpath?: string;\n\t\tdomain?: string;\n\t\tsameSite?: \"Strict\" | \"Lax\" | \"None\";\n\t\tsecure?: boolean;\n\t} = {},\n): void {\n\tif (typeof document === \"undefined\") {\n\t\treturn;\n\t}\n\n\tconst {\n\t\tmaxAge = 365 * 24 * 60 * 60,\n\t\tpath = \"/\",\n\t\tsameSite = \"Lax\",\n\t\tsecure = typeof window !== \"undefined\" &&\n\t\t\twindow.location.protocol === \"https:\",\n\t} = options;\n\n\tlet cookieString = `${name}=${encodeURIComponent(value)}`;\n\n\tif (maxAge) {\n\t\tcookieString += `; Max-Age=${maxAge}`;\n\t}\n\n\tif (path) {\n\t\tcookieString += `; Path=${path}`;\n\t}\n\n\tif (options.domain) {\n\t\tcookieString += `; Domain=${options.domain}`;\n\t}\n\n\tif (sameSite) {\n\t\tcookieString += `; SameSite=${sameSite}`;\n\t}\n\n\tif (secure) {\n\t\tcookieString += \"; Secure\";\n\t}\n\n\tdocument.cookie = cookieString;\n}\n\n/**\n * Find the best matching locale from available options.\n * Handles language codes and regional variants (e.g., 'en-US' -> 'en').\n */\nexport function getBestMatchingLocale(\n\tpreferredLocale: string,\n\tsupportedLocales: string[],\n\tfallback: string,\n): string {\n\tif (supportedLocales.includes(preferredLocale)) {\n\t\treturn preferredLocale;\n\t}\n\n\tconst languageCode = preferredLocale.split(\"-\")[0];\n\tif (languageCode && supportedLocales.includes(languageCode)) {\n\t\treturn languageCode;\n\t}\n\n\tconst similarLocale = supportedLocales.find((locale: string) =>\n\t\tlocale.startsWith(`${languageCode}-`),\n\t);\n\tif (similarLocale) {\n\t\treturn similarLocale;\n\t}\n\n\treturn fallback;\n}\n","import type { FormatMode } from \"./types\";\n\nexport interface FormatValueOptions {\n\tcurrency?: string;\n\tdateStyle?: \"full\" | \"long\" | \"medium\" | \"short\";\n\ttimeStyle?: \"full\" | \"long\" | \"medium\" | \"short\";\n}\n\nconst nfCache = new Map<string, Intl.NumberFormat>();\nconst dtfCache = new Map<string, Intl.DateTimeFormat>();\n\nfunction getNF(locale: string, options: Intl.NumberFormatOptions): Intl.NumberFormat {\n\tconst key = `${locale}:${options.style ?? \"\"}:${options.currency ?? \"\"}:${options.notation ?? \"\"}:${options.maximumFractionDigits ?? \"\"}`;\n\tlet fmt = nfCache.get(key);\n\tif (!fmt) {\n\t\tfmt = new Intl.NumberFormat(locale, options);\n\t\tnfCache.set(key, fmt);\n\t}\n\treturn fmt;\n}\n\nfunction getDTF(locale: string, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat {\n\tconst key = `${locale}:${options.dateStyle ?? \"\"}:${options.timeStyle ?? \"\"}`;\n\tlet fmt = dtfCache.get(key);\n\tif (!fmt) {\n\t\tfmt = new Intl.DateTimeFormat(locale, options);\n\t\tdtfCache.set(key, fmt);\n\t}\n\treturn fmt;\n}\n\nexport function formatValue(\n\tvalue: string | number | Date,\n\tformat: FormatMode,\n\tlocale: string,\n\toptions: FormatValueOptions = {},\n): string {\n\tconst { currency, dateStyle = \"medium\", timeStyle = \"short\" } = options;\n\tconst num = Number(value);\n\tconst date = value instanceof Date ? value : new Date(value as string | number);\n\n\tswitch (format) {\n\t\tcase \"number\":\n\t\t\treturn getNF(locale, {}).format(num);\n\t\tcase \"integer\":\n\t\t\treturn getNF(locale, { maximumFractionDigits: 0 }).format(num);\n\t\tcase \"percent\":\n\t\t\treturn getNF(locale, { style: \"percent\" }).format(num);\n\t\tcase \"compact\":\n\t\t\treturn getNF(locale, { notation: \"compact\" }).format(num);\n\t\tcase \"currency\": {\n\t\t\tif (!currency) {\n\t\t\t\tif (process.env.NODE_ENV === \"development\") {\n\t\t\t\t\tconsole.warn('[vocoder] format=\"currency\" requires a currency prop');\n\t\t\t\t}\n\t\t\t\treturn String(value);\n\t\t\t}\n\t\t\treturn getNF(locale, { style: \"currency\", currency }).format(num);\n\t\t}\n\t\tcase \"date\":\n\t\t\treturn getDTF(locale, { dateStyle }).format(date);\n\t\tcase \"time\":\n\t\t\treturn getDTF(locale, { timeStyle }).format(date);\n\t\tcase \"datetime\":\n\t\t\treturn getDTF(locale, { dateStyle, timeStyle }).format(date);\n\t\tdefault:\n\t\t\treturn String(value);\n\t}\n}\n","/**\n * FNV-1a 32-bit hash for generating stable message IDs from source text.\n *\n * Works identically in Node.js and browsers (no platform APIs).\n * Used by the extractor (build time) and the React runtime (browser) — both\n * always produce the same key for the same source text.\n *\n * Output: 7 base-36 chars (~2.2 billion values).\n * Collision probability ≈ 0.002% for 10K strings (birthday problem).\n * Add `context` to disambiguate identical strings with different meanings.\n * Add `formality` (\"formal\" | \"informal\") to produce separate keys for\n * register variants — \"neutral\", \"auto\", and undefined hash identically.\n *\n * Separators: \\x04 (ASCII EOT) for context, \\x05 (ASCII ENQ) for formality.\n */\nexport function generateMessageHash(\n\ttext: string,\n\tcontext?: string,\n\tformality?: string,\n): string {\n\tlet input = context ? `${text}\\x04${context}` : text;\n\tif (formality === \"formal\" || formality === \"informal\") {\n\t\tinput += `\\x05${formality}`;\n\t}\n\tlet h = 2166136261 >>> 0;\n\tfor (let i = 0; i < input.length; i++) {\n\t\th = Math.imul(h ^ input.charCodeAt(i), 16777619) >>> 0;\n\t}\n\treturn h.toString(36).padStart(7, \"0\");\n}\n","import IntlMessageFormat from \"intl-messageformat\";\nimport {\n\tisPluralElement,\n\tisSelectElement,\n\tisTagElement,\n\tparse,\n\tTYPE,\n} from \"@formatjs/icu-messageformat-parser\";\nimport type {\n\tLiteralElement,\n\tMessageFormatElement,\n\tPluralElement,\n} from \"@formatjs/icu-messageformat-parser\";\nimport type { OrdinalForms } from \"./types\";\n\n// ---------------------------------------------------------------------------\n// IntlMessageFormat cache — keyed by \"locale:text\"\n// ---------------------------------------------------------------------------\n\nconst imfCache = new Map<string, IntlMessageFormat>();\n\nfunction getIMF(text: string, locale: string): IntlMessageFormat {\n\tconst key = `${locale}:${text}`;\n\tlet msg = imfCache.get(key);\n\tif (!msg) {\n\t\t// ignoreTag: true — component placeholders (<c0>, <c1>) are handled\n\t\t// by formatElements, not by IMF. IMF handles only ICU primitives.\n\t\tmsg = new IntlMessageFormat(text, locale, undefined, { ignoreTag: true });\n\t\timfCache.set(key, msg);\n\t}\n\treturn msg;\n}\n\n/**\n * Format an ICU MessageFormat string with the given values and locale.\n * Returns the raw `text` unchanged if parsing or formatting throws — the\n * caller always gets a string, never an exception.\n */\nexport function formatICU(\n\ttext: string,\n\tvalues: Record<string, any>,\n\tlocale: string = \"en\",\n): string {\n\ttry {\n\t\tconst result = getIMF(text, locale.toLowerCase()).format(values);\n\t\treturn typeof result === \"string\" ? result : (result as unknown[]).join(\"\");\n\t} catch (error) {\n\t\tif (process.env.NODE_ENV !== \"production\") {\n\t\t\tconsole.error(\n\t\t\t\t`[vocoder] ICU formatting error for locale \"${locale}\":`,\n\t\t\t\terror,\n\t\t\t\t\"\\n ICU:\", text,\n\t\t\t\t\"\\n values:\", values,\n\t\t\t);\n\t\t}\n\t\treturn text;\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Embedded selectordinal rewriting — Bug 1 fix\n//\n// The translation pipeline's ordinal DB fast path (tryBuildOrdinalFromDB)\n// only applies when a selectordinal is the SOLE top-level element in the\n// ICU string. When it appears embedded inside a larger sentence (e.g.\n// \"Congrats! your {year, selectordinal, ...} anniversary!\"), the pipeline\n// falls through to the translation provider, which stores garbage branches\n// (e.g. \"1el\", \"1th\", \"1الـ\") in the DB.\n//\n// This function fixes the stored translation at render time by rewriting\n// any selectordinal nodes using the locale's ordinalForms data.\n// ---------------------------------------------------------------------------\n\nconst CLDR_ORDINAL_ORDER = [\n\t\"zero\",\n\t\"one\",\n\t\"two\",\n\t\"few\",\n\t\"many\",\n\t\"other\",\n] as const;\n\nfunction printICU(elements: MessageFormatElement[]): string {\n\treturn elements.map(printElement).join(\"\");\n}\n\nfunction printElement(el: MessageFormatElement): string {\n\tswitch (el.type) {\n\t\tcase TYPE.literal:\n\t\t\treturn (el as LiteralElement).value;\n\t\tcase TYPE.argument:\n\t\t\treturn `{${el.value}}`;\n\t\tcase TYPE.pound:\n\t\t\treturn \"#\";\n\t\tcase TYPE.number: {\n\t\t\tif (!el.style) return `{${el.value}, number}`;\n\t\t\tconst style =\n\t\t\t\ttypeof el.style === \"string\"\n\t\t\t\t\t? el.style\n\t\t\t\t\t: `::${(el.style as Record<string, any>).parsedOptions ?? \"\"}`;\n\t\t\treturn `{${el.value}, number, ${style}}`;\n\t\t}\n\t\tcase TYPE.date: {\n\t\t\tif (!el.style) return `{${el.value}, date}`;\n\t\t\tconst style =\n\t\t\t\ttypeof el.style === \"string\"\n\t\t\t\t\t? el.style\n\t\t\t\t\t: `::${(el.style as Record<string, any>).parsedOptions ?? \"\"}`;\n\t\t\treturn `{${el.value}, date, ${style}}`;\n\t\t}\n\t\tcase TYPE.time: {\n\t\t\tif (!el.style) return `{${el.value}, time}`;\n\t\t\tconst style =\n\t\t\t\ttypeof el.style === \"string\"\n\t\t\t\t\t? el.style\n\t\t\t\t\t: `::${(el.style as Record<string, any>).parsedOptions ?? \"\"}`;\n\t\t\treturn `{${el.value}, time, ${style}}`;\n\t\t}\n\t\tcase TYPE.select: {\n\t\t\tconst options = Object.entries(\n\t\t\t\t(el as Record<string, any>).options as Record<\n\t\t\t\t\tstring,\n\t\t\t\t\t{ value: MessageFormatElement[] }\n\t\t\t\t>,\n\t\t\t)\n\t\t\t\t.map(([k, v]) => `${k} {${printICU(v.value)}}`)\n\t\t\t\t.join(\" \");\n\t\t\treturn `{${el.value}, select, ${options}}`;\n\t\t}\n\t\tcase TYPE.plural: {\n\t\t\tconst pluralEl = el as PluralElement;\n\t\t\tconst pluralType =\n\t\t\t\tpluralEl.pluralType === \"ordinal\" ? \"selectordinal\" : \"plural\";\n\t\t\tconst offset =\n\t\t\t\tpluralEl.offset !== 0 ? `offset:${pluralEl.offset} ` : \"\";\n\t\t\tconst options = Object.entries(pluralEl.options)\n\t\t\t\t.map(([k, v]) => `${k} {${printICU(v.value)}}`)\n\t\t\t\t.join(\" \");\n\t\t\treturn `{${pluralEl.value}, ${pluralType}, ${offset}${options}}`;\n\t\t}\n\t\tcase TYPE.tag: {\n\t\t\tconst children = printICU((el as Record<string, any>).children as MessageFormatElement[]);\n\t\t\treturn `<${el.value}>${children}</${el.value}>`;\n\t\t}\n\t\tdefault:\n\t\t\treturn \"\";\n\t}\n}\n\nfunction rewriteElements(\n\telements: MessageFormatElement[],\n\tforms: OrdinalForms,\n\tvalues: Record<string, any>,\n): MessageFormatElement[] {\n\treturn elements.flatMap((el) => {\n\t\tif (isPluralElement(el) && el.pluralType === \"ordinal\") {\n\t\t\treturn [rewriteSelectordinalElement(el, forms, values)];\n\t\t}\n\t\tif (isSelectElement(el)) {\n\t\t\tconst options: Record<string, { value: MessageFormatElement[] }> = {};\n\t\t\tfor (const [key, opt] of Object.entries(\n\t\t\t\tel.options as Record<string, { value: MessageFormatElement[] }>,\n\t\t\t)) {\n\t\t\t\toptions[key] = { value: rewriteElements(opt.value, forms, values) };\n\t\t\t}\n\t\t\treturn [{ ...el, options } as MessageFormatElement];\n\t\t}\n\t\tif (isPluralElement(el)) {\n\t\t\tconst options: Record<string, { value: MessageFormatElement[] }> = {};\n\t\t\tfor (const [key, opt] of Object.entries(el.options)) {\n\t\t\t\toptions[key] = { value: rewriteElements(opt.value, forms, values) };\n\t\t\t}\n\t\t\treturn [{ ...el, options } as MessageFormatElement];\n\t\t}\n\t\tif (isTagElement(el)) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\t...el,\n\t\t\t\t\tchildren: rewriteElements(\n\t\t\t\t\t\t(el as Record<string, any>).children as MessageFormatElement[],\n\t\t\t\t\t\tforms,\n\t\t\t\t\t\tvalues,\n\t\t\t\t\t),\n\t\t\t\t} as MessageFormatElement,\n\t\t\t];\n\t\t}\n\t\treturn [el];\n\t});\n}\n\nfunction rewriteSelectordinalElement(\n\tel: PluralElement,\n\tforms: OrdinalForms,\n\tvalues: Record<string, any>,\n): MessageFormatElement {\n\tif (forms.type === \"suffix\") {\n\t\tconst newOptions: Record<string, { value: MessageFormatElement[] }> = {};\n\t\tfor (const cat of CLDR_ORDINAL_ORDER) {\n\t\t\tconst pattern = forms.suffixes[cat];\n\t\t\tif (pattern === undefined) continue;\n\t\t\tconst poundIdx = pattern.indexOf(\"#\");\n\t\t\tconst parts: MessageFormatElement[] = [];\n\t\t\tif (poundIdx === -1) {\n\t\t\t\tparts.push({ type: TYPE.literal, value: pattern } as LiteralElement);\n\t\t\t} else {\n\t\t\t\tif (poundIdx > 0)\n\t\t\t\t\tparts.push({\n\t\t\t\t\t\ttype: TYPE.literal,\n\t\t\t\t\t\tvalue: pattern.slice(0, poundIdx),\n\t\t\t\t\t} as LiteralElement);\n\t\t\t\tparts.push({ type: TYPE.pound });\n\t\t\t\tif (poundIdx < pattern.length - 1)\n\t\t\t\t\tparts.push({\n\t\t\t\t\t\ttype: TYPE.literal,\n\t\t\t\t\t\tvalue: pattern.slice(poundIdx + 1),\n\t\t\t\t\t} as LiteralElement);\n\t\t\t}\n\t\t\tnewOptions[cat] = { value: parts };\n\t\t}\n\t\treturn { ...el, options: newOptions };\n\t}\n\n\tif (forms.type === \"word\") {\n\t\tconst rank = values[el.value];\n\t\tif (typeof rank === \"number\") {\n\t\t\tconst genderMap =\n\t\t\t\tforms.words[\"masculine\"] ?? Object.values(forms.words)[0];\n\t\t\tconst word = genderMap?.[rank];\n\t\t\treturn {\n\t\t\t\ttype: TYPE.literal,\n\t\t\t\tvalue: word ?? String(rank),\n\t\t\t} as LiteralElement;\n\t\t}\n\t}\n\n\treturn el;\n}\n\n/**\n * Rewrite any embedded `selectordinal` nodes in an ICU string using\n * `ordinalForms` from the locale bundle, before passing the string to\n * `formatICU`.\n *\n * Returns `icu` unchanged when:\n * - the string contains no \"selectordinal\" substring (fast path — most strings)\n * - parsing throws (safe fallback to whatever formatICU receives)\n *\n * @param icu - Translated ICU string (may contain garbage ordinal branches from provider)\n * @param ordinalForms - Locale's ordinalForms from the compiled bundle\n * @param values - Runtime interpolation values (needed for word-based rank lookup)\n */\nexport function rewriteSelectordinalInICU(\n\ticu: string,\n\tordinalForms: OrdinalForms,\n\tvalues: Record<string, any>,\n): string {\n\tif (!icu.includes(\"selectordinal\")) return icu;\n\n\ttry {\n\t\tconst ast = parse(icu, { captureLocation: false });\n\t\tconst rewritten = rewriteElements(ast, ordinalForms, values);\n\t\treturn printICU(rewritten);\n\t} catch {\n\t\treturn icu;\n\t}\n}\n"],"mappings":"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","names":["IntlMessageFormat"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/cookies.ts","../src/format-value.ts","../src/hash.ts","../src/icu-builders.ts","../src/icu.ts"],"sourcesContent":["export { getCookie, getBestMatchingLocale, setCookie } from \"./cookies\";\nexport { formatValue } from \"./format-value\";\nexport type { FormatValueOptions } from \"./format-value\";\nexport { generateMessageHash } from \"./hash\";\nexport { ALL_CLDR, DEFAULT_ORDINAL_ICU, PLURAL_CLDR, buildPluralICU, buildSelectICU } from \"./icu-builders\";\nexport { applyOrdinalForms, formatICU, rewriteSelectordinalInICU } from \"./icu\";\nexport type {\n\tFormatMode,\n\tLocaleInfo,\n\tLocalesMap,\n\tOrdinalForms,\n\tOrdinalSuffixes,\n\tTOptions,\n\tTranslationsMap,\n\tVocoderTranslationData,\n} from \"./types\";\n","export function getCookie(name: string, cookieString?: string): string | null {\n\tconst cookies =\n\t\tcookieString || (typeof document !== \"undefined\" ? document.cookie : \"\");\n\n\tif (!cookies) {\n\t\treturn null;\n\t}\n\n\tconst value = cookies\n\t\t.split(\"; \")\n\t\t.find((row: string) => row.startsWith(`${name}=`))\n\t\t?.split(\"=\")[1];\n\n\treturn value ? decodeURIComponent(value) : null;\n}\n\nexport function setCookie(\n\tname: string,\n\tvalue: string,\n\toptions: {\n\t\tmaxAge?: number;\n\t\tpath?: string;\n\t\tdomain?: string;\n\t\tsameSite?: \"Strict\" | \"Lax\" | \"None\";\n\t\tsecure?: boolean;\n\t} = {},\n): void {\n\tif (typeof document === \"undefined\") {\n\t\treturn;\n\t}\n\n\tconst {\n\t\tmaxAge = 365 * 24 * 60 * 60,\n\t\tpath = \"/\",\n\t\tsameSite = \"Lax\",\n\t\tsecure = typeof window !== \"undefined\" &&\n\t\t\twindow.location.protocol === \"https:\",\n\t} = options;\n\n\tlet cookieString = `${name}=${encodeURIComponent(value)}`;\n\n\tif (maxAge) {\n\t\tcookieString += `; Max-Age=${maxAge}`;\n\t}\n\n\tif (path) {\n\t\tcookieString += `; Path=${path}`;\n\t}\n\n\tif (options.domain) {\n\t\tcookieString += `; Domain=${options.domain}`;\n\t}\n\n\tif (sameSite) {\n\t\tcookieString += `; SameSite=${sameSite}`;\n\t}\n\n\tif (secure) {\n\t\tcookieString += \"; Secure\";\n\t}\n\n\tdocument.cookie = cookieString;\n}\n\n/**\n * Find the best matching locale from available options.\n * Handles language codes and regional variants (e.g., 'en-US' -> 'en').\n */\nexport function getBestMatchingLocale(\n\tpreferredLocale: string,\n\tsupportedLocales: string[],\n\tfallback: string,\n): string {\n\tif (supportedLocales.includes(preferredLocale)) {\n\t\treturn preferredLocale;\n\t}\n\n\tconst languageCode = preferredLocale.split(\"-\")[0];\n\tif (languageCode && supportedLocales.includes(languageCode)) {\n\t\treturn languageCode;\n\t}\n\n\tconst similarLocale = supportedLocales.find((locale: string) =>\n\t\tlocale.startsWith(`${languageCode}-`),\n\t);\n\tif (similarLocale) {\n\t\treturn similarLocale;\n\t}\n\n\treturn fallback;\n}\n","import type { FormatMode } from \"./types\";\n\nexport interface FormatValueOptions {\n\tcurrency?: string;\n\tdateStyle?: \"full\" | \"long\" | \"medium\" | \"short\";\n\ttimeStyle?: \"full\" | \"long\" | \"medium\" | \"short\";\n}\n\nconst nfCache = new Map<string, Intl.NumberFormat>();\nconst dtfCache = new Map<string, Intl.DateTimeFormat>();\n\nfunction getNF(locale: string, options: Intl.NumberFormatOptions): Intl.NumberFormat {\n\tconst key = `${locale}:${options.style ?? \"\"}:${options.currency ?? \"\"}:${options.notation ?? \"\"}:${options.maximumFractionDigits ?? \"\"}`;\n\tlet fmt = nfCache.get(key);\n\tif (!fmt) {\n\t\tfmt = new Intl.NumberFormat(locale, options);\n\t\tnfCache.set(key, fmt);\n\t}\n\treturn fmt;\n}\n\nfunction getDTF(locale: string, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat {\n\tconst key = `${locale}:${options.dateStyle ?? \"\"}:${options.timeStyle ?? \"\"}`;\n\tlet fmt = dtfCache.get(key);\n\tif (!fmt) {\n\t\tfmt = new Intl.DateTimeFormat(locale, options);\n\t\tdtfCache.set(key, fmt);\n\t}\n\treturn fmt;\n}\n\nexport function formatValue(\n\tvalue: string | number | Date,\n\tformat: FormatMode,\n\tlocale: string,\n\toptions: FormatValueOptions = {},\n): string {\n\tconst { currency, dateStyle = \"medium\", timeStyle = \"short\" } = options;\n\tconst num = Number(value);\n\tconst date = value instanceof Date ? value : new Date(value as string | number);\n\n\tswitch (format) {\n\t\tcase \"number\":\n\t\t\treturn getNF(locale, {}).format(num);\n\t\tcase \"integer\":\n\t\t\treturn getNF(locale, { maximumFractionDigits: 0 }).format(num);\n\t\tcase \"percent\":\n\t\t\treturn getNF(locale, { style: \"percent\" }).format(num);\n\t\tcase \"compact\":\n\t\t\treturn getNF(locale, { notation: \"compact\" }).format(num);\n\t\tcase \"currency\": {\n\t\t\tif (!currency) {\n\t\t\t\tif (process.env.NODE_ENV === \"development\") {\n\t\t\t\t\tconsole.warn('[vocoder] format=\"currency\" requires a currency prop');\n\t\t\t\t}\n\t\t\t\treturn String(value);\n\t\t\t}\n\t\t\treturn getNF(locale, { style: \"currency\", currency }).format(num);\n\t\t}\n\t\tcase \"date\":\n\t\t\treturn getDTF(locale, { dateStyle }).format(date);\n\t\tcase \"time\":\n\t\t\treturn getDTF(locale, { timeStyle }).format(date);\n\t\tcase \"datetime\":\n\t\t\treturn getDTF(locale, { dateStyle, timeStyle }).format(date);\n\t\tdefault:\n\t\t\treturn String(value);\n\t}\n}\n","/**\n * FNV-1a 32-bit hash for generating stable message IDs from source text.\n *\n * Works identically in Node.js and browsers (no platform APIs).\n * Used by the extractor (build time) and the React runtime (browser) — both\n * always produce the same key for the same source text.\n *\n * Output: 7 base-36 chars (~2.2 billion values).\n * Collision probability ≈ 0.002% for 10K strings (birthday problem).\n * Add `context` to disambiguate identical strings with different meanings.\n * Add `formality` (\"formal\" | \"informal\") to produce separate keys for\n * register variants — \"neutral\", \"auto\", and undefined hash identically.\n *\n * Separators: \\x04 (ASCII EOT) for context, \\x05 (ASCII ENQ) for formality.\n */\nexport function generateMessageHash(\n\ttext: string,\n\tcontext?: string,\n\tformality?: string,\n): string {\n\tlet input = context ? `${text}\\x04${context}` : text;\n\tif (formality === \"formal\" || formality === \"informal\") {\n\t\tinput += `\\x05${formality}`;\n\t}\n\tlet h = 2166136261 >>> 0;\n\tfor (let i = 0; i < input.length; i++) {\n\t\th = Math.imul(h ^ input.charCodeAt(i), 16777619) >>> 0;\n\t}\n\treturn h.toString(36).padStart(7, \"0\");\n}\n","// Unambiguous plural CLDR categories. \"other\" is excluded — it's also the\n// required fallback in select mode, so it can't determine mode on its own.\nexport const PLURAL_CLDR = new Set([\"zero\", \"one\", \"two\", \"few\", \"many\"]);\n// Full set used only by buildPluralICU/buildSelectICU where mode is already known.\nexport const ALL_CLDR = new Set([\"zero\", \"one\", \"two\", \"few\", \"many\", \"other\"]);\n\n/**\n * Default ordinal ICU — locale-neutral structural placeholder used as the extraction\n * key and bundle lookup key for `<T value={rank} ordinal />` components.\n *\n * Uses a minimal single-branch form so the stored ICU carries no source-language\n * ordinal suffixes. The actual ordinal form is resolved at runtime:\n * Tier 1 — ordinalForms.suffixes/words from the compiled bundle (covers 93+ languages)\n * Tier 2 — this key's bundle translation (provider returns `other {#}` unchanged;\n * formatICU evaluates it to String(rank), same as Tier 3)\n * Tier 3 — String(rank) fallback\n */\nexport const DEFAULT_ORDINAL_ICU = \"{count, selectordinal, other {#}}\";\n\n/**\n * Build a plural or ordinal ICU string from plural prop key/value pairs.\n * Exact matches (_0, _1) come before CLDR categories (one, other, etc.).\n * Internal variable name is always \"count\" for consistent lookup keys.\n */\nexport function buildPluralICU(props: Record<string, string>, ordinal = false): string {\n\tconst type = ordinal ? \"selectordinal\" : \"plural\";\n\tconst exactParts: string[] = [];\n\tconst cldrParts: string[] = [];\n\n\tfor (const [key, text] of Object.entries(props)) {\n\t\tconst exactMatch = key.match(/^_(\\d+)$/);\n\t\tif (exactMatch) {\n\t\t\texactParts.push(`=${exactMatch[1]} {${text}}`);\n\t\t} else if (ALL_CLDR.has(key)) {\n\t\t\tcldrParts.push(`${key} {${text}}`);\n\t\t}\n\t}\n\n\treturn `{count, ${type}, ${[...exactParts, ...cldrParts].join(\" \")}}`;\n}\n\n/**\n * Build a select ICU string from select prop key/value pairs.\n * Internal variable name is always \"value\" for consistent lookup keys.\n */\nexport function buildSelectICU(props: Record<string, string>): string {\n\tconst cases: string[] = [];\n\tlet hasOther = false;\n\n\tfor (const [key, text] of Object.entries(props)) {\n\t\tif (key === \"other\") {\n\t\t\thasOther = true;\n\t\t\tcases.push(`other {${text}}`);\n\t\t} else {\n\t\t\tconst wordCase = key.match(/^_([a-zA-Z].*)$/);\n\t\t\tif (wordCase) cases.push(`${wordCase[1]} {${text}}`);\n\t\t}\n\t}\n\n\tif (!hasOther) cases.push(\"other {other}\");\n\treturn `{value, select, ${cases.join(\" \")}}`;\n}\n","import IntlMessageFormat from \"intl-messageformat\";\nimport {\n\tisPluralElement,\n\tisSelectElement,\n\tisTagElement,\n\tparse,\n\tTYPE,\n} from \"@formatjs/icu-messageformat-parser\";\nimport type {\n\tLiteralElement,\n\tMessageFormatElement,\n\tPluralElement,\n} from \"@formatjs/icu-messageformat-parser\";\nimport type { OrdinalForms } from \"./types\";\n\n// ---------------------------------------------------------------------------\n// IntlMessageFormat cache — keyed by \"locale:text\"\n// ---------------------------------------------------------------------------\n\nconst imfCache = new Map<string, IntlMessageFormat>();\n\nfunction getIMF(text: string, locale: string): IntlMessageFormat {\n\tconst key = `${locale}:${text}`;\n\tlet msg = imfCache.get(key);\n\tif (!msg) {\n\t\t// ignoreTag: true — component placeholders (<c0>, <c1>) are handled\n\t\t// by formatElements, not by IMF. IMF handles only ICU primitives.\n\t\tmsg = new IntlMessageFormat(text, locale, undefined, { ignoreTag: true });\n\t\timfCache.set(key, msg);\n\t}\n\treturn msg;\n}\n\n/**\n * Format an ICU MessageFormat string with the given values and locale.\n * Returns the raw `text` unchanged if parsing or formatting throws — the\n * caller always gets a string, never an exception.\n */\nexport function formatICU(\n\ttext: string,\n\tvalues: Record<string, any>,\n\tlocale: string = \"en\",\n): string {\n\ttry {\n\t\tconst result = getIMF(text, locale.toLowerCase()).format(values);\n\t\treturn typeof result === \"string\" ? result : (result as unknown[]).join(\"\");\n\t} catch (error) {\n\t\tif (process.env.NODE_ENV !== \"production\") {\n\t\t\tconsole.error(\n\t\t\t\t`[vocoder] ICU formatting error for locale \"${locale}\":`,\n\t\t\t\terror,\n\t\t\t\t\"\\n ICU:\", text,\n\t\t\t\t\"\\n values:\", values,\n\t\t\t);\n\t\t}\n\t\treturn text;\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Embedded selectordinal rewriting — Bug 1 fix\n//\n// The translation pipeline's ordinal DB fast path (tryBuildOrdinalFromDB)\n// only applies when a selectordinal is the SOLE top-level element in the\n// ICU string. When it appears embedded inside a larger sentence (e.g.\n// \"Congrats! your {year, selectordinal, ...} anniversary!\"), the pipeline\n// falls through to the translation provider, which stores garbage branches\n// (e.g. \"1el\", \"1th\", \"1الـ\") in the DB.\n//\n// This function fixes the stored translation at render time by rewriting\n// any selectordinal nodes using the locale's ordinalForms data.\n// ---------------------------------------------------------------------------\n\nconst CLDR_ORDINAL_ORDER = [\n\t\"zero\",\n\t\"one\",\n\t\"two\",\n\t\"few\",\n\t\"many\",\n\t\"other\",\n] as const;\n\nfunction printICU(elements: MessageFormatElement[]): string {\n\treturn elements.map(printElement).join(\"\");\n}\n\nfunction printElement(el: MessageFormatElement): string {\n\tswitch (el.type) {\n\t\tcase TYPE.literal:\n\t\t\treturn (el as LiteralElement).value;\n\t\tcase TYPE.argument:\n\t\t\treturn `{${el.value}}`;\n\t\tcase TYPE.pound:\n\t\t\treturn \"#\";\n\t\tcase TYPE.number: {\n\t\t\tif (!el.style) return `{${el.value}, number}`;\n\t\t\tconst style =\n\t\t\t\ttypeof el.style === \"string\"\n\t\t\t\t\t? el.style\n\t\t\t\t\t: `::${(el.style as Record<string, any>).parsedOptions ?? \"\"}`;\n\t\t\treturn `{${el.value}, number, ${style}}`;\n\t\t}\n\t\tcase TYPE.date: {\n\t\t\tif (!el.style) return `{${el.value}, date}`;\n\t\t\tconst style =\n\t\t\t\ttypeof el.style === \"string\"\n\t\t\t\t\t? el.style\n\t\t\t\t\t: `::${(el.style as Record<string, any>).parsedOptions ?? \"\"}`;\n\t\t\treturn `{${el.value}, date, ${style}}`;\n\t\t}\n\t\tcase TYPE.time: {\n\t\t\tif (!el.style) return `{${el.value}, time}`;\n\t\t\tconst style =\n\t\t\t\ttypeof el.style === \"string\"\n\t\t\t\t\t? el.style\n\t\t\t\t\t: `::${(el.style as Record<string, any>).parsedOptions ?? \"\"}`;\n\t\t\treturn `{${el.value}, time, ${style}}`;\n\t\t}\n\t\tcase TYPE.select: {\n\t\t\tconst options = Object.entries(\n\t\t\t\t(el as Record<string, any>).options as Record<\n\t\t\t\t\tstring,\n\t\t\t\t\t{ value: MessageFormatElement[] }\n\t\t\t\t>,\n\t\t\t)\n\t\t\t\t.map(([k, v]) => `${k} {${printICU(v.value)}}`)\n\t\t\t\t.join(\" \");\n\t\t\treturn `{${el.value}, select, ${options}}`;\n\t\t}\n\t\tcase TYPE.plural: {\n\t\t\tconst pluralEl = el as PluralElement;\n\t\t\tconst pluralType =\n\t\t\t\tpluralEl.pluralType === \"ordinal\" ? \"selectordinal\" : \"plural\";\n\t\t\tconst offset =\n\t\t\t\tpluralEl.offset !== 0 ? `offset:${pluralEl.offset} ` : \"\";\n\t\t\tconst options = Object.entries(pluralEl.options)\n\t\t\t\t.map(([k, v]) => `${k} {${printICU(v.value)}}`)\n\t\t\t\t.join(\" \");\n\t\t\treturn `{${pluralEl.value}, ${pluralType}, ${offset}${options}}`;\n\t\t}\n\t\tcase TYPE.tag: {\n\t\t\tconst children = printICU((el as Record<string, any>).children as MessageFormatElement[]);\n\t\t\treturn `<${el.value}>${children}</${el.value}>`;\n\t\t}\n\t\tdefault:\n\t\t\treturn \"\";\n\t}\n}\n\nfunction rewriteElements(\n\telements: MessageFormatElement[],\n\tforms: OrdinalForms,\n\tvalues: Record<string, any>,\n): MessageFormatElement[] {\n\treturn elements.flatMap((el) => {\n\t\tif (isPluralElement(el) && el.pluralType === \"ordinal\") {\n\t\t\treturn [rewriteSelectordinalElement(el, forms, values)];\n\t\t}\n\t\tif (isSelectElement(el)) {\n\t\t\tconst options: Record<string, { value: MessageFormatElement[] }> = {};\n\t\t\tfor (const [key, opt] of Object.entries(\n\t\t\t\tel.options as Record<string, { value: MessageFormatElement[] }>,\n\t\t\t)) {\n\t\t\t\toptions[key] = { value: rewriteElements(opt.value, forms, values) };\n\t\t\t}\n\t\t\treturn [{ ...el, options } as MessageFormatElement];\n\t\t}\n\t\tif (isPluralElement(el)) {\n\t\t\tconst options: Record<string, { value: MessageFormatElement[] }> = {};\n\t\t\tfor (const [key, opt] of Object.entries(el.options)) {\n\t\t\t\toptions[key] = { value: rewriteElements(opt.value, forms, values) };\n\t\t\t}\n\t\t\treturn [{ ...el, options } as MessageFormatElement];\n\t\t}\n\t\tif (isTagElement(el)) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\t...el,\n\t\t\t\t\tchildren: rewriteElements(\n\t\t\t\t\t\t(el as Record<string, any>).children as MessageFormatElement[],\n\t\t\t\t\t\tforms,\n\t\t\t\t\t\tvalues,\n\t\t\t\t\t),\n\t\t\t\t} as MessageFormatElement,\n\t\t\t];\n\t\t}\n\t\treturn [el];\n\t});\n}\n\nfunction rewriteSelectordinalElement(\n\tel: PluralElement,\n\tforms: OrdinalForms,\n\tvalues: Record<string, any>,\n): MessageFormatElement {\n\tif (forms.type === \"suffix\") {\n\t\tconst newOptions: Record<string, { value: MessageFormatElement[] }> = {};\n\t\tfor (const cat of CLDR_ORDINAL_ORDER) {\n\t\t\tconst pattern = forms.suffixes[cat];\n\t\t\tif (pattern === undefined) continue;\n\t\t\tconst poundIdx = pattern.indexOf(\"#\");\n\t\t\tconst parts: MessageFormatElement[] = [];\n\t\t\tif (poundIdx === -1) {\n\t\t\t\tparts.push({ type: TYPE.literal, value: pattern } as LiteralElement);\n\t\t\t} else {\n\t\t\t\tif (poundIdx > 0)\n\t\t\t\t\tparts.push({\n\t\t\t\t\t\ttype: TYPE.literal,\n\t\t\t\t\t\tvalue: pattern.slice(0, poundIdx),\n\t\t\t\t\t} as LiteralElement);\n\t\t\t\tparts.push({ type: TYPE.pound });\n\t\t\t\tif (poundIdx < pattern.length - 1)\n\t\t\t\t\tparts.push({\n\t\t\t\t\t\ttype: TYPE.literal,\n\t\t\t\t\t\tvalue: pattern.slice(poundIdx + 1),\n\t\t\t\t\t} as LiteralElement);\n\t\t\t}\n\t\t\tnewOptions[cat] = { value: parts };\n\t\t}\n\t\treturn { ...el, options: newOptions };\n\t}\n\n\tif (forms.type === \"word\") {\n\t\tconst rank = values[el.value];\n\t\tif (typeof rank === \"number\") {\n\t\t\tconst genderMap =\n\t\t\t\tforms.words[\"masculine\"] ?? Object.values(forms.words)[0];\n\t\t\tconst word = genderMap?.[rank];\n\t\t\treturn {\n\t\t\t\ttype: TYPE.literal,\n\t\t\t\tvalue: word ?? String(rank),\n\t\t\t} as LiteralElement;\n\t\t}\n\t}\n\n\treturn el;\n}\n\n/**\n * Rewrite any embedded `selectordinal` nodes in an ICU string using\n * `ordinalForms` from the locale bundle, before passing the string to\n * `formatICU`.\n *\n * Returns `icu` unchanged when:\n * - the string contains no \"selectordinal\" substring (fast path — most strings)\n * - parsing throws (safe fallback to whatever formatICU receives)\n *\n * @param icu - Translated ICU string (may contain garbage ordinal branches from provider)\n * @param ordinalForms - Locale's ordinalForms from the compiled bundle\n * @param values - Runtime interpolation values (needed for word-based rank lookup)\n */\nexport function rewriteSelectordinalInICU(\n\ticu: string,\n\tordinalForms: OrdinalForms,\n\tvalues: Record<string, any>,\n): string {\n\tif (!icu.includes(\"selectordinal\")) return icu;\n\n\ttry {\n\t\tconst ast = parse(icu, { captureLocation: false });\n\t\tconst rewritten = rewriteElements(ast, ordinalForms, values);\n\t\treturn printICU(rewritten);\n\t} catch {\n\t\treturn icu;\n\t}\n}\n\n/**\n * Apply ordinal forms data to produce a locale-correct ordinal string.\n *\n * Returns the formatted ordinal when ordinalForms covers the value, or\n * `String(value)` for word-based locales when the rank is outside the\n * compiled word map (e.g. ranks > 100). Returns `null` only when the\n * forms type is unrecognised — callers should fall through to their ICU\n * bundle or String(value) in that case.\n */\nexport function applyOrdinalForms(\n\tvalue: number,\n\tlocale: string,\n\tforms: OrdinalForms,\n\tgender?: string,\n): string | null {\n\tif (forms.type === \"suffix\") {\n\t\tconst pr = new Intl.PluralRules(locale, { type: \"ordinal\" });\n\t\tconst category = pr.select(value) as keyof typeof forms.suffixes;\n\t\tconst pattern = forms.suffixes[category] ?? forms.suffixes.other;\n\t\treturn pattern ? pattern.replace(\"#\", String(value)) : null;\n\t}\n\n\tif (forms.type === \"word\") {\n\t\tconst genderKey = gender ?? \"masculine\";\n\t\tconst genderMap =\n\t\t\tforms.words[genderKey] ??\n\t\t\tforms.words[\"masculine\"] ??\n\t\t\tObject.values(forms.words)[0];\n\t\tconst word = genderMap?.[value];\n\t\tif (word) return word;\n\t\t// Rank outside the word map — don't fall through to ICU (unreliable for\n\t\t// word-based locales where the pipeline's ordinal DB returns null).\n\t\treturn String(value);\n\t}\n\n\treturn null;\n}\n"],"mappings":"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","names":["IntlMessageFormat"]}
package/dist/index.mjs CHANGED
@@ -142,6 +142,40 @@ function generateMessageHash(text, context, formality) {
142
142
  return h.toString(36).padStart(7, "0");
143
143
  }
144
144
 
145
+ // src/icu-builders.ts
146
+ var PLURAL_CLDR = /* @__PURE__ */ new Set(["zero", "one", "two", "few", "many"]);
147
+ var ALL_CLDR = /* @__PURE__ */ new Set(["zero", "one", "two", "few", "many", "other"]);
148
+ var DEFAULT_ORDINAL_ICU = "{count, selectordinal, other {#}}";
149
+ function buildPluralICU(props, ordinal = false) {
150
+ const type = ordinal ? "selectordinal" : "plural";
151
+ const exactParts = [];
152
+ const cldrParts = [];
153
+ for (const [key, text] of Object.entries(props)) {
154
+ const exactMatch = key.match(/^_(\d+)$/);
155
+ if (exactMatch) {
156
+ exactParts.push(`=${exactMatch[1]} {${text}}`);
157
+ } else if (ALL_CLDR.has(key)) {
158
+ cldrParts.push(`${key} {${text}}`);
159
+ }
160
+ }
161
+ return `{count, ${type}, ${[...exactParts, ...cldrParts].join(" ")}}`;
162
+ }
163
+ function buildSelectICU(props) {
164
+ const cases = [];
165
+ let hasOther = false;
166
+ for (const [key, text] of Object.entries(props)) {
167
+ if (key === "other") {
168
+ hasOther = true;
169
+ cases.push(`other {${text}}`);
170
+ } else {
171
+ const wordCase = key.match(/^_([a-zA-Z].*)$/);
172
+ if (wordCase) cases.push(`${wordCase[1]} {${text}}`);
173
+ }
174
+ }
175
+ if (!hasOther) cases.push("other {other}");
176
+ return `{value, select, ${cases.join(" ")}}`;
177
+ }
178
+
145
179
  // src/icu.ts
146
180
  import IntlMessageFormat from "intl-messageformat";
147
181
  import {
@@ -321,7 +355,30 @@ function rewriteSelectordinalInICU(icu, ordinalForms, values) {
321
355
  return icu;
322
356
  }
323
357
  }
358
+ function applyOrdinalForms(value, locale, forms, gender) {
359
+ var _a, _b, _c;
360
+ if (forms.type === "suffix") {
361
+ const pr = new Intl.PluralRules(locale, { type: "ordinal" });
362
+ const category = pr.select(value);
363
+ const pattern = (_a = forms.suffixes[category]) != null ? _a : forms.suffixes.other;
364
+ return pattern ? pattern.replace("#", String(value)) : null;
365
+ }
366
+ if (forms.type === "word") {
367
+ const genderKey = gender != null ? gender : "masculine";
368
+ const genderMap = (_c = (_b = forms.words[genderKey]) != null ? _b : forms.words["masculine"]) != null ? _c : Object.values(forms.words)[0];
369
+ const word = genderMap == null ? void 0 : genderMap[value];
370
+ if (word) return word;
371
+ return String(value);
372
+ }
373
+ return null;
374
+ }
324
375
  export {
376
+ ALL_CLDR,
377
+ DEFAULT_ORDINAL_ICU,
378
+ PLURAL_CLDR,
379
+ applyOrdinalForms,
380
+ buildPluralICU,
381
+ buildSelectICU,
325
382
  formatICU,
326
383
  formatValue,
327
384
  generateMessageHash,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cookies.ts","../src/format-value.ts","../src/hash.ts","../src/icu.ts"],"sourcesContent":["export function getCookie(name: string, cookieString?: string): string | null {\n\tconst cookies =\n\t\tcookieString || (typeof document !== \"undefined\" ? document.cookie : \"\");\n\n\tif (!cookies) {\n\t\treturn null;\n\t}\n\n\tconst value = cookies\n\t\t.split(\"; \")\n\t\t.find((row: string) => row.startsWith(`${name}=`))\n\t\t?.split(\"=\")[1];\n\n\treturn value ? decodeURIComponent(value) : null;\n}\n\nexport function setCookie(\n\tname: string,\n\tvalue: string,\n\toptions: {\n\t\tmaxAge?: number;\n\t\tpath?: string;\n\t\tdomain?: string;\n\t\tsameSite?: \"Strict\" | \"Lax\" | \"None\";\n\t\tsecure?: boolean;\n\t} = {},\n): void {\n\tif (typeof document === \"undefined\") {\n\t\treturn;\n\t}\n\n\tconst {\n\t\tmaxAge = 365 * 24 * 60 * 60,\n\t\tpath = \"/\",\n\t\tsameSite = \"Lax\",\n\t\tsecure = typeof window !== \"undefined\" &&\n\t\t\twindow.location.protocol === \"https:\",\n\t} = options;\n\n\tlet cookieString = `${name}=${encodeURIComponent(value)}`;\n\n\tif (maxAge) {\n\t\tcookieString += `; Max-Age=${maxAge}`;\n\t}\n\n\tif (path) {\n\t\tcookieString += `; Path=${path}`;\n\t}\n\n\tif (options.domain) {\n\t\tcookieString += `; Domain=${options.domain}`;\n\t}\n\n\tif (sameSite) {\n\t\tcookieString += `; SameSite=${sameSite}`;\n\t}\n\n\tif (secure) {\n\t\tcookieString += \"; Secure\";\n\t}\n\n\tdocument.cookie = cookieString;\n}\n\n/**\n * Find the best matching locale from available options.\n * Handles language codes and regional variants (e.g., 'en-US' -> 'en').\n */\nexport function getBestMatchingLocale(\n\tpreferredLocale: string,\n\tsupportedLocales: string[],\n\tfallback: string,\n): string {\n\tif (supportedLocales.includes(preferredLocale)) {\n\t\treturn preferredLocale;\n\t}\n\n\tconst languageCode = preferredLocale.split(\"-\")[0];\n\tif (languageCode && supportedLocales.includes(languageCode)) {\n\t\treturn languageCode;\n\t}\n\n\tconst similarLocale = supportedLocales.find((locale: string) =>\n\t\tlocale.startsWith(`${languageCode}-`),\n\t);\n\tif (similarLocale) {\n\t\treturn similarLocale;\n\t}\n\n\treturn fallback;\n}\n","import type { FormatMode } from \"./types\";\n\nexport interface FormatValueOptions {\n\tcurrency?: string;\n\tdateStyle?: \"full\" | \"long\" | \"medium\" | \"short\";\n\ttimeStyle?: \"full\" | \"long\" | \"medium\" | \"short\";\n}\n\nconst nfCache = new Map<string, Intl.NumberFormat>();\nconst dtfCache = new Map<string, Intl.DateTimeFormat>();\n\nfunction getNF(locale: string, options: Intl.NumberFormatOptions): Intl.NumberFormat {\n\tconst key = `${locale}:${options.style ?? \"\"}:${options.currency ?? \"\"}:${options.notation ?? \"\"}:${options.maximumFractionDigits ?? \"\"}`;\n\tlet fmt = nfCache.get(key);\n\tif (!fmt) {\n\t\tfmt = new Intl.NumberFormat(locale, options);\n\t\tnfCache.set(key, fmt);\n\t}\n\treturn fmt;\n}\n\nfunction getDTF(locale: string, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat {\n\tconst key = `${locale}:${options.dateStyle ?? \"\"}:${options.timeStyle ?? \"\"}`;\n\tlet fmt = dtfCache.get(key);\n\tif (!fmt) {\n\t\tfmt = new Intl.DateTimeFormat(locale, options);\n\t\tdtfCache.set(key, fmt);\n\t}\n\treturn fmt;\n}\n\nexport function formatValue(\n\tvalue: string | number | Date,\n\tformat: FormatMode,\n\tlocale: string,\n\toptions: FormatValueOptions = {},\n): string {\n\tconst { currency, dateStyle = \"medium\", timeStyle = \"short\" } = options;\n\tconst num = Number(value);\n\tconst date = value instanceof Date ? value : new Date(value as string | number);\n\n\tswitch (format) {\n\t\tcase \"number\":\n\t\t\treturn getNF(locale, {}).format(num);\n\t\tcase \"integer\":\n\t\t\treturn getNF(locale, { maximumFractionDigits: 0 }).format(num);\n\t\tcase \"percent\":\n\t\t\treturn getNF(locale, { style: \"percent\" }).format(num);\n\t\tcase \"compact\":\n\t\t\treturn getNF(locale, { notation: \"compact\" }).format(num);\n\t\tcase \"currency\": {\n\t\t\tif (!currency) {\n\t\t\t\tif (process.env.NODE_ENV === \"development\") {\n\t\t\t\t\tconsole.warn('[vocoder] format=\"currency\" requires a currency prop');\n\t\t\t\t}\n\t\t\t\treturn String(value);\n\t\t\t}\n\t\t\treturn getNF(locale, { style: \"currency\", currency }).format(num);\n\t\t}\n\t\tcase \"date\":\n\t\t\treturn getDTF(locale, { dateStyle }).format(date);\n\t\tcase \"time\":\n\t\t\treturn getDTF(locale, { timeStyle }).format(date);\n\t\tcase \"datetime\":\n\t\t\treturn getDTF(locale, { dateStyle, timeStyle }).format(date);\n\t\tdefault:\n\t\t\treturn String(value);\n\t}\n}\n","/**\n * FNV-1a 32-bit hash for generating stable message IDs from source text.\n *\n * Works identically in Node.js and browsers (no platform APIs).\n * Used by the extractor (build time) and the React runtime (browser) — both\n * always produce the same key for the same source text.\n *\n * Output: 7 base-36 chars (~2.2 billion values).\n * Collision probability ≈ 0.002% for 10K strings (birthday problem).\n * Add `context` to disambiguate identical strings with different meanings.\n * Add `formality` (\"formal\" | \"informal\") to produce separate keys for\n * register variants — \"neutral\", \"auto\", and undefined hash identically.\n *\n * Separators: \\x04 (ASCII EOT) for context, \\x05 (ASCII ENQ) for formality.\n */\nexport function generateMessageHash(\n\ttext: string,\n\tcontext?: string,\n\tformality?: string,\n): string {\n\tlet input = context ? `${text}\\x04${context}` : text;\n\tif (formality === \"formal\" || formality === \"informal\") {\n\t\tinput += `\\x05${formality}`;\n\t}\n\tlet h = 2166136261 >>> 0;\n\tfor (let i = 0; i < input.length; i++) {\n\t\th = Math.imul(h ^ input.charCodeAt(i), 16777619) >>> 0;\n\t}\n\treturn h.toString(36).padStart(7, \"0\");\n}\n","import IntlMessageFormat from \"intl-messageformat\";\nimport {\n\tisPluralElement,\n\tisSelectElement,\n\tisTagElement,\n\tparse,\n\tTYPE,\n} from \"@formatjs/icu-messageformat-parser\";\nimport type {\n\tLiteralElement,\n\tMessageFormatElement,\n\tPluralElement,\n} from \"@formatjs/icu-messageformat-parser\";\nimport type { OrdinalForms } from \"./types\";\n\n// ---------------------------------------------------------------------------\n// IntlMessageFormat cache — keyed by \"locale:text\"\n// ---------------------------------------------------------------------------\n\nconst imfCache = new Map<string, IntlMessageFormat>();\n\nfunction getIMF(text: string, locale: string): IntlMessageFormat {\n\tconst key = `${locale}:${text}`;\n\tlet msg = imfCache.get(key);\n\tif (!msg) {\n\t\t// ignoreTag: true — component placeholders (<c0>, <c1>) are handled\n\t\t// by formatElements, not by IMF. IMF handles only ICU primitives.\n\t\tmsg = new IntlMessageFormat(text, locale, undefined, { ignoreTag: true });\n\t\timfCache.set(key, msg);\n\t}\n\treturn msg;\n}\n\n/**\n * Format an ICU MessageFormat string with the given values and locale.\n * Returns the raw `text` unchanged if parsing or formatting throws — the\n * caller always gets a string, never an exception.\n */\nexport function formatICU(\n\ttext: string,\n\tvalues: Record<string, any>,\n\tlocale: string = \"en\",\n): string {\n\ttry {\n\t\tconst result = getIMF(text, locale.toLowerCase()).format(values);\n\t\treturn typeof result === \"string\" ? result : (result as unknown[]).join(\"\");\n\t} catch (error) {\n\t\tif (process.env.NODE_ENV !== \"production\") {\n\t\t\tconsole.error(\n\t\t\t\t`[vocoder] ICU formatting error for locale \"${locale}\":`,\n\t\t\t\terror,\n\t\t\t\t\"\\n ICU:\", text,\n\t\t\t\t\"\\n values:\", values,\n\t\t\t);\n\t\t}\n\t\treturn text;\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Embedded selectordinal rewriting — Bug 1 fix\n//\n// The translation pipeline's ordinal DB fast path (tryBuildOrdinalFromDB)\n// only applies when a selectordinal is the SOLE top-level element in the\n// ICU string. When it appears embedded inside a larger sentence (e.g.\n// \"Congrats! your {year, selectordinal, ...} anniversary!\"), the pipeline\n// falls through to the translation provider, which stores garbage branches\n// (e.g. \"1el\", \"1th\", \"1الـ\") in the DB.\n//\n// This function fixes the stored translation at render time by rewriting\n// any selectordinal nodes using the locale's ordinalForms data.\n// ---------------------------------------------------------------------------\n\nconst CLDR_ORDINAL_ORDER = [\n\t\"zero\",\n\t\"one\",\n\t\"two\",\n\t\"few\",\n\t\"many\",\n\t\"other\",\n] as const;\n\nfunction printICU(elements: MessageFormatElement[]): string {\n\treturn elements.map(printElement).join(\"\");\n}\n\nfunction printElement(el: MessageFormatElement): string {\n\tswitch (el.type) {\n\t\tcase TYPE.literal:\n\t\t\treturn (el as LiteralElement).value;\n\t\tcase TYPE.argument:\n\t\t\treturn `{${el.value}}`;\n\t\tcase TYPE.pound:\n\t\t\treturn \"#\";\n\t\tcase TYPE.number: {\n\t\t\tif (!el.style) return `{${el.value}, number}`;\n\t\t\tconst style =\n\t\t\t\ttypeof el.style === \"string\"\n\t\t\t\t\t? el.style\n\t\t\t\t\t: `::${(el.style as Record<string, any>).parsedOptions ?? \"\"}`;\n\t\t\treturn `{${el.value}, number, ${style}}`;\n\t\t}\n\t\tcase TYPE.date: {\n\t\t\tif (!el.style) return `{${el.value}, date}`;\n\t\t\tconst style =\n\t\t\t\ttypeof el.style === \"string\"\n\t\t\t\t\t? el.style\n\t\t\t\t\t: `::${(el.style as Record<string, any>).parsedOptions ?? \"\"}`;\n\t\t\treturn `{${el.value}, date, ${style}}`;\n\t\t}\n\t\tcase TYPE.time: {\n\t\t\tif (!el.style) return `{${el.value}, time}`;\n\t\t\tconst style =\n\t\t\t\ttypeof el.style === \"string\"\n\t\t\t\t\t? el.style\n\t\t\t\t\t: `::${(el.style as Record<string, any>).parsedOptions ?? \"\"}`;\n\t\t\treturn `{${el.value}, time, ${style}}`;\n\t\t}\n\t\tcase TYPE.select: {\n\t\t\tconst options = Object.entries(\n\t\t\t\t(el as Record<string, any>).options as Record<\n\t\t\t\t\tstring,\n\t\t\t\t\t{ value: MessageFormatElement[] }\n\t\t\t\t>,\n\t\t\t)\n\t\t\t\t.map(([k, v]) => `${k} {${printICU(v.value)}}`)\n\t\t\t\t.join(\" \");\n\t\t\treturn `{${el.value}, select, ${options}}`;\n\t\t}\n\t\tcase TYPE.plural: {\n\t\t\tconst pluralEl = el as PluralElement;\n\t\t\tconst pluralType =\n\t\t\t\tpluralEl.pluralType === \"ordinal\" ? \"selectordinal\" : \"plural\";\n\t\t\tconst offset =\n\t\t\t\tpluralEl.offset !== 0 ? `offset:${pluralEl.offset} ` : \"\";\n\t\t\tconst options = Object.entries(pluralEl.options)\n\t\t\t\t.map(([k, v]) => `${k} {${printICU(v.value)}}`)\n\t\t\t\t.join(\" \");\n\t\t\treturn `{${pluralEl.value}, ${pluralType}, ${offset}${options}}`;\n\t\t}\n\t\tcase TYPE.tag: {\n\t\t\tconst children = printICU((el as Record<string, any>).children as MessageFormatElement[]);\n\t\t\treturn `<${el.value}>${children}</${el.value}>`;\n\t\t}\n\t\tdefault:\n\t\t\treturn \"\";\n\t}\n}\n\nfunction rewriteElements(\n\telements: MessageFormatElement[],\n\tforms: OrdinalForms,\n\tvalues: Record<string, any>,\n): MessageFormatElement[] {\n\treturn elements.flatMap((el) => {\n\t\tif (isPluralElement(el) && el.pluralType === \"ordinal\") {\n\t\t\treturn [rewriteSelectordinalElement(el, forms, values)];\n\t\t}\n\t\tif (isSelectElement(el)) {\n\t\t\tconst options: Record<string, { value: MessageFormatElement[] }> = {};\n\t\t\tfor (const [key, opt] of Object.entries(\n\t\t\t\tel.options as Record<string, { value: MessageFormatElement[] }>,\n\t\t\t)) {\n\t\t\t\toptions[key] = { value: rewriteElements(opt.value, forms, values) };\n\t\t\t}\n\t\t\treturn [{ ...el, options } as MessageFormatElement];\n\t\t}\n\t\tif (isPluralElement(el)) {\n\t\t\tconst options: Record<string, { value: MessageFormatElement[] }> = {};\n\t\t\tfor (const [key, opt] of Object.entries(el.options)) {\n\t\t\t\toptions[key] = { value: rewriteElements(opt.value, forms, values) };\n\t\t\t}\n\t\t\treturn [{ ...el, options } as MessageFormatElement];\n\t\t}\n\t\tif (isTagElement(el)) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\t...el,\n\t\t\t\t\tchildren: rewriteElements(\n\t\t\t\t\t\t(el as Record<string, any>).children as MessageFormatElement[],\n\t\t\t\t\t\tforms,\n\t\t\t\t\t\tvalues,\n\t\t\t\t\t),\n\t\t\t\t} as MessageFormatElement,\n\t\t\t];\n\t\t}\n\t\treturn [el];\n\t});\n}\n\nfunction rewriteSelectordinalElement(\n\tel: PluralElement,\n\tforms: OrdinalForms,\n\tvalues: Record<string, any>,\n): MessageFormatElement {\n\tif (forms.type === \"suffix\") {\n\t\tconst newOptions: Record<string, { value: MessageFormatElement[] }> = {};\n\t\tfor (const cat of CLDR_ORDINAL_ORDER) {\n\t\t\tconst pattern = forms.suffixes[cat];\n\t\t\tif (pattern === undefined) continue;\n\t\t\tconst poundIdx = pattern.indexOf(\"#\");\n\t\t\tconst parts: MessageFormatElement[] = [];\n\t\t\tif (poundIdx === -1) {\n\t\t\t\tparts.push({ type: TYPE.literal, value: pattern } as LiteralElement);\n\t\t\t} else {\n\t\t\t\tif (poundIdx > 0)\n\t\t\t\t\tparts.push({\n\t\t\t\t\t\ttype: TYPE.literal,\n\t\t\t\t\t\tvalue: pattern.slice(0, poundIdx),\n\t\t\t\t\t} as LiteralElement);\n\t\t\t\tparts.push({ type: TYPE.pound });\n\t\t\t\tif (poundIdx < pattern.length - 1)\n\t\t\t\t\tparts.push({\n\t\t\t\t\t\ttype: TYPE.literal,\n\t\t\t\t\t\tvalue: pattern.slice(poundIdx + 1),\n\t\t\t\t\t} as LiteralElement);\n\t\t\t}\n\t\t\tnewOptions[cat] = { value: parts };\n\t\t}\n\t\treturn { ...el, options: newOptions };\n\t}\n\n\tif (forms.type === \"word\") {\n\t\tconst rank = values[el.value];\n\t\tif (typeof rank === \"number\") {\n\t\t\tconst genderMap =\n\t\t\t\tforms.words[\"masculine\"] ?? Object.values(forms.words)[0];\n\t\t\tconst word = genderMap?.[rank];\n\t\t\treturn {\n\t\t\t\ttype: TYPE.literal,\n\t\t\t\tvalue: word ?? String(rank),\n\t\t\t} as LiteralElement;\n\t\t}\n\t}\n\n\treturn el;\n}\n\n/**\n * Rewrite any embedded `selectordinal` nodes in an ICU string using\n * `ordinalForms` from the locale bundle, before passing the string to\n * `formatICU`.\n *\n * Returns `icu` unchanged when:\n * - the string contains no \"selectordinal\" substring (fast path — most strings)\n * - parsing throws (safe fallback to whatever formatICU receives)\n *\n * @param icu - Translated ICU string (may contain garbage ordinal branches from provider)\n * @param ordinalForms - Locale's ordinalForms from the compiled bundle\n * @param values - Runtime interpolation values (needed for word-based rank lookup)\n */\nexport function rewriteSelectordinalInICU(\n\ticu: string,\n\tordinalForms: OrdinalForms,\n\tvalues: Record<string, any>,\n): string {\n\tif (!icu.includes(\"selectordinal\")) return icu;\n\n\ttry {\n\t\tconst ast = parse(icu, { captureLocation: false });\n\t\tconst rewritten = rewriteElements(ast, ordinalForms, values);\n\t\treturn printICU(rewritten);\n\t} catch {\n\t\treturn icu;\n\t}\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/cookies.ts","../src/format-value.ts","../src/hash.ts","../src/icu-builders.ts","../src/icu.ts"],"sourcesContent":["export function getCookie(name: string, cookieString?: string): string | null {\n\tconst cookies =\n\t\tcookieString || (typeof document !== \"undefined\" ? document.cookie : \"\");\n\n\tif (!cookies) {\n\t\treturn null;\n\t}\n\n\tconst value = cookies\n\t\t.split(\"; \")\n\t\t.find((row: string) => row.startsWith(`${name}=`))\n\t\t?.split(\"=\")[1];\n\n\treturn value ? decodeURIComponent(value) : null;\n}\n\nexport function setCookie(\n\tname: string,\n\tvalue: string,\n\toptions: {\n\t\tmaxAge?: number;\n\t\tpath?: string;\n\t\tdomain?: string;\n\t\tsameSite?: \"Strict\" | \"Lax\" | \"None\";\n\t\tsecure?: boolean;\n\t} = {},\n): void {\n\tif (typeof document === \"undefined\") {\n\t\treturn;\n\t}\n\n\tconst {\n\t\tmaxAge = 365 * 24 * 60 * 60,\n\t\tpath = \"/\",\n\t\tsameSite = \"Lax\",\n\t\tsecure = typeof window !== \"undefined\" &&\n\t\t\twindow.location.protocol === \"https:\",\n\t} = options;\n\n\tlet cookieString = `${name}=${encodeURIComponent(value)}`;\n\n\tif (maxAge) {\n\t\tcookieString += `; Max-Age=${maxAge}`;\n\t}\n\n\tif (path) {\n\t\tcookieString += `; Path=${path}`;\n\t}\n\n\tif (options.domain) {\n\t\tcookieString += `; Domain=${options.domain}`;\n\t}\n\n\tif (sameSite) {\n\t\tcookieString += `; SameSite=${sameSite}`;\n\t}\n\n\tif (secure) {\n\t\tcookieString += \"; Secure\";\n\t}\n\n\tdocument.cookie = cookieString;\n}\n\n/**\n * Find the best matching locale from available options.\n * Handles language codes and regional variants (e.g., 'en-US' -> 'en').\n */\nexport function getBestMatchingLocale(\n\tpreferredLocale: string,\n\tsupportedLocales: string[],\n\tfallback: string,\n): string {\n\tif (supportedLocales.includes(preferredLocale)) {\n\t\treturn preferredLocale;\n\t}\n\n\tconst languageCode = preferredLocale.split(\"-\")[0];\n\tif (languageCode && supportedLocales.includes(languageCode)) {\n\t\treturn languageCode;\n\t}\n\n\tconst similarLocale = supportedLocales.find((locale: string) =>\n\t\tlocale.startsWith(`${languageCode}-`),\n\t);\n\tif (similarLocale) {\n\t\treturn similarLocale;\n\t}\n\n\treturn fallback;\n}\n","import type { FormatMode } from \"./types\";\n\nexport interface FormatValueOptions {\n\tcurrency?: string;\n\tdateStyle?: \"full\" | \"long\" | \"medium\" | \"short\";\n\ttimeStyle?: \"full\" | \"long\" | \"medium\" | \"short\";\n}\n\nconst nfCache = new Map<string, Intl.NumberFormat>();\nconst dtfCache = new Map<string, Intl.DateTimeFormat>();\n\nfunction getNF(locale: string, options: Intl.NumberFormatOptions): Intl.NumberFormat {\n\tconst key = `${locale}:${options.style ?? \"\"}:${options.currency ?? \"\"}:${options.notation ?? \"\"}:${options.maximumFractionDigits ?? \"\"}`;\n\tlet fmt = nfCache.get(key);\n\tif (!fmt) {\n\t\tfmt = new Intl.NumberFormat(locale, options);\n\t\tnfCache.set(key, fmt);\n\t}\n\treturn fmt;\n}\n\nfunction getDTF(locale: string, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat {\n\tconst key = `${locale}:${options.dateStyle ?? \"\"}:${options.timeStyle ?? \"\"}`;\n\tlet fmt = dtfCache.get(key);\n\tif (!fmt) {\n\t\tfmt = new Intl.DateTimeFormat(locale, options);\n\t\tdtfCache.set(key, fmt);\n\t}\n\treturn fmt;\n}\n\nexport function formatValue(\n\tvalue: string | number | Date,\n\tformat: FormatMode,\n\tlocale: string,\n\toptions: FormatValueOptions = {},\n): string {\n\tconst { currency, dateStyle = \"medium\", timeStyle = \"short\" } = options;\n\tconst num = Number(value);\n\tconst date = value instanceof Date ? value : new Date(value as string | number);\n\n\tswitch (format) {\n\t\tcase \"number\":\n\t\t\treturn getNF(locale, {}).format(num);\n\t\tcase \"integer\":\n\t\t\treturn getNF(locale, { maximumFractionDigits: 0 }).format(num);\n\t\tcase \"percent\":\n\t\t\treturn getNF(locale, { style: \"percent\" }).format(num);\n\t\tcase \"compact\":\n\t\t\treturn getNF(locale, { notation: \"compact\" }).format(num);\n\t\tcase \"currency\": {\n\t\t\tif (!currency) {\n\t\t\t\tif (process.env.NODE_ENV === \"development\") {\n\t\t\t\t\tconsole.warn('[vocoder] format=\"currency\" requires a currency prop');\n\t\t\t\t}\n\t\t\t\treturn String(value);\n\t\t\t}\n\t\t\treturn getNF(locale, { style: \"currency\", currency }).format(num);\n\t\t}\n\t\tcase \"date\":\n\t\t\treturn getDTF(locale, { dateStyle }).format(date);\n\t\tcase \"time\":\n\t\t\treturn getDTF(locale, { timeStyle }).format(date);\n\t\tcase \"datetime\":\n\t\t\treturn getDTF(locale, { dateStyle, timeStyle }).format(date);\n\t\tdefault:\n\t\t\treturn String(value);\n\t}\n}\n","/**\n * FNV-1a 32-bit hash for generating stable message IDs from source text.\n *\n * Works identically in Node.js and browsers (no platform APIs).\n * Used by the extractor (build time) and the React runtime (browser) — both\n * always produce the same key for the same source text.\n *\n * Output: 7 base-36 chars (~2.2 billion values).\n * Collision probability ≈ 0.002% for 10K strings (birthday problem).\n * Add `context` to disambiguate identical strings with different meanings.\n * Add `formality` (\"formal\" | \"informal\") to produce separate keys for\n * register variants — \"neutral\", \"auto\", and undefined hash identically.\n *\n * Separators: \\x04 (ASCII EOT) for context, \\x05 (ASCII ENQ) for formality.\n */\nexport function generateMessageHash(\n\ttext: string,\n\tcontext?: string,\n\tformality?: string,\n): string {\n\tlet input = context ? `${text}\\x04${context}` : text;\n\tif (formality === \"formal\" || formality === \"informal\") {\n\t\tinput += `\\x05${formality}`;\n\t}\n\tlet h = 2166136261 >>> 0;\n\tfor (let i = 0; i < input.length; i++) {\n\t\th = Math.imul(h ^ input.charCodeAt(i), 16777619) >>> 0;\n\t}\n\treturn h.toString(36).padStart(7, \"0\");\n}\n","// Unambiguous plural CLDR categories. \"other\" is excluded — it's also the\n// required fallback in select mode, so it can't determine mode on its own.\nexport const PLURAL_CLDR = new Set([\"zero\", \"one\", \"two\", \"few\", \"many\"]);\n// Full set used only by buildPluralICU/buildSelectICU where mode is already known.\nexport const ALL_CLDR = new Set([\"zero\", \"one\", \"two\", \"few\", \"many\", \"other\"]);\n\n/**\n * Default ordinal ICU — locale-neutral structural placeholder used as the extraction\n * key and bundle lookup key for `<T value={rank} ordinal />` components.\n *\n * Uses a minimal single-branch form so the stored ICU carries no source-language\n * ordinal suffixes. The actual ordinal form is resolved at runtime:\n * Tier 1 — ordinalForms.suffixes/words from the compiled bundle (covers 93+ languages)\n * Tier 2 — this key's bundle translation (provider returns `other {#}` unchanged;\n * formatICU evaluates it to String(rank), same as Tier 3)\n * Tier 3 — String(rank) fallback\n */\nexport const DEFAULT_ORDINAL_ICU = \"{count, selectordinal, other {#}}\";\n\n/**\n * Build a plural or ordinal ICU string from plural prop key/value pairs.\n * Exact matches (_0, _1) come before CLDR categories (one, other, etc.).\n * Internal variable name is always \"count\" for consistent lookup keys.\n */\nexport function buildPluralICU(props: Record<string, string>, ordinal = false): string {\n\tconst type = ordinal ? \"selectordinal\" : \"plural\";\n\tconst exactParts: string[] = [];\n\tconst cldrParts: string[] = [];\n\n\tfor (const [key, text] of Object.entries(props)) {\n\t\tconst exactMatch = key.match(/^_(\\d+)$/);\n\t\tif (exactMatch) {\n\t\t\texactParts.push(`=${exactMatch[1]} {${text}}`);\n\t\t} else if (ALL_CLDR.has(key)) {\n\t\t\tcldrParts.push(`${key} {${text}}`);\n\t\t}\n\t}\n\n\treturn `{count, ${type}, ${[...exactParts, ...cldrParts].join(\" \")}}`;\n}\n\n/**\n * Build a select ICU string from select prop key/value pairs.\n * Internal variable name is always \"value\" for consistent lookup keys.\n */\nexport function buildSelectICU(props: Record<string, string>): string {\n\tconst cases: string[] = [];\n\tlet hasOther = false;\n\n\tfor (const [key, text] of Object.entries(props)) {\n\t\tif (key === \"other\") {\n\t\t\thasOther = true;\n\t\t\tcases.push(`other {${text}}`);\n\t\t} else {\n\t\t\tconst wordCase = key.match(/^_([a-zA-Z].*)$/);\n\t\t\tif (wordCase) cases.push(`${wordCase[1]} {${text}}`);\n\t\t}\n\t}\n\n\tif (!hasOther) cases.push(\"other {other}\");\n\treturn `{value, select, ${cases.join(\" \")}}`;\n}\n","import IntlMessageFormat from \"intl-messageformat\";\nimport {\n\tisPluralElement,\n\tisSelectElement,\n\tisTagElement,\n\tparse,\n\tTYPE,\n} from \"@formatjs/icu-messageformat-parser\";\nimport type {\n\tLiteralElement,\n\tMessageFormatElement,\n\tPluralElement,\n} from \"@formatjs/icu-messageformat-parser\";\nimport type { OrdinalForms } from \"./types\";\n\n// ---------------------------------------------------------------------------\n// IntlMessageFormat cache — keyed by \"locale:text\"\n// ---------------------------------------------------------------------------\n\nconst imfCache = new Map<string, IntlMessageFormat>();\n\nfunction getIMF(text: string, locale: string): IntlMessageFormat {\n\tconst key = `${locale}:${text}`;\n\tlet msg = imfCache.get(key);\n\tif (!msg) {\n\t\t// ignoreTag: true — component placeholders (<c0>, <c1>) are handled\n\t\t// by formatElements, not by IMF. IMF handles only ICU primitives.\n\t\tmsg = new IntlMessageFormat(text, locale, undefined, { ignoreTag: true });\n\t\timfCache.set(key, msg);\n\t}\n\treturn msg;\n}\n\n/**\n * Format an ICU MessageFormat string with the given values and locale.\n * Returns the raw `text` unchanged if parsing or formatting throws — the\n * caller always gets a string, never an exception.\n */\nexport function formatICU(\n\ttext: string,\n\tvalues: Record<string, any>,\n\tlocale: string = \"en\",\n): string {\n\ttry {\n\t\tconst result = getIMF(text, locale.toLowerCase()).format(values);\n\t\treturn typeof result === \"string\" ? result : (result as unknown[]).join(\"\");\n\t} catch (error) {\n\t\tif (process.env.NODE_ENV !== \"production\") {\n\t\t\tconsole.error(\n\t\t\t\t`[vocoder] ICU formatting error for locale \"${locale}\":`,\n\t\t\t\terror,\n\t\t\t\t\"\\n ICU:\", text,\n\t\t\t\t\"\\n values:\", values,\n\t\t\t);\n\t\t}\n\t\treturn text;\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Embedded selectordinal rewriting — Bug 1 fix\n//\n// The translation pipeline's ordinal DB fast path (tryBuildOrdinalFromDB)\n// only applies when a selectordinal is the SOLE top-level element in the\n// ICU string. When it appears embedded inside a larger sentence (e.g.\n// \"Congrats! your {year, selectordinal, ...} anniversary!\"), the pipeline\n// falls through to the translation provider, which stores garbage branches\n// (e.g. \"1el\", \"1th\", \"1الـ\") in the DB.\n//\n// This function fixes the stored translation at render time by rewriting\n// any selectordinal nodes using the locale's ordinalForms data.\n// ---------------------------------------------------------------------------\n\nconst CLDR_ORDINAL_ORDER = [\n\t\"zero\",\n\t\"one\",\n\t\"two\",\n\t\"few\",\n\t\"many\",\n\t\"other\",\n] as const;\n\nfunction printICU(elements: MessageFormatElement[]): string {\n\treturn elements.map(printElement).join(\"\");\n}\n\nfunction printElement(el: MessageFormatElement): string {\n\tswitch (el.type) {\n\t\tcase TYPE.literal:\n\t\t\treturn (el as LiteralElement).value;\n\t\tcase TYPE.argument:\n\t\t\treturn `{${el.value}}`;\n\t\tcase TYPE.pound:\n\t\t\treturn \"#\";\n\t\tcase TYPE.number: {\n\t\t\tif (!el.style) return `{${el.value}, number}`;\n\t\t\tconst style =\n\t\t\t\ttypeof el.style === \"string\"\n\t\t\t\t\t? el.style\n\t\t\t\t\t: `::${(el.style as Record<string, any>).parsedOptions ?? \"\"}`;\n\t\t\treturn `{${el.value}, number, ${style}}`;\n\t\t}\n\t\tcase TYPE.date: {\n\t\t\tif (!el.style) return `{${el.value}, date}`;\n\t\t\tconst style =\n\t\t\t\ttypeof el.style === \"string\"\n\t\t\t\t\t? el.style\n\t\t\t\t\t: `::${(el.style as Record<string, any>).parsedOptions ?? \"\"}`;\n\t\t\treturn `{${el.value}, date, ${style}}`;\n\t\t}\n\t\tcase TYPE.time: {\n\t\t\tif (!el.style) return `{${el.value}, time}`;\n\t\t\tconst style =\n\t\t\t\ttypeof el.style === \"string\"\n\t\t\t\t\t? el.style\n\t\t\t\t\t: `::${(el.style as Record<string, any>).parsedOptions ?? \"\"}`;\n\t\t\treturn `{${el.value}, time, ${style}}`;\n\t\t}\n\t\tcase TYPE.select: {\n\t\t\tconst options = Object.entries(\n\t\t\t\t(el as Record<string, any>).options as Record<\n\t\t\t\t\tstring,\n\t\t\t\t\t{ value: MessageFormatElement[] }\n\t\t\t\t>,\n\t\t\t)\n\t\t\t\t.map(([k, v]) => `${k} {${printICU(v.value)}}`)\n\t\t\t\t.join(\" \");\n\t\t\treturn `{${el.value}, select, ${options}}`;\n\t\t}\n\t\tcase TYPE.plural: {\n\t\t\tconst pluralEl = el as PluralElement;\n\t\t\tconst pluralType =\n\t\t\t\tpluralEl.pluralType === \"ordinal\" ? \"selectordinal\" : \"plural\";\n\t\t\tconst offset =\n\t\t\t\tpluralEl.offset !== 0 ? `offset:${pluralEl.offset} ` : \"\";\n\t\t\tconst options = Object.entries(pluralEl.options)\n\t\t\t\t.map(([k, v]) => `${k} {${printICU(v.value)}}`)\n\t\t\t\t.join(\" \");\n\t\t\treturn `{${pluralEl.value}, ${pluralType}, ${offset}${options}}`;\n\t\t}\n\t\tcase TYPE.tag: {\n\t\t\tconst children = printICU((el as Record<string, any>).children as MessageFormatElement[]);\n\t\t\treturn `<${el.value}>${children}</${el.value}>`;\n\t\t}\n\t\tdefault:\n\t\t\treturn \"\";\n\t}\n}\n\nfunction rewriteElements(\n\telements: MessageFormatElement[],\n\tforms: OrdinalForms,\n\tvalues: Record<string, any>,\n): MessageFormatElement[] {\n\treturn elements.flatMap((el) => {\n\t\tif (isPluralElement(el) && el.pluralType === \"ordinal\") {\n\t\t\treturn [rewriteSelectordinalElement(el, forms, values)];\n\t\t}\n\t\tif (isSelectElement(el)) {\n\t\t\tconst options: Record<string, { value: MessageFormatElement[] }> = {};\n\t\t\tfor (const [key, opt] of Object.entries(\n\t\t\t\tel.options as Record<string, { value: MessageFormatElement[] }>,\n\t\t\t)) {\n\t\t\t\toptions[key] = { value: rewriteElements(opt.value, forms, values) };\n\t\t\t}\n\t\t\treturn [{ ...el, options } as MessageFormatElement];\n\t\t}\n\t\tif (isPluralElement(el)) {\n\t\t\tconst options: Record<string, { value: MessageFormatElement[] }> = {};\n\t\t\tfor (const [key, opt] of Object.entries(el.options)) {\n\t\t\t\toptions[key] = { value: rewriteElements(opt.value, forms, values) };\n\t\t\t}\n\t\t\treturn [{ ...el, options } as MessageFormatElement];\n\t\t}\n\t\tif (isTagElement(el)) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\t...el,\n\t\t\t\t\tchildren: rewriteElements(\n\t\t\t\t\t\t(el as Record<string, any>).children as MessageFormatElement[],\n\t\t\t\t\t\tforms,\n\t\t\t\t\t\tvalues,\n\t\t\t\t\t),\n\t\t\t\t} as MessageFormatElement,\n\t\t\t];\n\t\t}\n\t\treturn [el];\n\t});\n}\n\nfunction rewriteSelectordinalElement(\n\tel: PluralElement,\n\tforms: OrdinalForms,\n\tvalues: Record<string, any>,\n): MessageFormatElement {\n\tif (forms.type === \"suffix\") {\n\t\tconst newOptions: Record<string, { value: MessageFormatElement[] }> = {};\n\t\tfor (const cat of CLDR_ORDINAL_ORDER) {\n\t\t\tconst pattern = forms.suffixes[cat];\n\t\t\tif (pattern === undefined) continue;\n\t\t\tconst poundIdx = pattern.indexOf(\"#\");\n\t\t\tconst parts: MessageFormatElement[] = [];\n\t\t\tif (poundIdx === -1) {\n\t\t\t\tparts.push({ type: TYPE.literal, value: pattern } as LiteralElement);\n\t\t\t} else {\n\t\t\t\tif (poundIdx > 0)\n\t\t\t\t\tparts.push({\n\t\t\t\t\t\ttype: TYPE.literal,\n\t\t\t\t\t\tvalue: pattern.slice(0, poundIdx),\n\t\t\t\t\t} as LiteralElement);\n\t\t\t\tparts.push({ type: TYPE.pound });\n\t\t\t\tif (poundIdx < pattern.length - 1)\n\t\t\t\t\tparts.push({\n\t\t\t\t\t\ttype: TYPE.literal,\n\t\t\t\t\t\tvalue: pattern.slice(poundIdx + 1),\n\t\t\t\t\t} as LiteralElement);\n\t\t\t}\n\t\t\tnewOptions[cat] = { value: parts };\n\t\t}\n\t\treturn { ...el, options: newOptions };\n\t}\n\n\tif (forms.type === \"word\") {\n\t\tconst rank = values[el.value];\n\t\tif (typeof rank === \"number\") {\n\t\t\tconst genderMap =\n\t\t\t\tforms.words[\"masculine\"] ?? Object.values(forms.words)[0];\n\t\t\tconst word = genderMap?.[rank];\n\t\t\treturn {\n\t\t\t\ttype: TYPE.literal,\n\t\t\t\tvalue: word ?? String(rank),\n\t\t\t} as LiteralElement;\n\t\t}\n\t}\n\n\treturn el;\n}\n\n/**\n * Rewrite any embedded `selectordinal` nodes in an ICU string using\n * `ordinalForms` from the locale bundle, before passing the string to\n * `formatICU`.\n *\n * Returns `icu` unchanged when:\n * - the string contains no \"selectordinal\" substring (fast path — most strings)\n * - parsing throws (safe fallback to whatever formatICU receives)\n *\n * @param icu - Translated ICU string (may contain garbage ordinal branches from provider)\n * @param ordinalForms - Locale's ordinalForms from the compiled bundle\n * @param values - Runtime interpolation values (needed for word-based rank lookup)\n */\nexport function rewriteSelectordinalInICU(\n\ticu: string,\n\tordinalForms: OrdinalForms,\n\tvalues: Record<string, any>,\n): string {\n\tif (!icu.includes(\"selectordinal\")) return icu;\n\n\ttry {\n\t\tconst ast = parse(icu, { captureLocation: false });\n\t\tconst rewritten = rewriteElements(ast, ordinalForms, values);\n\t\treturn printICU(rewritten);\n\t} catch {\n\t\treturn icu;\n\t}\n}\n\n/**\n * Apply ordinal forms data to produce a locale-correct ordinal string.\n *\n * Returns the formatted ordinal when ordinalForms covers the value, or\n * `String(value)` for word-based locales when the rank is outside the\n * compiled word map (e.g. ranks > 100). Returns `null` only when the\n * forms type is unrecognised — callers should fall through to their ICU\n * bundle or String(value) in that case.\n */\nexport function applyOrdinalForms(\n\tvalue: number,\n\tlocale: string,\n\tforms: OrdinalForms,\n\tgender?: string,\n): string | null {\n\tif (forms.type === \"suffix\") {\n\t\tconst pr = new Intl.PluralRules(locale, { type: \"ordinal\" });\n\t\tconst category = pr.select(value) as keyof typeof forms.suffixes;\n\t\tconst pattern = forms.suffixes[category] ?? forms.suffixes.other;\n\t\treturn pattern ? pattern.replace(\"#\", String(value)) : null;\n\t}\n\n\tif (forms.type === \"word\") {\n\t\tconst genderKey = gender ?? \"masculine\";\n\t\tconst genderMap =\n\t\t\tforms.words[genderKey] ??\n\t\t\tforms.words[\"masculine\"] ??\n\t\t\tObject.values(forms.words)[0];\n\t\tconst word = genderMap?.[value];\n\t\tif (word) return word;\n\t\t// Rank outside the word map — don't fall through to ICU (unreliable for\n\t\t// word-based locales where the pipeline's ordinal DB returns null).\n\t\treturn String(value);\n\t}\n\n\treturn null;\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vocoder/core",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Shared primitives for the Vocoder i18n SDK — hash, ICU formatting, locale utilities, and types",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",