@vielzeug/lingua 1.1.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/README.md +86 -0
- package/dist/_catalog-store.cjs +2 -0
- package/dist/_catalog-store.cjs.map +1 -0
- package/dist/_catalog-store.d.ts +33 -0
- package/dist/_catalog-store.d.ts.map +1 -0
- package/dist/_catalog-store.js +74 -0
- package/dist/_catalog-store.js.map +1 -0
- package/dist/_catalog.cjs +2 -0
- package/dist/_catalog.cjs.map +1 -0
- package/dist/_catalog.d.ts +18 -0
- package/dist/_catalog.d.ts.map +1 -0
- package/dist/_catalog.js +42 -0
- package/dist/_catalog.js.map +1 -0
- package/dist/_chain.cjs +2 -0
- package/dist/_chain.cjs.map +1 -0
- package/dist/_chain.d.ts +21 -0
- package/dist/_chain.d.ts.map +1 -0
- package/dist/_chain.js +45 -0
- package/dist/_chain.js.map +1 -0
- package/dist/_constants.cjs +2 -0
- package/dist/_constants.cjs.map +1 -0
- package/dist/_constants.d.ts +3 -0
- package/dist/_constants.d.ts.map +1 -0
- package/dist/_constants.js +17 -0
- package/dist/_constants.js.map +1 -0
- package/dist/_dev.cjs +2 -0
- package/dist/_dev.cjs.map +1 -0
- package/dist/_dev.d.ts +2 -0
- package/dist/_dev.d.ts.map +1 -0
- package/dist/_dev.js +12 -0
- package/dist/_dev.js.map +1 -0
- package/dist/_namespace-store.cjs +2 -0
- package/dist/_namespace-store.cjs.map +1 -0
- package/dist/_namespace-store.d.ts +31 -0
- package/dist/_namespace-store.d.ts.map +1 -0
- package/dist/_namespace-store.js +54 -0
- package/dist/_namespace-store.js.map +1 -0
- package/dist/errors.cjs +2 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.ts +30 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +23 -0
- package/dist/errors.js.map +1 -0
- package/dist/format.cjs +2 -0
- package/dist/format.cjs.map +1 -0
- package/dist/format.d.ts +73 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +91 -0
- package/dist/format.js.map +1 -0
- package/dist/i18n.cjs +2 -0
- package/dist/i18n.cjs.map +1 -0
- package/dist/i18n.d.ts +283 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +234 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/lingua.cjs +2 -0
- package/dist/lingua.cjs.map +1 -0
- package/dist/lingua.iife.js +2 -0
- package/dist/lingua.iife.js.map +1 -0
- package/dist/lingua.js +2 -0
- package/dist/lingua.js.map +1 -0
- package/dist/template.cjs +2 -0
- package/dist/template.cjs.map +1 -0
- package/dist/template.d.ts +15 -0
- package/dist/template.d.ts.map +1 -0
- package/dist/template.js +49 -0
- package/dist/template.js.map +1 -0
- package/dist/validate.cjs +2 -0
- package/dist/validate.cjs.map +1 -0
- package/dist/validate.d.ts +40 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +59 -0
- package/dist/validate.js.map +1 -0
- package/package.json +53 -0
package/dist/lingua.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=128;function t(t,n,r){let i=t.get(n);if(i!==void 0)return i;let a=r();return t.size>=e&&t.delete(t.keys().next().value),t.set(n,a),a}var n=[`years`,`months`,`weeks`,`days`,`hours`,`minutes`,`seconds`,`milliseconds`,`microseconds`,`nanoseconds`],r={days:`d`,hours:`h`,microseconds:`us`,milliseconds:`ms`,minutes:`min`,months:`mo`,nanoseconds:`ns`,seconds:`s`,weeks:`w`,years:`y`};function i(e){return n.map(t=>{let n=e[t];return typeof n==`number`?`${n}${r[t]}`:void 0}).filter(e=>e!==void 0).join(` `)}function a(e){let r=new Map,a=new Map,o=new Map,s=new Map,c=new Map,l=new Map,u=typeof e==`string`?()=>e:e;function d(e,t){if(!t)return e;let n={};for(let e of Object.keys(t).sort())n[e]=t[e];try{return`${e}:${JSON.stringify(n)}`}catch{return e}}return{clear(){r.clear(),a.clear(),o.clear(),s.clear(),c.clear(),l.clear()},currency(e,n,r){let i=u(),o={...r,currency:n,style:`currency`};return t(a,d(i,o),()=>new Intl.NumberFormat(i,o)).format(e)},date(e,n){let r=u();return t(o,d(r,n),()=>new Intl.DateTimeFormat(r,n)).format(e)},duration(e,r){let a=u(),o=Intl;return o.DurationFormat?n.every(t=>e[t]===void 0)?``:t(l,d(a,r),()=>new o.DurationFormat(a,r)).format(e):i(e)},list(e,n){let r=u(),i=e.map(e=>String(e)),a=n?.style??`long`,o=n?.type===`or`?`disjunction`:`conjunction`;return t(c,d(r,{style:a,type:o}),()=>new Intl.ListFormat(r,{style:a,type:o})).format(i)},number(e,n){let i=u();return t(r,d(i,n),()=>new Intl.NumberFormat(i,n)).format(e)},relative(e,n,r){let i=u();return t(s,d(i,r),()=>new Intl.RelativeTimeFormat(i,r)).format(e,n)}}}var o=new Set([`__proto__`,`constructor`,`prototype`]),s=!globalThis.__LINGUA_PROD__;function c(e){s&&console.warn(`[@vielzeug/lingua] ${e}`)}function l(e,...t){s&&console.error(`[@vielzeug/lingua] ${e}`,...t)}var u={2:[`one`,`other`],3:[`zero`,`one`,`other`],6:[`zero`,`one`,`two`,`few`,`many`,`other`]};function d(e){if(e.indexOf(`|`)===-1)return null;let t=e.split(`|`),n=u[t.length];if(!n)return c(`Pipe-plural shorthand with ${t.length} parts is not recognized (valid counts: 2, 3, 6). Treating as a plain string: "${e.slice(0,60)}${e.length>60?`…`:``}"`),null;if(t.some(e=>e.trim()===``))return null;let r={};for(let e=0;e<t.length;e++)r[n[e]]=t[e];return r}var f=/\{([\p{ID_Continue}-]+)\}/gu;function p(e){let t=[],n=0;for(let r of e.matchAll(f)){let{index:i}=r,a=i??0;a>n&&t.push(e.slice(n,a)),t.push({var:r[1]}),n=a+r[0].length}return n<e.length&&t.push(e.slice(n)),t}function m(e,t,n,r,i){let a=``;for(let o of e)if(typeof o==`string`)a+=o;else{let e=t?.[o.var];a+=e==null?i(o.var,n,r):String(e)}return a}var h=class e{entries=new Map;prefixes=new Set;get(e){return this.entries.get(e)}set(e,t){this.entries.set(e,{compiled:p(t),message:t});let n=e.indexOf(`.`);for(;n!==-1;)this.prefixes.add(e.slice(0,n)),n=e.indexOf(`.`,n+1)}setAll(e){for(let[t,n]of e)this.set(t,n)}clone(){let t=new e;for(let[e,n]of this.entries)t.entries.set(e,n);for(let e of this.prefixes)t.prefixes.add(e);return t}};function g(e,t=new Map,n){for(let[r,i]of Object.entries(e)){if(o.has(r))continue;let e=n?`${n}.${r}`:r;if(typeof i==`string`){let n=d(i);n?g(n,t,e):t.set(e,i)}else g(i,t,e)}return t}var _=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},v=class extends _{constructor(){super(`Operation called on a disposed i18n instance.`)}},y=class extends _{},b=class extends _{},x=class extends _{},S=class extends _{},C=class extends _{},w=class extends _{};function T(e){if(e)throw new v}function E(e){return e?Promise.reject(new v):null}function D(e){let t=new Map,n=new Map,r=new Map,i=new Set,a,o=(e,n)=>{let r=t.get(e);r||(r=new h,t.set(e,r)),r.setAll(n)},s=i=>{let s=E(e());if(s)return s;if(t.has(i))return Promise.resolve();let c=n.get(i);if(!c)return Promise.reject(new x(`Missing locale source for "${i}".`));let l=r.get(i);if(l)return l;let u=c().then(e=>{n.get(i)===c&&(n.delete(i),o(i,g(e)),r.delete(i),a?.(i))},e=>{throw n.get(i)===c&&r.delete(i),e});return r.set(i,u),u};return{get catalogs(){return t},dispose(){t.clear(),n.clear(),r.clear(),i.clear(),a=void 0},isLoaded(e){return t.has(e)},isRegistered(e){return i.has(e)},knownLocales(){return[...i]},get onChange(){return a},set onChange(e){a=e},patch(t,r){return E(e())||(n.has(t)?s(t).then(()=>{e()||(o(t,g(r)),i.add(t),a?.(t))}):(o(t,g(r)),i.add(t),a?.(t),Promise.resolve()))},get pendingLoaders(){return n},preload:s,register(l,u,d){T(e()),r.delete(l),i.add(l);let f=d.clearLocale(l);f.length>0&&c(`register('${l}') cleared loaded namespace markers for: ${f.map(e=>`'${e}'`).join(`, `)}. Call loadNamespace() again to reload.`);let p;return typeof u==`function`?(n.set(l,u),t.delete(l),p=s(l)):(n.delete(l),t.delete(l),o(l,g(u)),p=Promise.resolve(),a?.(l)),p},resolve(e){return t.get(e)},seedFrom(e,r){for(let[n,r]of e)t.set(n,r.clone()),i.add(n);for(let[e,t]of r)n.set(e,t),i.add(e)}}}function O(){return{canon:new Map,chain:new Map,plural:new Map}}function k(e,t){let n=t.canon.get(e);if(n!==void 0)return n;let r;try{[r]=Intl.getCanonicalLocales(e)}catch{}if(!r)throw new S(`Invalid BCP 47 locale tag: "${e}".`);return t.canon.set(e,r),r}function A(e,t,n,r){let i=`${e}:${n?`ordinal`:`cardinal`}`,a=r.plural.get(i);return a||(a=new Intl.PluralRules(e,{type:n?`ordinal`:`cardinal`}),r.plural.set(i,a)),a.select(t)}function j(e,t){let n=new Set;for(let r of[e,...t]){n.add(r);let e=r.split(`-`);for(let t=e.length-1;t>0;t--)n.add(e.slice(0,t).join(`-`))}return{chain:[...n],set:n}}function M(e,t,n){let r=t.length===0?e:`${e}|${t.join(`,`)}`,i=n.chain.get(r);if(i)return i;let a=j(e,t);return n.chain.set(r,a),a}function N(e){let t=new Map,n=new Map,r=new Map;return{clearLocale(e){let t=[];for(let[r,i]of n.entries())i.delete(e)&&t.push(r);return t},dispose(){t.clear(),n.clear(),r.clear()},isLoaded(e,t){return n.get(e)?.has(t)??!1},isRegistered(e){return t.has(e)},loadNamespace(i,a,o){let s=E(e());if(s)return s;let c=t.get(i);if(!c)return Promise.reject(new C(`Namespace '${i}' is not registered. Call registerNamespace() first.`));if(n.get(i)?.has(a))return Promise.resolve();let l=r.get(i)?.get(a);if(l)return l;let u=c(a).then(e=>o(a,e)).then(()=>{let e=n.get(i);e||(e=new Set,n.set(i,e)),e.add(a),r.get(i)?.delete(a)},e=>{throw r.get(i)?.delete(a),e});return r.has(i)||r.set(i,new Map),r.get(i).set(a,u),u},registerNamespace(n,r){T(e()),t.set(n,r)},seedFrom(e){for(let[n,r]of e.snapshotRegistry())t.set(n,r);for(let[t,r]of e.snapshotLoaded())n.set(t,new Set(r))},snapshotLoaded(){return n},snapshotRegistry(){return t}}}function P(e,t,n){let{chain:r,set:i}=M(e,t,n);return{chain:r,chainSet:i,locale:e}}function F(e,t,n,r){let i=[];return!r&&n===0&&i.push(`${e}.zero`),(t!==`zero`||r)&&i.push(`${e}.${t}`),t!==`other`&&i.push(`${e}.other`),i}function I(e){return L(e)}function L(e,t){let n=e??{},r=O(),i=e=>k(e,r),o=Array.isArray(n.fallback)?n.fallback.map(i):n.fallback?[i(n.fallback)]:[],s=!1,c=new AbortController,u=D(()=>s),d=N(()=>s),f=P(i(n.locale??`en`),o,r),p=new Set,_=n.onMissingKey??(e=>e),x=n.onMissingVar??(e=>`{${e}}`),S=n.onSubscriberError??(e=>l(`subscriber error`,e)),C,E=new Map,j=()=>(C||=a(()=>f.locale),C),M=e=>{for(let t of f.chain){let n=u.resolve(t)?.get(e);if(n!==void 0)return n}},I=e=>{if(M(e)!==void 0)return!0;for(let t of f.chain){let n=u.resolve(t);if(n&&n.prefixes.has(e))return!0}return!1},R=(e,t,n)=>m(t.compiled,n,e,f.locale,x),z=(e,t)=>{let n=String(e),r=M(n);return r?R(n,r,t):_(n,f.locale)},B=(e,t,n)=>{if(!Number.isFinite(t))throw new y("`count` must be a finite number.");let i=n?.vars,a=n?.ordinal??!1;if(i&&Object.hasOwn(i,`count`))throw new b("`tp` does not allow `vars.count`; `count` is injected automatically.");let o=String(e),s=i?{count:t,...i}:{count:t};for(let e of f.chain){let n=u.resolve(e);if(!n)continue;let i=F(o,A(e,t,a,r),t,a);for(let e of i){let t=n.get(e);if(t!==void 0)return R(e,t,s)}}return _(o,f.locale)},V={locale:f.locale,t:z,tp:B},H=()=>{V={locale:f.locale,t:z,tp:B};let e=[...p];for(let t of e)try{t(V)}catch(e){S(e)}};if(u.onChange=e=>{f.chainSet.has(e)&&H()},t?.catalogStore&&u.seedFrom(t.catalogStore.catalogs,t.catalogStore.pendingLoaders),t?.nsStore&&d.seedFrom(t.nsStore),n.catalogs){let e=new Map,t=new Map;for(let[r,a]of Object.entries(n.catalogs)){let n=i(r);if(typeof a==`function`)t.set(n,a);else{let t=new h;t.setAll(g(a)),e.set(n,t)}}u.seedFrom(e,t)}let U=e=>u.preload(i(e)),W=0;return{get disposalSignal(){return c.signal},dispose(){s||(s=!0,c.abort(),p.clear(),u.dispose(),d.dispose(),E.clear())},get disposed(){return s},extend(e,t,n){T(s),d.registerNamespace(e,t);let r=n?i(n):f.locale;return d.loadNamespace(e,r,(e,t)=>u.patch(e,t))},get fmt(){return j()},fork(e){return L({fallback:e?.fallback??(o.length>0?o:void 0),locale:e?.locale??f.locale,onMissingKey:e?.onMissingKey??n.onMissingKey,onMissingVar:e?.onMissingVar??n.onMissingVar,onSubscriberError:e?.onSubscriberError??n.onSubscriberError},{catalogStore:u,nsStore:d})},getSnapshot(){return V},getState(){let e={};for(let[t,n]of u.catalogs)e[t]=Object.fromEntries([...n.entries.entries()].map(([e,{message:t}])=>[e,t]));return{catalogs:e,locale:f.locale}},getSupportedLocales(e){let t=[...u.knownLocales()];return e===!0?t.sort():t},has(e){return I(String(e))},isLoaded(e){try{return u.isLoaded(i(e))}catch{return!1}},isNamespaceLoaded(e,t){return d.isLoaded(e,t?i(t):f.locale)},isNamespaceRegistered(e){return d.isRegistered(e)},isRegistered(e){try{return u.isRegistered(i(e))}catch{return!1}},loadNamespace(e,t){let n=t?i(t):f.locale;return d.loadNamespace(e,n,(e,t)=>u.patch(e,t))},get locale(){return f.locale},preload:U,register(e,t){let n=i(e);return u.register(n,t,d)},registerNamespace(e,t){d.registerNamespace(e,t)},restoreState(e){if(T(s),!Object.hasOwn(e.catalogs,e.locale))throw new w(`restoreState: locale "${e.locale}" has no catalog in the provided state.`);let t=new Map;for(let[n,r]of Object.entries(e.catalogs)){let e=i(n),a=new h;a.setAll(Object.entries(r)),t.set(e,a),d.clearLocale(e)}u.dispose(),u.onChange=e=>{f.chainSet.has(e)&&H()},u.seedFrom(t,new Map),f=P(i(e.locale),o,r),C?.clear(),H()},scope(e){let t=String(e),n=E.get(t);if(n)return n;let r={get fmt(){return j()},has:e=>I(`${t}.${e}`),t:(e,n)=>z(`${t}.${e}`,n),tp:(e,n,r)=>B(`${t}.${e}`,n,r)};return E.set(t,r),r},async setLocale(e){T(s);let t=i(e);if(f.locale===t)return;let n=++W;await U(t),!(s||W!==n)&&(f=P(t,o,r),C?.clear(),H())},subscribe:(e,t)=>{let n=()=>{p.delete(e)};if(s)throw new v;if(t?.signal?.aborted)return n;if(t?.immediate===!0)try{e(V)}catch(e){return S(e),n}return p.add(e),t?.signal?.addEventListener(`abort`,n,{once:!0}),n},[Symbol.dispose](){this.dispose()},t:z,tp:B}}function R(e){return e.getState()}function z(e,t){e.restoreState(t)}exports.LinguaCountInVarsError=b,exports.LinguaDisposedError=v,exports.LinguaError=_,exports.LinguaInvalidCountError=y,exports.LinguaInvalidLocaleError=S,exports.LinguaMissingLocaleError=x,exports.LinguaNamespaceMissingError=C,exports.LinguaRestoreError=w,exports.createFormatter=a,exports.createI18n=I,exports.hydrateI18n=z,exports.serializeI18n=R;
|
|
2
|
+
//# sourceMappingURL=lingua.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lingua.cjs","names":[],"sources":["../src/format.ts","../src/_constants.ts","../src/_dev.ts","../src/template.ts","../src/_catalog.ts","../src/errors.ts","../src/_catalog-store.ts","../src/_chain.ts","../src/_namespace-store.ts","../src/i18n.ts"],"sourcesContent":["/**\n * /lingua/format\n *\n * Standalone Intl formatter factory. Import from `/lingua/format`.\n * Creates formatters for numbers, dates, currencies, lists, durations, and relative time.\n *\n * Pass a static locale string or a reactive locale getter.\n *\n * @example\n * ```ts\n * import { createFormatter } from '@vielzeug/lingua/format';\n *\n * // Static locale\n * const fmt = createFormatter('en-US');\n *\n * // Reactive — always reads the current locale from the i18n instance\n * const fmt = createFormatter(() => i18n.locale);\n *\n * fmt.number(1_234.56);\n * fmt.currency(9.99, 'USD');\n * fmt.date(new Date());\n * fmt.relative(-1, 'day');\n * fmt.list(['A', 'B', 'C']);\n * fmt.duration({ hours: 1, minutes: 30 });\n * ```\n */\n\nconst FORMAT_CACHE_MAX = 128;\n\nfunction getOrCreate<F>(cache: Map<string, F>, key: string, build: () => F): F {\n const cached = cache.get(key);\n\n if (cached !== undefined) return cached;\n\n const value = build();\n\n if (cache.size >= FORMAT_CACHE_MAX) cache.delete(cache.keys().next().value as string);\n\n cache.set(key, value);\n\n return value;\n}\n\nexport type DurationValue = Partial<\n Record<\n | 'days'\n | 'hours'\n | 'microseconds'\n | 'milliseconds'\n | 'minutes'\n | 'months'\n | 'nanoseconds'\n | 'seconds'\n | 'weeks'\n | 'years',\n number\n >\n>;\n\nexport type DurationFormatOptions = {\n hours?: '2-digit' | 'numeric';\n microseconds?: 'numeric';\n milliseconds?: 'numeric';\n minutes?: '2-digit' | 'numeric';\n nanoseconds?: 'numeric';\n seconds?: '2-digit' | 'numeric';\n style?: 'digital' | 'long' | 'narrow' | 'short';\n};\n\nexport type ListFormatOptions = {\n style?: 'long' | 'narrow' | 'short';\n type?: 'and' | 'or';\n};\n\nexport type Formatter = {\n /**\n * Clears all cached `Intl` formatter instances. Useful after a locale change on a long-running\n * SSR server, or to reclaim memory.\n *\n * @note This clears the cache for **all callers sharing this formatter instance**. When called on\n * `i18n.fmt`, the cache is cleared for every part of the application that reads `i18n.fmt`.\n * `setLocale()` already calls `clear()` automatically — manual calls are rarely needed.\n */\n clear(): void;\n currency(value: number, currency: string, options?: Omit<Intl.NumberFormatOptions, 'currency' | 'style'>): string;\n date(value: Date | number, options?: Intl.DateTimeFormatOptions): string;\n /**\n * Formats a duration using `Intl.DurationFormat` when available, or a compact labeled fallback\n * (e.g. `'1h 30min'`). Returns `''` when every field of `value` is `undefined`.\n *\n * @note The fallback labels (`h`, `min`, `s`, `ms`, etc.) are English-only and are not\n * locale-aware. If `Intl.DurationFormat` is unavailable in your target environment and\n * you need localised duration output, provide your own formatter using the individual\n * duration fields from `DurationValue`.\n */\n duration(value: DurationValue, options?: DurationFormatOptions): string;\n list(value: Array<string | number>, options?: ListFormatOptions): string;\n /** Formats a number with the current locale. */\n number(value: number, options?: Intl.NumberFormatOptions): string;\n relative(value: number, unit: Intl.RelativeTimeFormatUnit, options?: Intl.RelativeTimeFormatOptions): string;\n};\n\n// ─── Internal ─────────────────────────────────────────────────────────────────\n\nconst DURATION_UNITS: Array<keyof DurationValue> = [\n 'years',\n 'months',\n 'weeks',\n 'days',\n 'hours',\n 'minutes',\n 'seconds',\n 'milliseconds',\n 'microseconds',\n 'nanoseconds',\n];\n\nconst DURATION_LABELS: Record<keyof DurationValue, string> = {\n days: 'd',\n hours: 'h',\n microseconds: 'us',\n milliseconds: 'ms',\n minutes: 'min',\n months: 'mo',\n nanoseconds: 'ns',\n seconds: 's',\n weeks: 'w',\n years: 'y',\n};\n\ntype DurationFormatterCtor = new (\n locale: string,\n options?: DurationFormatOptions,\n) => { format(value: DurationValue): string };\n\nfunction durationLabeled(value: DurationValue): string {\n return DURATION_UNITS.map((unit) => {\n const amount = value[unit];\n\n return typeof amount === 'number' ? `${amount}${DURATION_LABELS[unit]}` : undefined;\n })\n .filter((part): part is string => part !== undefined)\n .join(' ');\n}\n\n// ─── Factory ──────────────────────────────────────────────────────────────────\n\n/**\n * Creates a formatter bound to a locale. Pass a static locale string or a\n * reactive getter function `() => string` (e.g. `() => i18n.locale`).\n */\nexport function createFormatter(source: string | (() => string)): Formatter {\n const numberCache = new Map<string, Intl.NumberFormat>();\n const currencyCache = new Map<string, Intl.NumberFormat>();\n const dateCache = new Map<string, Intl.DateTimeFormat>();\n const relativeCache = new Map<string, Intl.RelativeTimeFormat>();\n const listCache = new Map<string, Intl.ListFormat>();\n const durationCache = new Map<string, { format(value: DurationValue): string }>();\n\n const getLocale = typeof source === 'string' ? () => source : source;\n\n function cachedKey(locale: string, options?: object): string {\n if (!options) return locale;\n\n const sorted: Record<string, unknown> = {};\n\n for (const key of Object.keys(options as Record<string, unknown>).sort()) {\n sorted[key] = (options as Record<string, unknown>)[key];\n }\n\n try {\n return `${locale}:${JSON.stringify(sorted)}`;\n } catch {\n // Circular references or BigInt values — fall back to locale-only key.\n // Multiple callers with different unserializable options will share the same formatter instance.\n return locale;\n }\n }\n\n return {\n clear() {\n numberCache.clear();\n currencyCache.clear();\n dateCache.clear();\n relativeCache.clear();\n listCache.clear();\n durationCache.clear();\n },\n\n currency(value, currency, options) {\n const locale = getLocale();\n const opts: Intl.NumberFormatOptions = { ...options, currency, style: 'currency' };\n\n return getOrCreate(currencyCache, cachedKey(locale, opts), () => new Intl.NumberFormat(locale, opts)).format(\n value,\n );\n },\n\n date(value, options) {\n const locale = getLocale();\n\n return getOrCreate(dateCache, cachedKey(locale, options), () => new Intl.DateTimeFormat(locale, options)).format(\n value,\n );\n },\n\n duration(value, options) {\n const locale = getLocale();\n const IntlExt = Intl as typeof Intl & { DurationFormat?: DurationFormatterCtor };\n\n if (!IntlExt.DurationFormat) return durationLabeled(value);\n\n if (DURATION_UNITS.every((u) => value[u] === undefined)) return '';\n\n return getOrCreate(\n durationCache,\n cachedKey(locale, options),\n () => new IntlExt.DurationFormat!(locale, options),\n ).format(value);\n },\n\n list(value, options) {\n const locale = getLocale();\n const items = value.map((v) => String(v));\n // list() has exactly two string options with small finite value domains.\n // We normalize both to their resolved defaults and build the key directly\n // rather than using cachedKey(). This also prevents cache misses when\n // callers pass { style: 'long', type: 'and' } vs {} (same ListFormat).\n const style = options?.style ?? 'long';\n const type = options?.type === 'or' ? 'disjunction' : 'conjunction';\n\n return getOrCreate(\n listCache,\n cachedKey(locale, { style, type }),\n () => new Intl.ListFormat(locale, { style, type }),\n ).format(items);\n },\n\n number(value, options) {\n const locale = getLocale();\n\n return getOrCreate(numberCache, cachedKey(locale, options), () => new Intl.NumberFormat(locale, options)).format(\n value,\n );\n },\n\n relative(value, unit, options) {\n const locale = getLocale();\n\n return getOrCreate(\n relativeCache,\n cachedKey(locale, options),\n () => new Intl.RelativeTimeFormat(locale, options),\n ).format(value, unit);\n },\n };\n}\n","// Shared constants used by both i18n.ts and validate.ts.\n// Not part of the public API — internal module only.\n\nexport const UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\n\nexport const CLDR_FORMS = new Set(['zero', 'one', 'two', 'few', 'many', 'other']);\n","const isDev = !(globalThis as { __LINGUA_PROD__?: boolean }).__LINGUA_PROD__;\n\n/** @internal @security Messages may include user-supplied data. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/lingua] ${msg}`);\n}\n\n/** @internal */\nexport function error(msg: string, ...args: unknown[]): void {\n if (isDev) console.error(`[@vielzeug/lingua] ${msg}`, ...args);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n","// ─── Template helpers ─────────────────────────────────────────────────────────\n// Shared by i18n.ts — extracted for navigability. Not part of the public API.\n\nimport { warn } from './_dev';\n\ntype Locale = string;\ntype TranslateVars = Record<string, unknown>;\n\ninterface Messages {\n [key: string]: string | Messages;\n}\n\n// ─── Pipe-plural shorthand (F1) ───────────────────────────────────────────────\n// A leaf string containing '|' is parsed as a pipe-delimited plural shorthand.\n// Supported part counts and their form mappings (positional, left-to-right):\n// 2 parts → one | other\n// 3 parts → zero | one | other\n// 6 parts → zero | one | two | few | many | other\n// Any other part count is treated as a plain string with no expansion.\n\nconst PIPE_FORM_MAPS: Readonly<Partial<Record<number, readonly string[]>>> = {\n 2: ['one', 'other'],\n 3: ['zero', 'one', 'other'],\n 6: ['zero', 'one', 'two', 'few', 'many', 'other'],\n};\n\nexport function parsePipePlural(value: string): Messages | null {\n const pipeIdx = value.indexOf('|');\n\n if (pipeIdx === -1) return null;\n\n const parts = value.split('|');\n const forms = PIPE_FORM_MAPS[parts.length];\n\n if (!forms) {\n warn(\n `Pipe-plural shorthand with ${parts.length} parts is not recognized (valid counts: 2, 3, 6). Treating as a plain string: \"${value.slice(0, 60)}${value.length > 60 ? '…' : ''}\"`,\n );\n\n return null;\n }\n\n // An empty part is almost certainly a catalog authoring error.\n // Treat the whole value as a plain string rather than silently producing an empty form.\n if (parts.some((p) => p.trim() === '')) return null;\n\n const result: Messages = {};\n\n for (let i = 0; i < parts.length; i++) {\n result[forms[i]] = parts[i];\n }\n\n return result;\n}\n\n// ─── Template compilation ─────────────────────────────────────────────────────\n// Message strings are parsed once at registration time into a pre-compiled form:\n// an array of static strings and variable names. Rendering a compiled template\n// skips the regex entirely.\n\ntype TemplatePart = string | { var: string };\nexport type CompiledTemplate = TemplatePart[];\n\nexport const INTERPOLATION_PATTERN = /\\{([\\p{ID_Continue}-]+)\\}/gu;\n\nexport function compileTemplate(template: string): CompiledTemplate {\n const parts: CompiledTemplate = [];\n let lastIndex = 0;\n\n for (const match of template.matchAll(INTERPOLATION_PATTERN)) {\n const { index } = match;\n const start = index ?? 0;\n\n if (start > lastIndex) {\n parts.push(template.slice(lastIndex, start));\n }\n\n parts.push({ var: match[1] });\n lastIndex = start + match[0].length;\n }\n\n if (lastIndex < template.length) {\n parts.push(template.slice(lastIndex));\n }\n\n return parts;\n}\n\nexport function renderTemplate(\n parts: CompiledTemplate,\n vars: TranslateVars | undefined,\n key: string,\n locale: Locale,\n onMissingVar: (varName: string, key: string, locale: Locale) => string,\n): string {\n let result = '';\n\n for (const part of parts) {\n if (typeof part === 'string') {\n result += part;\n } else {\n const value = vars?.[part.var];\n\n result += value == null ? onMissingVar(part.var, key, locale) : String(value);\n }\n }\n\n return result;\n}\n","// Internal — not part of the public API.\n// Encapsulates the CatalogEntry class, flattenStrings, and related utilities.\n\nimport { UNSAFE_KEYS } from './_constants';\nimport { compileTemplate, type CompiledTemplate, parsePipePlural } from './template';\n\nexport interface Messages {\n [key: string]: string | Messages;\n}\n\nexport type CatalogEntryData = {\n compiled: CompiledTemplate;\n message: string;\n};\n\nexport class CatalogEntry {\n readonly entries = new Map<string, CatalogEntryData>();\n readonly prefixes = new Set<string>();\n\n get(key: string): CatalogEntryData | undefined {\n return this.entries.get(key);\n }\n\n set(key: string, value: string): void {\n this.entries.set(key, { compiled: compileTemplate(value), message: value });\n\n // Populate prefix set for O(1) branch detection in has().\n let dot = key.indexOf('.');\n\n while (dot !== -1) {\n this.prefixes.add(key.slice(0, dot));\n dot = key.indexOf('.', dot + 1);\n }\n }\n\n setAll(flat: Iterable<[string, string]>): void {\n for (const [k, v] of flat) this.set(k, v);\n }\n\n clone(): CatalogEntry {\n const copy = new CatalogEntry();\n\n for (const [k, v] of this.entries) copy.entries.set(k, v);\n for (const p of this.prefixes) copy.prefixes.add(p);\n\n return copy;\n }\n}\n\nexport function flattenStrings(\n messages: Messages,\n result = new Map<string, string>(),\n prefix?: string,\n): Map<string, string> {\n for (const [key, value] of Object.entries(messages)) {\n if (UNSAFE_KEYS.has(key)) continue;\n\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n if (typeof value === 'string') {\n const plural = parsePipePlural(value);\n\n if (plural) {\n flattenStrings(plural, result, fullKey);\n } else {\n result.set(fullKey, value);\n }\n } else {\n flattenStrings(value as Messages, result, fullKey);\n }\n }\n\n return result;\n}\n","/** Base class for all lingua errors. Use `instanceof LinguaError` or `LinguaError.is()` to catch any lingua-originated error. */\nexport class LinguaError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is LinguaError {\n return err instanceof LinguaError;\n }\n}\n\n/** Thrown when a method is called on a disposed i18n instance. */\nexport class LinguaDisposedError extends LinguaError {\n constructor() {\n super('Operation called on a disposed i18n instance.');\n }\n}\n\n/** Thrown when `tp()` receives a non-finite `count` value. */\nexport class LinguaInvalidCountError extends LinguaError {}\n\n/** Thrown when `vars.count` is set alongside the `count` parameter in `tp()`. */\nexport class LinguaCountInVarsError extends LinguaError {}\n\n/** Thrown when a requested locale has not been registered. */\nexport class LinguaMissingLocaleError extends LinguaError {}\n\n/** Thrown when a locale string is not a valid BCP 47 tag. */\nexport class LinguaInvalidLocaleError extends LinguaError {}\n\n/** Thrown when `loadNamespace()` / `extend()` is called for a namespace that has not been registered with `registerNamespace()`. */\nexport class LinguaNamespaceMissingError extends LinguaError {}\n\n/** Thrown when restoring i18n state whose locale has no catalog. */\nexport class LinguaRestoreError extends LinguaError {}\n\n// ─── Internal helpers ─────────────────────────────────────────────────────────\n\nexport function checkDisposed(disposed: boolean): void {\n if (disposed) throw new LinguaDisposedError();\n}\n\nexport function checkDisposedAsync(disposed: boolean): Promise<never> | null {\n return disposed ? Promise.reject(new LinguaDisposedError()) : null;\n}\n","// Internal — not part of the public API.\n// Owns all locale → CatalogEntry state, loaders, and in-flight loading tasks.\n\nimport type { NamespaceStore } from './_namespace-store';\n\nimport { CatalogEntry, type Messages, flattenStrings } from './_catalog';\nimport { warn } from './_dev';\nimport { LinguaMissingLocaleError, checkDisposed, checkDisposedAsync } from './errors';\n\nexport type Locale = string;\nexport type Loader<M extends Messages = Messages> = () => Promise<M>;\nexport type LocaleSource<M extends Messages = Messages> = M | Loader<M>;\n\nexport type CatalogStore<M extends Messages = Messages> = {\n /** Direct access to the raw catalogs map (for SSR serialization). */\n readonly catalogs: ReadonlyMap<Locale, CatalogEntry>;\n dispose(): void;\n isLoaded(loc: Locale): boolean;\n isRegistered(loc: Locale): boolean;\n /** All registered locale keys in insertion order. */\n knownLocales(): readonly Locale[];\n /** Callback invoked whenever a catalog changes (drives bump/notify). */\n onChange: ((loc: Locale) => void) | undefined;\n /** Patch a locale catalog with additional flat messages (used by loadNamespace). */\n patch(loc: Locale, messages: Messages): Promise<void>;\n /** Direct access to the pending loaders map (for fork propagation). */\n readonly pendingLoaders: ReadonlyMap<Locale, Loader<M>>;\n /** Pre-load a locale catalog without switching. */\n preload(loc: Locale): Promise<void>;\n /** Register (or replace) a locale's source. Returns a Promise that resolves when the catalog is loaded. */\n register(loc: Locale, source: LocaleSource<M>, nsStore: NamespaceStore): Promise<void>;\n /** Resolve a compiled CatalogEntry for a locale (undefined if not loaded). */\n resolve(loc: Locale): CatalogEntry | undefined;\n /**\n * Seed the store with pre-compiled entries from a parent fork.\n * Called during fork() — compiled templates are shared by reference.\n */\n seedFrom(entries: ReadonlyMap<Locale, CatalogEntry>, loaderMap: ReadonlyMap<Locale, Loader<M>>): void;\n};\n\nexport function createCatalogStore<M extends Messages = Messages>(disposed: () => boolean): CatalogStore<M> {\n const catalogs = new Map<Locale, CatalogEntry>();\n const loaders = new Map<Locale, Loader<M>>();\n const loadingTasks = new Map<Locale, Promise<void>>();\n const known = new Set<Locale>();\n\n let onChange: ((loc: Locale) => void) | undefined;\n\n const registerRaw = (normalized: Locale, flat: Map<string, string>): void => {\n let entry = catalogs.get(normalized);\n\n if (!entry) {\n entry = new CatalogEntry();\n catalogs.set(normalized, entry);\n }\n\n entry.setAll(flat);\n };\n\n const preload = (loc: Locale): Promise<void> => {\n const early = checkDisposedAsync(disposed());\n\n if (early) return early;\n\n if (catalogs.has(loc)) return Promise.resolve();\n\n const loader = loaders.get(loc);\n\n if (!loader) return Promise.reject(new LinguaMissingLocaleError(`Missing locale source for \"${loc}\".`));\n\n const existing = loadingTasks.get(loc);\n\n if (existing) return existing;\n\n const task = loader().then(\n (messages) => {\n if (loaders.get(loc) !== loader) return;\n\n loaders.delete(loc);\n registerRaw(loc, flattenStrings(messages));\n loadingTasks.delete(loc);\n onChange?.(loc);\n },\n (error: unknown) => {\n if (loaders.get(loc) === loader) loadingTasks.delete(loc);\n\n throw error;\n },\n );\n\n loadingTasks.set(loc, task);\n\n return task;\n };\n\n return {\n get catalogs() {\n return catalogs as ReadonlyMap<Locale, CatalogEntry>;\n },\n\n dispose() {\n catalogs.clear();\n loaders.clear();\n loadingTasks.clear();\n known.clear();\n onChange = undefined;\n },\n\n isLoaded(loc) {\n return catalogs.has(loc);\n },\n\n isRegistered(loc) {\n return known.has(loc);\n },\n\n knownLocales() {\n return [...known];\n },\n\n get onChange() {\n return onChange;\n },\n\n set onChange(fn: ((loc: Locale) => void) | undefined) {\n onChange = fn;\n },\n\n patch(loc, messages) {\n const early = checkDisposedAsync(disposed());\n\n if (early) return early;\n\n if (loaders.has(loc)) {\n return preload(loc).then(() => {\n if (disposed()) return;\n\n registerRaw(loc, flattenStrings(messages));\n known.add(loc);\n onChange?.(loc);\n });\n }\n\n registerRaw(loc, flattenStrings(messages));\n known.add(loc);\n onChange?.(loc);\n\n return Promise.resolve();\n },\n\n get pendingLoaders() {\n return loaders as ReadonlyMap<Locale, Loader<M>>;\n },\n\n preload,\n\n register(loc, source, nsStore) {\n checkDisposed(disposed());\n\n loadingTasks.delete(loc);\n known.add(loc);\n\n // Clear namespace loaded-markers for this locale so namespaces can be re-applied\n // after catalog replacement.\n const clearedNs = nsStore.clearLocale(loc);\n\n if (clearedNs.length > 0) {\n warn(\n `register('${loc}') cleared loaded namespace markers for: ${clearedNs.map((ns) => `'${ns}'`).join(', ')}. Call loadNamespace() again to reload.`,\n );\n }\n\n let loadPromise: Promise<void>;\n\n if (typeof source === 'function') {\n loaders.set(loc, source as Loader<M>);\n catalogs.delete(loc);\n loadPromise = preload(loc);\n } else {\n loaders.delete(loc);\n catalogs.delete(loc);\n registerRaw(loc, flattenStrings(source as M));\n loadPromise = Promise.resolve();\n onChange?.(loc);\n }\n\n return loadPromise;\n },\n\n resolve(loc) {\n return catalogs.get(loc);\n },\n\n seedFrom(entries, loaderMap) {\n for (const [loc, entry] of entries) {\n catalogs.set(loc, entry.clone());\n known.add(loc);\n }\n\n for (const [loc, loader] of loaderMap) {\n loaders.set(loc, loader);\n known.add(loc);\n }\n },\n };\n}\n","// Internal — not part of the public API.\n// Locale chain building, canonicalization, and plural-rules selection.\n// All caches are per-instance — no shared module-level state.\n\nimport { LinguaInvalidLocaleError } from './errors';\n\nexport type Locale = string;\n\n// ─── Per-instance caches ──────────────────────────────────────────────────────\n\nexport type LocaleCaches = {\n canon: Map<string, string>;\n chain: Map<string, { chain: Locale[]; set: Set<Locale> }>;\n plural: Map<string, Intl.PluralRules>;\n};\n\nexport function createLocaleCaches(): LocaleCaches {\n return { canon: new Map(), chain: new Map(), plural: new Map() };\n}\n\n// ─── Canon ────────────────────────────────────────────────────────────────────\n\nexport function canon(locale: string, cache: LocaleCaches): string {\n const cached = cache.canon.get(locale);\n\n if (cached !== undefined) return cached;\n\n let canonical: string | undefined;\n\n try {\n [canonical] = Intl.getCanonicalLocales(locale);\n } catch {\n // Invalid BCP 47 tag — canonical stays undefined, guard below throws.\n }\n\n if (!canonical) throw new LinguaInvalidLocaleError(`Invalid BCP 47 locale tag: \"${locale}\".`);\n\n cache.canon.set(locale, canonical);\n\n return canonical;\n}\n\n// ─── Plural form selection ────────────────────────────────────────────────────\n\nexport function selectPluralForm(locale: Locale, count: number, ordinal: boolean, cache: LocaleCaches): string {\n const key = `${locale}:${ordinal ? 'ordinal' : 'cardinal'}`;\n let rules = cache.plural.get(key);\n\n if (!rules) {\n rules = new Intl.PluralRules(locale, { type: ordinal ? 'ordinal' : 'cardinal' });\n cache.plural.set(key, rules);\n }\n\n return rules.select(count);\n}\n\n// ─── Locale chain ─────────────────────────────────────────────────────────────\n\nfunction buildLocaleChainRaw(locale: Locale, fallback: Locale[]): { chain: Locale[]; set: Set<Locale> } {\n const set = new Set<Locale>();\n\n for (const value of [locale, ...fallback]) {\n set.add(value);\n\n const parts = value.split('-');\n\n for (let i = parts.length - 1; i > 0; i--) {\n set.add(parts.slice(0, i).join('-'));\n }\n }\n\n return { chain: [...set], set };\n}\n\n/**\n * Build a locale fallback chain, memoized per `(locale, fallback)` key using a provided cache.\n * The cache is per-instance (lives on LocaleCaches) — no shared module-level state.\n */\nexport function buildLocaleChain(\n locale: Locale,\n fallback: Locale[],\n cache: LocaleCaches,\n): { chain: Locale[]; set: Set<Locale> } {\n const key = fallback.length === 0 ? locale : `${locale}|${fallback.join(',')}`;\n const cached = cache.chain.get(key);\n\n if (cached) return cached;\n\n const result = buildLocaleChainRaw(locale, fallback);\n\n cache.chain.set(key, result);\n\n return result;\n}\n","// Internal — not part of the public API.\n// Owns namespace factory registry, per-locale loaded markers, and in-flight namespace tasks.\n\nimport type { Messages } from './_catalog';\n\nimport { LinguaNamespaceMissingError, checkDisposed, checkDisposedAsync } from './errors';\n\nexport type Locale = string;\nexport type NamespaceFactory<M extends Messages = Messages> = (locale: Locale) => Promise<M>;\n\nexport type NamespaceStore<M extends Messages = Messages> = {\n /**\n * Remove loaded-markers for a locale across all namespaces.\n * Called by CatalogStore.register() when a catalog is replaced.\n * Returns the list of namespace names whose markers were cleared.\n */\n clearLocale(loc: Locale): string[];\n dispose(): void;\n /** Returns true if the namespace has been loaded for the given locale. */\n isLoaded(ns: string, loc: Locale): boolean;\n /** Returns true if the namespace factory is registered. */\n isRegistered(ns: string): boolean;\n /**\n * Load a namespace for the given locale. Deduplicates concurrent and repeated calls.\n * The `patch` callback is responsible for merging the loaded messages into the catalog.\n */\n loadNamespace(ns: string, loc: Locale, patch: (loc: Locale, messages: Messages) => Promise<void>): Promise<void>;\n /** Register a namespace factory. Idempotent — re-registration updates the factory for future loads. */\n registerNamespace(ns: string, factory: NamespaceFactory<M>): void;\n /** Seed from a parent instance (fork). Copies loaded markers; registry is shared by reference. */\n seedFrom(parent: NamespaceStore<M>): void;\n /** Snapshot of loaded markers for fork() */\n snapshotLoaded(): ReadonlyMap<string, ReadonlySet<string>>;\n /** Snapshot of the registry for fork() */\n snapshotRegistry(): ReadonlyMap<string, NamespaceFactory<M>>;\n};\n\nexport function createNamespaceStore<M extends Messages = Messages>(disposed: () => boolean): NamespaceStore<M> {\n const registry = new Map<string, NamespaceFactory<M>>();\n // Two-level: Map<namespace, Set<locale>>\n const loaded = new Map<string, Set<string>>();\n const tasks = new Map<string, Map<string, Promise<void>>>();\n\n return {\n clearLocale(loc) {\n const cleared: string[] = [];\n\n for (const [ns, localeSet] of loaded.entries()) {\n if (localeSet.delete(loc)) cleared.push(ns);\n }\n\n return cleared;\n },\n\n dispose() {\n registry.clear();\n loaded.clear();\n tasks.clear();\n },\n\n isLoaded(ns, loc) {\n return loaded.get(ns)?.has(loc) ?? false;\n },\n\n isRegistered(ns) {\n return registry.has(ns);\n },\n\n loadNamespace(ns, loc, patch) {\n const early = checkDisposedAsync(disposed());\n\n if (early) return early;\n\n const factory = registry.get(ns);\n\n if (!factory) {\n return Promise.reject(\n new LinguaNamespaceMissingError(`Namespace '${ns}' is not registered. Call registerNamespace() first.`),\n );\n }\n\n if (loaded.get(ns)?.has(loc)) return Promise.resolve();\n\n const nsTasks = tasks.get(ns);\n const existing = nsTasks?.get(loc);\n\n if (existing) return existing;\n\n const task = factory(loc)\n .then((messages) => patch(loc, messages as Messages))\n .then(\n () => {\n let localeSet = loaded.get(ns);\n\n if (!localeSet) {\n localeSet = new Set();\n loaded.set(ns, localeSet);\n }\n\n localeSet.add(loc);\n tasks.get(ns)?.delete(loc);\n },\n (err: unknown) => {\n tasks.get(ns)?.delete(loc);\n throw err;\n },\n );\n\n if (!tasks.has(ns)) tasks.set(ns, new Map());\n\n tasks.get(ns)!.set(loc, task);\n\n return task;\n },\n\n registerNamespace(ns, factory) {\n checkDisposed(disposed());\n registry.set(ns, factory);\n },\n\n seedFrom(parent) {\n for (const [ns, factory] of parent.snapshotRegistry()) {\n registry.set(ns, factory);\n }\n\n for (const [ns, localeSet] of parent.snapshotLoaded()) {\n loaded.set(ns, new Set(localeSet));\n }\n },\n\n snapshotLoaded() {\n return loaded as ReadonlyMap<string, ReadonlySet<string>>;\n },\n\n snapshotRegistry() {\n return registry as ReadonlyMap<string, NamespaceFactory<M>>;\n },\n };\n}\n","import { CatalogEntry, type Messages, flattenStrings } from './_catalog';\nimport { type CatalogStore, type Loader, type LocaleSource, createCatalogStore } from './_catalog-store';\nimport { type LocaleCaches, buildLocaleChain, canon, createLocaleCaches, selectPluralForm } from './_chain';\nimport { error as logError } from './_dev';\nimport { type NamespaceFactory, type NamespaceStore, createNamespaceStore } from './_namespace-store';\nimport {\n LinguaCountInVarsError,\n LinguaDisposedError,\n LinguaInvalidCountError,\n LinguaRestoreError,\n checkDisposed,\n} from './errors';\nimport { type Formatter, createFormatter } from './format';\nimport { type CompiledTemplate, renderTemplate } from './template';\n\nexport {\n LinguaCountInVarsError,\n LinguaDisposedError,\n LinguaError,\n LinguaInvalidCountError,\n LinguaInvalidLocaleError,\n LinguaMissingLocaleError,\n LinguaNamespaceMissingError,\n LinguaRestoreError,\n} from './errors';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type Locale = string;\nexport type Unsubscribe = () => void;\n\nexport type { Messages } from './_catalog';\nexport type { Loader, LocaleSource } from './_catalog-store';\nexport type { NamespaceFactory } from './_namespace-store';\n\nexport type TranslateVars = Record<string, unknown>;\n\n/**\n * A snapshot of the i18n instance state at a point in time.\n * Object identity changes on every observable change (locale switch, catalog load).\n * `t` and `tp` are bound to the locale captured in this snapshot.\n */\nexport type I18nSnapshot = {\n readonly locale: Locale;\n /** @security Returns raw, unsanitized strings. Sanitize before `innerHTML` insertion. */\n readonly t: (key: string, vars?: TranslateVars) => string;\n readonly tp: (key: string, count: number, options?: TpOptions) => string;\n};\n\n/** Shape of the serialised state produced by `serializeI18n()`. Pass to `hydrateI18n()` on the client. */\nexport type I18nState = {\n readonly catalogs: Record<Locale, Record<string, string>>;\n readonly locale: Locale;\n};\n\nexport type SubscribeOptions = {\n immediate?: boolean;\n /** AbortSignal — automatically unsubscribes when the signal is aborted. */\n signal?: AbortSignal;\n};\n\nexport type TpOptions = {\n /** Use ordinal plural rules (1st, 2nd, 3rd) instead of cardinal (default: `false`). */\n ordinal?: boolean;\n /** Inject additional interpolation variables alongside the automatically injected `count`. */\n vars?: TranslateVars;\n};\n\nexport type ScopedI18n = {\n /** Intl formatter inherited from the parent instance. Follows locale changes automatically. */\n readonly fmt: Formatter;\n has(key: string): boolean;\n t(key: string, vars?: TranslateVars): string;\n tp(key: string, count: number, options?: TpOptions): string;\n};\n\n// ─── Key inference ────────────────────────────────────────────────────────────\n// Depth tuple prevents infinite recursion on recursive `Messages` type.\n// Depth 7 covers real-world catalog nesting without measurable TS instantiation cost.\ntype Depth = [never, 0, 1, 2, 3, 4, 5, 6];\n\nexport type MessageLeafKeys<T, P extends string = '', D extends number = 7> = [D] extends [0]\n ? never\n : T extends string\n ? P\n : T extends Record<string, unknown>\n ? { [K in string & keyof T]: MessageLeafKeys<T[K], P extends '' ? K : `${P}.${K}`, Depth[D]> }[string & keyof T]\n : never;\n\nexport type MessageBranchKeys<T, P extends string = '', D extends number = 7> = [D] extends [0]\n ? never\n : T extends Record<string, unknown>\n ? {\n [K in string & keyof T]: T[K] extends string\n ? never\n : (P extends '' ? K : `${P}.${K}`) | MessageBranchKeys<T[K], P extends '' ? K : `${P}.${K}`, Depth[D]>;\n }[string & keyof T]\n : never;\n\n// ─── Config ───────────────────────────────────────────────────────────────────\n\nexport type I18nOptions<M extends Messages = Messages> = {\n /** Locale registry. Values can be static message objects or async loaders. */\n catalogs?: Record<Locale, LocaleSource<M>>;\n /** Locale(s) to search when the active locale is missing a key. Subtags are expanded automatically (e.g. `en-US` → `en`). */\n fallback?: Locale | Locale[];\n /** Initial active locale. Defaults to `\"en\"`. Canonicalized via `Intl.getCanonicalLocales`. */\n locale?: Locale;\n /**\n * Called when a translation key is missing.\n * Defaults to returning the key string.\n *\n * @security The default handler returns `key` verbatim. Do not render the return value as HTML\n * if keys are constructed from untrusted user input.\n */\n onMissingKey?: (key: string, locale: Locale) => string;\n /**\n * Called when an interpolation variable is missing.\n * Defaults to returning `{varName}`.\n */\n onMissingVar?: (varName: string, key: string, locale: Locale) => string;\n /**\n * Called when a subscriber callback throws. Defaults to `console.error`.\n * Override in production to route errors to a structured logger rather than the browser console.\n */\n onSubscriberError?: (error: unknown) => void;\n};\n\n// ─── Public interface ─────────────────────────────────────────────────────────\n\nexport type I18n<M extends Messages = Messages> = {\n /** Delegates to `dispose()`. Enables `using` declarations. */\n [Symbol.dispose](): void;\n /** `AbortSignal` aborted when `dispose()` is called. Use to tie external lifetimes to this instance. */\n readonly disposalSignal: AbortSignal;\n /**\n * Disposes this i18n instance: removes all subscribers and clears catalog, loader, and namespace state.\n * After disposal, all mutation methods throw `LinguaDisposedError` and translation methods\n * fall back to `onMissingKey` for every key. Idempotent.\n */\n dispose(): void;\n /** `true` after `dispose()` has been called. */\n readonly disposed: boolean;\n /**\n * Registers a namespace factory and immediately starts loading it for the given locale\n * (defaults to the active locale). Deduplicates concurrent and repeated calls.\n *\n * @remarks\n * Call `registerNamespace()` first if you only want to register without loading.\n * `extend()` is a convenience that does both in one call.\n *\n * @throws `LinguaDisposedError` if called on a disposed instance.\n *\n * @example\n * await i18n.extend('settings', (locale) =>\n * import(`./locales/${locale}/settings.json`).then((m) => m.default),\n * );\n */\n extend(ns: string, factory: NamespaceFactory, locale?: Locale): Promise<void>;\n /** Intl formatter bound to this instance's locale. Follows locale changes automatically. */\n readonly fmt: Formatter;\n /**\n * Creates a derived instance that inherits the current catalog snapshot, loaders,\n * namespace registry, and loaded-namespace markers, but has its own locale, fallback chain,\n * and subscribers. Catalog mutations on the fork do not affect the parent.\n *\n * Resolved catalog entries are shared by reference (no template re-compilation), making\n * `fork()` cheap for SSR fork-per-request patterns with large catalogs.\n *\n * @example\n * // SSR: per-request locale without touching the shared instance\n * const reqI18n = i18n.fork({ locale: req.locale });\n */\n fork(overrides?: Omit<I18nOptions<M>, 'catalogs'>): I18n<M>;\n /** Returns the current snapshot. Object identity changes on every observable change. */\n getSnapshot(): I18nSnapshot;\n /**\n * Extracts a serializable snapshot of all loaded catalogs and the active locale.\n * Pass the result to `hydrateI18n()` on the client.\n *\n * **Warning:** Only fully resolved catalogs are included. Loader-only locales not yet\n * preloaded are omitted. Use `i18n.isLoaded(locale)` to verify before calling.\n *\n * **Warning:** The namespace registry is **not** serialized — factory functions cannot\n * be converted to JSON. After `hydrateI18n()`, call `extend()` again for each namespace\n * before relying on namespace-patched keys.\n */\n getState(): I18nState;\n /**\n * Returns all registered locales.\n * - Default (no argument): locales in registration order.\n * - `getSupportedLocales(true)`: sorted in ascending code-point order.\n */\n getSupportedLocales(sorted?: boolean): Locale[];\n /**\n * Returns `true` if the given key exists in the active fallback chain — either as a leaf\n * string key or as a plural branch (any key under `key.` prefix).\n *\n * @example\n * i18n.has('inbox') // true for leaf or pipe-plural expanded branch\n * i18n.has('inbox.one') // true for explicit sub-key\n */\n has(key: MessageLeafKeys<M> | MessageBranchKeys<M> | (string & {})): boolean;\n /**\n * Returns `true` if the catalog for `locale` is fully resolved.\n * Returns `false` for locales registered as async loaders not yet preloaded, and for unknown locales.\n */\n isLoaded(locale: Locale): boolean;\n /**\n * Returns `true` if the namespace has been fully loaded for the given locale.\n * Returns `false` if it is not registered or not yet loaded for this locale.\n */\n isNamespaceLoaded(ns: string, locale?: Locale): boolean;\n /**\n * Returns `true` if a namespace factory is registered under the given name.\n */\n isNamespaceRegistered(ns: string): boolean;\n /**\n * Returns `true` if `locale` is in the known locale registry — either resolved or pending loader.\n * Returns `false` for locales that have never been registered.\n */\n isRegistered(locale: Locale): boolean;\n /**\n * Loads a previously registered namespace for the given locale (defaults to the active locale).\n * Deduplicates concurrent and repeated calls.\n *\n * @throws `LinguaNamespaceMissingError` if the namespace has not been registered with `registerNamespace()` first.\n * @throws `LinguaDisposedError` if called on a disposed instance.\n */\n loadNamespace(ns: string, locale?: Locale): Promise<void>;\n readonly locale: Locale;\n preload(locale: Locale): Promise<void>;\n /**\n * Registers (or replaces) a locale source. If the source is an async loader, it is loaded\n * immediately and this method returns a Promise that resolves when the load is complete.\n * If the source is a static message object, it is synchronously registered and the returned\n * Promise resolves immediately.\n *\n * @throws `LinguaDisposedError` if called on a disposed instance.\n */\n register(locale: Locale, source: LocaleSource<M>): Promise<void>;\n /**\n * Registers a namespace factory without loading it. Use `loadNamespace()` to trigger loading,\n * or use `extend()` to register and load in one call.\n *\n * @remarks\n * Re-registering a namespace updates the factory for future loads but does **not** reload\n * the namespace if it is already loaded. The new factory takes effect the next time the\n * namespace marker is cleared (by a `register()` or `restoreState()` call).\n *\n * @throws `LinguaDisposedError` if called on a disposed instance.\n */\n registerNamespace(ns: string, factory: NamespaceFactory): void;\n /**\n * Hydrates this instance with pre-loaded state (e.g. from a server-rendered payload).\n *\n * @remarks The namespace registry is **not** included in `I18nState`. After restoring,\n * call `extend()` for each namespace before relying on namespace-patched keys.\n *\n * @throws `LinguaDisposedError` if called on a disposed instance.\n * @throws `LinguaRestoreError` if the state's locale has no catalog.\n */\n restoreState(state: I18nState): void;\n /**\n * Returns a scoped translator. All `t()` / `tp()` calls are automatically prefixed with `${prefix}.`.\n * The returned object is memoized — calling `scope(prefix)` with the same string always returns the\n * same reference.\n *\n * @example\n * const nav = i18n.scope('nav');\n * nav.t('home'); // i18n.t('nav.home')\n * nav.tp('items', 3); // i18n.tp('nav.items', 3)\n */\n scope(prefix: MessageBranchKeys<M> | (string & {})): ScopedI18n;\n /**\n * Switches the active locale. Loads the locale if it is registered as an async loader.\n * Last concurrent call wins; stale responses are discarded.\n * If loading fails, the active locale is unchanged.\n *\n * @throws `LinguaMissingLocaleError` if the locale is not registered.\n * @throws `LinguaDisposedError` if called on a disposed instance.\n */\n setLocale(locale: Locale): Promise<void>;\n /**\n * Subscribes to locale/catalog changes.\n * - `{ immediate: true }`: fires immediately and on every change.\n * - `{ signal }`: unsubscribes when the AbortSignal fires.\n *\n * @throws `LinguaDisposedError` if called on a disposed instance.\n */\n subscribe(callback: (snapshot: I18nSnapshot) => void, options?: SubscribeOptions): Unsubscribe;\n /** @security Returns raw, unsanitized strings. Sanitize before `innerHTML` insertion. */\n t(key: MessageLeafKeys<M> | (string & {}), vars?: TranslateVars): string;\n /**\n * Translates a plural branch key. `count` is injected automatically.\n *\n * @throws `LinguaInvalidCountError` if `count` is not finite.\n * @throws `LinguaCountInVarsError` if `options.vars.count` is set.\n * @security Returns raw, unsanitized strings.\n */\n tp(key: MessageBranchKeys<M> | (string & {}), count: number, options?: TpOptions): string;\n};\n\n// ─── Locale state ─────────────────────────────────────────────────────────────\n// Replaced atomically on every locale change.\n\ntype LocaleState = {\n readonly chain: readonly Locale[];\n readonly chainSet: ReadonlySet<Locale>;\n readonly locale: Locale;\n};\n\nfunction buildState(locale: Locale, fallback: Locale[], caches: LocaleCaches): LocaleState {\n const { chain, set } = buildLocaleChain(locale, fallback, caches);\n\n return { chain, chainSet: set, locale };\n}\n\n// ─── Plural key priority ──────────────────────────────────────────────────────\n// Cardinal zero: try .zero override first, then CLDR form, then .other as final fallback.\n// Ordinal / non-zero: try CLDR form, then .other as final fallback.\nfunction pluralKeyPriority(base: string, form: string, count: number, ordinal: boolean): string[] {\n const keys: string[] = [];\n\n if (!ordinal && count === 0) keys.push(`${base}.zero`);\n\n if (form !== 'zero' || ordinal) keys.push(`${base}.${form}`);\n\n if (form !== 'other') keys.push(`${base}.other`);\n\n return keys;\n}\n\n// ─── Factory ──────────────────────────────────────────────────────────────────\n\n/** Overload: explicit type parameter (strict typing) */\nexport function createI18n<M extends Messages>(config: I18nOptions<M>): I18n<M>;\n/** Overload: no type parameter (loose typing, allows heterogeneous catalogs) */\nexport function createI18n(config?: I18nOptions<Messages>): I18n<Messages>;\nexport function createI18n<M extends Messages = Messages>(config?: I18nOptions<M>): I18n<M> {\n return _createI18nImpl<M>(config);\n}\n\n// ─── Internal seed shape ──────────────────────────────────────────────────────\n\ntype I18nSeed<M extends Messages> = {\n catalogStore?: CatalogStore<M>;\n nsStore?: NamespaceStore;\n};\n\nfunction _createI18nImpl<M extends Messages = Messages>(config?: I18nOptions<M>, _seed?: I18nSeed<M>): I18n<M> {\n const cfg: I18nOptions<M> = config ?? {};\n\n // ─── Per-instance caches (no shared module-level state) ───────────────────\n const caches: LocaleCaches = createLocaleCaches();\n\n const canonL = (loc: string) => canon(loc, caches);\n\n const fallback = Array.isArray(cfg.fallback) ? cfg.fallback.map(canonL) : cfg.fallback ? [canonL(cfg.fallback)] : [];\n\n // ─── Disposal ─────────────────────────────────────────────────────────────\n let disposed = false;\n const disposeController = new AbortController();\n\n // ─── Bounded stores ───────────────────────────────────────────────────────\n const catalogStore: CatalogStore<M> = createCatalogStore(() => disposed);\n const nsStore: NamespaceStore = createNamespaceStore(() => disposed);\n\n // ─── Locale state ─────────────────────────────────────────────────────────\n let state: LocaleState = buildState(canonL(cfg.locale ?? 'en'), fallback, caches);\n\n // ─── Subscribers ──────────────────────────────────────────────────────────\n const subscribers = new Set<(snapshot: I18nSnapshot) => void>();\n\n const onMissingKey = cfg.onMissingKey ?? ((key: string) => key);\n const onMissingVar = cfg.onMissingVar ?? ((varName: string) => `{${varName}}`);\n const onSubscriberError = cfg.onSubscriberError ?? ((error: unknown) => logError('subscriber error', error));\n\n // ─── Lazy formatter — avoids Intl overhead for SSR forks that only need t(). ──\n let _fmt: Formatter | undefined;\n\n // ─── Scope cache — stable object references per prefix for reactive framework renders. ──\n const scopeCache = new Map<string, ScopedI18n>();\n\n const getFormatter = (): Formatter => {\n if (!_fmt) _fmt = createFormatter(() => state.locale);\n\n return _fmt;\n };\n\n // ─── Translate helpers ────────────────────────────────────────────────────\n\n // Single-pass entry lookup across the active fallback chain.\n const findEntry = (key: string): { compiled: CompiledTemplate; message: string } | undefined => {\n for (const candidate of state.chain) {\n const found = catalogStore.resolve(candidate)?.get(key);\n\n if (found !== undefined) return found;\n }\n\n return undefined;\n };\n\n // Shared by has() and scope().has() — true if `base` exists as a leaf key or a plural branch prefix.\n const hasKey = (base: string): boolean => {\n if (findEntry(base) !== undefined) return true;\n\n for (const candidate of state.chain) {\n const catalog = catalogStore.resolve(candidate);\n\n if (!catalog) continue;\n\n if (catalog.prefixes.has(base)) return true;\n }\n\n return false;\n };\n\n const interpolate = (\n key: string,\n found: { compiled: CompiledTemplate; message: string },\n vars: TranslateVars | undefined,\n ): string => renderTemplate(found.compiled, vars, key, state.locale, onMissingVar);\n\n const translate = (key: MessageLeafKeys<M> | (string & {}), vars?: TranslateVars): string => {\n const base = String(key);\n const found = findEntry(base);\n\n if (!found) return onMissingKey(base, state.locale);\n\n return interpolate(base, found, vars);\n };\n\n const translatePlural = (key: MessageBranchKeys<M> | (string & {}), count: number, options?: TpOptions): string => {\n if (!Number.isFinite(count)) {\n throw new LinguaInvalidCountError('`count` must be a finite number.');\n }\n\n const vars = options?.vars;\n const ordinal = options?.ordinal ?? false;\n\n if (vars && Object.hasOwn(vars, 'count')) {\n throw new LinguaCountInVarsError('`tp` does not allow `vars.count`; `count` is injected automatically.');\n }\n\n const base = String(key);\n const mergedVars = vars ? { count, ...vars } : { count };\n\n // Walk the fallback chain locale-by-locale, selecting CLDR plural form using each\n // locale's own rules. This ensures cross-locale fallbacks produce grammatically correct forms.\n for (const candidate of state.chain) {\n const catalog = catalogStore.resolve(candidate);\n\n if (!catalog) continue;\n\n const form = selectPluralForm(candidate, count, ordinal, caches);\n const keys = pluralKeyPriority(base, form, count, ordinal);\n\n for (const k of keys) {\n const found = catalog.get(k);\n\n if (found !== undefined) {\n return interpolate(k, found, mergedVars);\n }\n }\n }\n\n return onMissingKey(base, state.locale);\n };\n\n // ─── bump() ───────────────────────────────────────────────────────────────\n // Rebuilds the snapshot and notifies all current subscribers.\n\n let snapshot: I18nSnapshot = {\n locale: state.locale,\n t: translate,\n tp: translatePlural,\n };\n\n const bump = (): void => {\n snapshot = { locale: state.locale, t: translate, tp: translatePlural };\n\n const listeners = [...subscribers];\n\n for (const listener of listeners) {\n try {\n listener(snapshot);\n } catch (error) {\n onSubscriberError(error);\n }\n }\n };\n\n // ─── Wire catalog store onChange → bump ───────────────────────────────────\n catalogStore.onChange = (loc: Locale) => {\n if (state.chainSet.has(loc)) bump();\n };\n\n // ─── Seed from parent fork ─────────────────────────────────────────────────\n if (_seed?.catalogStore) {\n catalogStore.seedFrom(_seed.catalogStore.catalogs, _seed.catalogStore.pendingLoaders);\n }\n\n if (_seed?.nsStore) {\n nsStore.seedFrom(_seed.nsStore);\n }\n\n // ─── Initial catalogs from config ─────────────────────────────────────────\n if (cfg.catalogs) {\n const staticEntries = new Map<Locale, CatalogEntry>();\n const loaderEntries = new Map<Locale, Loader<M>>();\n\n for (const [loc, source] of Object.entries(cfg.catalogs)) {\n const normalized = canonL(loc);\n\n if (typeof source === 'function') {\n loaderEntries.set(normalized, source as Loader<M>);\n } else {\n const entry = new CatalogEntry();\n\n entry.setAll(flattenStrings(source as M));\n staticEntries.set(normalized, entry);\n }\n }\n\n // Use seedFrom for zero-overhead init (no bump, no notifications during setup)\n catalogStore.seedFrom(staticEntries, loaderEntries);\n }\n\n // ─── Preload helper ───────────────────────────────────────────────────────\n\n const preload = (loc: Locale): Promise<void> => catalogStore.preload(canonL(loc));\n\n // ─── Monotonic generation counter — last writer wins for concurrent setLocale() ──\n let switchGen = 0;\n\n // ─── Subscribe helper ─────────────────────────────────────────────────────\n\n const subscribeInternal = (callback: (snapshot: I18nSnapshot) => void, options?: SubscribeOptions): Unsubscribe => {\n const unsubscribe = (): void => {\n subscribers.delete(callback);\n };\n\n if (disposed) throw new LinguaDisposedError();\n\n if (options?.signal?.aborted) return unsubscribe;\n\n if (options?.immediate === true) {\n try {\n callback(snapshot);\n } catch (error) {\n onSubscriberError(error);\n\n return unsubscribe;\n }\n }\n\n subscribers.add(callback);\n options?.signal?.addEventListener('abort', unsubscribe, { once: true });\n\n return unsubscribe;\n };\n\n // ─── Public object ─────────────────────────────────────────────────────────\n\n return {\n get disposalSignal(): AbortSignal {\n return disposeController.signal;\n },\n\n dispose(): void {\n if (disposed) return;\n\n disposed = true;\n disposeController.abort();\n subscribers.clear();\n catalogStore.dispose();\n nsStore.dispose();\n scopeCache.clear();\n },\n\n get disposed(): boolean {\n return disposed;\n },\n\n extend(ns: string, factory: NamespaceFactory, loc?: Locale): Promise<void> {\n checkDisposed(disposed);\n\n nsStore.registerNamespace(ns, factory);\n\n const normalized = loc ? canonL(loc) : state.locale;\n\n return nsStore.loadNamespace(ns, normalized, (l, messages) => catalogStore.patch(l, messages));\n },\n\n get fmt(): Formatter {\n return getFormatter();\n },\n\n fork(overrides?: Omit<I18nOptions<M>, 'catalogs'>): I18n<M> {\n return _createI18nImpl(\n {\n fallback: overrides?.fallback ?? (fallback.length > 0 ? fallback : undefined),\n locale: overrides?.locale ?? state.locale,\n onMissingKey: overrides?.onMissingKey ?? cfg.onMissingKey,\n onMissingVar: overrides?.onMissingVar ?? cfg.onMissingVar,\n onSubscriberError: overrides?.onSubscriberError ?? cfg.onSubscriberError,\n },\n {\n catalogStore: catalogStore as CatalogStore<M>,\n nsStore: nsStore as NamespaceStore,\n },\n );\n },\n\n getSnapshot() {\n return snapshot;\n },\n\n getState(): I18nState {\n const catalogsOut: Record<Locale, Record<string, string>> = {};\n\n for (const [loc, entry] of catalogStore.catalogs) {\n catalogsOut[loc] = Object.fromEntries([...entry.entries.entries()].map(([k, { message }]) => [k, message]));\n }\n\n return { catalogs: catalogsOut, locale: state.locale };\n },\n\n getSupportedLocales(sorted?: boolean): Locale[] {\n const locales = [...catalogStore.knownLocales()];\n\n return sorted === true ? locales.sort() : locales;\n },\n\n has(key: MessageLeafKeys<M> | MessageBranchKeys<M> | (string & {})): boolean {\n return hasKey(String(key));\n },\n\n isLoaded(loc: Locale): boolean {\n try {\n return catalogStore.isLoaded(canonL(loc));\n } catch {\n return false;\n }\n },\n\n isNamespaceLoaded(ns: string, loc?: Locale): boolean {\n return nsStore.isLoaded(ns, loc ? canonL(loc) : state.locale);\n },\n\n isNamespaceRegistered(ns: string): boolean {\n return nsStore.isRegistered(ns);\n },\n\n isRegistered(loc: Locale): boolean {\n try {\n return catalogStore.isRegistered(canonL(loc));\n } catch {\n return false;\n }\n },\n\n loadNamespace(ns: string, loc?: Locale): Promise<void> {\n const normalized = loc ? canonL(loc) : state.locale;\n\n return nsStore.loadNamespace(ns, normalized, (l, messages) => catalogStore.patch(l, messages));\n },\n\n get locale(): Locale {\n return state.locale;\n },\n\n preload,\n\n register(loc: Locale, source: LocaleSource<M>): Promise<void> {\n const normalized = canonL(loc);\n\n return catalogStore.register(normalized, source, nsStore);\n },\n\n registerNamespace(ns: string, factory: NamespaceFactory): void {\n nsStore.registerNamespace(ns, factory);\n },\n\n restoreState(st: I18nState): void {\n checkDisposed(disposed);\n\n if (!Object.hasOwn(st.catalogs, st.locale)) {\n throw new LinguaRestoreError(`restoreState: locale \"${st.locale}\" has no catalog in the provided state.`);\n }\n\n const freshEntries = new Map<Locale, CatalogEntry>();\n\n for (const [loc, flatCatalog] of Object.entries(st.catalogs)) {\n const normalized = canonL(loc);\n const entry = new CatalogEntry();\n\n entry.setAll(Object.entries(flatCatalog));\n freshEntries.set(normalized, entry);\n nsStore.clearLocale(normalized);\n }\n\n // Dispose and re-seed the catalog store with the restored entries.\n // onChange is re-wired immediately after dispose.\n catalogStore.dispose();\n catalogStore.onChange = (loc: Locale) => {\n if (state.chainSet.has(loc)) bump();\n };\n catalogStore.seedFrom(freshEntries, new Map());\n\n const normalized = canonL(st.locale);\n\n state = buildState(normalized, fallback, caches);\n _fmt?.clear();\n bump();\n },\n\n scope(prefix: MessageBranchKeys<M> | (string & {})): ScopedI18n {\n const pre = String(prefix);\n const cached = scopeCache.get(pre);\n\n if (cached) return cached;\n\n const scoped: ScopedI18n = {\n get fmt() {\n return getFormatter();\n },\n has: (key) => hasKey(`${pre}.${key}`),\n t: (key, vars?) => translate(`${pre}.${key}`, vars),\n tp: (key, count, options?) => translatePlural(`${pre}.${key}`, count, options),\n };\n\n scopeCache.set(pre, scoped);\n\n return scoped;\n },\n\n async setLocale(next: Locale): Promise<void> {\n checkDisposed(disposed);\n\n const normalized = canonL(next);\n\n if (state.locale === normalized) return;\n\n // Monotonic generation counter — last writer wins.\n const gen = ++switchGen;\n\n await preload(normalized);\n\n if (disposed || switchGen !== gen) return;\n\n state = buildState(normalized, fallback, caches);\n _fmt?.clear();\n bump();\n },\n\n subscribe: subscribeInternal,\n\n [Symbol.dispose](): void {\n this.dispose();\n },\n\n t: translate,\n\n tp: translatePlural,\n };\n}\n\n// ─── SSR standalone helpers ───────────────────────────────────────────────────\n\n/**\n * Serialises the currently loaded catalogs and active locale into a plain object.\n * Pass the result to `hydrateI18n()` on the client.\n *\n * Prefer calling `i18n.getState()` directly — these standalone functions are provided\n * for convenience when you receive a plain `I18n` reference without the full type.\n *\n * **Warning:** Only fully resolved catalogs are included. Loader-only locales not yet\n * preloaded are omitted. Use `i18n.isLoaded(locale)` to verify before calling.\n *\n * **Warning:** The namespace registry is **not** serialized — factory functions cannot\n * be converted to JSON. After `hydrateI18n()`, call `extend()` again for each namespace\n * before relying on namespace-patched keys.\n */\nexport function serializeI18n(i18n: I18n): I18nState {\n return i18n.getState();\n}\n\n/**\n * Hydrates an i18n instance with pre-loaded state (e.g. from a server-rendered payload).\n *\n * Prefer calling `i18n.restoreState(state)` directly — these standalone functions are\n * provided for convenience.\n *\n * @remarks The namespace registry is **not** included in `I18nState`. After hydrating,\n * call `extend()` for each namespace before relying on namespace-patched keys.\n *\n * @throws `LinguaDisposedError` if called on a disposed instance.\n * @throws `LinguaRestoreError` if the state's locale has no catalog.\n */\nexport function hydrateI18n(i18n: I18n, state: I18nState): void {\n i18n.restoreState(state);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var Lingua=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=128;function n(e,n,r){let i=e.get(n);if(i!==void 0)return i;let a=r();return e.size>=t&&e.delete(e.keys().next().value),e.set(n,a),a}var r=[`years`,`months`,`weeks`,`days`,`hours`,`minutes`,`seconds`,`milliseconds`,`microseconds`,`nanoseconds`],i={days:`d`,hours:`h`,microseconds:`us`,milliseconds:`ms`,minutes:`min`,months:`mo`,nanoseconds:`ns`,seconds:`s`,weeks:`w`,years:`y`};function a(e){return r.map(t=>{let n=e[t];return typeof n==`number`?`${n}${i[t]}`:void 0}).filter(e=>e!==void 0).join(` `)}function o(e){let t=new Map,i=new Map,o=new Map,s=new Map,c=new Map,l=new Map,u=typeof e==`string`?()=>e:e;function d(e,t){if(!t)return e;let n={};for(let e of Object.keys(t).sort())n[e]=t[e];try{return`${e}:${JSON.stringify(n)}`}catch{return e}}return{clear(){t.clear(),i.clear(),o.clear(),s.clear(),c.clear(),l.clear()},currency(e,t,r){let a=u(),o={...r,currency:t,style:`currency`};return n(i,d(a,o),()=>new Intl.NumberFormat(a,o)).format(e)},date(e,t){let r=u();return n(o,d(r,t),()=>new Intl.DateTimeFormat(r,t)).format(e)},duration(e,t){let i=u(),o=Intl;return o.DurationFormat?r.every(t=>e[t]===void 0)?``:n(l,d(i,t),()=>new o.DurationFormat(i,t)).format(e):a(e)},list(e,t){let r=u(),i=e.map(e=>String(e)),a=t?.style??`long`,o=t?.type===`or`?`disjunction`:`conjunction`;return n(c,d(r,{style:a,type:o}),()=>new Intl.ListFormat(r,{style:a,type:o})).format(i)},number(e,r){let i=u();return n(t,d(i,r),()=>new Intl.NumberFormat(i,r)).format(e)},relative(e,t,r){let i=u();return n(s,d(i,r),()=>new Intl.RelativeTimeFormat(i,r)).format(e,t)}}}var s=new Set([`__proto__`,`constructor`,`prototype`]),c=!globalThis.__LINGUA_PROD__;function l(e){c&&console.warn(`[@vielzeug/lingua] ${e}`)}function u(e,...t){c&&console.error(`[@vielzeug/lingua] ${e}`,...t)}var d={2:[`one`,`other`],3:[`zero`,`one`,`other`],6:[`zero`,`one`,`two`,`few`,`many`,`other`]};function f(e){if(e.indexOf(`|`)===-1)return null;let t=e.split(`|`),n=d[t.length];if(!n)return l(`Pipe-plural shorthand with ${t.length} parts is not recognized (valid counts: 2, 3, 6). Treating as a plain string: "${e.slice(0,60)}${e.length>60?`…`:``}"`),null;if(t.some(e=>e.trim()===``))return null;let r={};for(let e=0;e<t.length;e++)r[n[e]]=t[e];return r}var p=/\{([\p{ID_Continue}-]+)\}/gu;function m(e){let t=[],n=0;for(let r of e.matchAll(p)){let{index:i}=r,a=i??0;a>n&&t.push(e.slice(n,a)),t.push({var:r[1]}),n=a+r[0].length}return n<e.length&&t.push(e.slice(n)),t}function h(e,t,n,r,i){let a=``;for(let o of e)if(typeof o==`string`)a+=o;else{let e=t?.[o.var];a+=e==null?i(o.var,n,r):String(e)}return a}var g=class e{entries=new Map;prefixes=new Set;get(e){return this.entries.get(e)}set(e,t){this.entries.set(e,{compiled:m(t),message:t});let n=e.indexOf(`.`);for(;n!==-1;)this.prefixes.add(e.slice(0,n)),n=e.indexOf(`.`,n+1)}setAll(e){for(let[t,n]of e)this.set(t,n)}clone(){let t=new e;for(let[e,n]of this.entries)t.entries.set(e,n);for(let e of this.prefixes)t.prefixes.add(e);return t}};function _(e,t=new Map,n){for(let[r,i]of Object.entries(e)){if(s.has(r))continue;let e=n?`${n}.${r}`:r;if(typeof i==`string`){let n=f(i);n?_(n,t,e):t.set(e,i)}else _(i,t,e)}return t}var v=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},y=class extends v{constructor(){super(`Operation called on a disposed i18n instance.`)}},b=class extends v{},x=class extends v{},S=class extends v{},C=class extends v{},w=class extends v{},T=class extends v{};function E(e){if(e)throw new y}function D(e){return e?Promise.reject(new y):null}function O(e){let t=new Map,n=new Map,r=new Map,i=new Set,a,o=(e,n)=>{let r=t.get(e);r||(r=new g,t.set(e,r)),r.setAll(n)},s=i=>{let s=D(e());if(s)return s;if(t.has(i))return Promise.resolve();let c=n.get(i);if(!c)return Promise.reject(new S(`Missing locale source for "${i}".`));let l=r.get(i);if(l)return l;let u=c().then(e=>{n.get(i)===c&&(n.delete(i),o(i,_(e)),r.delete(i),a?.(i))},e=>{throw n.get(i)===c&&r.delete(i),e});return r.set(i,u),u};return{get catalogs(){return t},dispose(){t.clear(),n.clear(),r.clear(),i.clear(),a=void 0},isLoaded(e){return t.has(e)},isRegistered(e){return i.has(e)},knownLocales(){return[...i]},get onChange(){return a},set onChange(e){a=e},patch(t,r){return D(e())||(n.has(t)?s(t).then(()=>{e()||(o(t,_(r)),i.add(t),a?.(t))}):(o(t,_(r)),i.add(t),a?.(t),Promise.resolve()))},get pendingLoaders(){return n},preload:s,register(c,u,d){E(e()),r.delete(c),i.add(c);let f=d.clearLocale(c);f.length>0&&l(`register('${c}') cleared loaded namespace markers for: ${f.map(e=>`'${e}'`).join(`, `)}. Call loadNamespace() again to reload.`);let p;return typeof u==`function`?(n.set(c,u),t.delete(c),p=s(c)):(n.delete(c),t.delete(c),o(c,_(u)),p=Promise.resolve(),a?.(c)),p},resolve(e){return t.get(e)},seedFrom(e,r){for(let[n,r]of e)t.set(n,r.clone()),i.add(n);for(let[e,t]of r)n.set(e,t),i.add(e)}}}function k(){return{canon:new Map,chain:new Map,plural:new Map}}function A(e,t){let n=t.canon.get(e);if(n!==void 0)return n;let r;try{[r]=Intl.getCanonicalLocales(e)}catch{}if(!r)throw new C(`Invalid BCP 47 locale tag: "${e}".`);return t.canon.set(e,r),r}function j(e,t,n,r){let i=`${e}:${n?`ordinal`:`cardinal`}`,a=r.plural.get(i);return a||(a=new Intl.PluralRules(e,{type:n?`ordinal`:`cardinal`}),r.plural.set(i,a)),a.select(t)}function M(e,t){let n=new Set;for(let r of[e,...t]){n.add(r);let e=r.split(`-`);for(let t=e.length-1;t>0;t--)n.add(e.slice(0,t).join(`-`))}return{chain:[...n],set:n}}function N(e,t,n){let r=t.length===0?e:`${e}|${t.join(`,`)}`,i=n.chain.get(r);if(i)return i;let a=M(e,t);return n.chain.set(r,a),a}function P(e){let t=new Map,n=new Map,r=new Map;return{clearLocale(e){let t=[];for(let[r,i]of n.entries())i.delete(e)&&t.push(r);return t},dispose(){t.clear(),n.clear(),r.clear()},isLoaded(e,t){return n.get(e)?.has(t)??!1},isRegistered(e){return t.has(e)},loadNamespace(i,a,o){let s=D(e());if(s)return s;let c=t.get(i);if(!c)return Promise.reject(new w(`Namespace '${i}' is not registered. Call registerNamespace() first.`));if(n.get(i)?.has(a))return Promise.resolve();let l=r.get(i)?.get(a);if(l)return l;let u=c(a).then(e=>o(a,e)).then(()=>{let e=n.get(i);e||(e=new Set,n.set(i,e)),e.add(a),r.get(i)?.delete(a)},e=>{throw r.get(i)?.delete(a),e});return r.has(i)||r.set(i,new Map),r.get(i).set(a,u),u},registerNamespace(n,r){E(e()),t.set(n,r)},seedFrom(e){for(let[n,r]of e.snapshotRegistry())t.set(n,r);for(let[t,r]of e.snapshotLoaded())n.set(t,new Set(r))},snapshotLoaded(){return n},snapshotRegistry(){return t}}}function F(e,t,n){let{chain:r,set:i}=N(e,t,n);return{chain:r,chainSet:i,locale:e}}function I(e,t,n,r){let i=[];return!r&&n===0&&i.push(`${e}.zero`),(t!==`zero`||r)&&i.push(`${e}.${t}`),t!==`other`&&i.push(`${e}.other`),i}function L(e){return R(e)}function R(e,t){let n=e??{},r=k(),i=e=>A(e,r),a=Array.isArray(n.fallback)?n.fallback.map(i):n.fallback?[i(n.fallback)]:[],s=!1,c=new AbortController,l=O(()=>s),d=P(()=>s),f=F(i(n.locale??`en`),a,r),p=new Set,m=n.onMissingKey??(e=>e),v=n.onMissingVar??(e=>`{${e}}`),S=n.onSubscriberError??(e=>u(`subscriber error`,e)),C,w=new Map,D=()=>(C||=o(()=>f.locale),C),M=e=>{for(let t of f.chain){let n=l.resolve(t)?.get(e);if(n!==void 0)return n}},N=e=>{if(M(e)!==void 0)return!0;for(let t of f.chain){let n=l.resolve(t);if(n&&n.prefixes.has(e))return!0}return!1},L=(e,t,n)=>h(t.compiled,n,e,f.locale,v),z=(e,t)=>{let n=String(e),r=M(n);return r?L(n,r,t):m(n,f.locale)},B=(e,t,n)=>{if(!Number.isFinite(t))throw new b("`count` must be a finite number.");let i=n?.vars,a=n?.ordinal??!1;if(i&&Object.hasOwn(i,`count`))throw new x("`tp` does not allow `vars.count`; `count` is injected automatically.");let o=String(e),s=i?{count:t,...i}:{count:t};for(let e of f.chain){let n=l.resolve(e);if(!n)continue;let i=I(o,j(e,t,a,r),t,a);for(let e of i){let t=n.get(e);if(t!==void 0)return L(e,t,s)}}return m(o,f.locale)},V={locale:f.locale,t:z,tp:B},H=()=>{V={locale:f.locale,t:z,tp:B};let e=[...p];for(let t of e)try{t(V)}catch(e){S(e)}};if(l.onChange=e=>{f.chainSet.has(e)&&H()},t?.catalogStore&&l.seedFrom(t.catalogStore.catalogs,t.catalogStore.pendingLoaders),t?.nsStore&&d.seedFrom(t.nsStore),n.catalogs){let e=new Map,t=new Map;for(let[r,a]of Object.entries(n.catalogs)){let n=i(r);if(typeof a==`function`)t.set(n,a);else{let t=new g;t.setAll(_(a)),e.set(n,t)}}l.seedFrom(e,t)}let U=e=>l.preload(i(e)),W=0;return{get disposalSignal(){return c.signal},dispose(){s||(s=!0,c.abort(),p.clear(),l.dispose(),d.dispose(),w.clear())},get disposed(){return s},extend(e,t,n){E(s),d.registerNamespace(e,t);let r=n?i(n):f.locale;return d.loadNamespace(e,r,(e,t)=>l.patch(e,t))},get fmt(){return D()},fork(e){return R({fallback:e?.fallback??(a.length>0?a:void 0),locale:e?.locale??f.locale,onMissingKey:e?.onMissingKey??n.onMissingKey,onMissingVar:e?.onMissingVar??n.onMissingVar,onSubscriberError:e?.onSubscriberError??n.onSubscriberError},{catalogStore:l,nsStore:d})},getSnapshot(){return V},getState(){let e={};for(let[t,n]of l.catalogs)e[t]=Object.fromEntries([...n.entries.entries()].map(([e,{message:t}])=>[e,t]));return{catalogs:e,locale:f.locale}},getSupportedLocales(e){let t=[...l.knownLocales()];return e===!0?t.sort():t},has(e){return N(String(e))},isLoaded(e){try{return l.isLoaded(i(e))}catch{return!1}},isNamespaceLoaded(e,t){return d.isLoaded(e,t?i(t):f.locale)},isNamespaceRegistered(e){return d.isRegistered(e)},isRegistered(e){try{return l.isRegistered(i(e))}catch{return!1}},loadNamespace(e,t){let n=t?i(t):f.locale;return d.loadNamespace(e,n,(e,t)=>l.patch(e,t))},get locale(){return f.locale},preload:U,register(e,t){let n=i(e);return l.register(n,t,d)},registerNamespace(e,t){d.registerNamespace(e,t)},restoreState(e){if(E(s),!Object.hasOwn(e.catalogs,e.locale))throw new T(`restoreState: locale "${e.locale}" has no catalog in the provided state.`);let t=new Map;for(let[n,r]of Object.entries(e.catalogs)){let e=i(n),a=new g;a.setAll(Object.entries(r)),t.set(e,a),d.clearLocale(e)}l.dispose(),l.onChange=e=>{f.chainSet.has(e)&&H()},l.seedFrom(t,new Map),f=F(i(e.locale),a,r),C?.clear(),H()},scope(e){let t=String(e),n=w.get(t);if(n)return n;let r={get fmt(){return D()},has:e=>N(`${t}.${e}`),t:(e,n)=>z(`${t}.${e}`,n),tp:(e,n,r)=>B(`${t}.${e}`,n,r)};return w.set(t,r),r},async setLocale(e){E(s);let t=i(e);if(f.locale===t)return;let n=++W;await U(t),!(s||W!==n)&&(f=F(t,a,r),C?.clear(),H())},subscribe:(e,t)=>{let n=()=>{p.delete(e)};if(s)throw new y;if(t?.signal?.aborted)return n;if(t?.immediate===!0)try{e(V)}catch(e){return S(e),n}return p.add(e),t?.signal?.addEventListener(`abort`,n,{once:!0}),n},[Symbol.dispose](){this.dispose()},t:z,tp:B}}function z(e){return e.getState()}function B(e,t){e.restoreState(t)}return e.LinguaCountInVarsError=x,e.LinguaDisposedError=y,e.LinguaError=v,e.LinguaInvalidCountError=b,e.LinguaInvalidLocaleError=C,e.LinguaMissingLocaleError=S,e.LinguaNamespaceMissingError=w,e.LinguaRestoreError=T,e.createFormatter=o,e.createI18n=L,e.hydrateI18n=B,e.serializeI18n=z,e})({});
|
|
2
|
+
//# sourceMappingURL=lingua.iife.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lingua.iife.js","names":[],"sources":["../src/format.ts","../src/_constants.ts","../src/_dev.ts","../src/template.ts","../src/_catalog.ts","../src/errors.ts","../src/_catalog-store.ts","../src/_chain.ts","../src/_namespace-store.ts","../src/i18n.ts"],"sourcesContent":["/**\n * /lingua/format\n *\n * Standalone Intl formatter factory. Import from `/lingua/format`.\n * Creates formatters for numbers, dates, currencies, lists, durations, and relative time.\n *\n * Pass a static locale string or a reactive locale getter.\n *\n * @example\n * ```ts\n * import { createFormatter } from '@vielzeug/lingua/format';\n *\n * // Static locale\n * const fmt = createFormatter('en-US');\n *\n * // Reactive — always reads the current locale from the i18n instance\n * const fmt = createFormatter(() => i18n.locale);\n *\n * fmt.number(1_234.56);\n * fmt.currency(9.99, 'USD');\n * fmt.date(new Date());\n * fmt.relative(-1, 'day');\n * fmt.list(['A', 'B', 'C']);\n * fmt.duration({ hours: 1, minutes: 30 });\n * ```\n */\n\nconst FORMAT_CACHE_MAX = 128;\n\nfunction getOrCreate<F>(cache: Map<string, F>, key: string, build: () => F): F {\n const cached = cache.get(key);\n\n if (cached !== undefined) return cached;\n\n const value = build();\n\n if (cache.size >= FORMAT_CACHE_MAX) cache.delete(cache.keys().next().value as string);\n\n cache.set(key, value);\n\n return value;\n}\n\nexport type DurationValue = Partial<\n Record<\n | 'days'\n | 'hours'\n | 'microseconds'\n | 'milliseconds'\n | 'minutes'\n | 'months'\n | 'nanoseconds'\n | 'seconds'\n | 'weeks'\n | 'years',\n number\n >\n>;\n\nexport type DurationFormatOptions = {\n hours?: '2-digit' | 'numeric';\n microseconds?: 'numeric';\n milliseconds?: 'numeric';\n minutes?: '2-digit' | 'numeric';\n nanoseconds?: 'numeric';\n seconds?: '2-digit' | 'numeric';\n style?: 'digital' | 'long' | 'narrow' | 'short';\n};\n\nexport type ListFormatOptions = {\n style?: 'long' | 'narrow' | 'short';\n type?: 'and' | 'or';\n};\n\nexport type Formatter = {\n /**\n * Clears all cached `Intl` formatter instances. Useful after a locale change on a long-running\n * SSR server, or to reclaim memory.\n *\n * @note This clears the cache for **all callers sharing this formatter instance**. When called on\n * `i18n.fmt`, the cache is cleared for every part of the application that reads `i18n.fmt`.\n * `setLocale()` already calls `clear()` automatically — manual calls are rarely needed.\n */\n clear(): void;\n currency(value: number, currency: string, options?: Omit<Intl.NumberFormatOptions, 'currency' | 'style'>): string;\n date(value: Date | number, options?: Intl.DateTimeFormatOptions): string;\n /**\n * Formats a duration using `Intl.DurationFormat` when available, or a compact labeled fallback\n * (e.g. `'1h 30min'`). Returns `''` when every field of `value` is `undefined`.\n *\n * @note The fallback labels (`h`, `min`, `s`, `ms`, etc.) are English-only and are not\n * locale-aware. If `Intl.DurationFormat` is unavailable in your target environment and\n * you need localised duration output, provide your own formatter using the individual\n * duration fields from `DurationValue`.\n */\n duration(value: DurationValue, options?: DurationFormatOptions): string;\n list(value: Array<string | number>, options?: ListFormatOptions): string;\n /** Formats a number with the current locale. */\n number(value: number, options?: Intl.NumberFormatOptions): string;\n relative(value: number, unit: Intl.RelativeTimeFormatUnit, options?: Intl.RelativeTimeFormatOptions): string;\n};\n\n// ─── Internal ─────────────────────────────────────────────────────────────────\n\nconst DURATION_UNITS: Array<keyof DurationValue> = [\n 'years',\n 'months',\n 'weeks',\n 'days',\n 'hours',\n 'minutes',\n 'seconds',\n 'milliseconds',\n 'microseconds',\n 'nanoseconds',\n];\n\nconst DURATION_LABELS: Record<keyof DurationValue, string> = {\n days: 'd',\n hours: 'h',\n microseconds: 'us',\n milliseconds: 'ms',\n minutes: 'min',\n months: 'mo',\n nanoseconds: 'ns',\n seconds: 's',\n weeks: 'w',\n years: 'y',\n};\n\ntype DurationFormatterCtor = new (\n locale: string,\n options?: DurationFormatOptions,\n) => { format(value: DurationValue): string };\n\nfunction durationLabeled(value: DurationValue): string {\n return DURATION_UNITS.map((unit) => {\n const amount = value[unit];\n\n return typeof amount === 'number' ? `${amount}${DURATION_LABELS[unit]}` : undefined;\n })\n .filter((part): part is string => part !== undefined)\n .join(' ');\n}\n\n// ─── Factory ──────────────────────────────────────────────────────────────────\n\n/**\n * Creates a formatter bound to a locale. Pass a static locale string or a\n * reactive getter function `() => string` (e.g. `() => i18n.locale`).\n */\nexport function createFormatter(source: string | (() => string)): Formatter {\n const numberCache = new Map<string, Intl.NumberFormat>();\n const currencyCache = new Map<string, Intl.NumberFormat>();\n const dateCache = new Map<string, Intl.DateTimeFormat>();\n const relativeCache = new Map<string, Intl.RelativeTimeFormat>();\n const listCache = new Map<string, Intl.ListFormat>();\n const durationCache = new Map<string, { format(value: DurationValue): string }>();\n\n const getLocale = typeof source === 'string' ? () => source : source;\n\n function cachedKey(locale: string, options?: object): string {\n if (!options) return locale;\n\n const sorted: Record<string, unknown> = {};\n\n for (const key of Object.keys(options as Record<string, unknown>).sort()) {\n sorted[key] = (options as Record<string, unknown>)[key];\n }\n\n try {\n return `${locale}:${JSON.stringify(sorted)}`;\n } catch {\n // Circular references or BigInt values — fall back to locale-only key.\n // Multiple callers with different unserializable options will share the same formatter instance.\n return locale;\n }\n }\n\n return {\n clear() {\n numberCache.clear();\n currencyCache.clear();\n dateCache.clear();\n relativeCache.clear();\n listCache.clear();\n durationCache.clear();\n },\n\n currency(value, currency, options) {\n const locale = getLocale();\n const opts: Intl.NumberFormatOptions = { ...options, currency, style: 'currency' };\n\n return getOrCreate(currencyCache, cachedKey(locale, opts), () => new Intl.NumberFormat(locale, opts)).format(\n value,\n );\n },\n\n date(value, options) {\n const locale = getLocale();\n\n return getOrCreate(dateCache, cachedKey(locale, options), () => new Intl.DateTimeFormat(locale, options)).format(\n value,\n );\n },\n\n duration(value, options) {\n const locale = getLocale();\n const IntlExt = Intl as typeof Intl & { DurationFormat?: DurationFormatterCtor };\n\n if (!IntlExt.DurationFormat) return durationLabeled(value);\n\n if (DURATION_UNITS.every((u) => value[u] === undefined)) return '';\n\n return getOrCreate(\n durationCache,\n cachedKey(locale, options),\n () => new IntlExt.DurationFormat!(locale, options),\n ).format(value);\n },\n\n list(value, options) {\n const locale = getLocale();\n const items = value.map((v) => String(v));\n // list() has exactly two string options with small finite value domains.\n // We normalize both to their resolved defaults and build the key directly\n // rather than using cachedKey(). This also prevents cache misses when\n // callers pass { style: 'long', type: 'and' } vs {} (same ListFormat).\n const style = options?.style ?? 'long';\n const type = options?.type === 'or' ? 'disjunction' : 'conjunction';\n\n return getOrCreate(\n listCache,\n cachedKey(locale, { style, type }),\n () => new Intl.ListFormat(locale, { style, type }),\n ).format(items);\n },\n\n number(value, options) {\n const locale = getLocale();\n\n return getOrCreate(numberCache, cachedKey(locale, options), () => new Intl.NumberFormat(locale, options)).format(\n value,\n );\n },\n\n relative(value, unit, options) {\n const locale = getLocale();\n\n return getOrCreate(\n relativeCache,\n cachedKey(locale, options),\n () => new Intl.RelativeTimeFormat(locale, options),\n ).format(value, unit);\n },\n };\n}\n","// Shared constants used by both i18n.ts and validate.ts.\n// Not part of the public API — internal module only.\n\nexport const UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\n\nexport const CLDR_FORMS = new Set(['zero', 'one', 'two', 'few', 'many', 'other']);\n","const isDev = !(globalThis as { __LINGUA_PROD__?: boolean }).__LINGUA_PROD__;\n\n/** @internal @security Messages may include user-supplied data. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/lingua] ${msg}`);\n}\n\n/** @internal */\nexport function error(msg: string, ...args: unknown[]): void {\n if (isDev) console.error(`[@vielzeug/lingua] ${msg}`, ...args);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n","// ─── Template helpers ─────────────────────────────────────────────────────────\n// Shared by i18n.ts — extracted for navigability. Not part of the public API.\n\nimport { warn } from './_dev';\n\ntype Locale = string;\ntype TranslateVars = Record<string, unknown>;\n\ninterface Messages {\n [key: string]: string | Messages;\n}\n\n// ─── Pipe-plural shorthand (F1) ───────────────────────────────────────────────\n// A leaf string containing '|' is parsed as a pipe-delimited plural shorthand.\n// Supported part counts and their form mappings (positional, left-to-right):\n// 2 parts → one | other\n// 3 parts → zero | one | other\n// 6 parts → zero | one | two | few | many | other\n// Any other part count is treated as a plain string with no expansion.\n\nconst PIPE_FORM_MAPS: Readonly<Partial<Record<number, readonly string[]>>> = {\n 2: ['one', 'other'],\n 3: ['zero', 'one', 'other'],\n 6: ['zero', 'one', 'two', 'few', 'many', 'other'],\n};\n\nexport function parsePipePlural(value: string): Messages | null {\n const pipeIdx = value.indexOf('|');\n\n if (pipeIdx === -1) return null;\n\n const parts = value.split('|');\n const forms = PIPE_FORM_MAPS[parts.length];\n\n if (!forms) {\n warn(\n `Pipe-plural shorthand with ${parts.length} parts is not recognized (valid counts: 2, 3, 6). Treating as a plain string: \"${value.slice(0, 60)}${value.length > 60 ? '…' : ''}\"`,\n );\n\n return null;\n }\n\n // An empty part is almost certainly a catalog authoring error.\n // Treat the whole value as a plain string rather than silently producing an empty form.\n if (parts.some((p) => p.trim() === '')) return null;\n\n const result: Messages = {};\n\n for (let i = 0; i < parts.length; i++) {\n result[forms[i]] = parts[i];\n }\n\n return result;\n}\n\n// ─── Template compilation ─────────────────────────────────────────────────────\n// Message strings are parsed once at registration time into a pre-compiled form:\n// an array of static strings and variable names. Rendering a compiled template\n// skips the regex entirely.\n\ntype TemplatePart = string | { var: string };\nexport type CompiledTemplate = TemplatePart[];\n\nexport const INTERPOLATION_PATTERN = /\\{([\\p{ID_Continue}-]+)\\}/gu;\n\nexport function compileTemplate(template: string): CompiledTemplate {\n const parts: CompiledTemplate = [];\n let lastIndex = 0;\n\n for (const match of template.matchAll(INTERPOLATION_PATTERN)) {\n const { index } = match;\n const start = index ?? 0;\n\n if (start > lastIndex) {\n parts.push(template.slice(lastIndex, start));\n }\n\n parts.push({ var: match[1] });\n lastIndex = start + match[0].length;\n }\n\n if (lastIndex < template.length) {\n parts.push(template.slice(lastIndex));\n }\n\n return parts;\n}\n\nexport function renderTemplate(\n parts: CompiledTemplate,\n vars: TranslateVars | undefined,\n key: string,\n locale: Locale,\n onMissingVar: (varName: string, key: string, locale: Locale) => string,\n): string {\n let result = '';\n\n for (const part of parts) {\n if (typeof part === 'string') {\n result += part;\n } else {\n const value = vars?.[part.var];\n\n result += value == null ? onMissingVar(part.var, key, locale) : String(value);\n }\n }\n\n return result;\n}\n","// Internal — not part of the public API.\n// Encapsulates the CatalogEntry class, flattenStrings, and related utilities.\n\nimport { UNSAFE_KEYS } from './_constants';\nimport { compileTemplate, type CompiledTemplate, parsePipePlural } from './template';\n\nexport interface Messages {\n [key: string]: string | Messages;\n}\n\nexport type CatalogEntryData = {\n compiled: CompiledTemplate;\n message: string;\n};\n\nexport class CatalogEntry {\n readonly entries = new Map<string, CatalogEntryData>();\n readonly prefixes = new Set<string>();\n\n get(key: string): CatalogEntryData | undefined {\n return this.entries.get(key);\n }\n\n set(key: string, value: string): void {\n this.entries.set(key, { compiled: compileTemplate(value), message: value });\n\n // Populate prefix set for O(1) branch detection in has().\n let dot = key.indexOf('.');\n\n while (dot !== -1) {\n this.prefixes.add(key.slice(0, dot));\n dot = key.indexOf('.', dot + 1);\n }\n }\n\n setAll(flat: Iterable<[string, string]>): void {\n for (const [k, v] of flat) this.set(k, v);\n }\n\n clone(): CatalogEntry {\n const copy = new CatalogEntry();\n\n for (const [k, v] of this.entries) copy.entries.set(k, v);\n for (const p of this.prefixes) copy.prefixes.add(p);\n\n return copy;\n }\n}\n\nexport function flattenStrings(\n messages: Messages,\n result = new Map<string, string>(),\n prefix?: string,\n): Map<string, string> {\n for (const [key, value] of Object.entries(messages)) {\n if (UNSAFE_KEYS.has(key)) continue;\n\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n if (typeof value === 'string') {\n const plural = parsePipePlural(value);\n\n if (plural) {\n flattenStrings(plural, result, fullKey);\n } else {\n result.set(fullKey, value);\n }\n } else {\n flattenStrings(value as Messages, result, fullKey);\n }\n }\n\n return result;\n}\n","/** Base class for all lingua errors. Use `instanceof LinguaError` or `LinguaError.is()` to catch any lingua-originated error. */\nexport class LinguaError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is LinguaError {\n return err instanceof LinguaError;\n }\n}\n\n/** Thrown when a method is called on a disposed i18n instance. */\nexport class LinguaDisposedError extends LinguaError {\n constructor() {\n super('Operation called on a disposed i18n instance.');\n }\n}\n\n/** Thrown when `tp()` receives a non-finite `count` value. */\nexport class LinguaInvalidCountError extends LinguaError {}\n\n/** Thrown when `vars.count` is set alongside the `count` parameter in `tp()`. */\nexport class LinguaCountInVarsError extends LinguaError {}\n\n/** Thrown when a requested locale has not been registered. */\nexport class LinguaMissingLocaleError extends LinguaError {}\n\n/** Thrown when a locale string is not a valid BCP 47 tag. */\nexport class LinguaInvalidLocaleError extends LinguaError {}\n\n/** Thrown when `loadNamespace()` / `extend()` is called for a namespace that has not been registered with `registerNamespace()`. */\nexport class LinguaNamespaceMissingError extends LinguaError {}\n\n/** Thrown when restoring i18n state whose locale has no catalog. */\nexport class LinguaRestoreError extends LinguaError {}\n\n// ─── Internal helpers ─────────────────────────────────────────────────────────\n\nexport function checkDisposed(disposed: boolean): void {\n if (disposed) throw new LinguaDisposedError();\n}\n\nexport function checkDisposedAsync(disposed: boolean): Promise<never> | null {\n return disposed ? Promise.reject(new LinguaDisposedError()) : null;\n}\n","// Internal — not part of the public API.\n// Owns all locale → CatalogEntry state, loaders, and in-flight loading tasks.\n\nimport type { NamespaceStore } from './_namespace-store';\n\nimport { CatalogEntry, type Messages, flattenStrings } from './_catalog';\nimport { warn } from './_dev';\nimport { LinguaMissingLocaleError, checkDisposed, checkDisposedAsync } from './errors';\n\nexport type Locale = string;\nexport type Loader<M extends Messages = Messages> = () => Promise<M>;\nexport type LocaleSource<M extends Messages = Messages> = M | Loader<M>;\n\nexport type CatalogStore<M extends Messages = Messages> = {\n /** Direct access to the raw catalogs map (for SSR serialization). */\n readonly catalogs: ReadonlyMap<Locale, CatalogEntry>;\n dispose(): void;\n isLoaded(loc: Locale): boolean;\n isRegistered(loc: Locale): boolean;\n /** All registered locale keys in insertion order. */\n knownLocales(): readonly Locale[];\n /** Callback invoked whenever a catalog changes (drives bump/notify). */\n onChange: ((loc: Locale) => void) | undefined;\n /** Patch a locale catalog with additional flat messages (used by loadNamespace). */\n patch(loc: Locale, messages: Messages): Promise<void>;\n /** Direct access to the pending loaders map (for fork propagation). */\n readonly pendingLoaders: ReadonlyMap<Locale, Loader<M>>;\n /** Pre-load a locale catalog without switching. */\n preload(loc: Locale): Promise<void>;\n /** Register (or replace) a locale's source. Returns a Promise that resolves when the catalog is loaded. */\n register(loc: Locale, source: LocaleSource<M>, nsStore: NamespaceStore): Promise<void>;\n /** Resolve a compiled CatalogEntry for a locale (undefined if not loaded). */\n resolve(loc: Locale): CatalogEntry | undefined;\n /**\n * Seed the store with pre-compiled entries from a parent fork.\n * Called during fork() — compiled templates are shared by reference.\n */\n seedFrom(entries: ReadonlyMap<Locale, CatalogEntry>, loaderMap: ReadonlyMap<Locale, Loader<M>>): void;\n};\n\nexport function createCatalogStore<M extends Messages = Messages>(disposed: () => boolean): CatalogStore<M> {\n const catalogs = new Map<Locale, CatalogEntry>();\n const loaders = new Map<Locale, Loader<M>>();\n const loadingTasks = new Map<Locale, Promise<void>>();\n const known = new Set<Locale>();\n\n let onChange: ((loc: Locale) => void) | undefined;\n\n const registerRaw = (normalized: Locale, flat: Map<string, string>): void => {\n let entry = catalogs.get(normalized);\n\n if (!entry) {\n entry = new CatalogEntry();\n catalogs.set(normalized, entry);\n }\n\n entry.setAll(flat);\n };\n\n const preload = (loc: Locale): Promise<void> => {\n const early = checkDisposedAsync(disposed());\n\n if (early) return early;\n\n if (catalogs.has(loc)) return Promise.resolve();\n\n const loader = loaders.get(loc);\n\n if (!loader) return Promise.reject(new LinguaMissingLocaleError(`Missing locale source for \"${loc}\".`));\n\n const existing = loadingTasks.get(loc);\n\n if (existing) return existing;\n\n const task = loader().then(\n (messages) => {\n if (loaders.get(loc) !== loader) return;\n\n loaders.delete(loc);\n registerRaw(loc, flattenStrings(messages));\n loadingTasks.delete(loc);\n onChange?.(loc);\n },\n (error: unknown) => {\n if (loaders.get(loc) === loader) loadingTasks.delete(loc);\n\n throw error;\n },\n );\n\n loadingTasks.set(loc, task);\n\n return task;\n };\n\n return {\n get catalogs() {\n return catalogs as ReadonlyMap<Locale, CatalogEntry>;\n },\n\n dispose() {\n catalogs.clear();\n loaders.clear();\n loadingTasks.clear();\n known.clear();\n onChange = undefined;\n },\n\n isLoaded(loc) {\n return catalogs.has(loc);\n },\n\n isRegistered(loc) {\n return known.has(loc);\n },\n\n knownLocales() {\n return [...known];\n },\n\n get onChange() {\n return onChange;\n },\n\n set onChange(fn: ((loc: Locale) => void) | undefined) {\n onChange = fn;\n },\n\n patch(loc, messages) {\n const early = checkDisposedAsync(disposed());\n\n if (early) return early;\n\n if (loaders.has(loc)) {\n return preload(loc).then(() => {\n if (disposed()) return;\n\n registerRaw(loc, flattenStrings(messages));\n known.add(loc);\n onChange?.(loc);\n });\n }\n\n registerRaw(loc, flattenStrings(messages));\n known.add(loc);\n onChange?.(loc);\n\n return Promise.resolve();\n },\n\n get pendingLoaders() {\n return loaders as ReadonlyMap<Locale, Loader<M>>;\n },\n\n preload,\n\n register(loc, source, nsStore) {\n checkDisposed(disposed());\n\n loadingTasks.delete(loc);\n known.add(loc);\n\n // Clear namespace loaded-markers for this locale so namespaces can be re-applied\n // after catalog replacement.\n const clearedNs = nsStore.clearLocale(loc);\n\n if (clearedNs.length > 0) {\n warn(\n `register('${loc}') cleared loaded namespace markers for: ${clearedNs.map((ns) => `'${ns}'`).join(', ')}. Call loadNamespace() again to reload.`,\n );\n }\n\n let loadPromise: Promise<void>;\n\n if (typeof source === 'function') {\n loaders.set(loc, source as Loader<M>);\n catalogs.delete(loc);\n loadPromise = preload(loc);\n } else {\n loaders.delete(loc);\n catalogs.delete(loc);\n registerRaw(loc, flattenStrings(source as M));\n loadPromise = Promise.resolve();\n onChange?.(loc);\n }\n\n return loadPromise;\n },\n\n resolve(loc) {\n return catalogs.get(loc);\n },\n\n seedFrom(entries, loaderMap) {\n for (const [loc, entry] of entries) {\n catalogs.set(loc, entry.clone());\n known.add(loc);\n }\n\n for (const [loc, loader] of loaderMap) {\n loaders.set(loc, loader);\n known.add(loc);\n }\n },\n };\n}\n","// Internal — not part of the public API.\n// Locale chain building, canonicalization, and plural-rules selection.\n// All caches are per-instance — no shared module-level state.\n\nimport { LinguaInvalidLocaleError } from './errors';\n\nexport type Locale = string;\n\n// ─── Per-instance caches ──────────────────────────────────────────────────────\n\nexport type LocaleCaches = {\n canon: Map<string, string>;\n chain: Map<string, { chain: Locale[]; set: Set<Locale> }>;\n plural: Map<string, Intl.PluralRules>;\n};\n\nexport function createLocaleCaches(): LocaleCaches {\n return { canon: new Map(), chain: new Map(), plural: new Map() };\n}\n\n// ─── Canon ────────────────────────────────────────────────────────────────────\n\nexport function canon(locale: string, cache: LocaleCaches): string {\n const cached = cache.canon.get(locale);\n\n if (cached !== undefined) return cached;\n\n let canonical: string | undefined;\n\n try {\n [canonical] = Intl.getCanonicalLocales(locale);\n } catch {\n // Invalid BCP 47 tag — canonical stays undefined, guard below throws.\n }\n\n if (!canonical) throw new LinguaInvalidLocaleError(`Invalid BCP 47 locale tag: \"${locale}\".`);\n\n cache.canon.set(locale, canonical);\n\n return canonical;\n}\n\n// ─── Plural form selection ────────────────────────────────────────────────────\n\nexport function selectPluralForm(locale: Locale, count: number, ordinal: boolean, cache: LocaleCaches): string {\n const key = `${locale}:${ordinal ? 'ordinal' : 'cardinal'}`;\n let rules = cache.plural.get(key);\n\n if (!rules) {\n rules = new Intl.PluralRules(locale, { type: ordinal ? 'ordinal' : 'cardinal' });\n cache.plural.set(key, rules);\n }\n\n return rules.select(count);\n}\n\n// ─── Locale chain ─────────────────────────────────────────────────────────────\n\nfunction buildLocaleChainRaw(locale: Locale, fallback: Locale[]): { chain: Locale[]; set: Set<Locale> } {\n const set = new Set<Locale>();\n\n for (const value of [locale, ...fallback]) {\n set.add(value);\n\n const parts = value.split('-');\n\n for (let i = parts.length - 1; i > 0; i--) {\n set.add(parts.slice(0, i).join('-'));\n }\n }\n\n return { chain: [...set], set };\n}\n\n/**\n * Build a locale fallback chain, memoized per `(locale, fallback)` key using a provided cache.\n * The cache is per-instance (lives on LocaleCaches) — no shared module-level state.\n */\nexport function buildLocaleChain(\n locale: Locale,\n fallback: Locale[],\n cache: LocaleCaches,\n): { chain: Locale[]; set: Set<Locale> } {\n const key = fallback.length === 0 ? locale : `${locale}|${fallback.join(',')}`;\n const cached = cache.chain.get(key);\n\n if (cached) return cached;\n\n const result = buildLocaleChainRaw(locale, fallback);\n\n cache.chain.set(key, result);\n\n return result;\n}\n","// Internal — not part of the public API.\n// Owns namespace factory registry, per-locale loaded markers, and in-flight namespace tasks.\n\nimport type { Messages } from './_catalog';\n\nimport { LinguaNamespaceMissingError, checkDisposed, checkDisposedAsync } from './errors';\n\nexport type Locale = string;\nexport type NamespaceFactory<M extends Messages = Messages> = (locale: Locale) => Promise<M>;\n\nexport type NamespaceStore<M extends Messages = Messages> = {\n /**\n * Remove loaded-markers for a locale across all namespaces.\n * Called by CatalogStore.register() when a catalog is replaced.\n * Returns the list of namespace names whose markers were cleared.\n */\n clearLocale(loc: Locale): string[];\n dispose(): void;\n /** Returns true if the namespace has been loaded for the given locale. */\n isLoaded(ns: string, loc: Locale): boolean;\n /** Returns true if the namespace factory is registered. */\n isRegistered(ns: string): boolean;\n /**\n * Load a namespace for the given locale. Deduplicates concurrent and repeated calls.\n * The `patch` callback is responsible for merging the loaded messages into the catalog.\n */\n loadNamespace(ns: string, loc: Locale, patch: (loc: Locale, messages: Messages) => Promise<void>): Promise<void>;\n /** Register a namespace factory. Idempotent — re-registration updates the factory for future loads. */\n registerNamespace(ns: string, factory: NamespaceFactory<M>): void;\n /** Seed from a parent instance (fork). Copies loaded markers; registry is shared by reference. */\n seedFrom(parent: NamespaceStore<M>): void;\n /** Snapshot of loaded markers for fork() */\n snapshotLoaded(): ReadonlyMap<string, ReadonlySet<string>>;\n /** Snapshot of the registry for fork() */\n snapshotRegistry(): ReadonlyMap<string, NamespaceFactory<M>>;\n};\n\nexport function createNamespaceStore<M extends Messages = Messages>(disposed: () => boolean): NamespaceStore<M> {\n const registry = new Map<string, NamespaceFactory<M>>();\n // Two-level: Map<namespace, Set<locale>>\n const loaded = new Map<string, Set<string>>();\n const tasks = new Map<string, Map<string, Promise<void>>>();\n\n return {\n clearLocale(loc) {\n const cleared: string[] = [];\n\n for (const [ns, localeSet] of loaded.entries()) {\n if (localeSet.delete(loc)) cleared.push(ns);\n }\n\n return cleared;\n },\n\n dispose() {\n registry.clear();\n loaded.clear();\n tasks.clear();\n },\n\n isLoaded(ns, loc) {\n return loaded.get(ns)?.has(loc) ?? false;\n },\n\n isRegistered(ns) {\n return registry.has(ns);\n },\n\n loadNamespace(ns, loc, patch) {\n const early = checkDisposedAsync(disposed());\n\n if (early) return early;\n\n const factory = registry.get(ns);\n\n if (!factory) {\n return Promise.reject(\n new LinguaNamespaceMissingError(`Namespace '${ns}' is not registered. Call registerNamespace() first.`),\n );\n }\n\n if (loaded.get(ns)?.has(loc)) return Promise.resolve();\n\n const nsTasks = tasks.get(ns);\n const existing = nsTasks?.get(loc);\n\n if (existing) return existing;\n\n const task = factory(loc)\n .then((messages) => patch(loc, messages as Messages))\n .then(\n () => {\n let localeSet = loaded.get(ns);\n\n if (!localeSet) {\n localeSet = new Set();\n loaded.set(ns, localeSet);\n }\n\n localeSet.add(loc);\n tasks.get(ns)?.delete(loc);\n },\n (err: unknown) => {\n tasks.get(ns)?.delete(loc);\n throw err;\n },\n );\n\n if (!tasks.has(ns)) tasks.set(ns, new Map());\n\n tasks.get(ns)!.set(loc, task);\n\n return task;\n },\n\n registerNamespace(ns, factory) {\n checkDisposed(disposed());\n registry.set(ns, factory);\n },\n\n seedFrom(parent) {\n for (const [ns, factory] of parent.snapshotRegistry()) {\n registry.set(ns, factory);\n }\n\n for (const [ns, localeSet] of parent.snapshotLoaded()) {\n loaded.set(ns, new Set(localeSet));\n }\n },\n\n snapshotLoaded() {\n return loaded as ReadonlyMap<string, ReadonlySet<string>>;\n },\n\n snapshotRegistry() {\n return registry as ReadonlyMap<string, NamespaceFactory<M>>;\n },\n };\n}\n","import { CatalogEntry, type Messages, flattenStrings } from './_catalog';\nimport { type CatalogStore, type Loader, type LocaleSource, createCatalogStore } from './_catalog-store';\nimport { type LocaleCaches, buildLocaleChain, canon, createLocaleCaches, selectPluralForm } from './_chain';\nimport { error as logError } from './_dev';\nimport { type NamespaceFactory, type NamespaceStore, createNamespaceStore } from './_namespace-store';\nimport {\n LinguaCountInVarsError,\n LinguaDisposedError,\n LinguaInvalidCountError,\n LinguaRestoreError,\n checkDisposed,\n} from './errors';\nimport { type Formatter, createFormatter } from './format';\nimport { type CompiledTemplate, renderTemplate } from './template';\n\nexport {\n LinguaCountInVarsError,\n LinguaDisposedError,\n LinguaError,\n LinguaInvalidCountError,\n LinguaInvalidLocaleError,\n LinguaMissingLocaleError,\n LinguaNamespaceMissingError,\n LinguaRestoreError,\n} from './errors';\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type Locale = string;\nexport type Unsubscribe = () => void;\n\nexport type { Messages } from './_catalog';\nexport type { Loader, LocaleSource } from './_catalog-store';\nexport type { NamespaceFactory } from './_namespace-store';\n\nexport type TranslateVars = Record<string, unknown>;\n\n/**\n * A snapshot of the i18n instance state at a point in time.\n * Object identity changes on every observable change (locale switch, catalog load).\n * `t` and `tp` are bound to the locale captured in this snapshot.\n */\nexport type I18nSnapshot = {\n readonly locale: Locale;\n /** @security Returns raw, unsanitized strings. Sanitize before `innerHTML` insertion. */\n readonly t: (key: string, vars?: TranslateVars) => string;\n readonly tp: (key: string, count: number, options?: TpOptions) => string;\n};\n\n/** Shape of the serialised state produced by `serializeI18n()`. Pass to `hydrateI18n()` on the client. */\nexport type I18nState = {\n readonly catalogs: Record<Locale, Record<string, string>>;\n readonly locale: Locale;\n};\n\nexport type SubscribeOptions = {\n immediate?: boolean;\n /** AbortSignal — automatically unsubscribes when the signal is aborted. */\n signal?: AbortSignal;\n};\n\nexport type TpOptions = {\n /** Use ordinal plural rules (1st, 2nd, 3rd) instead of cardinal (default: `false`). */\n ordinal?: boolean;\n /** Inject additional interpolation variables alongside the automatically injected `count`. */\n vars?: TranslateVars;\n};\n\nexport type ScopedI18n = {\n /** Intl formatter inherited from the parent instance. Follows locale changes automatically. */\n readonly fmt: Formatter;\n has(key: string): boolean;\n t(key: string, vars?: TranslateVars): string;\n tp(key: string, count: number, options?: TpOptions): string;\n};\n\n// ─── Key inference ────────────────────────────────────────────────────────────\n// Depth tuple prevents infinite recursion on recursive `Messages` type.\n// Depth 7 covers real-world catalog nesting without measurable TS instantiation cost.\ntype Depth = [never, 0, 1, 2, 3, 4, 5, 6];\n\nexport type MessageLeafKeys<T, P extends string = '', D extends number = 7> = [D] extends [0]\n ? never\n : T extends string\n ? P\n : T extends Record<string, unknown>\n ? { [K in string & keyof T]: MessageLeafKeys<T[K], P extends '' ? K : `${P}.${K}`, Depth[D]> }[string & keyof T]\n : never;\n\nexport type MessageBranchKeys<T, P extends string = '', D extends number = 7> = [D] extends [0]\n ? never\n : T extends Record<string, unknown>\n ? {\n [K in string & keyof T]: T[K] extends string\n ? never\n : (P extends '' ? K : `${P}.${K}`) | MessageBranchKeys<T[K], P extends '' ? K : `${P}.${K}`, Depth[D]>;\n }[string & keyof T]\n : never;\n\n// ─── Config ───────────────────────────────────────────────────────────────────\n\nexport type I18nOptions<M extends Messages = Messages> = {\n /** Locale registry. Values can be static message objects or async loaders. */\n catalogs?: Record<Locale, LocaleSource<M>>;\n /** Locale(s) to search when the active locale is missing a key. Subtags are expanded automatically (e.g. `en-US` → `en`). */\n fallback?: Locale | Locale[];\n /** Initial active locale. Defaults to `\"en\"`. Canonicalized via `Intl.getCanonicalLocales`. */\n locale?: Locale;\n /**\n * Called when a translation key is missing.\n * Defaults to returning the key string.\n *\n * @security The default handler returns `key` verbatim. Do not render the return value as HTML\n * if keys are constructed from untrusted user input.\n */\n onMissingKey?: (key: string, locale: Locale) => string;\n /**\n * Called when an interpolation variable is missing.\n * Defaults to returning `{varName}`.\n */\n onMissingVar?: (varName: string, key: string, locale: Locale) => string;\n /**\n * Called when a subscriber callback throws. Defaults to `console.error`.\n * Override in production to route errors to a structured logger rather than the browser console.\n */\n onSubscriberError?: (error: unknown) => void;\n};\n\n// ─── Public interface ─────────────────────────────────────────────────────────\n\nexport type I18n<M extends Messages = Messages> = {\n /** Delegates to `dispose()`. Enables `using` declarations. */\n [Symbol.dispose](): void;\n /** `AbortSignal` aborted when `dispose()` is called. Use to tie external lifetimes to this instance. */\n readonly disposalSignal: AbortSignal;\n /**\n * Disposes this i18n instance: removes all subscribers and clears catalog, loader, and namespace state.\n * After disposal, all mutation methods throw `LinguaDisposedError` and translation methods\n * fall back to `onMissingKey` for every key. Idempotent.\n */\n dispose(): void;\n /** `true` after `dispose()` has been called. */\n readonly disposed: boolean;\n /**\n * Registers a namespace factory and immediately starts loading it for the given locale\n * (defaults to the active locale). Deduplicates concurrent and repeated calls.\n *\n * @remarks\n * Call `registerNamespace()` first if you only want to register without loading.\n * `extend()` is a convenience that does both in one call.\n *\n * @throws `LinguaDisposedError` if called on a disposed instance.\n *\n * @example\n * await i18n.extend('settings', (locale) =>\n * import(`./locales/${locale}/settings.json`).then((m) => m.default),\n * );\n */\n extend(ns: string, factory: NamespaceFactory, locale?: Locale): Promise<void>;\n /** Intl formatter bound to this instance's locale. Follows locale changes automatically. */\n readonly fmt: Formatter;\n /**\n * Creates a derived instance that inherits the current catalog snapshot, loaders,\n * namespace registry, and loaded-namespace markers, but has its own locale, fallback chain,\n * and subscribers. Catalog mutations on the fork do not affect the parent.\n *\n * Resolved catalog entries are shared by reference (no template re-compilation), making\n * `fork()` cheap for SSR fork-per-request patterns with large catalogs.\n *\n * @example\n * // SSR: per-request locale without touching the shared instance\n * const reqI18n = i18n.fork({ locale: req.locale });\n */\n fork(overrides?: Omit<I18nOptions<M>, 'catalogs'>): I18n<M>;\n /** Returns the current snapshot. Object identity changes on every observable change. */\n getSnapshot(): I18nSnapshot;\n /**\n * Extracts a serializable snapshot of all loaded catalogs and the active locale.\n * Pass the result to `hydrateI18n()` on the client.\n *\n * **Warning:** Only fully resolved catalogs are included. Loader-only locales not yet\n * preloaded are omitted. Use `i18n.isLoaded(locale)` to verify before calling.\n *\n * **Warning:** The namespace registry is **not** serialized — factory functions cannot\n * be converted to JSON. After `hydrateI18n()`, call `extend()` again for each namespace\n * before relying on namespace-patched keys.\n */\n getState(): I18nState;\n /**\n * Returns all registered locales.\n * - Default (no argument): locales in registration order.\n * - `getSupportedLocales(true)`: sorted in ascending code-point order.\n */\n getSupportedLocales(sorted?: boolean): Locale[];\n /**\n * Returns `true` if the given key exists in the active fallback chain — either as a leaf\n * string key or as a plural branch (any key under `key.` prefix).\n *\n * @example\n * i18n.has('inbox') // true for leaf or pipe-plural expanded branch\n * i18n.has('inbox.one') // true for explicit sub-key\n */\n has(key: MessageLeafKeys<M> | MessageBranchKeys<M> | (string & {})): boolean;\n /**\n * Returns `true` if the catalog for `locale` is fully resolved.\n * Returns `false` for locales registered as async loaders not yet preloaded, and for unknown locales.\n */\n isLoaded(locale: Locale): boolean;\n /**\n * Returns `true` if the namespace has been fully loaded for the given locale.\n * Returns `false` if it is not registered or not yet loaded for this locale.\n */\n isNamespaceLoaded(ns: string, locale?: Locale): boolean;\n /**\n * Returns `true` if a namespace factory is registered under the given name.\n */\n isNamespaceRegistered(ns: string): boolean;\n /**\n * Returns `true` if `locale` is in the known locale registry — either resolved or pending loader.\n * Returns `false` for locales that have never been registered.\n */\n isRegistered(locale: Locale): boolean;\n /**\n * Loads a previously registered namespace for the given locale (defaults to the active locale).\n * Deduplicates concurrent and repeated calls.\n *\n * @throws `LinguaNamespaceMissingError` if the namespace has not been registered with `registerNamespace()` first.\n * @throws `LinguaDisposedError` if called on a disposed instance.\n */\n loadNamespace(ns: string, locale?: Locale): Promise<void>;\n readonly locale: Locale;\n preload(locale: Locale): Promise<void>;\n /**\n * Registers (or replaces) a locale source. If the source is an async loader, it is loaded\n * immediately and this method returns a Promise that resolves when the load is complete.\n * If the source is a static message object, it is synchronously registered and the returned\n * Promise resolves immediately.\n *\n * @throws `LinguaDisposedError` if called on a disposed instance.\n */\n register(locale: Locale, source: LocaleSource<M>): Promise<void>;\n /**\n * Registers a namespace factory without loading it. Use `loadNamespace()` to trigger loading,\n * or use `extend()` to register and load in one call.\n *\n * @remarks\n * Re-registering a namespace updates the factory for future loads but does **not** reload\n * the namespace if it is already loaded. The new factory takes effect the next time the\n * namespace marker is cleared (by a `register()` or `restoreState()` call).\n *\n * @throws `LinguaDisposedError` if called on a disposed instance.\n */\n registerNamespace(ns: string, factory: NamespaceFactory): void;\n /**\n * Hydrates this instance with pre-loaded state (e.g. from a server-rendered payload).\n *\n * @remarks The namespace registry is **not** included in `I18nState`. After restoring,\n * call `extend()` for each namespace before relying on namespace-patched keys.\n *\n * @throws `LinguaDisposedError` if called on a disposed instance.\n * @throws `LinguaRestoreError` if the state's locale has no catalog.\n */\n restoreState(state: I18nState): void;\n /**\n * Returns a scoped translator. All `t()` / `tp()` calls are automatically prefixed with `${prefix}.`.\n * The returned object is memoized — calling `scope(prefix)` with the same string always returns the\n * same reference.\n *\n * @example\n * const nav = i18n.scope('nav');\n * nav.t('home'); // i18n.t('nav.home')\n * nav.tp('items', 3); // i18n.tp('nav.items', 3)\n */\n scope(prefix: MessageBranchKeys<M> | (string & {})): ScopedI18n;\n /**\n * Switches the active locale. Loads the locale if it is registered as an async loader.\n * Last concurrent call wins; stale responses are discarded.\n * If loading fails, the active locale is unchanged.\n *\n * @throws `LinguaMissingLocaleError` if the locale is not registered.\n * @throws `LinguaDisposedError` if called on a disposed instance.\n */\n setLocale(locale: Locale): Promise<void>;\n /**\n * Subscribes to locale/catalog changes.\n * - `{ immediate: true }`: fires immediately and on every change.\n * - `{ signal }`: unsubscribes when the AbortSignal fires.\n *\n * @throws `LinguaDisposedError` if called on a disposed instance.\n */\n subscribe(callback: (snapshot: I18nSnapshot) => void, options?: SubscribeOptions): Unsubscribe;\n /** @security Returns raw, unsanitized strings. Sanitize before `innerHTML` insertion. */\n t(key: MessageLeafKeys<M> | (string & {}), vars?: TranslateVars): string;\n /**\n * Translates a plural branch key. `count` is injected automatically.\n *\n * @throws `LinguaInvalidCountError` if `count` is not finite.\n * @throws `LinguaCountInVarsError` if `options.vars.count` is set.\n * @security Returns raw, unsanitized strings.\n */\n tp(key: MessageBranchKeys<M> | (string & {}), count: number, options?: TpOptions): string;\n};\n\n// ─── Locale state ─────────────────────────────────────────────────────────────\n// Replaced atomically on every locale change.\n\ntype LocaleState = {\n readonly chain: readonly Locale[];\n readonly chainSet: ReadonlySet<Locale>;\n readonly locale: Locale;\n};\n\nfunction buildState(locale: Locale, fallback: Locale[], caches: LocaleCaches): LocaleState {\n const { chain, set } = buildLocaleChain(locale, fallback, caches);\n\n return { chain, chainSet: set, locale };\n}\n\n// ─── Plural key priority ──────────────────────────────────────────────────────\n// Cardinal zero: try .zero override first, then CLDR form, then .other as final fallback.\n// Ordinal / non-zero: try CLDR form, then .other as final fallback.\nfunction pluralKeyPriority(base: string, form: string, count: number, ordinal: boolean): string[] {\n const keys: string[] = [];\n\n if (!ordinal && count === 0) keys.push(`${base}.zero`);\n\n if (form !== 'zero' || ordinal) keys.push(`${base}.${form}`);\n\n if (form !== 'other') keys.push(`${base}.other`);\n\n return keys;\n}\n\n// ─── Factory ──────────────────────────────────────────────────────────────────\n\n/** Overload: explicit type parameter (strict typing) */\nexport function createI18n<M extends Messages>(config: I18nOptions<M>): I18n<M>;\n/** Overload: no type parameter (loose typing, allows heterogeneous catalogs) */\nexport function createI18n(config?: I18nOptions<Messages>): I18n<Messages>;\nexport function createI18n<M extends Messages = Messages>(config?: I18nOptions<M>): I18n<M> {\n return _createI18nImpl<M>(config);\n}\n\n// ─── Internal seed shape ──────────────────────────────────────────────────────\n\ntype I18nSeed<M extends Messages> = {\n catalogStore?: CatalogStore<M>;\n nsStore?: NamespaceStore;\n};\n\nfunction _createI18nImpl<M extends Messages = Messages>(config?: I18nOptions<M>, _seed?: I18nSeed<M>): I18n<M> {\n const cfg: I18nOptions<M> = config ?? {};\n\n // ─── Per-instance caches (no shared module-level state) ───────────────────\n const caches: LocaleCaches = createLocaleCaches();\n\n const canonL = (loc: string) => canon(loc, caches);\n\n const fallback = Array.isArray(cfg.fallback) ? cfg.fallback.map(canonL) : cfg.fallback ? [canonL(cfg.fallback)] : [];\n\n // ─── Disposal ─────────────────────────────────────────────────────────────\n let disposed = false;\n const disposeController = new AbortController();\n\n // ─── Bounded stores ───────────────────────────────────────────────────────\n const catalogStore: CatalogStore<M> = createCatalogStore(() => disposed);\n const nsStore: NamespaceStore = createNamespaceStore(() => disposed);\n\n // ─── Locale state ─────────────────────────────────────────────────────────\n let state: LocaleState = buildState(canonL(cfg.locale ?? 'en'), fallback, caches);\n\n // ─── Subscribers ──────────────────────────────────────────────────────────\n const subscribers = new Set<(snapshot: I18nSnapshot) => void>();\n\n const onMissingKey = cfg.onMissingKey ?? ((key: string) => key);\n const onMissingVar = cfg.onMissingVar ?? ((varName: string) => `{${varName}}`);\n const onSubscriberError = cfg.onSubscriberError ?? ((error: unknown) => logError('subscriber error', error));\n\n // ─── Lazy formatter — avoids Intl overhead for SSR forks that only need t(). ──\n let _fmt: Formatter | undefined;\n\n // ─── Scope cache — stable object references per prefix for reactive framework renders. ──\n const scopeCache = new Map<string, ScopedI18n>();\n\n const getFormatter = (): Formatter => {\n if (!_fmt) _fmt = createFormatter(() => state.locale);\n\n return _fmt;\n };\n\n // ─── Translate helpers ────────────────────────────────────────────────────\n\n // Single-pass entry lookup across the active fallback chain.\n const findEntry = (key: string): { compiled: CompiledTemplate; message: string } | undefined => {\n for (const candidate of state.chain) {\n const found = catalogStore.resolve(candidate)?.get(key);\n\n if (found !== undefined) return found;\n }\n\n return undefined;\n };\n\n // Shared by has() and scope().has() — true if `base` exists as a leaf key or a plural branch prefix.\n const hasKey = (base: string): boolean => {\n if (findEntry(base) !== undefined) return true;\n\n for (const candidate of state.chain) {\n const catalog = catalogStore.resolve(candidate);\n\n if (!catalog) continue;\n\n if (catalog.prefixes.has(base)) return true;\n }\n\n return false;\n };\n\n const interpolate = (\n key: string,\n found: { compiled: CompiledTemplate; message: string },\n vars: TranslateVars | undefined,\n ): string => renderTemplate(found.compiled, vars, key, state.locale, onMissingVar);\n\n const translate = (key: MessageLeafKeys<M> | (string & {}), vars?: TranslateVars): string => {\n const base = String(key);\n const found = findEntry(base);\n\n if (!found) return onMissingKey(base, state.locale);\n\n return interpolate(base, found, vars);\n };\n\n const translatePlural = (key: MessageBranchKeys<M> | (string & {}), count: number, options?: TpOptions): string => {\n if (!Number.isFinite(count)) {\n throw new LinguaInvalidCountError('`count` must be a finite number.');\n }\n\n const vars = options?.vars;\n const ordinal = options?.ordinal ?? false;\n\n if (vars && Object.hasOwn(vars, 'count')) {\n throw new LinguaCountInVarsError('`tp` does not allow `vars.count`; `count` is injected automatically.');\n }\n\n const base = String(key);\n const mergedVars = vars ? { count, ...vars } : { count };\n\n // Walk the fallback chain locale-by-locale, selecting CLDR plural form using each\n // locale's own rules. This ensures cross-locale fallbacks produce grammatically correct forms.\n for (const candidate of state.chain) {\n const catalog = catalogStore.resolve(candidate);\n\n if (!catalog) continue;\n\n const form = selectPluralForm(candidate, count, ordinal, caches);\n const keys = pluralKeyPriority(base, form, count, ordinal);\n\n for (const k of keys) {\n const found = catalog.get(k);\n\n if (found !== undefined) {\n return interpolate(k, found, mergedVars);\n }\n }\n }\n\n return onMissingKey(base, state.locale);\n };\n\n // ─── bump() ───────────────────────────────────────────────────────────────\n // Rebuilds the snapshot and notifies all current subscribers.\n\n let snapshot: I18nSnapshot = {\n locale: state.locale,\n t: translate,\n tp: translatePlural,\n };\n\n const bump = (): void => {\n snapshot = { locale: state.locale, t: translate, tp: translatePlural };\n\n const listeners = [...subscribers];\n\n for (const listener of listeners) {\n try {\n listener(snapshot);\n } catch (error) {\n onSubscriberError(error);\n }\n }\n };\n\n // ─── Wire catalog store onChange → bump ───────────────────────────────────\n catalogStore.onChange = (loc: Locale) => {\n if (state.chainSet.has(loc)) bump();\n };\n\n // ─── Seed from parent fork ─────────────────────────────────────────────────\n if (_seed?.catalogStore) {\n catalogStore.seedFrom(_seed.catalogStore.catalogs, _seed.catalogStore.pendingLoaders);\n }\n\n if (_seed?.nsStore) {\n nsStore.seedFrom(_seed.nsStore);\n }\n\n // ─── Initial catalogs from config ─────────────────────────────────────────\n if (cfg.catalogs) {\n const staticEntries = new Map<Locale, CatalogEntry>();\n const loaderEntries = new Map<Locale, Loader<M>>();\n\n for (const [loc, source] of Object.entries(cfg.catalogs)) {\n const normalized = canonL(loc);\n\n if (typeof source === 'function') {\n loaderEntries.set(normalized, source as Loader<M>);\n } else {\n const entry = new CatalogEntry();\n\n entry.setAll(flattenStrings(source as M));\n staticEntries.set(normalized, entry);\n }\n }\n\n // Use seedFrom for zero-overhead init (no bump, no notifications during setup)\n catalogStore.seedFrom(staticEntries, loaderEntries);\n }\n\n // ─── Preload helper ───────────────────────────────────────────────────────\n\n const preload = (loc: Locale): Promise<void> => catalogStore.preload(canonL(loc));\n\n // ─── Monotonic generation counter — last writer wins for concurrent setLocale() ──\n let switchGen = 0;\n\n // ─── Subscribe helper ─────────────────────────────────────────────────────\n\n const subscribeInternal = (callback: (snapshot: I18nSnapshot) => void, options?: SubscribeOptions): Unsubscribe => {\n const unsubscribe = (): void => {\n subscribers.delete(callback);\n };\n\n if (disposed) throw new LinguaDisposedError();\n\n if (options?.signal?.aborted) return unsubscribe;\n\n if (options?.immediate === true) {\n try {\n callback(snapshot);\n } catch (error) {\n onSubscriberError(error);\n\n return unsubscribe;\n }\n }\n\n subscribers.add(callback);\n options?.signal?.addEventListener('abort', unsubscribe, { once: true });\n\n return unsubscribe;\n };\n\n // ─── Public object ─────────────────────────────────────────────────────────\n\n return {\n get disposalSignal(): AbortSignal {\n return disposeController.signal;\n },\n\n dispose(): void {\n if (disposed) return;\n\n disposed = true;\n disposeController.abort();\n subscribers.clear();\n catalogStore.dispose();\n nsStore.dispose();\n scopeCache.clear();\n },\n\n get disposed(): boolean {\n return disposed;\n },\n\n extend(ns: string, factory: NamespaceFactory, loc?: Locale): Promise<void> {\n checkDisposed(disposed);\n\n nsStore.registerNamespace(ns, factory);\n\n const normalized = loc ? canonL(loc) : state.locale;\n\n return nsStore.loadNamespace(ns, normalized, (l, messages) => catalogStore.patch(l, messages));\n },\n\n get fmt(): Formatter {\n return getFormatter();\n },\n\n fork(overrides?: Omit<I18nOptions<M>, 'catalogs'>): I18n<M> {\n return _createI18nImpl(\n {\n fallback: overrides?.fallback ?? (fallback.length > 0 ? fallback : undefined),\n locale: overrides?.locale ?? state.locale,\n onMissingKey: overrides?.onMissingKey ?? cfg.onMissingKey,\n onMissingVar: overrides?.onMissingVar ?? cfg.onMissingVar,\n onSubscriberError: overrides?.onSubscriberError ?? cfg.onSubscriberError,\n },\n {\n catalogStore: catalogStore as CatalogStore<M>,\n nsStore: nsStore as NamespaceStore,\n },\n );\n },\n\n getSnapshot() {\n return snapshot;\n },\n\n getState(): I18nState {\n const catalogsOut: Record<Locale, Record<string, string>> = {};\n\n for (const [loc, entry] of catalogStore.catalogs) {\n catalogsOut[loc] = Object.fromEntries([...entry.entries.entries()].map(([k, { message }]) => [k, message]));\n }\n\n return { catalogs: catalogsOut, locale: state.locale };\n },\n\n getSupportedLocales(sorted?: boolean): Locale[] {\n const locales = [...catalogStore.knownLocales()];\n\n return sorted === true ? locales.sort() : locales;\n },\n\n has(key: MessageLeafKeys<M> | MessageBranchKeys<M> | (string & {})): boolean {\n return hasKey(String(key));\n },\n\n isLoaded(loc: Locale): boolean {\n try {\n return catalogStore.isLoaded(canonL(loc));\n } catch {\n return false;\n }\n },\n\n isNamespaceLoaded(ns: string, loc?: Locale): boolean {\n return nsStore.isLoaded(ns, loc ? canonL(loc) : state.locale);\n },\n\n isNamespaceRegistered(ns: string): boolean {\n return nsStore.isRegistered(ns);\n },\n\n isRegistered(loc: Locale): boolean {\n try {\n return catalogStore.isRegistered(canonL(loc));\n } catch {\n return false;\n }\n },\n\n loadNamespace(ns: string, loc?: Locale): Promise<void> {\n const normalized = loc ? canonL(loc) : state.locale;\n\n return nsStore.loadNamespace(ns, normalized, (l, messages) => catalogStore.patch(l, messages));\n },\n\n get locale(): Locale {\n return state.locale;\n },\n\n preload,\n\n register(loc: Locale, source: LocaleSource<M>): Promise<void> {\n const normalized = canonL(loc);\n\n return catalogStore.register(normalized, source, nsStore);\n },\n\n registerNamespace(ns: string, factory: NamespaceFactory): void {\n nsStore.registerNamespace(ns, factory);\n },\n\n restoreState(st: I18nState): void {\n checkDisposed(disposed);\n\n if (!Object.hasOwn(st.catalogs, st.locale)) {\n throw new LinguaRestoreError(`restoreState: locale \"${st.locale}\" has no catalog in the provided state.`);\n }\n\n const freshEntries = new Map<Locale, CatalogEntry>();\n\n for (const [loc, flatCatalog] of Object.entries(st.catalogs)) {\n const normalized = canonL(loc);\n const entry = new CatalogEntry();\n\n entry.setAll(Object.entries(flatCatalog));\n freshEntries.set(normalized, entry);\n nsStore.clearLocale(normalized);\n }\n\n // Dispose and re-seed the catalog store with the restored entries.\n // onChange is re-wired immediately after dispose.\n catalogStore.dispose();\n catalogStore.onChange = (loc: Locale) => {\n if (state.chainSet.has(loc)) bump();\n };\n catalogStore.seedFrom(freshEntries, new Map());\n\n const normalized = canonL(st.locale);\n\n state = buildState(normalized, fallback, caches);\n _fmt?.clear();\n bump();\n },\n\n scope(prefix: MessageBranchKeys<M> | (string & {})): ScopedI18n {\n const pre = String(prefix);\n const cached = scopeCache.get(pre);\n\n if (cached) return cached;\n\n const scoped: ScopedI18n = {\n get fmt() {\n return getFormatter();\n },\n has: (key) => hasKey(`${pre}.${key}`),\n t: (key, vars?) => translate(`${pre}.${key}`, vars),\n tp: (key, count, options?) => translatePlural(`${pre}.${key}`, count, options),\n };\n\n scopeCache.set(pre, scoped);\n\n return scoped;\n },\n\n async setLocale(next: Locale): Promise<void> {\n checkDisposed(disposed);\n\n const normalized = canonL(next);\n\n if (state.locale === normalized) return;\n\n // Monotonic generation counter — last writer wins.\n const gen = ++switchGen;\n\n await preload(normalized);\n\n if (disposed || switchGen !== gen) return;\n\n state = buildState(normalized, fallback, caches);\n _fmt?.clear();\n bump();\n },\n\n subscribe: subscribeInternal,\n\n [Symbol.dispose](): void {\n this.dispose();\n },\n\n t: translate,\n\n tp: translatePlural,\n };\n}\n\n// ─── SSR standalone helpers ───────────────────────────────────────────────────\n\n/**\n * Serialises the currently loaded catalogs and active locale into a plain object.\n * Pass the result to `hydrateI18n()` on the client.\n *\n * Prefer calling `i18n.getState()` directly — these standalone functions are provided\n * for convenience when you receive a plain `I18n` reference without the full type.\n *\n * **Warning:** Only fully resolved catalogs are included. Loader-only locales not yet\n * preloaded are omitted. Use `i18n.isLoaded(locale)` to verify before calling.\n *\n * **Warning:** The namespace registry is **not** serialized — factory functions cannot\n * be converted to JSON. After `hydrateI18n()`, call `extend()` again for each namespace\n * before relying on namespace-patched keys.\n */\nexport function serializeI18n(i18n: I18n): I18nState {\n return i18n.getState();\n}\n\n/**\n * Hydrates an i18n instance with pre-loaded state (e.g. from a server-rendered payload).\n *\n * Prefer calling `i18n.restoreState(state)` directly — these standalone functions are\n * provided for convenience.\n *\n * @remarks The namespace registry is **not** included in `I18nState`. After hydrating,\n * call `extend()` for each namespace before relying on namespace-patched keys.\n *\n * @throws `LinguaDisposedError` if called on a disposed instance.\n * @throws `LinguaRestoreError` if the state's locale has no catalog.\n */\nexport function hydrateI18n(i18n: I18n, state: I18nState): void {\n i18n.restoreState(state);\n}\n"],"mappings":"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"}
|
package/dist/lingua.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function e(e,t,n){let r=e.get(t);if(r!==void 0)return r;let i=n();return e.size>=128&&e.delete(e.keys().next().value),e.set(t,i),i}var t=[`years`,`months`,`weeks`,`days`,`hours`,`minutes`,`seconds`,`milliseconds`,`microseconds`,`nanoseconds`],n={days:`d`,hours:`h`,microseconds:`us`,milliseconds:`ms`,minutes:`min`,months:`mo`,nanoseconds:`ns`,seconds:`s`,weeks:`w`,years:`y`};function r(e){return t.map(t=>{let r=e[t];return typeof r==`number`?`${r}${n[t]}`:void 0}).filter(e=>e!==void 0).join(` `)}function i(n){let i=new Map,a=new Map,o=new Map,s=new Map,c=new Map,l=new Map,u=typeof n==`string`?()=>n:n;function d(e,t){if(!t)return e;let n={};for(let e of Object.keys(t).sort())n[e]=t[e];try{return`${e}:${JSON.stringify(n)}`}catch{return e}}return{clear(){i.clear(),a.clear(),o.clear(),s.clear(),c.clear(),l.clear()},currency(t,n,r){let i=u(),o={...r,currency:n,style:`currency`};return e(a,d(i,o),()=>new Intl.NumberFormat(i,o)).format(t)},date(t,n){let r=u();return e(o,d(r,n),()=>new Intl.DateTimeFormat(r,n)).format(t)},duration(n,i){let a=u(),o=Intl;return o.DurationFormat?t.every(e=>n[e]===void 0)?``:e(l,d(a,i),()=>new o.DurationFormat(a,i)).format(n):r(n)},list(t,n){let r=u(),i=t.map(e=>String(e)),a=n?.style??`long`,o=n?.type===`or`?`disjunction`:`conjunction`;return e(c,d(r,{style:a,type:o}),()=>new Intl.ListFormat(r,{style:a,type:o})).format(i)},number(t,n){let r=u();return e(i,d(r,n),()=>new Intl.NumberFormat(r,n)).format(t)},relative(t,n,r){let i=u();return e(s,d(i,r),()=>new Intl.RelativeTimeFormat(i,r)).format(t,n)}}}var a=new Set([`__proto__`,`constructor`,`prototype`]),o=!globalThis.__LINGUA_PROD__;function s(e){o&&console.warn(`[@vielzeug/lingua] ${e}`)}function c(e,...t){o&&console.error(`[@vielzeug/lingua] ${e}`,...t)}var l={2:[`one`,`other`],3:[`zero`,`one`,`other`],6:[`zero`,`one`,`two`,`few`,`many`,`other`]};function u(e){if(e.indexOf(`|`)===-1)return null;let t=e.split(`|`),n=l[t.length];if(!n)return s(`Pipe-plural shorthand with ${t.length} parts is not recognized (valid counts: 2, 3, 6). Treating as a plain string: "${e.slice(0,60)}${e.length>60?`…`:``}"`),null;if(t.some(e=>e.trim()===``))return null;let r={};for(let e=0;e<t.length;e++)r[n[e]]=t[e];return r}var d=/\{([\p{ID_Continue}-]+)\}/gu;function f(e){let t=[],n=0;for(let r of e.matchAll(d)){let{index:i}=r,a=i??0;a>n&&t.push(e.slice(n,a)),t.push({var:r[1]}),n=a+r[0].length}return n<e.length&&t.push(e.slice(n)),t}function p(e,t,n,r,i){let a=``;for(let o of e)if(typeof o==`string`)a+=o;else{let e=t?.[o.var];a+=e==null?i(o.var,n,r):String(e)}return a}var m=class e{entries=new Map;prefixes=new Set;get(e){return this.entries.get(e)}set(e,t){this.entries.set(e,{compiled:f(t),message:t});let n=e.indexOf(`.`);for(;n!==-1;)this.prefixes.add(e.slice(0,n)),n=e.indexOf(`.`,n+1)}setAll(e){for(let[t,n]of e)this.set(t,n)}clone(){let t=new e;for(let[e,n]of this.entries)t.entries.set(e,n);for(let e of this.prefixes)t.prefixes.add(e);return t}};function h(e,t=new Map,n){for(let[r,i]of Object.entries(e)){if(a.has(r))continue;let e=n?`${n}.${r}`:r;if(typeof i==`string`){let n=u(i);n?h(n,t,e):t.set(e,i)}else h(i,t,e)}return t}var g=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},_=class extends g{constructor(){super(`Operation called on a disposed i18n instance.`)}},v=class extends g{},y=class extends g{},b=class extends g{},x=class extends g{},S=class extends g{},C=class extends g{};function w(e){if(e)throw new _}function T(e){return e?Promise.reject(new _):null}function E(e){let t=new Map,n=new Map,r=new Map,i=new Set,a,o=(e,n)=>{let r=t.get(e);r||(r=new m,t.set(e,r)),r.setAll(n)},c=i=>{let s=T(e());if(s)return s;if(t.has(i))return Promise.resolve();let c=n.get(i);if(!c)return Promise.reject(new b(`Missing locale source for "${i}".`));let l=r.get(i);if(l)return l;let u=c().then(e=>{n.get(i)===c&&(n.delete(i),o(i,h(e)),r.delete(i),a?.(i))},e=>{throw n.get(i)===c&&r.delete(i),e});return r.set(i,u),u};return{get catalogs(){return t},dispose(){t.clear(),n.clear(),r.clear(),i.clear(),a=void 0},isLoaded(e){return t.has(e)},isRegistered(e){return i.has(e)},knownLocales(){return[...i]},get onChange(){return a},set onChange(e){a=e},patch(t,r){return T(e())||(n.has(t)?c(t).then(()=>{e()||(o(t,h(r)),i.add(t),a?.(t))}):(o(t,h(r)),i.add(t),a?.(t),Promise.resolve()))},get pendingLoaders(){return n},preload:c,register(l,u,d){w(e()),r.delete(l),i.add(l);let f=d.clearLocale(l);f.length>0&&s(`register('${l}') cleared loaded namespace markers for: ${f.map(e=>`'${e}'`).join(`, `)}. Call loadNamespace() again to reload.`);let p;return typeof u==`function`?(n.set(l,u),t.delete(l),p=c(l)):(n.delete(l),t.delete(l),o(l,h(u)),p=Promise.resolve(),a?.(l)),p},resolve(e){return t.get(e)},seedFrom(e,r){for(let[n,r]of e)t.set(n,r.clone()),i.add(n);for(let[e,t]of r)n.set(e,t),i.add(e)}}}function D(){return{canon:new Map,chain:new Map,plural:new Map}}function O(e,t){let n=t.canon.get(e);if(n!==void 0)return n;let r;try{[r]=Intl.getCanonicalLocales(e)}catch{}if(!r)throw new x(`Invalid BCP 47 locale tag: "${e}".`);return t.canon.set(e,r),r}function k(e,t,n,r){let i=`${e}:${n?`ordinal`:`cardinal`}`,a=r.plural.get(i);return a||(a=new Intl.PluralRules(e,{type:n?`ordinal`:`cardinal`}),r.plural.set(i,a)),a.select(t)}function A(e,t){let n=new Set;for(let r of[e,...t]){n.add(r);let e=r.split(`-`);for(let t=e.length-1;t>0;t--)n.add(e.slice(0,t).join(`-`))}return{chain:[...n],set:n}}function j(e,t,n){let r=t.length===0?e:`${e}|${t.join(`,`)}`,i=n.chain.get(r);if(i)return i;let a=A(e,t);return n.chain.set(r,a),a}function M(e){let t=new Map,n=new Map,r=new Map;return{clearLocale(e){let t=[];for(let[r,i]of n.entries())i.delete(e)&&t.push(r);return t},dispose(){t.clear(),n.clear(),r.clear()},isLoaded(e,t){return n.get(e)?.has(t)??!1},isRegistered(e){return t.has(e)},loadNamespace(i,a,o){let s=T(e());if(s)return s;let c=t.get(i);if(!c)return Promise.reject(new S(`Namespace '${i}' is not registered. Call registerNamespace() first.`));if(n.get(i)?.has(a))return Promise.resolve();let l=r.get(i)?.get(a);if(l)return l;let u=c(a).then(e=>o(a,e)).then(()=>{let e=n.get(i);e||(e=new Set,n.set(i,e)),e.add(a),r.get(i)?.delete(a)},e=>{throw r.get(i)?.delete(a),e});return r.has(i)||r.set(i,new Map),r.get(i).set(a,u),u},registerNamespace(n,r){w(e()),t.set(n,r)},seedFrom(e){for(let[n,r]of e.snapshotRegistry())t.set(n,r);for(let[t,r]of e.snapshotLoaded())n.set(t,new Set(r))},snapshotLoaded(){return n},snapshotRegistry(){return t}}}function N(e,t,n){let{chain:r,set:i}=j(e,t,n);return{chain:r,chainSet:i,locale:e}}function P(e,t,n,r){let i=[];return!r&&n===0&&i.push(`${e}.zero`),(t!==`zero`||r)&&i.push(`${e}.${t}`),t!==`other`&&i.push(`${e}.other`),i}function F(e){return I(e)}function I(e,t){let n=e??{},r=D(),a=e=>O(e,r),o=Array.isArray(n.fallback)?n.fallback.map(a):n.fallback?[a(n.fallback)]:[],s=!1,l=new AbortController,u=E(()=>s),d=M(()=>s),f=N(a(n.locale??`en`),o,r),g=new Set,b=n.onMissingKey??(e=>e),x=n.onMissingVar??(e=>`{${e}}`),S=n.onSubscriberError??(e=>c(`subscriber error`,e)),T,A=new Map,j=()=>(T||=i(()=>f.locale),T),F=e=>{for(let t of f.chain){let n=u.resolve(t)?.get(e);if(n!==void 0)return n}},L=e=>{if(F(e)!==void 0)return!0;for(let t of f.chain){let n=u.resolve(t);if(n&&n.prefixes.has(e))return!0}return!1},R=(e,t,n)=>p(t.compiled,n,e,f.locale,x),z=(e,t)=>{let n=String(e),r=F(n);return r?R(n,r,t):b(n,f.locale)},B=(e,t,n)=>{if(!Number.isFinite(t))throw new v("`count` must be a finite number.");let i=n?.vars,a=n?.ordinal??!1;if(i&&Object.hasOwn(i,`count`))throw new y("`tp` does not allow `vars.count`; `count` is injected automatically.");let o=String(e),s=i?{count:t,...i}:{count:t};for(let e of f.chain){let n=u.resolve(e);if(!n)continue;let i=P(o,k(e,t,a,r),t,a);for(let e of i){let t=n.get(e);if(t!==void 0)return R(e,t,s)}}return b(o,f.locale)},V={locale:f.locale,t:z,tp:B},H=()=>{V={locale:f.locale,t:z,tp:B};let e=[...g];for(let t of e)try{t(V)}catch(e){S(e)}};if(u.onChange=e=>{f.chainSet.has(e)&&H()},t?.catalogStore&&u.seedFrom(t.catalogStore.catalogs,t.catalogStore.pendingLoaders),t?.nsStore&&d.seedFrom(t.nsStore),n.catalogs){let e=new Map,t=new Map;for(let[r,i]of Object.entries(n.catalogs)){let n=a(r);if(typeof i==`function`)t.set(n,i);else{let t=new m;t.setAll(h(i)),e.set(n,t)}}u.seedFrom(e,t)}let U=e=>u.preload(a(e)),W=0;return{get disposalSignal(){return l.signal},dispose(){s||(s=!0,l.abort(),g.clear(),u.dispose(),d.dispose(),A.clear())},get disposed(){return s},extend(e,t,n){w(s),d.registerNamespace(e,t);let r=n?a(n):f.locale;return d.loadNamespace(e,r,(e,t)=>u.patch(e,t))},get fmt(){return j()},fork(e){return I({fallback:e?.fallback??(o.length>0?o:void 0),locale:e?.locale??f.locale,onMissingKey:e?.onMissingKey??n.onMissingKey,onMissingVar:e?.onMissingVar??n.onMissingVar,onSubscriberError:e?.onSubscriberError??n.onSubscriberError},{catalogStore:u,nsStore:d})},getSnapshot(){return V},getState(){let e={};for(let[t,n]of u.catalogs)e[t]=Object.fromEntries([...n.entries.entries()].map(([e,{message:t}])=>[e,t]));return{catalogs:e,locale:f.locale}},getSupportedLocales(e){let t=[...u.knownLocales()];return e===!0?t.sort():t},has(e){return L(String(e))},isLoaded(e){try{return u.isLoaded(a(e))}catch{return!1}},isNamespaceLoaded(e,t){return d.isLoaded(e,t?a(t):f.locale)},isNamespaceRegistered(e){return d.isRegistered(e)},isRegistered(e){try{return u.isRegistered(a(e))}catch{return!1}},loadNamespace(e,t){let n=t?a(t):f.locale;return d.loadNamespace(e,n,(e,t)=>u.patch(e,t))},get locale(){return f.locale},preload:U,register(e,t){let n=a(e);return u.register(n,t,d)},registerNamespace(e,t){d.registerNamespace(e,t)},restoreState(e){if(w(s),!Object.hasOwn(e.catalogs,e.locale))throw new C(`restoreState: locale "${e.locale}" has no catalog in the provided state.`);let t=new Map;for(let[n,r]of Object.entries(e.catalogs)){let e=a(n),i=new m;i.setAll(Object.entries(r)),t.set(e,i),d.clearLocale(e)}u.dispose(),u.onChange=e=>{f.chainSet.has(e)&&H()},u.seedFrom(t,new Map),f=N(a(e.locale),o,r),T?.clear(),H()},scope(e){let t=String(e),n=A.get(t);if(n)return n;let r={get fmt(){return j()},has:e=>L(`${t}.${e}`),t:(e,n)=>z(`${t}.${e}`,n),tp:(e,n,r)=>B(`${t}.${e}`,n,r)};return A.set(t,r),r},async setLocale(e){w(s);let t=a(e);if(f.locale===t)return;let n=++W;await U(t),!(s||W!==n)&&(f=N(t,o,r),T?.clear(),H())},subscribe:(e,t)=>{let n=()=>{g.delete(e)};if(s)throw new _;if(t?.signal?.aborted)return n;if(t?.immediate===!0)try{e(V)}catch(e){return S(e),n}return g.add(e),t?.signal?.addEventListener(`abort`,n,{once:!0}),n},[Symbol.dispose](){this.dispose()},t:z,tp:B}}function L(e){return e.getState()}function R(e,t){e.restoreState(t)}export{y as LinguaCountInVarsError,_ as LinguaDisposedError,g as LinguaError,v as LinguaInvalidCountError,x as LinguaInvalidLocaleError,b as LinguaMissingLocaleError,S as LinguaNamespaceMissingError,C as LinguaRestoreError,i as createFormatter,F as createI18n,R as hydrateI18n,L as serializeI18n};
|
|
2
|
+
//# sourceMappingURL=lingua.js.map
|