@vielzeug/lingua 26.10.14 → 26.10.16

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.
Files changed (51) hide show
  1. package/dist/_bounded-cache.cjs.map +1 -1
  2. package/dist/_bounded-cache.js +9 -1
  3. package/dist/_bounded-cache.js.map +1 -1
  4. package/dist/_catalog.cjs +1 -1
  5. package/dist/_catalog.cjs.map +1 -1
  6. package/dist/_catalog.js +46 -1
  7. package/dist/_catalog.js.map +1 -1
  8. package/dist/_dev.cjs.map +1 -1
  9. package/dist/_dev.js +6 -1
  10. package/dist/_dev.js.map +1 -1
  11. package/dist/_locale.cjs.map +1 -1
  12. package/dist/_locale.js +25 -1
  13. package/dist/_locale.js.map +1 -1
  14. package/dist/_resources.cjs.map +1 -1
  15. package/dist/_resources.js +48 -1
  16. package/dist/_resources.js.map +1 -1
  17. package/dist/_template.cjs +1 -1
  18. package/dist/_template.cjs.map +1 -1
  19. package/dist/_template.js +34 -1
  20. package/dist/_template.js.map +1 -1
  21. package/dist/catalog.cjs.map +1 -1
  22. package/dist/catalog.js +8 -1
  23. package/dist/catalog.js.map +1 -1
  24. package/dist/errors.cjs.map +1 -1
  25. package/dist/errors.js +13 -1
  26. package/dist/errors.js.map +1 -1
  27. package/dist/format.cjs.map +1 -1
  28. package/dist/format.js +86 -1
  29. package/dist/format.js.map +1 -1
  30. package/dist/i18n.cjs +1 -1
  31. package/dist/i18n.cjs.map +1 -1
  32. package/dist/i18n.js +97 -1
  33. package/dist/i18n.js.map +1 -1
  34. package/dist/index.js +5 -1
  35. package/dist/lingua.cjs +1 -1
  36. package/dist/lingua.cjs.map +1 -1
  37. package/dist/lingua.iife.js +1 -1
  38. package/dist/lingua.iife.js.map +1 -1
  39. package/dist/lingua.js +314 -1
  40. package/dist/lingua.js.map +1 -1
  41. package/dist/ripple.cjs.map +1 -1
  42. package/dist/ripple.js +17 -1
  43. package/dist/ripple.js.map +1 -1
  44. package/dist/translator.cjs.map +1 -1
  45. package/dist/translator.js +77 -1
  46. package/dist/translator.js.map +1 -1
  47. package/dist/validate.cjs +1 -1
  48. package/dist/validate.cjs.map +1 -1
  49. package/dist/validate.js +42 -1
  50. package/dist/validate.js.map +1 -1
  51. package/package.json +6 -6
@@ -1 +1 @@
1
- {"version":3,"file":"_bounded-cache.cjs","names":[],"sources":["../src/_bounded-cache.ts"],"sourcesContent":["// Internal: not part of the public API.\n// Minimal bounded cache: evicts the oldest entry (insertion order) once `maxSize` is exceeded.\n// Not LRU: no access-time reordering, only insertion order matters. These caches exist purely\n// to avoid rebuilding cheap-but-not-free values (compiled `Intl` formatters, scoped translator\n// objects) for a bounded number of frequently-reused keys, not to model real recency.\n\nexport function getOrCreate<K, V>(cache: Map<K, V>, key: K, maxSize: number, build: () => V): V {\n if (cache.has(key)) return cache.get(key)!;\n\n const value = build();\n\n if (cache.size >= maxSize) cache.delete(cache.keys().next().value as K);\n\n cache.set(key, value);\n\n return value;\n}\n"],"mappings":"AAMA,SAAgB,YAAkB,EAAkB,EAAQ,EAAiB,EAAmB,CAC9F,GAAI,EAAM,IAAI,CAAG,EAAG,OAAO,EAAM,IAAI,CAAG,EAExC,IAAM,EAAQ,EAAM,EAMpB,OAJI,EAAM,MAAQ,GAAS,EAAM,OAAO,EAAM,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAU,EAEtE,EAAM,IAAI,EAAK,CAAK,EAEb,CACT"}
1
+ {"version":3,"file":"_bounded-cache.cjs","names":["cache","key","value","build","maxSize"],"sources":["../src/_bounded-cache.ts"],"sourcesContent":["// Internal: not part of the public API.\n// Minimal bounded cache: evicts the oldest entry (insertion order) once `maxSize` is exceeded.\n// Not LRU: no access-time reordering, only insertion order matters. These caches exist purely\n// to avoid rebuilding cheap-but-not-free values (compiled `Intl` formatters, scoped translator\n// objects) for a bounded number of frequently-reused keys, not to model real recency.\n\nexport function getOrCreate<K, V>(cache: Map<K, V>, key: K, maxSize: number, build: () => V): V {\n if (cache.has(key)) return cache.get(key)!;\n\n const value = build();\n\n if (cache.size >= maxSize) cache.delete(cache.keys().next().value as K);\n\n cache.set(key, value);\n\n return value;\n}\n"],"mappings":"AAMA,SAAgB,YAAkB,EAAkB,EAAQ,EAAiB,EAAmB,CAC9F,GAAIA,EAAM,IAAIC,CAAG,EAAG,OAAOD,EAAM,IAAIC,CAAG,EAExC,IAAMC,EAAQC,EAAM,EAMpB,OAJIH,EAAM,MAAQI,GAASJ,EAAM,OAAOA,EAAM,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAU,EAEtEA,EAAM,IAAIC,EAAKC,CAAK,EAEbA,CACT,C"}
@@ -1,2 +1,10 @@
1
- function getOrCreate(e,t,n,r){if(e.has(t))return e.get(t);let i=r();return e.size>=n&&e.delete(e.keys().next().value),e.set(t,i),i}export{getOrCreate};
1
+ //#region src/_bounded-cache.ts
2
+ function getOrCreate(e, t, n, r) {
3
+ if (e.has(t)) return e.get(t);
4
+ let i = r();
5
+ return e.size >= n && e.delete(e.keys().next().value), e.set(t, i), i;
6
+ }
7
+ //#endregion
8
+ export { getOrCreate };
9
+
2
10
  //# sourceMappingURL=_bounded-cache.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"_bounded-cache.js","names":[],"sources":["../src/_bounded-cache.ts"],"sourcesContent":["// Internal: not part of the public API.\n// Minimal bounded cache: evicts the oldest entry (insertion order) once `maxSize` is exceeded.\n// Not LRU: no access-time reordering, only insertion order matters. These caches exist purely\n// to avoid rebuilding cheap-but-not-free values (compiled `Intl` formatters, scoped translator\n// objects) for a bounded number of frequently-reused keys, not to model real recency.\n\nexport function getOrCreate<K, V>(cache: Map<K, V>, key: K, maxSize: number, build: () => V): V {\n if (cache.has(key)) return cache.get(key)!;\n\n const value = build();\n\n if (cache.size >= maxSize) cache.delete(cache.keys().next().value as K);\n\n cache.set(key, value);\n\n return value;\n}\n"],"mappings":"AAMA,SAAgB,YAAkB,EAAkB,EAAQ,EAAiB,EAAmB,CAC9F,GAAI,EAAM,IAAI,CAAG,EAAG,OAAO,EAAM,IAAI,CAAG,EAExC,IAAM,EAAQ,EAAM,EAMpB,OAJI,EAAM,MAAQ,GAAS,EAAM,OAAO,EAAM,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAU,EAEtE,EAAM,IAAI,EAAK,CAAK,EAEb,CACT"}
1
+ {"version":3,"file":"_bounded-cache.js","names":["cache","key","value","build","maxSize"],"sources":["../src/_bounded-cache.ts"],"sourcesContent":["// Internal: not part of the public API.\n// Minimal bounded cache: evicts the oldest entry (insertion order) once `maxSize` is exceeded.\n// Not LRU: no access-time reordering, only insertion order matters. These caches exist purely\n// to avoid rebuilding cheap-but-not-free values (compiled `Intl` formatters, scoped translator\n// objects) for a bounded number of frequently-reused keys, not to model real recency.\n\nexport function getOrCreate<K, V>(cache: Map<K, V>, key: K, maxSize: number, build: () => V): V {\n if (cache.has(key)) return cache.get(key)!;\n\n const value = build();\n\n if (cache.size >= maxSize) cache.delete(cache.keys().next().value as K);\n\n cache.set(key, value);\n\n return value;\n}\n"],"mappings":";AAMA,SAAgB,YAAkB,GAAkB,GAAQ,GAAiB,GAAmB;CAC9F,IAAIA,EAAM,IAAIC,CAAG,GAAG,OAAOD,EAAM,IAAIC,CAAG;CAExC,IAAMC,IAAQC,EAAM;CAMpB,OAJIH,EAAM,QAAQI,KAASJ,EAAM,OAAOA,EAAM,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAU,GAEtEA,EAAM,IAAIC,GAAKC,CAAK,GAEbA;AACT"}
package/dist/_catalog.cjs CHANGED
@@ -1,2 +1,2 @@
1
- const e=require("./_template.cjs"),t=require("./errors.cjs");var n=new Set([`__proto__`,`constructor`,`prototype`]);function isPluralMessage(e){return typeof e==`object`&&!!e&&Object.hasOwn(e,`plural`)}function compileCatalog(r){let i=new Map,visit=(r,a)=>{if(typeof r==`string`){i.set(a,{kind:`text`,template:e.compileTemplate(r)});return}if(typeof r!=`object`||!r||Array.isArray(r))throw new t.LinguaInvalidCatalogError(`Catalog node "${a}" must be a string, plural message, or object.`);if(isPluralMessage(r)){if(Reflect.ownKeys(r).some(e=>e!==`plural`))throw new t.LinguaInvalidCatalogError(`Plural message "${a}" must contain only a "plural" property.`);if(typeof r.plural!=`object`||r.plural===null||Array.isArray(r.plural))throw new t.LinguaInvalidCatalogError(`Plural message "${a}" must provide an object of string forms.`);let n=new Map;for(let[i,o]of Object.entries(r.plural)){if(typeof o!=`string`)throw new t.LinguaInvalidCatalogError(`Plural form "${a}.${i}" must be a string.`);n.set(i,e.compileTemplate(o))}i.set(a,{forms:n,kind:`plural`});return}for(let[e,i]of Object.entries(r)){if(n.has(e))throw new t.LinguaInvalidCatalogError(`Catalog key "${e}" is reserved.`);visit(i,a?`${a}.${e}`:e)}};for(let[e,i]of Object.entries(r)){if(n.has(e))throw new t.LinguaInvalidCatalogError(`Catalog key "${e}" is reserved.`);visit(i,e)}return i}exports.compileCatalog=compileCatalog,exports.isPluralMessage=isPluralMessage;
1
+ const e=require("./_template.cjs"),t=require("./errors.cjs");var n=new Set([`__proto__`,`constructor`,`prototype`]);function isPluralMessage(e){return typeof e==`object`&&!!e&&Object.hasOwn(e,`plural`)}function compileCatalog(r){let i=new Map,visit=(r,a)=>{if(typeof r==`string`)i.set(a,{kind:`text`,template:e.compileTemplate(r)});else{if(typeof r!=`object`||!r||Array.isArray(r))throw new t.LinguaInvalidCatalogError(`Catalog node "${a}" must be a string, plural message, or object.`);if(isPluralMessage(r)){if(Reflect.ownKeys(r).some(e=>e!==`plural`))throw new t.LinguaInvalidCatalogError(`Plural message "${a}" must contain only a "plural" property.`);if(typeof r.plural!=`object`||r.plural===null||Array.isArray(r.plural))throw new t.LinguaInvalidCatalogError(`Plural message "${a}" must provide an object of string forms.`);let n=new Map;for(let[i,o]of Object.entries(r.plural)){if(typeof o!=`string`)throw new t.LinguaInvalidCatalogError(`Plural form "${a}.${i}" must be a string.`);n.set(i,e.compileTemplate(o))}i.set(a,{forms:n,kind:`plural`})}else for(let[e,i]of Object.entries(r)){if(n.has(e))throw new t.LinguaInvalidCatalogError(`Catalog key "${e}" is reserved.`);visit(i,a?`${a}.${e}`:e)}}};for(let[e,i]of Object.entries(r)){if(n.has(e))throw new t.LinguaInvalidCatalogError(`Catalog key "${e}" is reserved.`);visit(i,e)}return i}exports.compileCatalog=compileCatalog,exports.isPluralMessage=isPluralMessage;
2
2
  //# sourceMappingURL=_catalog.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"_catalog.cjs","names":[],"sources":["../src/_catalog.ts"],"sourcesContent":["import { compileTemplate, type Template } from './_template';\nimport { LinguaInvalidCatalogError } from './errors';\nimport type { Catalog, CatalogNode, PluralMessage } from './types';\n\nconst unsafeKeys = new Set(['__proto__', 'constructor', 'prototype']);\n\nexport type CompiledText = { readonly kind: 'text'; readonly template: Template };\nexport type CompiledPlural = { readonly forms: ReadonlyMap<string, Template>; readonly kind: 'plural' };\nexport type CompiledMessage = CompiledPlural | CompiledText;\nexport type CompiledCatalog = ReadonlyMap<string, CompiledMessage>;\n\nexport function isPluralMessage(node: CatalogNode): node is PluralMessage {\n return typeof node === 'object' && node !== null && Object.hasOwn(node, 'plural');\n}\n\n/** Compile explicit catalog nodes once. Nested objects only group keys; plural intent is never inferred. */\nexport function compileCatalog(catalog: Catalog): CompiledCatalog {\n const messages = new Map<string, CompiledMessage>();\n\n const visit = (node: CatalogNode, prefix: string): void => {\n if (typeof node === 'string') {\n messages.set(prefix, { kind: 'text', template: compileTemplate(node) });\n\n return;\n }\n\n if (typeof node !== 'object' || node === null || Array.isArray(node)) {\n throw new LinguaInvalidCatalogError(`Catalog node \"${prefix}\" must be a string, plural message, or object.`);\n }\n\n if (isPluralMessage(node)) {\n if (Reflect.ownKeys(node).some((key) => key !== 'plural')) {\n throw new LinguaInvalidCatalogError(`Plural message \"${prefix}\" must contain only a \"plural\" property.`);\n }\n\n if (typeof node.plural !== 'object' || node.plural === null || Array.isArray(node.plural)) {\n throw new LinguaInvalidCatalogError(`Plural message \"${prefix}\" must provide an object of string forms.`);\n }\n\n const forms = new Map<string, Template>();\n\n for (const [form, template] of Object.entries(node.plural)) {\n if (typeof template !== 'string') {\n throw new LinguaInvalidCatalogError(`Plural form \"${prefix}.${form}\" must be a string.`);\n }\n\n forms.set(form, compileTemplate(template));\n }\n\n messages.set(prefix, { forms, kind: 'plural' });\n\n return;\n }\n\n for (const [key, value] of Object.entries(node)) {\n if (unsafeKeys.has(key)) {\n throw new LinguaInvalidCatalogError(`Catalog key \"${key}\" is reserved.`);\n }\n\n visit(value, prefix ? `${prefix}.${key}` : key);\n }\n };\n\n for (const [key, value] of Object.entries(catalog)) {\n if (unsafeKeys.has(key)) throw new LinguaInvalidCatalogError(`Catalog key \"${key}\" is reserved.`);\n\n visit(value, key);\n }\n\n return messages;\n}\n"],"mappings":"6DAIA,IAAM,EAAa,IAAI,IAAI,CAAC,YAAa,cAAe,WAAW,CAAC,EAOpE,SAAgB,gBAAgB,EAA0C,CACxE,OAAO,OAAO,GAAS,YAAY,GAAiB,OAAO,OAAO,EAAM,QAAQ,CAClF,CAGA,SAAgB,eAAe,EAAmC,CAChE,IAAM,EAAW,IAAI,IAEf,OAAS,EAAmB,IAAyB,CACzD,GAAI,OAAO,GAAS,SAAU,CAC5B,EAAS,IAAI,EAAQ,CAAE,KAAM,OAAQ,SAAU,EAAA,gBAAgB,CAAI,CAAE,CAAC,EAEtE,MACF,CAEA,GAAI,OAAO,GAAS,WAAY,GAAiB,MAAM,QAAQ,CAAI,EACjE,MAAM,IAAI,EAAA,0BAA0B,iBAAiB,EAAO,+CAA+C,EAG7G,GAAI,gBAAgB,CAAI,EAAG,CACzB,GAAI,QAAQ,QAAQ,CAAI,CAAC,CAAC,KAAM,GAAQ,IAAQ,QAAQ,EACtD,MAAM,IAAI,EAAA,0BAA0B,mBAAmB,EAAO,yCAAyC,EAGzG,GAAI,OAAO,EAAK,QAAW,UAAY,EAAK,SAAW,MAAQ,MAAM,QAAQ,EAAK,MAAM,EACtF,MAAM,IAAI,EAAA,0BAA0B,mBAAmB,EAAO,0CAA0C,EAG1G,IAAM,EAAQ,IAAI,IAElB,IAAK,GAAM,CAAC,EAAM,KAAa,OAAO,QAAQ,EAAK,MAAM,EAAG,CAC1D,GAAI,OAAO,GAAa,SACtB,MAAM,IAAI,EAAA,0BAA0B,gBAAgB,EAAO,GAAG,EAAK,oBAAoB,EAGzF,EAAM,IAAI,EAAM,EAAA,gBAAgB,CAAQ,CAAC,CAC3C,CAEA,EAAS,IAAI,EAAQ,CAAE,QAAO,KAAM,QAAS,CAAC,EAE9C,MACF,CAEA,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAI,EAAG,CAC/C,GAAI,EAAW,IAAI,CAAG,EACpB,MAAM,IAAI,EAAA,0BAA0B,gBAAgB,EAAI,eAAe,EAGzE,MAAM,EAAO,EAAS,GAAG,EAAO,GAAG,IAAQ,CAAG,CAChD,CACF,EAEA,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAO,EAAG,CAClD,GAAI,EAAW,IAAI,CAAG,EAAG,MAAM,IAAI,EAAA,0BAA0B,gBAAgB,EAAI,eAAe,EAEhG,MAAM,EAAO,CAAG,CAClB,CAEA,OAAO,CACT"}
1
+ {"version":3,"file":"_catalog.cjs","names":["compileTemplate","LinguaInvalidCatalogError","require__template","require_errors","unsafeKeys","node","messages","prefix","key","forms","form","template","value","catalog"],"sources":["../src/_catalog.ts"],"sourcesContent":["import { compileTemplate, type Template } from './_template';\nimport { LinguaInvalidCatalogError } from './errors';\nimport type { Catalog, CatalogNode, PluralMessage } from './types';\n\nconst unsafeKeys = new Set(['__proto__', 'constructor', 'prototype']);\n\nexport type CompiledText = { readonly kind: 'text'; readonly template: Template };\nexport type CompiledPlural = { readonly forms: ReadonlyMap<string, Template>; readonly kind: 'plural' };\nexport type CompiledMessage = CompiledPlural | CompiledText;\nexport type CompiledCatalog = ReadonlyMap<string, CompiledMessage>;\n\nexport function isPluralMessage(node: CatalogNode): node is PluralMessage {\n return typeof node === 'object' && node !== null && Object.hasOwn(node, 'plural');\n}\n\n/** Compile explicit catalog nodes once. Nested objects only group keys; plural intent is never inferred. */\nexport function compileCatalog(catalog: Catalog): CompiledCatalog {\n const messages = new Map<string, CompiledMessage>();\n\n const visit = (node: CatalogNode, prefix: string): void => {\n if (typeof node === 'string') {\n messages.set(prefix, { kind: 'text', template: compileTemplate(node) });\n\n return;\n }\n\n if (typeof node !== 'object' || node === null || Array.isArray(node)) {\n throw new LinguaInvalidCatalogError(`Catalog node \"${prefix}\" must be a string, plural message, or object.`);\n }\n\n if (isPluralMessage(node)) {\n if (Reflect.ownKeys(node).some((key) => key !== 'plural')) {\n throw new LinguaInvalidCatalogError(`Plural message \"${prefix}\" must contain only a \"plural\" property.`);\n }\n\n if (typeof node.plural !== 'object' || node.plural === null || Array.isArray(node.plural)) {\n throw new LinguaInvalidCatalogError(`Plural message \"${prefix}\" must provide an object of string forms.`);\n }\n\n const forms = new Map<string, Template>();\n\n for (const [form, template] of Object.entries(node.plural)) {\n if (typeof template !== 'string') {\n throw new LinguaInvalidCatalogError(`Plural form \"${prefix}.${form}\" must be a string.`);\n }\n\n forms.set(form, compileTemplate(template));\n }\n\n messages.set(prefix, { forms, kind: 'plural' });\n\n return;\n }\n\n for (const [key, value] of Object.entries(node)) {\n if (unsafeKeys.has(key)) {\n throw new LinguaInvalidCatalogError(`Catalog key \"${key}\" is reserved.`);\n }\n\n visit(value, prefix ? `${prefix}.${key}` : key);\n }\n };\n\n for (const [key, value] of Object.entries(catalog)) {\n if (unsafeKeys.has(key)) throw new LinguaInvalidCatalogError(`Catalog key \"${key}\" is reserved.`);\n\n visit(value, key);\n }\n\n return messages;\n}\n"],"mappings":"A,6DAIA,IAAMI,EAAa,IAAI,IAAI,CAAC,YAAa,cAAe,WAAW,CAAC,EAOpE,SAAgB,gBAAgB,EAA0C,CACxE,OAAO,OAAOC,GAAS,YAAYA,GAAiB,OAAO,OAAOA,EAAM,QAAQ,CAClF,CAGA,SAAgB,eAAe,EAAmC,CAChE,IAAMC,EAAW,IAAI,IAEf,OAAS,EAAmB,IAAyB,CACzD,GAAI,OAAOD,GAAS,SAClBC,EAAS,IAAIC,EAAQ,CAAE,KAAM,OAAQ,SAAUP,EAAAA,gBAAgBK,CAAI,CAAE,CAAC,MAKxE,IAAI,OAAOA,GAAS,WAAYA,GAAiB,MAAM,QAAQA,CAAI,EACjE,MAAM,IAAIJ,EAAAA,0BAA0B,iBAAiBM,EAAO,+CAA+C,EAG7G,GAAI,gBAAgBF,CAAI,EAAG,CACzB,GAAI,QAAQ,QAAQA,CAAI,CAAC,CAAC,KAAM,GAAQG,IAAQ,QAAQ,EACtD,MAAM,IAAIP,EAAAA,0BAA0B,mBAAmBM,EAAO,yCAAyC,EAGzG,GAAI,OAAOF,EAAK,QAAW,UAAYA,EAAK,SAAW,MAAQ,MAAM,QAAQA,EAAK,MAAM,EACtF,MAAM,IAAIJ,EAAAA,0BAA0B,mBAAmBM,EAAO,0CAA0C,EAG1G,IAAME,EAAQ,IAAI,IAElB,IAAK,GAAM,CAACC,EAAMC,KAAa,OAAO,QAAQN,EAAK,MAAM,EAAG,CAC1D,GAAI,OAAOM,GAAa,SACtB,MAAM,IAAIV,EAAAA,0BAA0B,gBAAgBM,EAAO,GAAGG,EAAK,oBAAoB,EAGzFD,EAAM,IAAIC,EAAMV,EAAAA,gBAAgBW,CAAQ,CAAC,CAC3C,CAEAL,EAAS,IAAIC,EAAQ,CAAE,QAAO,KAAM,QAAS,CAAC,CAGhD,MAEA,IAAK,GAAM,CAACC,EAAKI,KAAU,OAAO,QAAQP,CAAI,EAAG,CAC/C,GAAID,EAAW,IAAII,CAAG,EACpB,MAAM,IAAIP,EAAAA,0BAA0B,gBAAgBO,EAAI,eAAe,EAGzE,MAAMI,EAAOL,EAAS,GAAGA,EAAO,GAAGC,IAAQA,CAAG,CAChD,CAjC6G,CAkC/G,EAEA,IAAK,GAAM,CAACA,EAAKI,KAAU,OAAO,QAAQC,CAAO,EAAG,CAClD,GAAIT,EAAW,IAAII,CAAG,EAAG,MAAM,IAAIP,EAAAA,0BAA0B,gBAAgBO,EAAI,eAAe,EAEhG,MAAMI,EAAOJ,CAAG,CAClB,CAEA,OAAOF,CACT,C"}
package/dist/_catalog.js CHANGED
@@ -1,2 +1,47 @@
1
- import{compileTemplate as e}from"./_template.js";import{LinguaInvalidCatalogError as t}from"./errors.js";var n=new Set([`__proto__`,`constructor`,`prototype`]);function isPluralMessage(e){return typeof e==`object`&&!!e&&Object.hasOwn(e,`plural`)}function compileCatalog(r){let i=new Map,visit=(r,a)=>{if(typeof r==`string`){i.set(a,{kind:`text`,template:e(r)});return}if(typeof r!=`object`||!r||Array.isArray(r))throw new t(`Catalog node "${a}" must be a string, plural message, or object.`);if(isPluralMessage(r)){if(Reflect.ownKeys(r).some(e=>e!==`plural`))throw new t(`Plural message "${a}" must contain only a "plural" property.`);if(typeof r.plural!=`object`||r.plural===null||Array.isArray(r.plural))throw new t(`Plural message "${a}" must provide an object of string forms.`);let n=new Map;for(let[i,o]of Object.entries(r.plural)){if(typeof o!=`string`)throw new t(`Plural form "${a}.${i}" must be a string.`);n.set(i,e(o))}i.set(a,{forms:n,kind:`plural`});return}for(let[e,i]of Object.entries(r)){if(n.has(e))throw new t(`Catalog key "${e}" is reserved.`);visit(i,a?`${a}.${e}`:e)}};for(let[e,i]of Object.entries(r)){if(n.has(e))throw new t(`Catalog key "${e}" is reserved.`);visit(i,e)}return i}export{compileCatalog,isPluralMessage};
1
+ import { compileTemplate as e } from "./_template.js";
2
+ import { LinguaInvalidCatalogError as t } from "./errors.js";
3
+ //#region src/_catalog.ts
4
+ var n = /* @__PURE__ */ new Set([
5
+ "__proto__",
6
+ "constructor",
7
+ "prototype"
8
+ ]);
9
+ function isPluralMessage(e) {
10
+ return typeof e == "object" && !!e && Object.hasOwn(e, "plural");
11
+ }
12
+ function compileCatalog(r) {
13
+ let i = /* @__PURE__ */ new Map(), visit = (r, a) => {
14
+ if (typeof r == "string") i.set(a, {
15
+ kind: "text",
16
+ template: e(r)
17
+ });
18
+ else {
19
+ if (typeof r != "object" || !r || Array.isArray(r)) throw new t(`Catalog node "${a}" must be a string, plural message, or object.`);
20
+ if (isPluralMessage(r)) {
21
+ if (Reflect.ownKeys(r).some((e) => e !== "plural")) throw new t(`Plural message "${a}" must contain only a "plural" property.`);
22
+ if (typeof r.plural != "object" || r.plural === null || Array.isArray(r.plural)) throw new t(`Plural message "${a}" must provide an object of string forms.`);
23
+ let n = /* @__PURE__ */ new Map();
24
+ for (let [i, o] of Object.entries(r.plural)) {
25
+ if (typeof o != "string") throw new t(`Plural form "${a}.${i}" must be a string.`);
26
+ n.set(i, e(o));
27
+ }
28
+ i.set(a, {
29
+ forms: n,
30
+ kind: "plural"
31
+ });
32
+ } else for (let [e, i] of Object.entries(r)) {
33
+ if (n.has(e)) throw new t(`Catalog key "${e}" is reserved.`);
34
+ visit(i, a ? `${a}.${e}` : e);
35
+ }
36
+ }
37
+ };
38
+ for (let [e, i] of Object.entries(r)) {
39
+ if (n.has(e)) throw new t(`Catalog key "${e}" is reserved.`);
40
+ visit(i, e);
41
+ }
42
+ return i;
43
+ }
44
+ //#endregion
45
+ export { compileCatalog, isPluralMessage };
46
+
2
47
  //# sourceMappingURL=_catalog.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"_catalog.js","names":[],"sources":["../src/_catalog.ts"],"sourcesContent":["import { compileTemplate, type Template } from './_template';\nimport { LinguaInvalidCatalogError } from './errors';\nimport type { Catalog, CatalogNode, PluralMessage } from './types';\n\nconst unsafeKeys = new Set(['__proto__', 'constructor', 'prototype']);\n\nexport type CompiledText = { readonly kind: 'text'; readonly template: Template };\nexport type CompiledPlural = { readonly forms: ReadonlyMap<string, Template>; readonly kind: 'plural' };\nexport type CompiledMessage = CompiledPlural | CompiledText;\nexport type CompiledCatalog = ReadonlyMap<string, CompiledMessage>;\n\nexport function isPluralMessage(node: CatalogNode): node is PluralMessage {\n return typeof node === 'object' && node !== null && Object.hasOwn(node, 'plural');\n}\n\n/** Compile explicit catalog nodes once. Nested objects only group keys; plural intent is never inferred. */\nexport function compileCatalog(catalog: Catalog): CompiledCatalog {\n const messages = new Map<string, CompiledMessage>();\n\n const visit = (node: CatalogNode, prefix: string): void => {\n if (typeof node === 'string') {\n messages.set(prefix, { kind: 'text', template: compileTemplate(node) });\n\n return;\n }\n\n if (typeof node !== 'object' || node === null || Array.isArray(node)) {\n throw new LinguaInvalidCatalogError(`Catalog node \"${prefix}\" must be a string, plural message, or object.`);\n }\n\n if (isPluralMessage(node)) {\n if (Reflect.ownKeys(node).some((key) => key !== 'plural')) {\n throw new LinguaInvalidCatalogError(`Plural message \"${prefix}\" must contain only a \"plural\" property.`);\n }\n\n if (typeof node.plural !== 'object' || node.plural === null || Array.isArray(node.plural)) {\n throw new LinguaInvalidCatalogError(`Plural message \"${prefix}\" must provide an object of string forms.`);\n }\n\n const forms = new Map<string, Template>();\n\n for (const [form, template] of Object.entries(node.plural)) {\n if (typeof template !== 'string') {\n throw new LinguaInvalidCatalogError(`Plural form \"${prefix}.${form}\" must be a string.`);\n }\n\n forms.set(form, compileTemplate(template));\n }\n\n messages.set(prefix, { forms, kind: 'plural' });\n\n return;\n }\n\n for (const [key, value] of Object.entries(node)) {\n if (unsafeKeys.has(key)) {\n throw new LinguaInvalidCatalogError(`Catalog key \"${key}\" is reserved.`);\n }\n\n visit(value, prefix ? `${prefix}.${key}` : key);\n }\n };\n\n for (const [key, value] of Object.entries(catalog)) {\n if (unsafeKeys.has(key)) throw new LinguaInvalidCatalogError(`Catalog key \"${key}\" is reserved.`);\n\n visit(value, key);\n }\n\n return messages;\n}\n"],"mappings":"yGAIA,IAAM,EAAa,IAAI,IAAI,CAAC,YAAa,cAAe,WAAW,CAAC,EAOpE,SAAgB,gBAAgB,EAA0C,CACxE,OAAO,OAAO,GAAS,YAAY,GAAiB,OAAO,OAAO,EAAM,QAAQ,CAClF,CAGA,SAAgB,eAAe,EAAmC,CAChE,IAAM,EAAW,IAAI,IAEf,OAAS,EAAmB,IAAyB,CACzD,GAAI,OAAO,GAAS,SAAU,CAC5B,EAAS,IAAI,EAAQ,CAAE,KAAM,OAAQ,SAAU,EAAgB,CAAI,CAAE,CAAC,EAEtE,MACF,CAEA,GAAI,OAAO,GAAS,WAAY,GAAiB,MAAM,QAAQ,CAAI,EACjE,MAAM,IAAI,EAA0B,iBAAiB,EAAO,+CAA+C,EAG7G,GAAI,gBAAgB,CAAI,EAAG,CACzB,GAAI,QAAQ,QAAQ,CAAI,CAAC,CAAC,KAAM,GAAQ,IAAQ,QAAQ,EACtD,MAAM,IAAI,EAA0B,mBAAmB,EAAO,yCAAyC,EAGzG,GAAI,OAAO,EAAK,QAAW,UAAY,EAAK,SAAW,MAAQ,MAAM,QAAQ,EAAK,MAAM,EACtF,MAAM,IAAI,EAA0B,mBAAmB,EAAO,0CAA0C,EAG1G,IAAM,EAAQ,IAAI,IAElB,IAAK,GAAM,CAAC,EAAM,KAAa,OAAO,QAAQ,EAAK,MAAM,EAAG,CAC1D,GAAI,OAAO,GAAa,SACtB,MAAM,IAAI,EAA0B,gBAAgB,EAAO,GAAG,EAAK,oBAAoB,EAGzF,EAAM,IAAI,EAAM,EAAgB,CAAQ,CAAC,CAC3C,CAEA,EAAS,IAAI,EAAQ,CAAE,QAAO,KAAM,QAAS,CAAC,EAE9C,MACF,CAEA,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAI,EAAG,CAC/C,GAAI,EAAW,IAAI,CAAG,EACpB,MAAM,IAAI,EAA0B,gBAAgB,EAAI,eAAe,EAGzE,MAAM,EAAO,EAAS,GAAG,EAAO,GAAG,IAAQ,CAAG,CAChD,CACF,EAEA,IAAK,GAAM,CAAC,EAAK,KAAU,OAAO,QAAQ,CAAO,EAAG,CAClD,GAAI,EAAW,IAAI,CAAG,EAAG,MAAM,IAAI,EAA0B,gBAAgB,EAAI,eAAe,EAEhG,MAAM,EAAO,CAAG,CAClB,CAEA,OAAO,CACT"}
1
+ {"version":3,"file":"_catalog.js","names":["unsafeKeys","node","messages","prefix","compileTemplate","LinguaInvalidCatalogError","key","forms","form","template","value","catalog"],"sources":["../src/_catalog.ts"],"sourcesContent":["import { compileTemplate, type Template } from './_template';\nimport { LinguaInvalidCatalogError } from './errors';\nimport type { Catalog, CatalogNode, PluralMessage } from './types';\n\nconst unsafeKeys = new Set(['__proto__', 'constructor', 'prototype']);\n\nexport type CompiledText = { readonly kind: 'text'; readonly template: Template };\nexport type CompiledPlural = { readonly forms: ReadonlyMap<string, Template>; readonly kind: 'plural' };\nexport type CompiledMessage = CompiledPlural | CompiledText;\nexport type CompiledCatalog = ReadonlyMap<string, CompiledMessage>;\n\nexport function isPluralMessage(node: CatalogNode): node is PluralMessage {\n return typeof node === 'object' && node !== null && Object.hasOwn(node, 'plural');\n}\n\n/** Compile explicit catalog nodes once. Nested objects only group keys; plural intent is never inferred. */\nexport function compileCatalog(catalog: Catalog): CompiledCatalog {\n const messages = new Map<string, CompiledMessage>();\n\n const visit = (node: CatalogNode, prefix: string): void => {\n if (typeof node === 'string') {\n messages.set(prefix, { kind: 'text', template: compileTemplate(node) });\n\n return;\n }\n\n if (typeof node !== 'object' || node === null || Array.isArray(node)) {\n throw new LinguaInvalidCatalogError(`Catalog node \"${prefix}\" must be a string, plural message, or object.`);\n }\n\n if (isPluralMessage(node)) {\n if (Reflect.ownKeys(node).some((key) => key !== 'plural')) {\n throw new LinguaInvalidCatalogError(`Plural message \"${prefix}\" must contain only a \"plural\" property.`);\n }\n\n if (typeof node.plural !== 'object' || node.plural === null || Array.isArray(node.plural)) {\n throw new LinguaInvalidCatalogError(`Plural message \"${prefix}\" must provide an object of string forms.`);\n }\n\n const forms = new Map<string, Template>();\n\n for (const [form, template] of Object.entries(node.plural)) {\n if (typeof template !== 'string') {\n throw new LinguaInvalidCatalogError(`Plural form \"${prefix}.${form}\" must be a string.`);\n }\n\n forms.set(form, compileTemplate(template));\n }\n\n messages.set(prefix, { forms, kind: 'plural' });\n\n return;\n }\n\n for (const [key, value] of Object.entries(node)) {\n if (unsafeKeys.has(key)) {\n throw new LinguaInvalidCatalogError(`Catalog key \"${key}\" is reserved.`);\n }\n\n visit(value, prefix ? `${prefix}.${key}` : key);\n }\n };\n\n for (const [key, value] of Object.entries(catalog)) {\n if (unsafeKeys.has(key)) throw new LinguaInvalidCatalogError(`Catalog key \"${key}\" is reserved.`);\n\n visit(value, key);\n }\n\n return messages;\n}\n"],"mappings":";;;AAIA,IAAMA,oBAAa,IAAI,IAAI;CAAC;CAAa;CAAe;AAAW,CAAC;AAOpE,SAAgB,gBAAgB,GAA0C;CACxE,OAAO,OAAOC,KAAS,cAAYA,KAAiB,OAAO,OAAOA,GAAM,QAAQ;AAClF;AAGA,SAAgB,eAAe,GAAmC;CAChE,IAAMC,oBAAW,IAAI,IAA6B,GAE5C,SAAS,GAAmB,MAAyB;EACzD,IAAI,OAAOD,KAAS,UAClB,EAAS,IAAIE,GAAQ;GAAE,MAAM;GAAQ,UAAUC,EAAgBH,CAAI;EAAE,CAAC;OAKxE;OAAI,OAAOA,KAAS,aAAYA,KAAiB,MAAM,QAAQA,CAAI,GACjE,MAAM,IAAII,EAA0B,iBAAiBF,EAAO,+CAA+C;GAG7G,IAAI,gBAAgBF,CAAI,GAAG;IACzB,IAAI,QAAQ,QAAQA,CAAI,CAAC,CAAC,MAAM,MAAQK,MAAQ,QAAQ,GACtD,MAAM,IAAID,EAA0B,mBAAmBF,EAAO,yCAAyC;IAGzG,IAAI,OAAOF,EAAK,UAAW,YAAYA,EAAK,WAAW,QAAQ,MAAM,QAAQA,EAAK,MAAM,GACtF,MAAM,IAAII,EAA0B,mBAAmBF,EAAO,0CAA0C;IAG1G,IAAMI,oBAAQ,IAAI,IAAsB;IAExC,KAAK,IAAM,CAACC,GAAMC,MAAa,OAAO,QAAQR,EAAK,MAAM,GAAG;KAC1D,IAAI,OAAOQ,KAAa,UACtB,MAAM,IAAIJ,EAA0B,gBAAgBF,EAAO,GAAGK,EAAK,oBAAoB;KAGzF,EAAM,IAAIA,GAAMJ,EAAgBK,CAAQ,CAAC;IAC3C;IAEA,EAAS,IAAIN,GAAQ;KAAE;KAAO,MAAM;IAAS,CAAC;GAGhD,OAEA,KAAK,IAAM,CAACG,GAAKI,MAAU,OAAO,QAAQT,CAAI,GAAG;IAC/C,IAAID,EAAW,IAAIM,CAAG,GACpB,MAAM,IAAID,EAA0B,gBAAgBC,EAAI,eAAe;IAGzE,MAAMI,GAAOP,IAAS,GAAGA,EAAO,GAAGG,MAAQA,CAAG;GAChD;EAjC6G;CAkC/G;CAEA,KAAK,IAAM,CAACA,GAAKI,MAAU,OAAO,QAAQC,CAAO,GAAG;EAClD,IAAIX,EAAW,IAAIM,CAAG,GAAG,MAAM,IAAID,EAA0B,gBAAgBC,EAAI,eAAe;EAEhG,MAAMI,GAAOJ,CAAG;CAClB;CAEA,OAAOJ;AACT"}
package/dist/_dev.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"_dev.cjs","names":[],"sources":["../src/_dev.ts"],"sourcesContent":["export 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"],"mappings":"AAGA,SAAgB,KAAK,EAAmB,CAExC,CAGA,SAAgB,MAAM,EAAa,GAAG,EAAuB,CAE7D"}
1
+ {"version":3,"file":"_dev.cjs","names":["args"],"sources":["../src/_dev.ts"],"sourcesContent":["export 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"],"mappings":"AAGA,SAAgB,KAAK,EAAmB,CAExC,CAGA,SAAgB,MAAM,EAAa,GAAGA,EAAuB,CAE7D,C"}
package/dist/_dev.js CHANGED
@@ -1,2 +1,7 @@
1
- function warn(e){}function error(e,...t){}export{error,warn};
1
+ //#region src/_dev.ts
2
+ function warn(e) {}
3
+ function error(e, ...t) {}
4
+ //#endregion
5
+ export { error, warn };
6
+
2
7
  //# sourceMappingURL=_dev.js.map
package/dist/_dev.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"_dev.js","names":[],"sources":["../src/_dev.ts"],"sourcesContent":["export 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"],"mappings":"AAGA,SAAgB,KAAK,EAAmB,CAExC,CAGA,SAAgB,MAAM,EAAa,GAAG,EAAuB,CAE7D"}
1
+ {"version":3,"file":"_dev.js","names":["args"],"sources":["../src/_dev.ts"],"sourcesContent":["export 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"],"mappings":";AAGA,SAAgB,KAAK,GAAmB,CAExC;AAGA,SAAgB,MAAM,GAAa,GAAGA,GAAuB,CAE7D"}
@@ -1 +1 @@
1
- {"version":3,"file":"_locale.cjs","names":[],"sources":["../src/_locale.ts"],"sourcesContent":["import { LinguaInvalidLocaleError } from './errors';\nimport type { Locale } from './types';\n\nconst pluralRules = new Map<string, Intl.PluralRules>();\n\nexport function canonicalLocale(locale: string): Locale {\n try {\n const [canonical] = Intl.getCanonicalLocales(locale);\n\n if (canonical) return canonical;\n } catch {\n // Error below names the failed public input.\n }\n\n throw new LinguaInvalidLocaleError(`Invalid BCP 47 locale tag: \"${locale}\".`);\n}\n\nexport function localeChain(locale: Locale, fallback: readonly Locale[]): readonly Locale[] {\n const chain = new Set<Locale>();\n\n for (const candidate of [locale, ...fallback]) {\n const parts = candidate.split('-');\n\n for (let length = parts.length; length > 0; length--) {\n chain.add(parts.slice(0, length).join('-'));\n }\n }\n\n return [...chain];\n}\n\nexport function pluralCategory(locale: Locale, count: number, ordinal: boolean): Intl.LDMLPluralRule {\n const key = `${locale}:${ordinal ? 'ordinal' : 'cardinal'}`;\n let rules = pluralRules.get(key);\n\n if (!rules) {\n rules = new Intl.PluralRules(locale, { type: ordinal ? 'ordinal' : 'cardinal' });\n pluralRules.set(key, rules);\n }\n\n return rules.select(count);\n}\n"],"mappings":"gCAGA,IAAM,EAAc,IAAI,IAExB,SAAgB,gBAAgB,EAAwB,CACtD,GAAI,CACF,GAAM,CAAC,GAAa,KAAK,oBAAoB,CAAM,EAEnD,GAAI,EAAW,OAAO,CACxB,MAAQ,CAER,CAEA,MAAM,IAAI,EAAA,yBAAyB,+BAA+B,EAAO,GAAG,CAC9E,CAEA,SAAgB,YAAY,EAAgB,EAAgD,CAC1F,IAAM,EAAQ,IAAI,IAElB,IAAK,IAAM,IAAa,CAAC,EAAQ,GAAG,CAAQ,EAAG,CAC7C,IAAM,EAAQ,EAAU,MAAM,GAAG,EAEjC,IAAK,IAAI,EAAS,EAAM,OAAQ,EAAS,EAAG,IAC1C,EAAM,IAAI,EAAM,MAAM,EAAG,CAAM,CAAC,CAAC,KAAK,GAAG,CAAC,CAE9C,CAEA,MAAO,CAAC,GAAG,CAAK,CAClB,CAEA,SAAgB,eAAe,EAAgB,EAAe,EAAuC,CACnG,IAAM,EAAM,GAAG,EAAO,GAAG,EAAU,UAAY,aAC3C,EAAQ,EAAY,IAAI,CAAG,EAO/B,OALK,IACH,EAAQ,IAAI,KAAK,YAAY,EAAQ,CAAE,KAAM,EAAU,UAAY,UAAW,CAAC,EAC/E,EAAY,IAAI,EAAK,CAAK,GAGrB,EAAM,OAAO,CAAK,CAC3B"}
1
+ {"version":3,"file":"_locale.cjs","names":["LinguaInvalidLocaleError","require_errors","pluralRules","canonical","locale","chain","candidate","fallback","parts","length","key","ordinal","rules","count"],"sources":["../src/_locale.ts"],"sourcesContent":["import { LinguaInvalidLocaleError } from './errors';\nimport type { Locale } from './types';\n\nconst pluralRules = new Map<string, Intl.PluralRules>();\n\nexport function canonicalLocale(locale: string): Locale {\n try {\n const [canonical] = Intl.getCanonicalLocales(locale);\n\n if (canonical) return canonical;\n } catch {\n // Error below names the failed public input.\n }\n\n throw new LinguaInvalidLocaleError(`Invalid BCP 47 locale tag: \"${locale}\".`);\n}\n\nexport function localeChain(locale: Locale, fallback: readonly Locale[]): readonly Locale[] {\n const chain = new Set<Locale>();\n\n for (const candidate of [locale, ...fallback]) {\n const parts = candidate.split('-');\n\n for (let length = parts.length; length > 0; length--) {\n chain.add(parts.slice(0, length).join('-'));\n }\n }\n\n return [...chain];\n}\n\nexport function pluralCategory(locale: Locale, count: number, ordinal: boolean): Intl.LDMLPluralRule {\n const key = `${locale}:${ordinal ? 'ordinal' : 'cardinal'}`;\n let rules = pluralRules.get(key);\n\n if (!rules) {\n rules = new Intl.PluralRules(locale, { type: ordinal ? 'ordinal' : 'cardinal' });\n pluralRules.set(key, rules);\n }\n\n return rules.select(count);\n}\n"],"mappings":"A,gCAGA,IAAME,EAAc,IAAI,IAExB,SAAgB,gBAAgB,EAAwB,CACtD,GAAI,CACF,GAAM,CAACC,GAAa,KAAK,oBAAoBC,CAAM,EAEnD,GAAID,EAAW,OAAOA,CACxB,MAAQ,CAER,CAEA,MAAM,IAAIH,EAAAA,yBAAyB,+BAA+BI,EAAO,GAAG,CAC9E,CAEA,SAAgB,YAAY,EAAgB,EAAgD,CAC1F,IAAMC,EAAQ,IAAI,IAElB,IAAK,IAAMC,IAAa,CAACF,EAAQ,GAAGG,CAAQ,EAAG,CAC7C,IAAMC,EAAQF,EAAU,MAAM,GAAG,EAEjC,IAAK,IAAIG,EAASD,EAAM,OAAQC,EAAS,EAAG,IAC1CJ,EAAM,IAAIG,EAAM,MAAM,EAAGC,CAAM,CAAC,CAAC,KAAK,GAAG,CAAC,CAE9C,CAEA,MAAO,CAAC,GAAGJ,CAAK,CAClB,CAEA,SAAgB,eAAe,EAAgB,EAAe,EAAuC,CACnG,IAAMK,EAAM,GAAGN,EAAO,GAAGO,EAAU,UAAY,aAC3CC,EAAQV,EAAY,IAAIQ,CAAG,EAO/B,OALKE,IACH,EAAQ,IAAI,KAAK,YAAYR,EAAQ,CAAE,KAAMO,EAAU,UAAY,UAAW,CAAC,EAC/ET,EAAY,IAAIQ,EAAKE,CAAK,GAGrBA,EAAM,OAAOC,CAAK,CAC3B,C"}
package/dist/_locale.js CHANGED
@@ -1,2 +1,26 @@
1
- import{LinguaInvalidLocaleError as e}from"./errors.js";var t=new Map;function canonicalLocale(t){try{let[e]=Intl.getCanonicalLocales(t);if(e)return e}catch{}throw new e(`Invalid BCP 47 locale tag: "${t}".`)}function localeChain(e,t){let n=new Set;for(let r of[e,...t]){let e=r.split(`-`);for(let t=e.length;t>0;t--)n.add(e.slice(0,t).join(`-`))}return[...n]}function pluralCategory(e,n,r){let i=`${e}:${r?`ordinal`:`cardinal`}`,a=t.get(i);return a||(a=new Intl.PluralRules(e,{type:r?`ordinal`:`cardinal`}),t.set(i,a)),a.select(n)}export{canonicalLocale,localeChain,pluralCategory};
1
+ import { LinguaInvalidLocaleError as e } from "./errors.js";
2
+ //#region src/_locale.ts
3
+ var t = /* @__PURE__ */ new Map();
4
+ function canonicalLocale(t) {
5
+ try {
6
+ let [e] = Intl.getCanonicalLocales(t);
7
+ if (e) return e;
8
+ } catch {}
9
+ throw new e(`Invalid BCP 47 locale tag: "${t}".`);
10
+ }
11
+ function localeChain(e, t) {
12
+ let n = /* @__PURE__ */ new Set();
13
+ for (let r of [e, ...t]) {
14
+ let e = r.split("-");
15
+ for (let t = e.length; t > 0; t--) n.add(e.slice(0, t).join("-"));
16
+ }
17
+ return [...n];
18
+ }
19
+ function pluralCategory(e, n, r) {
20
+ let i = `${e}:${r ? "ordinal" : "cardinal"}`, a = t.get(i);
21
+ return a || (a = new Intl.PluralRules(e, { type: r ? "ordinal" : "cardinal" }), t.set(i, a)), a.select(n);
22
+ }
23
+ //#endregion
24
+ export { canonicalLocale, localeChain, pluralCategory };
25
+
2
26
  //# sourceMappingURL=_locale.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"_locale.js","names":[],"sources":["../src/_locale.ts"],"sourcesContent":["import { LinguaInvalidLocaleError } from './errors';\nimport type { Locale } from './types';\n\nconst pluralRules = new Map<string, Intl.PluralRules>();\n\nexport function canonicalLocale(locale: string): Locale {\n try {\n const [canonical] = Intl.getCanonicalLocales(locale);\n\n if (canonical) return canonical;\n } catch {\n // Error below names the failed public input.\n }\n\n throw new LinguaInvalidLocaleError(`Invalid BCP 47 locale tag: \"${locale}\".`);\n}\n\nexport function localeChain(locale: Locale, fallback: readonly Locale[]): readonly Locale[] {\n const chain = new Set<Locale>();\n\n for (const candidate of [locale, ...fallback]) {\n const parts = candidate.split('-');\n\n for (let length = parts.length; length > 0; length--) {\n chain.add(parts.slice(0, length).join('-'));\n }\n }\n\n return [...chain];\n}\n\nexport function pluralCategory(locale: Locale, count: number, ordinal: boolean): Intl.LDMLPluralRule {\n const key = `${locale}:${ordinal ? 'ordinal' : 'cardinal'}`;\n let rules = pluralRules.get(key);\n\n if (!rules) {\n rules = new Intl.PluralRules(locale, { type: ordinal ? 'ordinal' : 'cardinal' });\n pluralRules.set(key, rules);\n }\n\n return rules.select(count);\n}\n"],"mappings":"uDAGA,IAAM,EAAc,IAAI,IAExB,SAAgB,gBAAgB,EAAwB,CACtD,GAAI,CACF,GAAM,CAAC,GAAa,KAAK,oBAAoB,CAAM,EAEnD,GAAI,EAAW,OAAO,CACxB,MAAQ,CAER,CAEA,MAAM,IAAI,EAAyB,+BAA+B,EAAO,GAAG,CAC9E,CAEA,SAAgB,YAAY,EAAgB,EAAgD,CAC1F,IAAM,EAAQ,IAAI,IAElB,IAAK,IAAM,IAAa,CAAC,EAAQ,GAAG,CAAQ,EAAG,CAC7C,IAAM,EAAQ,EAAU,MAAM,GAAG,EAEjC,IAAK,IAAI,EAAS,EAAM,OAAQ,EAAS,EAAG,IAC1C,EAAM,IAAI,EAAM,MAAM,EAAG,CAAM,CAAC,CAAC,KAAK,GAAG,CAAC,CAE9C,CAEA,MAAO,CAAC,GAAG,CAAK,CAClB,CAEA,SAAgB,eAAe,EAAgB,EAAe,EAAuC,CACnG,IAAM,EAAM,GAAG,EAAO,GAAG,EAAU,UAAY,aAC3C,EAAQ,EAAY,IAAI,CAAG,EAO/B,OALK,IACH,EAAQ,IAAI,KAAK,YAAY,EAAQ,CAAE,KAAM,EAAU,UAAY,UAAW,CAAC,EAC/E,EAAY,IAAI,EAAK,CAAK,GAGrB,EAAM,OAAO,CAAK,CAC3B"}
1
+ {"version":3,"file":"_locale.js","names":["pluralRules","canonical","locale","LinguaInvalidLocaleError","chain","candidate","fallback","parts","length","key","ordinal","rules","count"],"sources":["../src/_locale.ts"],"sourcesContent":["import { LinguaInvalidLocaleError } from './errors';\nimport type { Locale } from './types';\n\nconst pluralRules = new Map<string, Intl.PluralRules>();\n\nexport function canonicalLocale(locale: string): Locale {\n try {\n const [canonical] = Intl.getCanonicalLocales(locale);\n\n if (canonical) return canonical;\n } catch {\n // Error below names the failed public input.\n }\n\n throw new LinguaInvalidLocaleError(`Invalid BCP 47 locale tag: \"${locale}\".`);\n}\n\nexport function localeChain(locale: Locale, fallback: readonly Locale[]): readonly Locale[] {\n const chain = new Set<Locale>();\n\n for (const candidate of [locale, ...fallback]) {\n const parts = candidate.split('-');\n\n for (let length = parts.length; length > 0; length--) {\n chain.add(parts.slice(0, length).join('-'));\n }\n }\n\n return [...chain];\n}\n\nexport function pluralCategory(locale: Locale, count: number, ordinal: boolean): Intl.LDMLPluralRule {\n const key = `${locale}:${ordinal ? 'ordinal' : 'cardinal'}`;\n let rules = pluralRules.get(key);\n\n if (!rules) {\n rules = new Intl.PluralRules(locale, { type: ordinal ? 'ordinal' : 'cardinal' });\n pluralRules.set(key, rules);\n }\n\n return rules.select(count);\n}\n"],"mappings":";;AAGA,IAAMA,oBAAc,IAAI,IAA8B;AAEtD,SAAgB,gBAAgB,GAAwB;CACtD,IAAI;EACF,IAAM,CAACC,KAAa,KAAK,oBAAoBC,CAAM;EAEnD,IAAID,GAAW,OAAOA;CACxB,QAAQ,CAER;CAEA,MAAM,IAAIE,EAAyB,+BAA+BD,EAAO,GAAG;AAC9E;AAEA,SAAgB,YAAY,GAAgB,GAAgD;CAC1F,IAAME,oBAAQ,IAAI,IAAY;CAE9B,KAAK,IAAMC,KAAa,CAACH,GAAQ,GAAGI,CAAQ,GAAG;EAC7C,IAAMC,IAAQF,EAAU,MAAM,GAAG;EAEjC,KAAK,IAAIG,IAASD,EAAM,QAAQC,IAAS,GAAG,KAC1C,EAAM,IAAID,EAAM,MAAM,GAAGC,CAAM,CAAC,CAAC,KAAK,GAAG,CAAC;CAE9C;CAEA,OAAO,CAAC,GAAGJ,CAAK;AAClB;AAEA,SAAgB,eAAe,GAAgB,GAAe,GAAuC;CACnG,IAAMK,IAAM,GAAGP,EAAO,GAAGQ,IAAU,YAAY,cAC3CC,IAAQX,EAAY,IAAIS,CAAG;CAO/B,OALKE,MACH,IAAQ,IAAI,KAAK,YAAYT,GAAQ,EAAE,MAAMQ,IAAU,YAAY,WAAW,CAAC,GAC/EV,EAAY,IAAIS,GAAKE,CAAK,IAGrBA,EAAM,OAAOC,CAAK;AAC3B"}
@@ -1 +1 @@
1
- {"version":3,"file":"_resources.cjs","names":[],"sources":["../src/_resources.ts"],"sourcesContent":["import { type CompiledCatalog, compileCatalog } from './_catalog';\nimport { canonicalLocale } from './_locale';\nimport { LinguaMissingCatalogError } from './errors';\nimport type { Catalog, Catalogs, Locale, TranslationState } from './types';\n\ntype CatalogStoreOptions<C extends Catalog> = {\n readonly catalogs?: Catalogs<C>;\n readonly loadCatalog?: (locale: Locale) => Promise<C> | C;\n};\n\n/** One catalog state machine owns loaded catalogs and in-flight loading work. */\nexport function createCatalogStore<C extends Catalog>(options: CatalogStoreOptions<C>) {\n const loaded = new Map<Locale, { readonly catalog: C; readonly compiled: CompiledCatalog }>();\n const tasks = new Map<Locale, Promise<void>>();\n\n const hydrate = (locale: Locale, catalog: C): void => {\n loaded.set(canonicalLocale(locale), { catalog, compiled: compileCatalog(catalog) });\n };\n\n for (const [locale, catalog] of Object.entries(options.catalogs ?? {})) hydrate(locale, catalog);\n\n const load = async (requestedLocale: Locale): Promise<boolean> => {\n const locale = canonicalLocale(requestedLocale);\n\n if (loaded.has(locale)) return false;\n\n const existing = tasks.get(locale);\n\n if (existing) {\n await existing;\n\n return false;\n }\n\n if (!options.loadCatalog) {\n throw new LinguaMissingCatalogError(`No catalog source provided for locale \"${locale}\".`);\n }\n\n const task = Promise.resolve(options.loadCatalog(locale)).then(\n (catalog) => {\n hydrate(locale, catalog);\n tasks.delete(locale);\n },\n (error: unknown) => {\n tasks.delete(locale);\n throw error;\n },\n );\n\n tasks.set(locale, task);\n await task;\n\n return true;\n };\n\n return {\n catalogMap(): ReadonlyMap<Locale, CompiledCatalog> {\n return new Map([...loaded].map(([locale, { compiled }]) => [locale, compiled]));\n },\n hydrate,\n isLoaded(locale: Locale): boolean {\n return loaded.has(canonicalLocale(locale));\n },\n load,\n state(locale: Locale): TranslationState<C> {\n const catalogs: Catalogs<C> = {};\n\n for (const [loadedLocale, { catalog }] of loaded) catalogs[loadedLocale] = catalog;\n\n return { catalogs, locale, version: 1 };\n },\n };\n}\n"],"mappings":"uFAWA,SAAgB,mBAAsC,EAAiC,CACrF,IAAM,EAAS,IAAI,IACb,EAAQ,IAAI,IAEZ,SAAW,EAAgB,IAAqB,CACpD,EAAO,IAAI,EAAA,gBAAgB,CAAM,EAAG,CAAE,UAAS,SAAU,EAAA,eAAe,CAAO,CAAE,CAAC,CACpF,EAEA,IAAK,GAAM,CAAC,EAAQ,KAAY,OAAO,QAAQ,EAAQ,UAAY,CAAC,CAAC,EAAG,QAAQ,EAAQ,CAAO,EAE/F,IAAM,KAAO,KAAO,IAA8C,CAChE,IAAM,EAAS,EAAA,gBAAgB,CAAe,EAE9C,GAAI,EAAO,IAAI,CAAM,EAAG,MAAO,GAE/B,IAAM,EAAW,EAAM,IAAI,CAAM,EAEjC,GAAI,EAGF,OAFA,MAAM,EAEC,GAGT,GAAI,CAAC,EAAQ,YACX,MAAM,IAAI,EAAA,0BAA0B,0CAA0C,EAAO,GAAG,EAG1F,IAAM,EAAO,QAAQ,QAAQ,EAAQ,YAAY,CAAM,CAAC,CAAC,CAAC,KACvD,GAAY,CACX,QAAQ,EAAQ,CAAO,EACvB,EAAM,OAAO,CAAM,CACrB,EACC,GAAmB,CAElB,MADA,EAAM,OAAO,CAAM,EACb,CACR,CACF,EAKA,OAHA,EAAM,IAAI,EAAQ,CAAI,EACtB,MAAM,EAEC,EACT,EAEA,MAAO,CACL,YAAmD,CACjD,OAAO,IAAI,IAAI,CAAC,GAAG,CAAM,CAAC,CAAC,KAAK,CAAC,EAAQ,CAAE,eAAgB,CAAC,EAAQ,CAAQ,CAAC,CAAC,CAChF,EACA,QACA,SAAS,EAAyB,CAChC,OAAO,EAAO,IAAI,EAAA,gBAAgB,CAAM,CAAC,CAC3C,EACA,KACA,MAAM,EAAqC,CACzC,IAAM,EAAwB,CAAC,EAE/B,IAAK,GAAM,CAAC,EAAc,CAAE,cAAc,EAAQ,EAAS,GAAgB,EAE3E,MAAO,CAAE,WAAU,SAAQ,QAAS,CAAE,CACxC,CACF,CACF"}
1
+ {"version":3,"file":"_resources.cjs","names":["canonicalLocale","compileCatalog","LinguaMissingCatalogError","require_errors","require__catalog","require__locale","loaded","tasks","locale","catalog","options","requestedLocale","existing","task","error","compiled","catalogs","loadedLocale"],"sources":["../src/_resources.ts"],"sourcesContent":["import { type CompiledCatalog, compileCatalog } from './_catalog';\nimport { canonicalLocale } from './_locale';\nimport { LinguaMissingCatalogError } from './errors';\nimport type { Catalog, Catalogs, Locale, TranslationState } from './types';\n\ntype CatalogStoreOptions<C extends Catalog> = {\n readonly catalogs?: Catalogs<C>;\n readonly loadCatalog?: (locale: Locale) => Promise<C> | C;\n};\n\n/** One catalog state machine owns loaded catalogs and in-flight loading work. */\nexport function createCatalogStore<C extends Catalog>(options: CatalogStoreOptions<C>) {\n const loaded = new Map<Locale, { readonly catalog: C; readonly compiled: CompiledCatalog }>();\n const tasks = new Map<Locale, Promise<void>>();\n\n const hydrate = (locale: Locale, catalog: C): void => {\n loaded.set(canonicalLocale(locale), { catalog, compiled: compileCatalog(catalog) });\n };\n\n for (const [locale, catalog] of Object.entries(options.catalogs ?? {})) hydrate(locale, catalog);\n\n const load = async (requestedLocale: Locale): Promise<boolean> => {\n const locale = canonicalLocale(requestedLocale);\n\n if (loaded.has(locale)) return false;\n\n const existing = tasks.get(locale);\n\n if (existing) {\n await existing;\n\n return false;\n }\n\n if (!options.loadCatalog) {\n throw new LinguaMissingCatalogError(`No catalog source provided for locale \"${locale}\".`);\n }\n\n const task = Promise.resolve(options.loadCatalog(locale)).then(\n (catalog) => {\n hydrate(locale, catalog);\n tasks.delete(locale);\n },\n (error: unknown) => {\n tasks.delete(locale);\n throw error;\n },\n );\n\n tasks.set(locale, task);\n await task;\n\n return true;\n };\n\n return {\n catalogMap(): ReadonlyMap<Locale, CompiledCatalog> {\n return new Map([...loaded].map(([locale, { compiled }]) => [locale, compiled]));\n },\n hydrate,\n isLoaded(locale: Locale): boolean {\n return loaded.has(canonicalLocale(locale));\n },\n load,\n state(locale: Locale): TranslationState<C> {\n const catalogs: Catalogs<C> = {};\n\n for (const [loadedLocale, { catalog }] of loaded) catalogs[loadedLocale] = catalog;\n\n return { catalogs, locale, version: 1 };\n },\n };\n}\n"],"mappings":"A,uFAWA,SAAgB,mBAAsC,EAAiC,CACrF,IAAMM,EAAS,IAAI,IACbC,EAAQ,IAAI,IAEZ,SAAW,EAAgB,IAAqB,CACpDD,EAAO,IAAIN,EAAAA,gBAAgBQ,CAAM,EAAG,CAAE,UAAS,SAAUP,EAAAA,eAAeQ,CAAO,CAAE,CAAC,CACpF,EAEA,IAAK,GAAM,CAACD,EAAQC,KAAY,OAAO,QAAQC,EAAQ,UAAY,CAAC,CAAC,EAAG,QAAQF,EAAQC,CAAO,EAE/F,IAAM,KAAO,KAAO,IAA8C,CAChE,IAAMD,EAASR,EAAAA,gBAAgBW,CAAe,EAE9C,GAAIL,EAAO,IAAIE,CAAM,EAAG,MAAO,GAE/B,IAAMI,EAAWL,EAAM,IAAIC,CAAM,EAEjC,GAAII,EAGF,OAFA,MAAMA,EAEC,GAGT,GAAI,CAACF,EAAQ,YACX,MAAM,IAAIR,EAAAA,0BAA0B,0CAA0CM,EAAO,GAAG,EAG1F,IAAMK,EAAO,QAAQ,QAAQH,EAAQ,YAAYF,CAAM,CAAC,CAAC,CAAC,KACvD,GAAY,CACX,QAAQA,EAAQC,CAAO,EACvBF,EAAM,OAAOC,CAAM,CACrB,EACC,GAAmB,CAElB,MADAD,EAAM,OAAOC,CAAM,EACbM,CACR,CACF,EAKA,OAHAP,EAAM,IAAIC,EAAQK,CAAI,EACtB,MAAMA,EAEC,EACT,EAEA,MAAO,CACL,YAAmD,CACjD,OAAO,IAAI,IAAI,CAAC,GAAGP,CAAM,CAAC,CAAC,KAAK,CAACE,EAAQ,CAAE,eAAgB,CAACA,EAAQO,CAAQ,CAAC,CAAC,CAChF,EACA,QACA,SAAS,EAAyB,CAChC,OAAOT,EAAO,IAAIN,EAAAA,gBAAgBQ,CAAM,CAAC,CAC3C,EACA,KACA,MAAM,EAAqC,CACzC,IAAMQ,EAAwB,CAAC,EAE/B,IAAK,GAAM,CAACC,EAAc,CAAE,cAAcX,EAAQ,EAASW,GAAgBR,EAE3E,MAAO,CAAE,WAAU,SAAQ,QAAS,CAAE,CACxC,CACF,CACF,C"}
@@ -1,2 +1,49 @@
1
- import{LinguaMissingCatalogError as e}from"./errors.js";import{compileCatalog as t}from"./_catalog.js";import{canonicalLocale as n}from"./_locale.js";function createCatalogStore(r){let i=new Map,a=new Map,hydrate=(e,r)=>{i.set(n(e),{catalog:r,compiled:t(r)})};for(let[e,t]of Object.entries(r.catalogs??{}))hydrate(e,t);let load=async t=>{let o=n(t);if(i.has(o))return!1;let s=a.get(o);if(s)return await s,!1;if(!r.loadCatalog)throw new e(`No catalog source provided for locale "${o}".`);let c=Promise.resolve(r.loadCatalog(o)).then(e=>{hydrate(o,e),a.delete(o)},e=>{throw a.delete(o),e});return a.set(o,c),await c,!0};return{catalogMap(){return new Map([...i].map(([e,{compiled:t}])=>[e,t]))},hydrate,isLoaded(e){return i.has(n(e))},load,state(e){let t={};for(let[e,{catalog:n}]of i)t[e]=n;return{catalogs:t,locale:e,version:1}}}}export{createCatalogStore};
1
+ import { LinguaMissingCatalogError as e } from "./errors.js";
2
+ import { compileCatalog as t } from "./_catalog.js";
3
+ import { canonicalLocale as n } from "./_locale.js";
4
+ //#region src/_resources.ts
5
+ function createCatalogStore(r) {
6
+ let i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Map(), hydrate = (e, r) => {
7
+ i.set(n(e), {
8
+ catalog: r,
9
+ compiled: t(r)
10
+ });
11
+ };
12
+ for (let [e, t] of Object.entries(r.catalogs ?? {})) hydrate(e, t);
13
+ let load = async (t) => {
14
+ let o = n(t);
15
+ if (i.has(o)) return !1;
16
+ let s = a.get(o);
17
+ if (s) return await s, !1;
18
+ if (!r.loadCatalog) throw new e(`No catalog source provided for locale "${o}".`);
19
+ let c = Promise.resolve(r.loadCatalog(o)).then((e) => {
20
+ hydrate(o, e), a.delete(o);
21
+ }, (e) => {
22
+ throw a.delete(o), e;
23
+ });
24
+ return a.set(o, c), await c, !0;
25
+ };
26
+ return {
27
+ catalogMap() {
28
+ return new Map([...i].map(([e, { compiled: t }]) => [e, t]));
29
+ },
30
+ hydrate,
31
+ isLoaded(e) {
32
+ return i.has(n(e));
33
+ },
34
+ load,
35
+ state(e) {
36
+ let t = {};
37
+ for (let [e, { catalog: n }] of i) t[e] = n;
38
+ return {
39
+ catalogs: t,
40
+ locale: e,
41
+ version: 1
42
+ };
43
+ }
44
+ };
45
+ }
46
+ //#endregion
47
+ export { createCatalogStore };
48
+
2
49
  //# sourceMappingURL=_resources.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"_resources.js","names":[],"sources":["../src/_resources.ts"],"sourcesContent":["import { type CompiledCatalog, compileCatalog } from './_catalog';\nimport { canonicalLocale } from './_locale';\nimport { LinguaMissingCatalogError } from './errors';\nimport type { Catalog, Catalogs, Locale, TranslationState } from './types';\n\ntype CatalogStoreOptions<C extends Catalog> = {\n readonly catalogs?: Catalogs<C>;\n readonly loadCatalog?: (locale: Locale) => Promise<C> | C;\n};\n\n/** One catalog state machine owns loaded catalogs and in-flight loading work. */\nexport function createCatalogStore<C extends Catalog>(options: CatalogStoreOptions<C>) {\n const loaded = new Map<Locale, { readonly catalog: C; readonly compiled: CompiledCatalog }>();\n const tasks = new Map<Locale, Promise<void>>();\n\n const hydrate = (locale: Locale, catalog: C): void => {\n loaded.set(canonicalLocale(locale), { catalog, compiled: compileCatalog(catalog) });\n };\n\n for (const [locale, catalog] of Object.entries(options.catalogs ?? {})) hydrate(locale, catalog);\n\n const load = async (requestedLocale: Locale): Promise<boolean> => {\n const locale = canonicalLocale(requestedLocale);\n\n if (loaded.has(locale)) return false;\n\n const existing = tasks.get(locale);\n\n if (existing) {\n await existing;\n\n return false;\n }\n\n if (!options.loadCatalog) {\n throw new LinguaMissingCatalogError(`No catalog source provided for locale \"${locale}\".`);\n }\n\n const task = Promise.resolve(options.loadCatalog(locale)).then(\n (catalog) => {\n hydrate(locale, catalog);\n tasks.delete(locale);\n },\n (error: unknown) => {\n tasks.delete(locale);\n throw error;\n },\n );\n\n tasks.set(locale, task);\n await task;\n\n return true;\n };\n\n return {\n catalogMap(): ReadonlyMap<Locale, CompiledCatalog> {\n return new Map([...loaded].map(([locale, { compiled }]) => [locale, compiled]));\n },\n hydrate,\n isLoaded(locale: Locale): boolean {\n return loaded.has(canonicalLocale(locale));\n },\n load,\n state(locale: Locale): TranslationState<C> {\n const catalogs: Catalogs<C> = {};\n\n for (const [loadedLocale, { catalog }] of loaded) catalogs[loadedLocale] = catalog;\n\n return { catalogs, locale, version: 1 };\n },\n };\n}\n"],"mappings":"sJAWA,SAAgB,mBAAsC,EAAiC,CACrF,IAAM,EAAS,IAAI,IACb,EAAQ,IAAI,IAEZ,SAAW,EAAgB,IAAqB,CACpD,EAAO,IAAI,EAAgB,CAAM,EAAG,CAAE,UAAS,SAAU,EAAe,CAAO,CAAE,CAAC,CACpF,EAEA,IAAK,GAAM,CAAC,EAAQ,KAAY,OAAO,QAAQ,EAAQ,UAAY,CAAC,CAAC,EAAG,QAAQ,EAAQ,CAAO,EAE/F,IAAM,KAAO,KAAO,IAA8C,CAChE,IAAM,EAAS,EAAgB,CAAe,EAE9C,GAAI,EAAO,IAAI,CAAM,EAAG,MAAO,GAE/B,IAAM,EAAW,EAAM,IAAI,CAAM,EAEjC,GAAI,EAGF,OAFA,MAAM,EAEC,GAGT,GAAI,CAAC,EAAQ,YACX,MAAM,IAAI,EAA0B,0CAA0C,EAAO,GAAG,EAG1F,IAAM,EAAO,QAAQ,QAAQ,EAAQ,YAAY,CAAM,CAAC,CAAC,CAAC,KACvD,GAAY,CACX,QAAQ,EAAQ,CAAO,EACvB,EAAM,OAAO,CAAM,CACrB,EACC,GAAmB,CAElB,MADA,EAAM,OAAO,CAAM,EACb,CACR,CACF,EAKA,OAHA,EAAM,IAAI,EAAQ,CAAI,EACtB,MAAM,EAEC,EACT,EAEA,MAAO,CACL,YAAmD,CACjD,OAAO,IAAI,IAAI,CAAC,GAAG,CAAM,CAAC,CAAC,KAAK,CAAC,EAAQ,CAAE,eAAgB,CAAC,EAAQ,CAAQ,CAAC,CAAC,CAChF,EACA,QACA,SAAS,EAAyB,CAChC,OAAO,EAAO,IAAI,EAAgB,CAAM,CAAC,CAC3C,EACA,KACA,MAAM,EAAqC,CACzC,IAAM,EAAwB,CAAC,EAE/B,IAAK,GAAM,CAAC,EAAc,CAAE,cAAc,EAAQ,EAAS,GAAgB,EAE3E,MAAO,CAAE,WAAU,SAAQ,QAAS,CAAE,CACxC,CACF,CACF"}
1
+ {"version":3,"file":"_resources.js","names":["loaded","tasks","canonicalLocale","locale","compileCatalog","catalog","options","requestedLocale","existing","LinguaMissingCatalogError","task","error","compiled","catalogs","loadedLocale"],"sources":["../src/_resources.ts"],"sourcesContent":["import { type CompiledCatalog, compileCatalog } from './_catalog';\nimport { canonicalLocale } from './_locale';\nimport { LinguaMissingCatalogError } from './errors';\nimport type { Catalog, Catalogs, Locale, TranslationState } from './types';\n\ntype CatalogStoreOptions<C extends Catalog> = {\n readonly catalogs?: Catalogs<C>;\n readonly loadCatalog?: (locale: Locale) => Promise<C> | C;\n};\n\n/** One catalog state machine owns loaded catalogs and in-flight loading work. */\nexport function createCatalogStore<C extends Catalog>(options: CatalogStoreOptions<C>) {\n const loaded = new Map<Locale, { readonly catalog: C; readonly compiled: CompiledCatalog }>();\n const tasks = new Map<Locale, Promise<void>>();\n\n const hydrate = (locale: Locale, catalog: C): void => {\n loaded.set(canonicalLocale(locale), { catalog, compiled: compileCatalog(catalog) });\n };\n\n for (const [locale, catalog] of Object.entries(options.catalogs ?? {})) hydrate(locale, catalog);\n\n const load = async (requestedLocale: Locale): Promise<boolean> => {\n const locale = canonicalLocale(requestedLocale);\n\n if (loaded.has(locale)) return false;\n\n const existing = tasks.get(locale);\n\n if (existing) {\n await existing;\n\n return false;\n }\n\n if (!options.loadCatalog) {\n throw new LinguaMissingCatalogError(`No catalog source provided for locale \"${locale}\".`);\n }\n\n const task = Promise.resolve(options.loadCatalog(locale)).then(\n (catalog) => {\n hydrate(locale, catalog);\n tasks.delete(locale);\n },\n (error: unknown) => {\n tasks.delete(locale);\n throw error;\n },\n );\n\n tasks.set(locale, task);\n await task;\n\n return true;\n };\n\n return {\n catalogMap(): ReadonlyMap<Locale, CompiledCatalog> {\n return new Map([...loaded].map(([locale, { compiled }]) => [locale, compiled]));\n },\n hydrate,\n isLoaded(locale: Locale): boolean {\n return loaded.has(canonicalLocale(locale));\n },\n load,\n state(locale: Locale): TranslationState<C> {\n const catalogs: Catalogs<C> = {};\n\n for (const [loadedLocale, { catalog }] of loaded) catalogs[loadedLocale] = catalog;\n\n return { catalogs, locale, version: 1 };\n },\n };\n}\n"],"mappings":";;;;AAWA,SAAgB,mBAAsC,GAAiC;CACrF,IAAMA,oBAAS,IAAI,IAAyE,GACtFC,oBAAQ,IAAI,IAA2B,GAEvC,WAAW,GAAgB,MAAqB;EACpD,EAAO,IAAIC,EAAgBC,CAAM,GAAG;GAAE;GAAS,UAAUC,EAAeC,CAAO;EAAE,CAAC;CACpF;CAEA,KAAK,IAAM,CAACF,GAAQE,MAAY,OAAO,QAAQC,EAAQ,YAAY,CAAC,CAAC,GAAG,QAAQH,GAAQE,CAAO;CAE/F,IAAM,OAAO,OAAO,MAA8C;EAChE,IAAMF,IAASD,EAAgBK,CAAe;EAE9C,IAAIP,EAAO,IAAIG,CAAM,GAAG,OAAO;EAE/B,IAAMK,IAAWP,EAAM,IAAIE,CAAM;EAEjC,IAAIK,GAGF,OAFA,MAAMA,GAEC;EAGT,IAAI,CAACF,EAAQ,aACX,MAAM,IAAIG,EAA0B,0CAA0CN,EAAO,GAAG;EAG1F,IAAMO,IAAO,QAAQ,QAAQJ,EAAQ,YAAYH,CAAM,CAAC,CAAC,CAAC,MACvD,MAAY;GAEX,AADA,QAAQA,GAAQE,CAAO,GACvBJ,EAAM,OAAOE,CAAM;EACrB,IACC,MAAmB;GAElB,MADAF,EAAM,OAAOE,CAAM,GACbQ;EACR,CACF;EAKA,OAHAV,EAAM,IAAIE,GAAQO,CAAI,GACtB,MAAMA,GAEC;CACT;CAEA,OAAO;EACL,aAAmD;GACjD,OAAO,IAAI,IAAI,CAAC,GAAGV,CAAM,CAAC,CAAC,KAAK,CAACG,GAAQ,EAAE,mBAAgB,CAACA,GAAQS,CAAQ,CAAC,CAAC;EAChF;EACA;EACA,SAAS,GAAyB;GAChC,OAAOZ,EAAO,IAAIE,EAAgBC,CAAM,CAAC;EAC3C;EACA;EACA,MAAM,GAAqC;GACzC,IAAMU,IAAwB,CAAC;GAE/B,KAAK,IAAM,CAACC,GAAc,EAAE,iBAAcd,GAAQ,EAASc,KAAgBT;GAE3E,OAAO;IAAE;IAAU;IAAQ,SAAS;GAAE;EACxC;CACF;AACF"}
@@ -1,2 +1,2 @@
1
- var e=/\{([\p{ID_Continue}-]+)\}/gu;function compileTemplate(t){let n=[],r=0;for(let i of t.matchAll(e)){let e=i.index??0;e>r&&n.push(t.slice(r,e)),n.push({value:i[1]}),r=e+i[0].length}return r<t.length&&n.push(t.slice(r)),n}function renderText(e,t,n){return e.map(e=>{if(typeof e==`string`)return e;let r=Object.hasOwn(t,e.value)?t[e.value]:void 0;return r==null?n(e.value):String(r)}).join(``)}function renderParts(e,t,n){let r=[];for(let i of e){if(typeof i==`string`){i!==``&&r.push({type:`text`,value:i});continue}Object.hasOwn(t,i.value)?r.push({type:`value`,value:t[i.value]}):r.push({type:`text`,value:n(i.value)})}return r}exports.compileTemplate=compileTemplate,exports.renderParts=renderParts,exports.renderText=renderText;
1
+ var e=/\{([\p{ID_Continue}-]+)\}/gu;function compileTemplate(t){let n=[],r=0;for(let i of t.matchAll(e)){let e=i.index??0;e>r&&n.push(t.slice(r,e)),n.push({value:i[1]}),r=e+i[0].length}return r<t.length&&n.push(t.slice(r)),n}function renderText(e,t,n){return e.map(e=>{if(typeof e==`string`)return e;let r=Object.hasOwn(t,e.value)?t[e.value]:void 0;return r==null?n(e.value):String(r)}).join(``)}function renderParts(e,t,n){let r=[];for(let i of e)typeof i==`string`?i!==``&&r.push({type:`text`,value:i}):Object.hasOwn(t,i.value)?r.push({type:`value`,value:t[i.value]}):r.push({type:`text`,value:n(i.value)});return r}exports.compileTemplate=compileTemplate,exports.renderParts=renderParts,exports.renderText=renderText;
2
2
  //# sourceMappingURL=_template.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"_template.cjs","names":[],"sources":["../src/_template.ts"],"sourcesContent":["import type { Part } from './types';\n\nexport type TemplatePart = string | { readonly value: string };\nexport type Template = readonly TemplatePart[];\n\nconst interpolation = /\\{([\\p{ID_Continue}-]+)\\}/gu;\n\nexport function compileTemplate(value: string): Template {\n const parts: TemplatePart[] = [];\n let offset = 0;\n\n for (const match of value.matchAll(interpolation)) {\n const index = match.index ?? 0;\n\n if (index > offset) parts.push(value.slice(offset, index));\n\n parts.push({ value: match[1] });\n offset = index + match[0].length;\n }\n\n if (offset < value.length) parts.push(value.slice(offset));\n\n return parts;\n}\n\nexport function renderText(\n parts: Template,\n values: Record<string, unknown>,\n missing: (name: string) => string,\n): string {\n return parts\n .map((part) => {\n if (typeof part === 'string') return part;\n\n const value = Object.hasOwn(values, part.value) ? values[part.value] : undefined;\n\n return value == null ? missing(part.value) : String(value);\n })\n .join('');\n}\n\nexport function renderParts<V>(\n parts: Template,\n values: Record<string, V | number>,\n missing: (name: string) => string,\n): Array<Part<V | number>> {\n const result: Array<Part<V | number>> = [];\n\n for (const part of parts) {\n if (typeof part === 'string') {\n if (part !== '') result.push({ type: 'text', value: part });\n\n continue;\n }\n\n if (Object.hasOwn(values, part.value)) {\n result.push({ type: 'value', value: values[part.value]! as V | number });\n } else {\n result.push({ type: 'text', value: missing(part.value) });\n }\n }\n\n return result;\n}\n"],"mappings":"AAKA,IAAM,EAAgB,8BAEtB,SAAgB,gBAAgB,EAAyB,CACvD,IAAM,EAAwB,CAAC,EAC3B,EAAS,EAEb,IAAK,IAAM,KAAS,EAAM,SAAS,CAAa,EAAG,CACjD,IAAM,EAAQ,EAAM,OAAS,EAEzB,EAAQ,GAAQ,EAAM,KAAK,EAAM,MAAM,EAAQ,CAAK,CAAC,EAEzD,EAAM,KAAK,CAAE,MAAO,EAAM,EAAG,CAAC,EAC9B,EAAS,EAAQ,EAAM,EAAE,CAAC,MAC5B,CAIA,OAFI,EAAS,EAAM,QAAQ,EAAM,KAAK,EAAM,MAAM,CAAM,CAAC,EAElD,CACT,CAEA,SAAgB,WACd,EACA,EACA,EACQ,CACR,OAAO,EACJ,IAAK,GAAS,CACb,GAAI,OAAO,GAAS,SAAU,OAAO,EAErC,IAAM,EAAQ,OAAO,OAAO,EAAQ,EAAK,KAAK,EAAI,EAAO,EAAK,OAAS,IAAA,GAEvE,OAAO,GAAS,KAAO,EAAQ,EAAK,KAAK,EAAI,OAAO,CAAK,CAC3D,CAAC,CAAC,CACD,KAAK,EAAE,CACZ,CAEA,SAAgB,YACd,EACA,EACA,EACyB,CACzB,IAAM,EAAkC,CAAC,EAEzC,IAAK,IAAM,KAAQ,EAAO,CACxB,GAAI,OAAO,GAAS,SAAU,CACxB,IAAS,IAAI,EAAO,KAAK,CAAE,KAAM,OAAQ,MAAO,CAAK,CAAC,EAE1D,QACF,CAEI,OAAO,OAAO,EAAQ,EAAK,KAAK,EAClC,EAAO,KAAK,CAAE,KAAM,QAAS,MAAO,EAAO,EAAK,MAAsB,CAAC,EAEvE,EAAO,KAAK,CAAE,KAAM,OAAQ,MAAO,EAAQ,EAAK,KAAK,CAAE,CAAC,CAE5D,CAEA,OAAO,CACT"}
1
+ {"version":3,"file":"_template.cjs","names":["interpolation","parts","offset","match","value","index","part","values","missing","result"],"sources":["../src/_template.ts"],"sourcesContent":["import type { Part } from './types';\n\nexport type TemplatePart = string | { readonly value: string };\nexport type Template = readonly TemplatePart[];\n\nconst interpolation = /\\{([\\p{ID_Continue}-]+)\\}/gu;\n\nexport function compileTemplate(value: string): Template {\n const parts: TemplatePart[] = [];\n let offset = 0;\n\n for (const match of value.matchAll(interpolation)) {\n const index = match.index ?? 0;\n\n if (index > offset) parts.push(value.slice(offset, index));\n\n parts.push({ value: match[1] });\n offset = index + match[0].length;\n }\n\n if (offset < value.length) parts.push(value.slice(offset));\n\n return parts;\n}\n\nexport function renderText(\n parts: Template,\n values: Record<string, unknown>,\n missing: (name: string) => string,\n): string {\n return parts\n .map((part) => {\n if (typeof part === 'string') return part;\n\n const value = Object.hasOwn(values, part.value) ? values[part.value] : undefined;\n\n return value == null ? missing(part.value) : String(value);\n })\n .join('');\n}\n\nexport function renderParts<V>(\n parts: Template,\n values: Record<string, V | number>,\n missing: (name: string) => string,\n): Array<Part<V | number>> {\n const result: Array<Part<V | number>> = [];\n\n for (const part of parts) {\n if (typeof part === 'string') {\n if (part !== '') result.push({ type: 'text', value: part });\n\n continue;\n }\n\n if (Object.hasOwn(values, part.value)) {\n result.push({ type: 'value', value: values[part.value]! as V | number });\n } else {\n result.push({ type: 'text', value: missing(part.value) });\n }\n }\n\n return result;\n}\n"],"mappings":"AAKA,IAAMA,EAAgB,8BAEtB,SAAgB,gBAAgB,EAAyB,CACvD,IAAMC,EAAwB,CAAC,EAC3BC,EAAS,EAEb,IAAK,IAAMC,KAASC,EAAM,SAASJ,CAAa,EAAG,CACjD,IAAMK,EAAQF,EAAM,OAAS,EAEzBE,EAAQH,GAAQD,EAAM,KAAKG,EAAM,MAAMF,EAAQG,CAAK,CAAC,EAEzDJ,EAAM,KAAK,CAAE,MAAOE,EAAM,EAAG,CAAC,EAC9B,EAASE,EAAQF,EAAM,EAAE,CAAC,MAC5B,CAIA,OAFID,EAASE,EAAM,QAAQH,EAAM,KAAKG,EAAM,MAAMF,CAAM,CAAC,EAElDD,CACT,CAEA,SAAgB,WACd,EACA,EACA,EACQ,CACR,OAAOA,EACJ,IAAK,GAAS,CACb,GAAI,OAAOK,GAAS,SAAU,OAAOA,EAErC,IAAMF,EAAQ,OAAO,OAAOG,EAAQD,EAAK,KAAK,EAAIC,EAAOD,EAAK,OAAS,IAAA,GAEvE,OAAOF,GAAS,KAAOI,EAAQF,EAAK,KAAK,EAAI,OAAOF,CAAK,CAC3D,CAAC,CAAC,CACD,KAAK,EAAE,CACZ,CAEA,SAAgB,YACd,EACA,EACA,EACyB,CACzB,IAAMK,EAAkC,CAAC,EAEzC,IAAK,IAAMH,KAAQL,EACb,OAAOK,GAAS,SACdA,IAAS,IAAIG,EAAO,KAAK,CAAE,KAAM,OAAQ,MAAOH,CAAK,CAAC,EAKxD,OAAO,OAAOC,EAAQD,EAAK,KAAK,EAClCG,EAAO,KAAK,CAAE,KAAM,QAAS,MAAOF,EAAOD,EAAK,MAAsB,CAAC,EAEvEG,EAAO,KAAK,CAAE,KAAM,OAAQ,MAAOD,EAAQF,EAAK,KAAK,CAAE,CAAC,EAI5D,OAAOG,CACT,C"}
package/dist/_template.js CHANGED
@@ -1,2 +1,35 @@
1
- var e=/\{([\p{ID_Continue}-]+)\}/gu;function compileTemplate(t){let n=[],r=0;for(let i of t.matchAll(e)){let e=i.index??0;e>r&&n.push(t.slice(r,e)),n.push({value:i[1]}),r=e+i[0].length}return r<t.length&&n.push(t.slice(r)),n}function renderText(e,t,n){return e.map(e=>{if(typeof e==`string`)return e;let r=Object.hasOwn(t,e.value)?t[e.value]:void 0;return r==null?n(e.value):String(r)}).join(``)}function renderParts(e,t,n){let r=[];for(let i of e){if(typeof i==`string`){i!==``&&r.push({type:`text`,value:i});continue}Object.hasOwn(t,i.value)?r.push({type:`value`,value:t[i.value]}):r.push({type:`text`,value:n(i.value)})}return r}export{compileTemplate,renderParts,renderText};
1
+ //#region src/_template.ts
2
+ var e = /\{([\p{ID_Continue}-]+)\}/gu;
3
+ function compileTemplate(t) {
4
+ let n = [], r = 0;
5
+ for (let i of t.matchAll(e)) {
6
+ let e = i.index ?? 0;
7
+ e > r && n.push(t.slice(r, e)), n.push({ value: i[1] }), r = e + i[0].length;
8
+ }
9
+ return r < t.length && n.push(t.slice(r)), n;
10
+ }
11
+ function renderText(e, t, n) {
12
+ return e.map((e) => {
13
+ if (typeof e == "string") return e;
14
+ let r = Object.hasOwn(t, e.value) ? t[e.value] : void 0;
15
+ return r == null ? n(e.value) : String(r);
16
+ }).join("");
17
+ }
18
+ function renderParts(e, t, n) {
19
+ let r = [];
20
+ for (let i of e) typeof i == "string" ? i !== "" && r.push({
21
+ type: "text",
22
+ value: i
23
+ }) : Object.hasOwn(t, i.value) ? r.push({
24
+ type: "value",
25
+ value: t[i.value]
26
+ }) : r.push({
27
+ type: "text",
28
+ value: n(i.value)
29
+ });
30
+ return r;
31
+ }
32
+ //#endregion
33
+ export { compileTemplate, renderParts, renderText };
34
+
2
35
  //# sourceMappingURL=_template.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"_template.js","names":[],"sources":["../src/_template.ts"],"sourcesContent":["import type { Part } from './types';\n\nexport type TemplatePart = string | { readonly value: string };\nexport type Template = readonly TemplatePart[];\n\nconst interpolation = /\\{([\\p{ID_Continue}-]+)\\}/gu;\n\nexport function compileTemplate(value: string): Template {\n const parts: TemplatePart[] = [];\n let offset = 0;\n\n for (const match of value.matchAll(interpolation)) {\n const index = match.index ?? 0;\n\n if (index > offset) parts.push(value.slice(offset, index));\n\n parts.push({ value: match[1] });\n offset = index + match[0].length;\n }\n\n if (offset < value.length) parts.push(value.slice(offset));\n\n return parts;\n}\n\nexport function renderText(\n parts: Template,\n values: Record<string, unknown>,\n missing: (name: string) => string,\n): string {\n return parts\n .map((part) => {\n if (typeof part === 'string') return part;\n\n const value = Object.hasOwn(values, part.value) ? values[part.value] : undefined;\n\n return value == null ? missing(part.value) : String(value);\n })\n .join('');\n}\n\nexport function renderParts<V>(\n parts: Template,\n values: Record<string, V | number>,\n missing: (name: string) => string,\n): Array<Part<V | number>> {\n const result: Array<Part<V | number>> = [];\n\n for (const part of parts) {\n if (typeof part === 'string') {\n if (part !== '') result.push({ type: 'text', value: part });\n\n continue;\n }\n\n if (Object.hasOwn(values, part.value)) {\n result.push({ type: 'value', value: values[part.value]! as V | number });\n } else {\n result.push({ type: 'text', value: missing(part.value) });\n }\n }\n\n return result;\n}\n"],"mappings":"AAKA,IAAM,EAAgB,8BAEtB,SAAgB,gBAAgB,EAAyB,CACvD,IAAM,EAAwB,CAAC,EAC3B,EAAS,EAEb,IAAK,IAAM,KAAS,EAAM,SAAS,CAAa,EAAG,CACjD,IAAM,EAAQ,EAAM,OAAS,EAEzB,EAAQ,GAAQ,EAAM,KAAK,EAAM,MAAM,EAAQ,CAAK,CAAC,EAEzD,EAAM,KAAK,CAAE,MAAO,EAAM,EAAG,CAAC,EAC9B,EAAS,EAAQ,EAAM,EAAE,CAAC,MAC5B,CAIA,OAFI,EAAS,EAAM,QAAQ,EAAM,KAAK,EAAM,MAAM,CAAM,CAAC,EAElD,CACT,CAEA,SAAgB,WACd,EACA,EACA,EACQ,CACR,OAAO,EACJ,IAAK,GAAS,CACb,GAAI,OAAO,GAAS,SAAU,OAAO,EAErC,IAAM,EAAQ,OAAO,OAAO,EAAQ,EAAK,KAAK,EAAI,EAAO,EAAK,OAAS,IAAA,GAEvE,OAAO,GAAS,KAAO,EAAQ,EAAK,KAAK,EAAI,OAAO,CAAK,CAC3D,CAAC,CAAC,CACD,KAAK,EAAE,CACZ,CAEA,SAAgB,YACd,EACA,EACA,EACyB,CACzB,IAAM,EAAkC,CAAC,EAEzC,IAAK,IAAM,KAAQ,EAAO,CACxB,GAAI,OAAO,GAAS,SAAU,CACxB,IAAS,IAAI,EAAO,KAAK,CAAE,KAAM,OAAQ,MAAO,CAAK,CAAC,EAE1D,QACF,CAEI,OAAO,OAAO,EAAQ,EAAK,KAAK,EAClC,EAAO,KAAK,CAAE,KAAM,QAAS,MAAO,EAAO,EAAK,MAAsB,CAAC,EAEvE,EAAO,KAAK,CAAE,KAAM,OAAQ,MAAO,EAAQ,EAAK,KAAK,CAAE,CAAC,CAE5D,CAEA,OAAO,CACT"}
1
+ {"version":3,"file":"_template.js","names":["interpolation","parts","offset","match","value","index","part","values","missing","result"],"sources":["../src/_template.ts"],"sourcesContent":["import type { Part } from './types';\n\nexport type TemplatePart = string | { readonly value: string };\nexport type Template = readonly TemplatePart[];\n\nconst interpolation = /\\{([\\p{ID_Continue}-]+)\\}/gu;\n\nexport function compileTemplate(value: string): Template {\n const parts: TemplatePart[] = [];\n let offset = 0;\n\n for (const match of value.matchAll(interpolation)) {\n const index = match.index ?? 0;\n\n if (index > offset) parts.push(value.slice(offset, index));\n\n parts.push({ value: match[1] });\n offset = index + match[0].length;\n }\n\n if (offset < value.length) parts.push(value.slice(offset));\n\n return parts;\n}\n\nexport function renderText(\n parts: Template,\n values: Record<string, unknown>,\n missing: (name: string) => string,\n): string {\n return parts\n .map((part) => {\n if (typeof part === 'string') return part;\n\n const value = Object.hasOwn(values, part.value) ? values[part.value] : undefined;\n\n return value == null ? missing(part.value) : String(value);\n })\n .join('');\n}\n\nexport function renderParts<V>(\n parts: Template,\n values: Record<string, V | number>,\n missing: (name: string) => string,\n): Array<Part<V | number>> {\n const result: Array<Part<V | number>> = [];\n\n for (const part of parts) {\n if (typeof part === 'string') {\n if (part !== '') result.push({ type: 'text', value: part });\n\n continue;\n }\n\n if (Object.hasOwn(values, part.value)) {\n result.push({ type: 'value', value: values[part.value]! as V | number });\n } else {\n result.push({ type: 'text', value: missing(part.value) });\n }\n }\n\n return result;\n}\n"],"mappings":";AAKA,IAAMA,IAAgB;AAEtB,SAAgB,gBAAgB,GAAyB;CACvD,IAAMC,IAAwB,CAAC,GAC3BC,IAAS;CAEb,KAAK,IAAMC,KAASC,EAAM,SAASJ,CAAa,GAAG;EACjD,IAAMK,IAAQF,EAAM,SAAS;EAK7B,AAHIE,IAAQH,KAAQD,EAAM,KAAKG,EAAM,MAAMF,GAAQG,CAAK,CAAC,GAEzDJ,EAAM,KAAK,EAAE,OAAOE,EAAM,GAAG,CAAC,GAC9B,IAASE,IAAQF,EAAM,EAAE,CAAC;CAC5B;CAIA,OAFID,IAASE,EAAM,UAAQH,EAAM,KAAKG,EAAM,MAAMF,CAAM,CAAC,GAElDD;AACT;AAEA,SAAgB,WACd,GACA,GACA,GACQ;CACR,OAAOA,EACJ,KAAK,MAAS;EACb,IAAI,OAAOK,KAAS,UAAU,OAAOA;EAErC,IAAMF,IAAQ,OAAO,OAAOG,GAAQD,EAAK,KAAK,IAAIC,EAAOD,EAAK,SAAS,KAAA;EAEvE,OAAOF,KAAS,OAAOI,EAAQF,EAAK,KAAK,IAAI,OAAOF,CAAK;CAC3D,CAAC,CAAC,CACD,KAAK,EAAE;AACZ;AAEA,SAAgB,YACd,GACA,GACA,GACyB;CACzB,IAAMK,IAAkC,CAAC;CAEzC,KAAK,IAAMH,KAAQL,GACjB,AAAI,OAAOK,KAAS,WACdA,MAAS,MAAIG,EAAO,KAAK;EAAE,MAAM;EAAQ,OAAOH;CAAK,CAAC,IAKxD,OAAO,OAAOC,GAAQD,EAAK,KAAK,IAClCG,EAAO,KAAK;EAAE,MAAM;EAAS,OAAOF,EAAOD,EAAK;CAAsB,CAAC,IAEvEG,EAAO,KAAK;EAAE,MAAM;EAAQ,OAAOD,EAAQF,EAAK,KAAK;CAAE,CAAC;CAI5D,OAAOG;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.cjs","names":[],"sources":["../src/catalog.ts"],"sourcesContent":["import { compileCatalog } from './_catalog';\nimport type { Catalog, MessageKey } from './types';\n\n/** Enumerate every message key in a catalog as a dotted path.\n *\n * Traverses nested grouping objects and explicit `{ plural: ... }` messages,\n * producing the same dotted paths that `MessageKey<C>` represents at the type\n * level. Use this to derive key arrays from the catalog itself instead of\n * maintaining a parallel list that can go stale.\n *\n * Pass any catalog subtree to enumerate group-scoped keys. For an `I18n`\n * instance, pass its current locale catalog explicitly.\n *\n * @example\n * ```ts\n * const messages = {\n * nav: { home: '...', settings: '...' },\n * };\n * const keys = catalogKeys(messages); // ['nav.home', 'nav.settings']\n * const navKeys = catalogKeys(messages.nav); // ['home', 'settings']\n *\n * // From an i18n instance: read the current locale's catalog first\n * const i18n = createI18n({ catalogs: { en: messages }, locale: 'en' });\n * const state = i18n.serialize();\n * const allKeys = catalogKeys(state.catalogs[state.locale]);\n * ```\n */\nexport function catalogKeys<C extends Catalog>(catalog: C): ReadonlyArray<MessageKey<C>> {\n return [...compileCatalog(catalog).keys()] as unknown as ReadonlyArray<MessageKey<C>>;\n}\n"],"mappings":"kCA2BA,SAAgB,YAA+B,EAA0C,CACvF,MAAO,CAAC,GAAG,EAAA,eAAe,CAAO,CAAC,CAAC,KAAK,CAAC,CAC3C"}
1
+ {"version":3,"file":"catalog.cjs","names":["compileCatalog","require__catalog","catalog"],"sources":["../src/catalog.ts"],"sourcesContent":["import { compileCatalog } from './_catalog';\nimport type { Catalog, MessageKey } from './types';\n\n/** Enumerate every message key in a catalog as a dotted path.\n *\n * Traverses nested grouping objects and explicit `{ plural: ... }` messages,\n * producing the same dotted paths that `MessageKey<C>` represents at the type\n * level. Use this to derive key arrays from the catalog itself instead of\n * maintaining a parallel list that can go stale.\n *\n * Pass any catalog subtree to enumerate group-scoped keys. For an `I18n`\n * instance, pass its current locale catalog explicitly.\n *\n * @example\n * ```ts\n * const messages = {\n * nav: { home: '...', settings: '...' },\n * };\n * const keys = catalogKeys(messages); // ['nav.home', 'nav.settings']\n * const navKeys = catalogKeys(messages.nav); // ['home', 'settings']\n *\n * // From an i18n instance: read the current locale's catalog first\n * const i18n = createI18n({ catalogs: { en: messages }, locale: 'en' });\n * const state = i18n.serialize();\n * const allKeys = catalogKeys(state.catalogs[state.locale]);\n * ```\n */\nexport function catalogKeys<C extends Catalog>(catalog: C): ReadonlyArray<MessageKey<C>> {\n return [...compileCatalog(catalog).keys()] as unknown as ReadonlyArray<MessageKey<C>>;\n}\n"],"mappings":"A,kCA2BA,SAAgB,YAA+B,EAA0C,CACvF,MAAO,CAAC,GAAGA,EAAAA,eAAeE,CAAO,CAAC,CAAC,KAAK,CAAC,CAC3C,C"}
package/dist/catalog.js CHANGED
@@ -1,2 +1,9 @@
1
- import{compileCatalog as e}from"./_catalog.js";function catalogKeys(t){return[...e(t).keys()]}export{catalogKeys};
1
+ import { compileCatalog as e } from "./_catalog.js";
2
+ //#region src/catalog.ts
3
+ function catalogKeys(t) {
4
+ return [...e(t).keys()];
5
+ }
6
+ //#endregion
7
+ export { catalogKeys };
8
+
2
9
  //# sourceMappingURL=catalog.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.js","names":[],"sources":["../src/catalog.ts"],"sourcesContent":["import { compileCatalog } from './_catalog';\nimport type { Catalog, MessageKey } from './types';\n\n/** Enumerate every message key in a catalog as a dotted path.\n *\n * Traverses nested grouping objects and explicit `{ plural: ... }` messages,\n * producing the same dotted paths that `MessageKey<C>` represents at the type\n * level. Use this to derive key arrays from the catalog itself instead of\n * maintaining a parallel list that can go stale.\n *\n * Pass any catalog subtree to enumerate group-scoped keys. For an `I18n`\n * instance, pass its current locale catalog explicitly.\n *\n * @example\n * ```ts\n * const messages = {\n * nav: { home: '...', settings: '...' },\n * };\n * const keys = catalogKeys(messages); // ['nav.home', 'nav.settings']\n * const navKeys = catalogKeys(messages.nav); // ['home', 'settings']\n *\n * // From an i18n instance: read the current locale's catalog first\n * const i18n = createI18n({ catalogs: { en: messages }, locale: 'en' });\n * const state = i18n.serialize();\n * const allKeys = catalogKeys(state.catalogs[state.locale]);\n * ```\n */\nexport function catalogKeys<C extends Catalog>(catalog: C): ReadonlyArray<MessageKey<C>> {\n return [...compileCatalog(catalog).keys()] as unknown as ReadonlyArray<MessageKey<C>>;\n}\n"],"mappings":"+CA2BA,SAAgB,YAA+B,EAA0C,CACvF,MAAO,CAAC,GAAG,EAAe,CAAO,CAAC,CAAC,KAAK,CAAC,CAC3C"}
1
+ {"version":3,"file":"catalog.js","names":["compileCatalog","catalog"],"sources":["../src/catalog.ts"],"sourcesContent":["import { compileCatalog } from './_catalog';\nimport type { Catalog, MessageKey } from './types';\n\n/** Enumerate every message key in a catalog as a dotted path.\n *\n * Traverses nested grouping objects and explicit `{ plural: ... }` messages,\n * producing the same dotted paths that `MessageKey<C>` represents at the type\n * level. Use this to derive key arrays from the catalog itself instead of\n * maintaining a parallel list that can go stale.\n *\n * Pass any catalog subtree to enumerate group-scoped keys. For an `I18n`\n * instance, pass its current locale catalog explicitly.\n *\n * @example\n * ```ts\n * const messages = {\n * nav: { home: '...', settings: '...' },\n * };\n * const keys = catalogKeys(messages); // ['nav.home', 'nav.settings']\n * const navKeys = catalogKeys(messages.nav); // ['home', 'settings']\n *\n * // From an i18n instance: read the current locale's catalog first\n * const i18n = createI18n({ catalogs: { en: messages }, locale: 'en' });\n * const state = i18n.serialize();\n * const allKeys = catalogKeys(state.catalogs[state.locale]);\n * ```\n */\nexport function catalogKeys<C extends Catalog>(catalog: C): ReadonlyArray<MessageKey<C>> {\n return [...compileCatalog(catalog).keys()] as unknown as ReadonlyArray<MessageKey<C>>;\n}\n"],"mappings":";;AA2BA,SAAgB,YAA+B,GAA0C;CACvF,OAAO,CAAC,GAAGA,EAAeC,CAAO,CAAC,CAAC,KAAK,CAAC;AAC3C"}
@@ -1 +1 @@
1
- {"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["export 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\nexport class LinguaDisposedError extends LinguaError {\n constructor() {\n super('Operation called on a disposed i18n instance.');\n }\n}\n\nexport class LinguaInvalidCatalogError extends LinguaError {}\nexport class LinguaInvalidLocaleError extends LinguaError {}\nexport class LinguaInvalidPluralCountError extends LinguaError {}\nexport class LinguaInvalidStateError extends LinguaError {}\nexport class LinguaMissingCatalogError extends LinguaError {}\nexport class LinguaMissingKeyError extends LinguaError {}\nexport class LinguaMissingValueError extends LinguaError {}\n"],"mappings":"AAAA,IAAa,YAAb,cAAiC,KAAM,CACrC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CACF,EAEa,oBAAb,cAAyC,WAAY,CACnD,aAAc,CACZ,MAAM,+CAA+C,CACvD,CACF,EAEa,0BAAb,cAA+C,WAAY,CAAC,EAC/C,yBAAb,cAA8C,WAAY,CAAC,EAC9C,8BAAb,cAAmD,WAAY,CAAC,EACnD,wBAAb,cAA6C,WAAY,CAAC,EAC7C,0BAAb,cAA+C,WAAY,CAAC,EAC/C,sBAAb,cAA2C,WAAY,CAAC,EAC3C,wBAAb,cAA6C,WAAY,CAAC"}
1
+ {"version":3,"file":"errors.cjs","names":["message","opts"],"sources":["../src/errors.ts"],"sourcesContent":["export 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\nexport class LinguaDisposedError extends LinguaError {\n constructor() {\n super('Operation called on a disposed i18n instance.');\n }\n}\n\nexport class LinguaInvalidCatalogError extends LinguaError {}\nexport class LinguaInvalidLocaleError extends LinguaError {}\nexport class LinguaInvalidPluralCountError extends LinguaError {}\nexport class LinguaInvalidStateError extends LinguaError {}\nexport class LinguaMissingCatalogError extends LinguaError {}\nexport class LinguaMissingKeyError extends LinguaError {}\nexport class LinguaMissingValueError extends LinguaError {}\n"],"mappings":"AAAA,IAAa,YAAb,cAAiC,KAAM,CACrC,YAAY,EAAiB,EAAqB,CAChD,MAAMA,EAASC,CAAI,EACnB,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CACF,EAEa,oBAAb,cAAyC,WAAY,CACnD,aAAc,CACZ,MAAM,+CAA+C,CACvD,CACF,EAEa,0BAAb,cAA+C,WAAY,CAAC,EAC/C,yBAAb,cAA8C,WAAY,CAAC,EAC9C,8BAAb,cAAmD,WAAY,CAAC,EACnD,wBAAb,cAA6C,WAAY,CAAC,EAC7C,0BAAb,cAA+C,WAAY,CAAC,EAC/C,sBAAb,cAA2C,WAAY,CAAC,EAC3C,wBAAb,cAA6C,WAAY,CAAC,E"}
package/dist/errors.js CHANGED
@@ -1,2 +1,14 @@
1
- var LinguaError=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},LinguaDisposedError=class extends LinguaError{constructor(){super(`Operation called on a disposed i18n instance.`)}},LinguaInvalidCatalogError=class extends LinguaError{},LinguaInvalidLocaleError=class extends LinguaError{},LinguaInvalidPluralCountError=class extends LinguaError{},LinguaInvalidStateError=class extends LinguaError{},LinguaMissingCatalogError=class extends LinguaError{},LinguaMissingKeyError=class extends LinguaError{},LinguaMissingValueError=class extends LinguaError{};export{LinguaDisposedError,LinguaError,LinguaInvalidCatalogError,LinguaInvalidLocaleError,LinguaInvalidPluralCountError,LinguaInvalidStateError,LinguaMissingCatalogError,LinguaMissingKeyError,LinguaMissingValueError};
1
+ //#region src/errors.ts
2
+ var LinguaError = class extends Error {
3
+ constructor(e, t) {
4
+ super(e, t), this.name = new.target.name, Object.setPrototypeOf(this, new.target.prototype);
5
+ }
6
+ }, LinguaDisposedError = class extends LinguaError {
7
+ constructor() {
8
+ super("Operation called on a disposed i18n instance.");
9
+ }
10
+ }, LinguaInvalidCatalogError = class extends LinguaError {}, LinguaInvalidLocaleError = class extends LinguaError {}, LinguaInvalidPluralCountError = class extends LinguaError {}, LinguaInvalidStateError = class extends LinguaError {}, LinguaMissingCatalogError = class extends LinguaError {}, LinguaMissingKeyError = class extends LinguaError {}, LinguaMissingValueError = class extends LinguaError {};
11
+ //#endregion
12
+ export { LinguaDisposedError, LinguaError, LinguaInvalidCatalogError, LinguaInvalidLocaleError, LinguaInvalidPluralCountError, LinguaInvalidStateError, LinguaMissingCatalogError, LinguaMissingKeyError, LinguaMissingValueError };
13
+
2
14
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["export 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\nexport class LinguaDisposedError extends LinguaError {\n constructor() {\n super('Operation called on a disposed i18n instance.');\n }\n}\n\nexport class LinguaInvalidCatalogError extends LinguaError {}\nexport class LinguaInvalidLocaleError extends LinguaError {}\nexport class LinguaInvalidPluralCountError extends LinguaError {}\nexport class LinguaInvalidStateError extends LinguaError {}\nexport class LinguaMissingCatalogError extends LinguaError {}\nexport class LinguaMissingKeyError extends LinguaError {}\nexport class LinguaMissingValueError extends LinguaError {}\n"],"mappings":"AAAA,IAAa,YAAb,cAAiC,KAAM,CACrC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CACF,EAEa,oBAAb,cAAyC,WAAY,CACnD,aAAc,CACZ,MAAM,+CAA+C,CACvD,CACF,EAEa,0BAAb,cAA+C,WAAY,CAAC,EAC/C,yBAAb,cAA8C,WAAY,CAAC,EAC9C,8BAAb,cAAmD,WAAY,CAAC,EACnD,wBAAb,cAA6C,WAAY,CAAC,EAC7C,0BAAb,cAA+C,WAAY,CAAC,EAC/C,sBAAb,cAA2C,WAAY,CAAC,EAC3C,wBAAb,cAA6C,WAAY,CAAC"}
1
+ {"version":3,"file":"errors.js","names":["message","opts"],"sources":["../src/errors.ts"],"sourcesContent":["export 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\nexport class LinguaDisposedError extends LinguaError {\n constructor() {\n super('Operation called on a disposed i18n instance.');\n }\n}\n\nexport class LinguaInvalidCatalogError extends LinguaError {}\nexport class LinguaInvalidLocaleError extends LinguaError {}\nexport class LinguaInvalidPluralCountError extends LinguaError {}\nexport class LinguaInvalidStateError extends LinguaError {}\nexport class LinguaMissingCatalogError extends LinguaError {}\nexport class LinguaMissingKeyError extends LinguaError {}\nexport class LinguaMissingValueError extends LinguaError {}\n"],"mappings":";AAAA,IAAa,cAAb,cAAiC,MAAM;CACrC,YAAY,GAAiB,GAAqB;EAGhD,AAFA,MAAMA,GAASC,CAAI,GACnB,KAAK,OAAO,WAAW,MACvB,OAAO,eAAe,MAAM,WAAW,SAAS;CAClD;AACF,GAEa,sBAAb,cAAyC,YAAY;CACnD,cAAc;EACZ,MAAM,+CAA+C;CACvD;AACF,GAEa,4BAAb,cAA+C,YAAY,CAAC,GAC/C,2BAAb,cAA8C,YAAY,CAAC,GAC9C,gCAAb,cAAmD,YAAY,CAAC,GACnD,0BAAb,cAA6C,YAAY,CAAC,GAC7C,4BAAb,cAA+C,YAAY,CAAC,GAC/C,wBAAb,cAA2C,YAAY,CAAC,GAC3C,0BAAb,cAA6C,YAAY,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"format.cjs","names":[],"sources":["../src/format.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\nimport { getOrCreate } from './_bounded-cache';\n\nconst FORMAT_CACHE_MAX = 128;\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 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 // Options that cannot be serialized (circular references, BigInt) get no cache key at\n // all, so each call builds a fresh formatter: sharing one instance across different\n // options would silently format wrong.\n function cachedKey(locale: string, options?: object): string | undefined {\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 return undefined;\n }\n }\n\n function cached<T>(cache: Map<string, T>, key: string | undefined, build: () => T): T {\n return key === undefined ? build() : getOrCreate(cache, key, FORMAT_CACHE_MAX, build);\n }\n\n return {\n currency(value, currency, options) {\n const locale = getLocale();\n const opts: Intl.NumberFormatOptions = { ...options, currency, style: 'currency' };\n\n return cached(currencyCache, cachedKey(locale, opts), () => new Intl.NumberFormat(locale, opts)).format(value);\n },\n\n date(value, options) {\n const locale = getLocale();\n\n return cached(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 cached(\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 cached(\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 cached(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 cached(\n relativeCache,\n cachedKey(locale, options),\n () => new Intl.RelativeTimeFormat(locale, options),\n ).format(value, unit);\n },\n };\n}\n"],"mappings":"2GA6BA,IAAM,EAAmB,IAsDnB,EAA6C,CACjD,QACA,SACA,QACA,OACA,QACA,UACA,UACA,eACA,eACA,aACF,EAEM,EAAuD,CAC3D,KAAM,IACN,MAAO,IACP,aAAc,KACd,aAAc,KACd,QAAS,MACT,OAAQ,KACR,YAAa,KACb,QAAS,IACT,MAAO,IACP,MAAO,GACT,EAOA,SAAS,gBAAgB,EAA8B,CACrD,OAAO,EAAe,IAAK,GAAS,CAClC,IAAM,EAAS,EAAM,GAErB,OAAO,OAAO,GAAW,SAAW,GAAG,IAAS,EAAgB,KAAU,IAAA,EAC5E,CAAC,CAAC,CACC,OAAQ,GAAyB,IAAS,IAAA,EAAS,CAAC,CACpD,KAAK,GAAG,CACb,CAQA,SAAgB,gBAAgB,EAA4C,CAC1E,IAAM,EAAc,IAAI,IAClB,EAAgB,IAAI,IACpB,EAAY,IAAI,IAChB,EAAgB,IAAI,IACpB,EAAY,IAAI,IAChB,EAAgB,IAAI,IAEpB,EAAY,OAAO,GAAW,aAAiB,EAAS,EAK9D,SAAS,UAAU,EAAgB,EAAsC,CACvE,GAAI,CAAC,EAAS,OAAO,EAErB,IAAM,EAAkC,CAAC,EAEzC,IAAK,IAAM,KAAO,OAAO,KAAK,CAAkC,CAAC,CAAC,KAAK,EACrE,EAAO,GAAQ,EAAoC,GAGrD,GAAI,CACF,MAAO,GAAG,EAAO,GAAG,KAAK,UAAU,CAAM,GAC3C,MAAQ,CACN,MACF,CACF,CAEA,SAAS,OAAU,EAAuB,EAAyB,EAAmB,CACpF,OAAO,IAAQ,IAAA,GAAY,EAAM,EAAI,EAAA,YAAY,EAAO,EAAK,EAAkB,CAAK,CACtF,CAEA,MAAO,CACL,SAAS,EAAO,EAAU,EAAS,CACjC,IAAM,EAAS,EAAU,EACnB,EAAiC,CAAE,GAAG,EAAS,WAAU,MAAO,UAAW,EAEjF,OAAO,OAAO,EAAe,UAAU,EAAQ,CAAI,MAAS,IAAI,KAAK,aAAa,EAAQ,CAAI,CAAC,CAAC,CAAC,OAAO,CAAK,CAC/G,EAEA,KAAK,EAAO,EAAS,CACnB,IAAM,EAAS,EAAU,EAEzB,OAAO,OAAO,EAAW,UAAU,EAAQ,CAAO,MAAS,IAAI,KAAK,eAAe,EAAQ,CAAO,CAAC,CAAC,CAAC,OACnG,CACF,CACF,EAEA,SAAS,EAAO,EAAS,CACvB,IAAM,EAAS,EAAU,EACnB,EAAU,KAMhB,OAJK,EAAQ,eAET,EAAe,MAAO,GAAM,EAAM,KAAO,IAAA,EAAS,EAAU,GAEzD,OACL,EACA,UAAU,EAAQ,CAAO,MACnB,IAAI,EAAQ,eAAgB,EAAQ,CAAO,CACnD,CAAC,CAAC,OAAO,CAAK,EARsB,gBAAgB,CAAK,CAS3D,EAEA,KAAK,EAAO,EAAS,CACnB,IAAM,EAAS,EAAU,EACnB,EAAQ,EAAM,IAAK,GAAM,OAAO,CAAC,CAAC,EAKlC,EAAQ,GAAS,OAAS,OAC1B,EAAO,GAAS,OAAS,KAAO,cAAgB,cAEtD,OAAO,OACL,EACA,UAAU,EAAQ,CAAE,QAAO,MAAK,CAAC,MAC3B,IAAI,KAAK,WAAW,EAAQ,CAAE,QAAO,MAAK,CAAC,CACnD,CAAC,CAAC,OAAO,CAAK,CAChB,EAEA,OAAO,EAAO,EAAS,CACrB,IAAM,EAAS,EAAU,EAEzB,OAAO,OAAO,EAAa,UAAU,EAAQ,CAAO,MAAS,IAAI,KAAK,aAAa,EAAQ,CAAO,CAAC,CAAC,CAAC,OACnG,CACF,CACF,EAEA,SAAS,EAAO,EAAM,EAAS,CAC7B,IAAM,EAAS,EAAU,EAEzB,OAAO,OACL,EACA,UAAU,EAAQ,CAAO,MACnB,IAAI,KAAK,mBAAmB,EAAQ,CAAO,CACnD,CAAC,CAAC,OAAO,EAAO,CAAI,CACtB,CACF,CACF"}
1
+ {"version":3,"file":"format.cjs","names":["getOrCreate","require__bounded_cache","FORMAT_CACHE_MAX","DURATION_UNITS","DURATION_LABELS","amount","value","unit","part","numberCache","currencyCache","dateCache","relativeCache","listCache","durationCache","getLocale","source","options","locale","sorted","key","build","cache","opts","IntlExt","u","items","v","style","type"],"sources":["../src/format.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\nimport { getOrCreate } from './_bounded-cache';\n\nconst FORMAT_CACHE_MAX = 128;\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 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 // Options that cannot be serialized (circular references, BigInt) get no cache key at\n // all, so each call builds a fresh formatter: sharing one instance across different\n // options would silently format wrong.\n function cachedKey(locale: string, options?: object): string | undefined {\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 return undefined;\n }\n }\n\n function cached<T>(cache: Map<string, T>, key: string | undefined, build: () => T): T {\n return key === undefined ? build() : getOrCreate(cache, key, FORMAT_CACHE_MAX, build);\n }\n\n return {\n currency(value, currency, options) {\n const locale = getLocale();\n const opts: Intl.NumberFormatOptions = { ...options, currency, style: 'currency' };\n\n return cached(currencyCache, cachedKey(locale, opts), () => new Intl.NumberFormat(locale, opts)).format(value);\n },\n\n date(value, options) {\n const locale = getLocale();\n\n return cached(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 cached(\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 cached(\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 cached(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 cached(\n relativeCache,\n cachedKey(locale, options),\n () => new Intl.RelativeTimeFormat(locale, options),\n ).format(value, unit);\n },\n };\n}\n"],"mappings":"A,2GA6BA,IAAME,EAAmB,IAsDnBC,EAA6C,CACjD,QACA,SACA,QACA,OACA,QACA,UACA,UACA,eACA,eACA,aACF,EAEMC,EAAuD,CAC3D,KAAM,IACN,MAAO,IACP,aAAc,KACd,aAAc,KACd,QAAS,MACT,OAAQ,KACR,YAAa,KACb,QAAS,IACT,MAAO,IACP,MAAO,GACT,EAOA,SAAS,gBAAgB,EAA8B,CACrD,OAAOD,EAAe,IAAK,GAAS,CAClC,IAAME,EAASC,EAAMC,GAErB,OAAO,OAAOF,GAAW,SAAW,GAAGA,IAASD,EAAgBG,KAAU,IAAA,EAC5E,CAAC,CAAC,CACC,OAAQ,GAAyBC,IAAS,IAAA,EAAS,CAAC,CACpD,KAAK,GAAG,CACb,CAQA,SAAgB,gBAAgB,EAA4C,CAC1E,IAAMC,EAAc,IAAI,IAClBC,EAAgB,IAAI,IACpBC,EAAY,IAAI,IAChBC,EAAgB,IAAI,IACpBC,EAAY,IAAI,IAChBC,EAAgB,IAAI,IAEpBC,EAAY,OAAOC,GAAW,aAAiBA,EAASA,EAK9D,SAAS,UAAU,EAAgB,EAAsC,CACvE,GAAI,CAACC,EAAS,OAAOC,EAErB,IAAMC,EAAkC,CAAC,EAEzC,IAAK,IAAMC,KAAO,OAAO,KAAKH,CAAkC,CAAC,CAAC,KAAK,EACrE,EAAOG,GAAQH,EAAoCG,GAGrD,GAAI,CACF,MAAO,GAAGF,EAAO,GAAG,KAAK,UAAUC,CAAM,GAC3C,MAAQ,CACN,MACF,CACF,CAEA,SAAS,OAAU,EAAuB,EAAyB,EAAmB,CACpF,OAAOC,IAAQ,IAAA,GAAYC,EAAM,EAAIrB,EAAAA,YAAYsB,EAAOF,EAAKlB,EAAkBmB,CAAK,CACtF,CAEA,MAAO,CACL,SAAS,EAAO,EAAU,EAAS,CACjC,IAAMH,EAASH,EAAU,EACnBQ,EAAiC,CAAE,GAAGN,EAAS,WAAU,MAAO,UAAW,EAEjF,OAAO,OAAOP,EAAe,UAAUQ,EAAQK,CAAI,MAAS,IAAI,KAAK,aAAaL,EAAQK,CAAI,CAAC,CAAC,CAAC,OAAOjB,CAAK,CAC/G,EAEA,KAAK,EAAO,EAAS,CACnB,IAAMY,EAASH,EAAU,EAEzB,OAAO,OAAOJ,EAAW,UAAUO,EAAQD,CAAO,MAAS,IAAI,KAAK,eAAeC,EAAQD,CAAO,CAAC,CAAC,CAAC,OACnGX,CACF,CACF,EAEA,SAAS,EAAO,EAAS,CACvB,IAAMY,EAASH,EAAU,EACnBS,EAAU,KAMhB,OAJKA,EAAQ,eAETrB,EAAe,MAAO,GAAMG,EAAMmB,KAAO,IAAA,EAAS,EAAU,GAEzD,OACLX,EACA,UAAUI,EAAQD,CAAO,MACnB,IAAIO,EAAQ,eAAgBN,EAAQD,CAAO,CACnD,CAAC,CAAC,OAAOX,CAAK,EARsB,gBAAgBA,CAAK,CAS3D,EAEA,KAAK,EAAO,EAAS,CACnB,IAAMY,EAASH,EAAU,EACnBW,EAAQpB,EAAM,IAAK,GAAM,OAAOqB,CAAC,CAAC,EAKlCC,EAAQX,GAAS,OAAS,OAC1BY,EAAOZ,GAAS,OAAS,KAAO,cAAgB,cAEtD,OAAO,OACLJ,EACA,UAAUK,EAAQ,CAAE,QAAO,MAAK,CAAC,MAC3B,IAAI,KAAK,WAAWA,EAAQ,CAAE,QAAO,MAAK,CAAC,CACnD,CAAC,CAAC,OAAOQ,CAAK,CAChB,EAEA,OAAO,EAAO,EAAS,CACrB,IAAMR,EAASH,EAAU,EAEzB,OAAO,OAAON,EAAa,UAAUS,EAAQD,CAAO,MAAS,IAAI,KAAK,aAAaC,EAAQD,CAAO,CAAC,CAAC,CAAC,OACnGX,CACF,CACF,EAEA,SAAS,EAAO,EAAM,EAAS,CAC7B,IAAMY,EAASH,EAAU,EAEzB,OAAO,OACLH,EACA,UAAUM,EAAQD,CAAO,MACnB,IAAI,KAAK,mBAAmBC,EAAQD,CAAO,CACnD,CAAC,CAAC,OAAOX,EAAOC,CAAI,CACtB,CACF,CACF,C"}