@vielzeug/lingua 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"_catalog.cjs","names":[],"sources":["../src/_catalog.ts"],"sourcesContent":["import type { Catalog, CatalogNode, PluralMessage } from './types';\n\nimport { compileTemplate, type Template } from './_template';\nimport { LinguaInvalidCatalogError } from './errors';\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\nfunction 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":"6DAKA,IAAM,EAAa,IAAI,IAAI,CAAC,YAAa,cAAe,WAAW,CAAC,EAOpE,SAAS,EAAgB,EAA0C,CACjE,OAAO,OAAO,GAAS,YAAY,GAAiB,OAAO,OAAO,EAAM,QAAQ,CAClF,CAGA,SAAgB,EAAe,EAAmC,CAChE,IAAM,EAAW,IAAI,IAEf,GAAS,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,EAAgB,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,EAAM,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,EAAM,EAAO,CAAG,CAClB,CAEA,OAAO,CACT"}
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\nfunction 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,SAAS,EAAgB,EAA0C,CACjE,OAAO,OAAO,GAAS,YAAY,GAAiB,OAAO,OAAO,EAAM,QAAQ,CAClF,CAGA,SAAgB,EAAe,EAAmC,CAChE,IAAM,EAAW,IAAI,IAEf,GAAS,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,EAAgB,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,EAAM,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,EAAM,EAAO,CAAG,CAClB,CAEA,OAAO,CACT"}
@@ -1,5 +1,5 @@
1
- import type { Catalog } from './types';
2
1
  import { type Template } from './_template';
2
+ import type { Catalog } from './types';
3
3
  export type CompiledText = {
4
4
  readonly kind: 'text';
5
5
  readonly template: Template;
@@ -1 +1 @@
1
- {"version":3,"file":"_catalog.d.ts","sourceRoot":"","sources":["../src/_catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAA8B,MAAM,SAAS,CAAC;AAEnE,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAK7D,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC;AAClF,MAAM,MAAM,cAAc,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AACxG,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,YAAY,CAAC;AAC5D,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAMnE,4GAA4G;AAC5G,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,eAAe,CAsDhE"}
1
+ {"version":3,"file":"_catalog.d.ts","sourceRoot":"","sources":["../src/_catalog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,KAAK,EAAE,OAAO,EAA8B,MAAM,SAAS,CAAC;AAInE,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC;AAClF,MAAM,MAAM,cAAc,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AACxG,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,YAAY,CAAC;AAC5D,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAMnE,4GAA4G;AAC5G,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,eAAe,CAsDhE"}
@@ -1 +1 @@
1
- {"version":3,"file":"_catalog.js","names":[],"sources":["../src/_catalog.ts"],"sourcesContent":["import type { Catalog, CatalogNode, PluralMessage } from './types';\n\nimport { compileTemplate, type Template } from './_template';\nimport { LinguaInvalidCatalogError } from './errors';\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\nfunction 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":";;;AAKA,IAAM,oBAAa,IAAI,IAAI;CAAC;CAAa;CAAe;AAAW,CAAC;AAOpE,SAAS,EAAgB,GAA0C;CACjE,OAAO,OAAO,KAAS,cAAY,KAAiB,OAAO,OAAO,GAAM,QAAQ;AAClF;AAGA,SAAgB,EAAe,GAAmC;CAChE,IAAM,oBAAW,IAAI,IAA6B,GAE5C,KAAS,GAAmB,MAAyB;EACzD,IAAI,OAAO,KAAS,UAAU;GAC5B,EAAS,IAAI,GAAQ;IAAE,MAAM;IAAQ,UAAU,EAAgB,CAAI;GAAE,CAAC;GAEtE;EACF;EAEA,IAAI,OAAO,KAAS,aAAY,KAAiB,MAAM,QAAQ,CAAI,GACjE,MAAM,IAAI,EAA0B,iBAAiB,EAAO,+CAA+C;EAG7G,IAAI,EAAgB,CAAI,GAAG;GACzB,IAAI,QAAQ,QAAQ,CAAI,CAAC,CAAC,MAAM,MAAQ,MAAQ,QAAQ,GACtD,MAAM,IAAI,EAA0B,mBAAmB,EAAO,yCAAyC;GAGzG,IAAI,OAAO,EAAK,UAAW,YAAY,EAAK,WAAW,QAAQ,MAAM,QAAQ,EAAK,MAAM,GACtF,MAAM,IAAI,EAA0B,mBAAmB,EAAO,0CAA0C;GAG1G,IAAM,oBAAQ,IAAI,IAAsB;GAExC,KAAK,IAAM,CAAC,GAAM,MAAa,OAAO,QAAQ,EAAK,MAAM,GAAG;IAC1D,IAAI,OAAO,KAAa,UACtB,MAAM,IAAI,EAA0B,gBAAgB,EAAO,GAAG,EAAK,oBAAoB;IAGzF,EAAM,IAAI,GAAM,EAAgB,CAAQ,CAAC;GAC3C;GAEA,EAAS,IAAI,GAAQ;IAAE;IAAO,MAAM;GAAS,CAAC;GAE9C;EACF;EAEA,KAAK,IAAM,CAAC,GAAK,MAAU,OAAO,QAAQ,CAAI,GAAG;GAC/C,IAAI,EAAW,IAAI,CAAG,GACpB,MAAM,IAAI,EAA0B,gBAAgB,EAAI,eAAe;GAGzE,EAAM,GAAO,IAAS,GAAG,EAAO,GAAG,MAAQ,CAAG;EAChD;CACF;CAEA,KAAK,IAAM,CAAC,GAAK,MAAU,OAAO,QAAQ,CAAO,GAAG;EAClD,IAAI,EAAW,IAAI,CAAG,GAAG,MAAM,IAAI,EAA0B,gBAAgB,EAAI,eAAe;EAEhG,EAAM,GAAO,CAAG;CAClB;CAEA,OAAO;AACT"}
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\nfunction 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,IAAM,oBAAa,IAAI,IAAI;CAAC;CAAa;CAAe;AAAW,CAAC;AAOpE,SAAS,EAAgB,GAA0C;CACjE,OAAO,OAAO,KAAS,cAAY,KAAiB,OAAO,OAAO,GAAM,QAAQ;AAClF;AAGA,SAAgB,EAAe,GAAmC;CAChE,IAAM,oBAAW,IAAI,IAA6B,GAE5C,KAAS,GAAmB,MAAyB;EACzD,IAAI,OAAO,KAAS,UAAU;GAC5B,EAAS,IAAI,GAAQ;IAAE,MAAM;IAAQ,UAAU,EAAgB,CAAI;GAAE,CAAC;GAEtE;EACF;EAEA,IAAI,OAAO,KAAS,aAAY,KAAiB,MAAM,QAAQ,CAAI,GACjE,MAAM,IAAI,EAA0B,iBAAiB,EAAO,+CAA+C;EAG7G,IAAI,EAAgB,CAAI,GAAG;GACzB,IAAI,QAAQ,QAAQ,CAAI,CAAC,CAAC,MAAM,MAAQ,MAAQ,QAAQ,GACtD,MAAM,IAAI,EAA0B,mBAAmB,EAAO,yCAAyC;GAGzG,IAAI,OAAO,EAAK,UAAW,YAAY,EAAK,WAAW,QAAQ,MAAM,QAAQ,EAAK,MAAM,GACtF,MAAM,IAAI,EAA0B,mBAAmB,EAAO,0CAA0C;GAG1G,IAAM,oBAAQ,IAAI,IAAsB;GAExC,KAAK,IAAM,CAAC,GAAM,MAAa,OAAO,QAAQ,EAAK,MAAM,GAAG;IAC1D,IAAI,OAAO,KAAa,UACtB,MAAM,IAAI,EAA0B,gBAAgB,EAAO,GAAG,EAAK,oBAAoB;IAGzF,EAAM,IAAI,GAAM,EAAgB,CAAQ,CAAC;GAC3C;GAEA,EAAS,IAAI,GAAQ;IAAE;IAAO,MAAM;GAAS,CAAC;GAE9C;EACF;EAEA,KAAK,IAAM,CAAC,GAAK,MAAU,OAAO,QAAQ,CAAI,GAAG;GAC/C,IAAI,EAAW,IAAI,CAAG,GACpB,MAAM,IAAI,EAA0B,gBAAgB,EAAI,eAAe;GAGzE,EAAM,GAAO,IAAS,GAAG,EAAO,GAAG,MAAQ,CAAG;EAChD;CACF;CAEA,KAAK,IAAM,CAAC,GAAK,MAAU,OAAO,QAAQ,CAAO,GAAG;EAClD,IAAI,EAAW,IAAI,CAAG,GAAG,MAAM,IAAI,EAA0B,gBAAgB,EAAI,eAAe;EAEhG,EAAM,GAAO,CAAG;CAClB;CAEA,OAAO;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"_locale.cjs","names":[],"sources":["../src/_locale.ts"],"sourcesContent":["import type { Locale } from './types';\n\nimport { LinguaInvalidLocaleError } from './errors';\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":"gCAIA,IAAM,EAAc,IAAI,IAExB,SAAgB,EAAgB,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,EAAY,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":[],"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,EAAgB,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,EAAY,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 +1 @@
1
- {"version":3,"file":"_locale.d.ts","sourceRoot":"","sources":["../src/_locale.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAMtC,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAUtD;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,EAAE,CAY1F;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC,cAAc,CAUnG"}
1
+ {"version":3,"file":"_locale.d.ts","sourceRoot":"","sources":["../src/_locale.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAItC,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAUtD;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,EAAE,CAY1F;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC,cAAc,CAUnG"}
@@ -1 +1 @@
1
- {"version":3,"file":"_locale.js","names":[],"sources":["../src/_locale.ts"],"sourcesContent":["import type { Locale } from './types';\n\nimport { LinguaInvalidLocaleError } from './errors';\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":";;AAIA,IAAM,oBAAc,IAAI,IAA8B;AAEtD,SAAgB,EAAgB,GAAwB;CACtD,IAAI;EACF,IAAM,CAAC,KAAa,KAAK,oBAAoB,CAAM;EAEnD,IAAI,GAAW,OAAO;CACxB,QAAQ,CAER;CAEA,MAAM,IAAI,EAAyB,+BAA+B,EAAO,GAAG;AAC9E;AAEA,SAAgB,EAAY,GAAgB,GAAgD;CAC1F,IAAM,oBAAQ,IAAI,IAAY;CAE9B,KAAK,IAAM,KAAa,CAAC,GAAQ,GAAG,CAAQ,GAAG;EAC7C,IAAM,IAAQ,EAAU,MAAM,GAAG;EAEjC,KAAK,IAAI,IAAS,EAAM,QAAQ,IAAS,GAAG,KAC1C,EAAM,IAAI,EAAM,MAAM,GAAG,CAAM,CAAC,CAAC,KAAK,GAAG,CAAC;CAE9C;CAEA,OAAO,CAAC,GAAG,CAAK;AAClB;AAEA,SAAgB,EAAe,GAAgB,GAAe,GAAuC;CACnG,IAAM,IAAM,GAAG,EAAO,GAAG,IAAU,YAAY,cAC3C,IAAQ,EAAY,IAAI,CAAG;CAO/B,OALK,MACH,IAAQ,IAAI,KAAK,YAAY,GAAQ,EAAE,MAAM,IAAU,YAAY,WAAW,CAAC,GAC/E,EAAY,IAAI,GAAK,CAAK,IAGrB,EAAM,OAAO,CAAK;AAC3B"}
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":";;AAGA,IAAM,oBAAc,IAAI,IAA8B;AAEtD,SAAgB,EAAgB,GAAwB;CACtD,IAAI;EACF,IAAM,CAAC,KAAa,KAAK,oBAAoB,CAAM;EAEnD,IAAI,GAAW,OAAO;CACxB,QAAQ,CAER;CAEA,MAAM,IAAI,EAAyB,+BAA+B,EAAO,GAAG;AAC9E;AAEA,SAAgB,EAAY,GAAgB,GAAgD;CAC1F,IAAM,oBAAQ,IAAI,IAAY;CAE9B,KAAK,IAAM,KAAa,CAAC,GAAQ,GAAG,CAAQ,GAAG;EAC7C,IAAM,IAAQ,EAAU,MAAM,GAAG;EAEjC,KAAK,IAAI,IAAS,EAAM,QAAQ,IAAS,GAAG,KAC1C,EAAM,IAAI,EAAM,MAAM,GAAG,CAAM,CAAC,CAAC,KAAK,GAAG,CAAC;CAE9C;CAEA,OAAO,CAAC,GAAG,CAAK;AAClB;AAEA,SAAgB,EAAe,GAAgB,GAAe,GAAuC;CACnG,IAAM,IAAM,GAAG,EAAO,GAAG,IAAU,YAAY,cAC3C,IAAQ,EAAY,IAAI,CAAG;CAO/B,OALK,MACH,IAAQ,IAAI,KAAK,YAAY,GAAQ,EAAE,MAAM,IAAU,YAAY,WAAW,CAAC,GAC/E,EAAY,IAAI,GAAK,CAAK,IAGrB,EAAM,OAAO,CAAK;AAC3B"}
@@ -1 +1 @@
1
- {"version":3,"file":"_resources.cjs","names":[],"sources":["../src/_resources.ts"],"sourcesContent":["import type { Catalog, CatalogSources, TranslationState, LoadedCatalogs, Locale } from './types';\n\nimport { type CompiledCatalog, compileCatalog } from './_catalog';\nimport { canonicalLocale } from './_locale';\nimport { LinguaMissingCatalogError } from './errors';\n\n/** One catalog state machine owns static sources, lazy sources, and in-flight work. */\nexport function createCatalogStore<C extends Catalog>(sources: CatalogSources<C>) {\n const definitions = new Map<Locale, C | (() => Promise<C>)>();\n const loaded = new Map<Locale, { readonly catalog: C; readonly compiled: CompiledCatalog }>();\n const tasks = new Map<Locale, Promise<void>>();\n\n for (const [locale, source] of Object.entries(sources)) definitions.set(canonicalLocale(locale), source);\n\n const add = (locale: Locale, catalog: C): void => {\n loaded.set(locale, { catalog, compiled: compileCatalog(catalog) });\n };\n\n for (const [locale, source] of definitions) {\n if (typeof source !== 'function') add(locale, source);\n }\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 source = definitions.get(locale);\n\n if (!source) throw new LinguaMissingCatalogError(`Catalog has no source for locale \"${locale}\".`);\n\n if (typeof source !== 'function') {\n add(locale, source);\n\n return true;\n }\n\n const existing = tasks.get(locale);\n\n if (existing) {\n await existing;\n\n return false;\n }\n\n const task = source().then(\n (catalog) => {\n add(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 isLoaded(locale: Locale): boolean {\n return loaded.has(canonicalLocale(locale));\n },\n load,\n state(locale: Locale): TranslationState<C> {\n const catalogs: LoadedCatalogs<C> = {};\n\n for (const [loadedLocale, { catalog }] of loaded) catalogs[loadedLocale] = catalog;\n\n return { catalogs, locale, version: 3 };\n },\n };\n}\n"],"mappings":"uFAOA,SAAgB,EAAsC,EAA4B,CAChF,IAAM,EAAc,IAAI,IAClB,EAAS,IAAI,IACb,EAAQ,IAAI,IAElB,IAAK,GAAM,CAAC,EAAQ,KAAW,OAAO,QAAQ,CAAO,EAAG,EAAY,IAAI,EAAA,gBAAgB,CAAM,EAAG,CAAM,EAEvG,IAAM,GAAO,EAAgB,IAAqB,CAChD,EAAO,IAAI,EAAQ,CAAE,UAAS,SAAU,EAAA,eAAe,CAAO,CAAE,CAAC,CACnE,EAEA,IAAK,GAAM,CAAC,EAAQ,KAAW,EACzB,OAAO,GAAW,YAAY,EAAI,EAAQ,CAAM,EA2CtD,MAAO,CACL,YAAmD,CACjD,OAAO,IAAI,IAAI,CAAC,GAAG,CAAM,CAAC,CAAC,KAAK,CAAC,EAAQ,CAAE,eAAgB,CAAC,EAAQ,CAAQ,CAAC,CAAC,CAChF,EACA,SAAS,EAAyB,CAChC,OAAO,EAAO,IAAI,EAAA,gBAAgB,CAAM,CAAC,CAC3C,EACA,UA/CkB,IAA8C,CAChE,IAAM,EAAS,EAAA,gBAAgB,CAAe,EAE9C,GAAI,EAAO,IAAI,CAAM,EAAG,MAAO,GAE/B,IAAM,EAAS,EAAY,IAAI,CAAM,EAErC,GAAI,CAAC,EAAQ,MAAM,IAAI,EAAA,0BAA0B,qCAAqC,EAAO,GAAG,EAEhG,GAAI,OAAO,GAAW,WAGpB,OAFA,EAAI,EAAQ,CAAM,EAEX,GAGT,IAAM,EAAW,EAAM,IAAI,CAAM,EAEjC,GAAI,EAGF,OAFA,MAAM,EAEC,GAGT,IAAM,EAAO,EAAO,CAAC,CAAC,KACnB,GAAY,CACX,EAAI,EAAQ,CAAO,EACnB,EAAM,OAAO,CAAM,CACrB,EACC,GAAmB,CAElB,MADA,EAAM,OAAO,CAAM,EACb,CACR,CACF,EAKA,OAHA,EAAM,IAAI,EAAQ,CAAI,EACtB,MAAM,EAEC,EACT,EAUE,MAAM,EAAqC,CACzC,IAAM,EAA8B,CAAC,EAErC,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":[],"sources":["../src/_resources.ts"],"sourcesContent":["import { type CompiledCatalog, compileCatalog } from './_catalog';\nimport { canonicalLocale } from './_locale';\nimport { LinguaMissingCatalogError } from './errors';\nimport type { Catalog, CatalogSources, Catalogs, Locale, TranslationState } from './types';\n\n/** One catalog state machine owns static sources, lazy sources, and in-flight work. */\nexport function createCatalogStore<C extends Catalog>(sources: CatalogSources<C>) {\n const definitions = new Map<Locale, C | (() => Promise<C>)>();\n const loaded = new Map<Locale, { readonly catalog: C; readonly compiled: CompiledCatalog }>();\n const tasks = new Map<Locale, Promise<void>>();\n\n for (const [locale, source] of Object.entries(sources)) definitions.set(canonicalLocale(locale), source);\n\n const add = (locale: Locale, catalog: C): void => {\n loaded.set(locale, { catalog, compiled: compileCatalog(catalog) });\n };\n\n for (const [locale, source] of definitions) {\n if (typeof source !== 'function') add(locale, source);\n }\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 source = definitions.get(locale);\n\n if (!source) throw new LinguaMissingCatalogError(`Catalog has no source for locale \"${locale}\".`);\n\n if (typeof source !== 'function') {\n add(locale, source);\n\n return true;\n }\n\n const existing = tasks.get(locale);\n\n if (existing) {\n await existing;\n\n return false;\n }\n\n const task = source().then(\n (catalog) => {\n add(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 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: 3 };\n },\n };\n}\n"],"mappings":"uFAMA,SAAgB,EAAsC,EAA4B,CAChF,IAAM,EAAc,IAAI,IAClB,EAAS,IAAI,IACb,EAAQ,IAAI,IAElB,IAAK,GAAM,CAAC,EAAQ,KAAW,OAAO,QAAQ,CAAO,EAAG,EAAY,IAAI,EAAA,gBAAgB,CAAM,EAAG,CAAM,EAEvG,IAAM,GAAO,EAAgB,IAAqB,CAChD,EAAO,IAAI,EAAQ,CAAE,UAAS,SAAU,EAAA,eAAe,CAAO,CAAE,CAAC,CACnE,EAEA,IAAK,GAAM,CAAC,EAAQ,KAAW,EACzB,OAAO,GAAW,YAAY,EAAI,EAAQ,CAAM,EA2CtD,MAAO,CACL,YAAmD,CACjD,OAAO,IAAI,IAAI,CAAC,GAAG,CAAM,CAAC,CAAC,KAAK,CAAC,EAAQ,CAAE,eAAgB,CAAC,EAAQ,CAAQ,CAAC,CAAC,CAChF,EACA,SAAS,EAAyB,CAChC,OAAO,EAAO,IAAI,EAAA,gBAAgB,CAAM,CAAC,CAC3C,EACA,UA/CkB,IAA8C,CAChE,IAAM,EAAS,EAAA,gBAAgB,CAAe,EAE9C,GAAI,EAAO,IAAI,CAAM,EAAG,MAAO,GAE/B,IAAM,EAAS,EAAY,IAAI,CAAM,EAErC,GAAI,CAAC,EAAQ,MAAM,IAAI,EAAA,0BAA0B,qCAAqC,EAAO,GAAG,EAEhG,GAAI,OAAO,GAAW,WAGpB,OAFA,EAAI,EAAQ,CAAM,EAEX,GAGT,IAAM,EAAW,EAAM,IAAI,CAAM,EAEjC,GAAI,EAGF,OAFA,MAAM,EAEC,GAGT,IAAM,EAAO,EAAO,CAAC,CAAC,KACnB,GAAY,CACX,EAAI,EAAQ,CAAO,EACnB,EAAM,OAAO,CAAM,CACrB,EACC,GAAmB,CAElB,MADA,EAAM,OAAO,CAAM,EACb,CACR,CACF,EAKA,OAHA,EAAM,IAAI,EAAQ,CAAI,EACtB,MAAM,EAEC,EACT,EAUE,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,5 +1,5 @@
1
- import type { Catalog, CatalogSources, TranslationState, Locale } from './types';
2
1
  import { type CompiledCatalog } from './_catalog';
2
+ import type { Catalog, CatalogSources, Locale, TranslationState } from './types';
3
3
  /** One catalog state machine owns static sources, lazy sources, and in-flight work. */
4
4
  export declare function createCatalogStore<C extends Catalog>(sources: CatalogSources<C>): {
5
5
  catalogMap(): ReadonlyMap<Locale, CompiledCatalog>;
@@ -1 +1 @@
1
- {"version":3,"file":"_resources.d.ts","sourceRoot":"","sources":["../src/_resources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAkB,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjG,OAAO,EAAE,KAAK,eAAe,EAAkB,MAAM,YAAY,CAAC;AAIlE,uFAAuF;AACvF,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,OAAO,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC;kBAwD9D,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC;qBAGjC,MAAM,GAAG,OAAO;4BA5CE,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;kBAgD9C,MAAM,GAAG,gBAAgB,CAAC,CAAC,CAAC;EAQ7C"}
1
+ {"version":3,"file":"_resources.d.ts","sourceRoot":"","sources":["../src/_resources.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAkB,MAAM,YAAY,CAAC;AAGlE,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAY,MAAM,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE3F,uFAAuF;AACvF,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,OAAO,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC;kBAwD9D,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC;qBAGjC,MAAM,GAAG,OAAO;4BA5CE,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;kBAgD9C,MAAM,GAAG,gBAAgB,CAAC,CAAC,CAAC;EAQ7C"}
@@ -1 +1 @@
1
- {"version":3,"file":"_resources.js","names":[],"sources":["../src/_resources.ts"],"sourcesContent":["import type { Catalog, CatalogSources, TranslationState, LoadedCatalogs, Locale } from './types';\n\nimport { type CompiledCatalog, compileCatalog } from './_catalog';\nimport { canonicalLocale } from './_locale';\nimport { LinguaMissingCatalogError } from './errors';\n\n/** One catalog state machine owns static sources, lazy sources, and in-flight work. */\nexport function createCatalogStore<C extends Catalog>(sources: CatalogSources<C>) {\n const definitions = new Map<Locale, C | (() => Promise<C>)>();\n const loaded = new Map<Locale, { readonly catalog: C; readonly compiled: CompiledCatalog }>();\n const tasks = new Map<Locale, Promise<void>>();\n\n for (const [locale, source] of Object.entries(sources)) definitions.set(canonicalLocale(locale), source);\n\n const add = (locale: Locale, catalog: C): void => {\n loaded.set(locale, { catalog, compiled: compileCatalog(catalog) });\n };\n\n for (const [locale, source] of definitions) {\n if (typeof source !== 'function') add(locale, source);\n }\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 source = definitions.get(locale);\n\n if (!source) throw new LinguaMissingCatalogError(`Catalog has no source for locale \"${locale}\".`);\n\n if (typeof source !== 'function') {\n add(locale, source);\n\n return true;\n }\n\n const existing = tasks.get(locale);\n\n if (existing) {\n await existing;\n\n return false;\n }\n\n const task = source().then(\n (catalog) => {\n add(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 isLoaded(locale: Locale): boolean {\n return loaded.has(canonicalLocale(locale));\n },\n load,\n state(locale: Locale): TranslationState<C> {\n const catalogs: LoadedCatalogs<C> = {};\n\n for (const [loadedLocale, { catalog }] of loaded) catalogs[loadedLocale] = catalog;\n\n return { catalogs, locale, version: 3 };\n },\n };\n}\n"],"mappings":";;;;AAOA,SAAgB,EAAsC,GAA4B;CAChF,IAAM,oBAAc,IAAI,IAAoC,GACtD,oBAAS,IAAI,IAAyE,GACtF,oBAAQ,IAAI,IAA2B;CAE7C,KAAK,IAAM,CAAC,GAAQ,MAAW,OAAO,QAAQ,CAAO,GAAG,EAAY,IAAI,EAAgB,CAAM,GAAG,CAAM;CAEvG,IAAM,KAAO,GAAgB,MAAqB;EAChD,EAAO,IAAI,GAAQ;GAAE;GAAS,UAAU,EAAe,CAAO;EAAE,CAAC;CACnE;CAEA,KAAK,IAAM,CAAC,GAAQ,MAAW,GAC7B,AAAI,OAAO,KAAW,cAAY,EAAI,GAAQ,CAAM;CA2CtD,OAAO;EACL,aAAmD;GACjD,OAAO,IAAI,IAAI,CAAC,GAAG,CAAM,CAAC,CAAC,KAAK,CAAC,GAAQ,EAAE,mBAAgB,CAAC,GAAQ,CAAQ,CAAC,CAAC;EAChF;EACA,SAAS,GAAyB;GAChC,OAAO,EAAO,IAAI,EAAgB,CAAM,CAAC;EAC3C;EACA,aA/CkB,MAA8C;GAChE,IAAM,IAAS,EAAgB,CAAe;GAE9C,IAAI,EAAO,IAAI,CAAM,GAAG,OAAO;GAE/B,IAAM,IAAS,EAAY,IAAI,CAAM;GAErC,IAAI,CAAC,GAAQ,MAAM,IAAI,EAA0B,qCAAqC,EAAO,GAAG;GAEhG,IAAI,OAAO,KAAW,YAGpB,OAFA,EAAI,GAAQ,CAAM,GAEX;GAGT,IAAM,IAAW,EAAM,IAAI,CAAM;GAEjC,IAAI,GAGF,OAFA,MAAM,GAEC;GAGT,IAAM,IAAO,EAAO,CAAC,CAAC,MACnB,MAAY;IAEX,AADA,EAAI,GAAQ,CAAO,GACnB,EAAM,OAAO,CAAM;GACrB,IACC,MAAmB;IAElB,MADA,EAAM,OAAO,CAAM,GACb;GACR,CACF;GAKA,OAHA,EAAM,IAAI,GAAQ,CAAI,GACtB,MAAM,GAEC;EACT;EAUE,MAAM,GAAqC;GACzC,IAAM,IAA8B,CAAC;GAErC,KAAK,IAAM,CAAC,GAAc,EAAE,iBAAc,GAAQ,EAAS,KAAgB;GAE3E,OAAO;IAAE;IAAU;IAAQ,SAAS;GAAE;EACxC;CACF;AACF"}
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, CatalogSources, Catalogs, Locale, TranslationState } from './types';\n\n/** One catalog state machine owns static sources, lazy sources, and in-flight work. */\nexport function createCatalogStore<C extends Catalog>(sources: CatalogSources<C>) {\n const definitions = new Map<Locale, C | (() => Promise<C>)>();\n const loaded = new Map<Locale, { readonly catalog: C; readonly compiled: CompiledCatalog }>();\n const tasks = new Map<Locale, Promise<void>>();\n\n for (const [locale, source] of Object.entries(sources)) definitions.set(canonicalLocale(locale), source);\n\n const add = (locale: Locale, catalog: C): void => {\n loaded.set(locale, { catalog, compiled: compileCatalog(catalog) });\n };\n\n for (const [locale, source] of definitions) {\n if (typeof source !== 'function') add(locale, source);\n }\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 source = definitions.get(locale);\n\n if (!source) throw new LinguaMissingCatalogError(`Catalog has no source for locale \"${locale}\".`);\n\n if (typeof source !== 'function') {\n add(locale, source);\n\n return true;\n }\n\n const existing = tasks.get(locale);\n\n if (existing) {\n await existing;\n\n return false;\n }\n\n const task = source().then(\n (catalog) => {\n add(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 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: 3 };\n },\n };\n}\n"],"mappings":";;;;AAMA,SAAgB,EAAsC,GAA4B;CAChF,IAAM,oBAAc,IAAI,IAAoC,GACtD,oBAAS,IAAI,IAAyE,GACtF,oBAAQ,IAAI,IAA2B;CAE7C,KAAK,IAAM,CAAC,GAAQ,MAAW,OAAO,QAAQ,CAAO,GAAG,EAAY,IAAI,EAAgB,CAAM,GAAG,CAAM;CAEvG,IAAM,KAAO,GAAgB,MAAqB;EAChD,EAAO,IAAI,GAAQ;GAAE;GAAS,UAAU,EAAe,CAAO;EAAE,CAAC;CACnE;CAEA,KAAK,IAAM,CAAC,GAAQ,MAAW,GAC7B,AAAI,OAAO,KAAW,cAAY,EAAI,GAAQ,CAAM;CA2CtD,OAAO;EACL,aAAmD;GACjD,OAAO,IAAI,IAAI,CAAC,GAAG,CAAM,CAAC,CAAC,KAAK,CAAC,GAAQ,EAAE,mBAAgB,CAAC,GAAQ,CAAQ,CAAC,CAAC;EAChF;EACA,SAAS,GAAyB;GAChC,OAAO,EAAO,IAAI,EAAgB,CAAM,CAAC;EAC3C;EACA,aA/CkB,MAA8C;GAChE,IAAM,IAAS,EAAgB,CAAe;GAE9C,IAAI,EAAO,IAAI,CAAM,GAAG,OAAO;GAE/B,IAAM,IAAS,EAAY,IAAI,CAAM;GAErC,IAAI,CAAC,GAAQ,MAAM,IAAI,EAA0B,qCAAqC,EAAO,GAAG;GAEhG,IAAI,OAAO,KAAW,YAGpB,OAFA,EAAI,GAAQ,CAAM,GAEX;GAGT,IAAM,IAAW,EAAM,IAAI,CAAM;GAEjC,IAAI,GAGF,OAFA,MAAM,GAEC;GAGT,IAAM,IAAO,EAAO,CAAC,CAAC,MACnB,MAAY;IAEX,AADA,EAAI,GAAQ,CAAO,GACnB,EAAM,OAAO,CAAM;GACrB,IACC,MAAmB;IAElB,MADA,EAAM,OAAO,CAAM,GACb;GACR,CACF;GAKA,OAHA,EAAM,IAAI,GAAQ,CAAI,GACtB,MAAM,GAEC;EACT;EAUE,MAAM,GAAqC;GACzC,IAAM,IAAwB,CAAC;GAE/B,KAAK,IAAM,CAAC,GAAc,EAAE,iBAAc,GAAQ,EAAS,KAAgB;GAE3E,OAAO;IAAE;IAAU;IAAQ,SAAS;GAAE;EACxC;CACF;AACF"}
package/dist/i18n.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.cjs","names":[],"sources":["../src/i18n.ts"],"sourcesContent":["import type { Catalog, TranslationStoreOptions, TranslationState, Locale, SubscribeOptions } from './types';\n\nimport { error as logError } from './_dev';\nimport { canonicalLocale, localeChain } from './_locale';\nimport { createCatalogStore } from './_resources';\nimport { LinguaDisposedError, LinguaInvalidStateError } from './errors';\nimport { type Translator, createTranslatorFromCompiled } from './translator';\n\nexport type TranslationSnapshot<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n readonly revision: number;\n readonly translator: Translator<C>;\n};\n\nexport type TranslationStore<C extends Catalog = Catalog> = Translator<C> & {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n getSnapshot(): TranslationSnapshot<C>;\n isLoaded(options?: { locale?: Locale }): boolean;\n load(options?: { locale?: Locale }): Promise<void>;\n serialize(): TranslationState<C>;\n setLocale(locale: Locale): Promise<void>;\n subscribe(listener: (snapshot: TranslationSnapshot<C>) => void, options?: SubscribeOptions): () => void;\n};\n\nexport function createTranslationStore<C extends Catalog>(options: TranslationStoreOptions<C>): TranslationStore<C> {\n const catalogs = createCatalogStore(options.catalogs);\n const fallback = options.fallback;\n const fallbackLocales = (Array.isArray(fallback) ? fallback : fallback ? [fallback] : []).map(canonicalLocale);\n const controller = new AbortController();\n const subscribers = new Set<(snapshot: TranslationSnapshot<C>) => void>();\n let disposed = false;\n let locale = canonicalLocale(options.locale ?? 'en');\n let revision = 0;\n\n const buildSnapshot = (): TranslationSnapshot<C> => ({\n locale,\n revision,\n translator: createTranslatorFromCompiled<C>(catalogs.catalogMap(), { ...options, fallback, locale }),\n });\n let snapshot = buildSnapshot();\n\n const assertLive = (): void => {\n if (disposed) throw new LinguaDisposedError();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n subscribers.clear();\n controller.abort();\n };\n\n const dispatch = (listener: (next: TranslationSnapshot<C>) => void): void => {\n try {\n listener(snapshot);\n } catch (error) {\n logError('subscriber error', error);\n }\n };\n\n const notify = (): void => {\n revision++;\n snapshot = buildSnapshot();\n\n for (const listener of [...subscribers]) dispatch(listener);\n };\n\n const relevant = (candidate: Locale): boolean => localeChain(locale, fallbackLocales).includes(candidate);\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n getSnapshot() {\n return snapshot;\n },\n isLoaded(loadOptions) {\n return !disposed && catalogs.isLoaded(loadOptions?.locale ?? locale);\n },\n async load(loadOptions) {\n assertLive();\n\n const targetLocale = canonicalLocale(loadOptions?.locale ?? locale);\n const changed = await catalogs.load(targetLocale);\n\n if (!disposed && changed && relevant(targetLocale)) notify();\n },\n get locale() {\n return locale;\n },\n segments(key: string, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n segmentsDynamic(key, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n serialize() {\n assertLive();\n\n return catalogs.state(locale);\n },\n async setLocale(nextLocale) {\n assertLive();\n\n const next = canonicalLocale(nextLocale);\n\n if (next === locale) return;\n\n locale = next;\n notify();\n },\n subscribe(listener, subscribeOptions) {\n assertLive();\n\n if (subscribeOptions?.signal?.aborted) return () => {};\n\n const unsubscribe = (): void => {\n subscribers.delete(listener);\n subscribeOptions?.signal?.removeEventListener('abort', unsubscribe);\n };\n\n subscribeOptions?.signal?.addEventListener('abort', unsubscribe, { once: true });\n subscribers.add(listener);\n\n if (subscribeOptions?.immediate) dispatch(listener);\n\n return unsubscribe;\n },\n [Symbol.dispose]: dispose,\n translate(key: string, translateOptions = {}) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n translateDynamic(key, translateOptions) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n } as TranslationStore<C>;\n}\n\nexport function hydrateTranslationStore<C extends Catalog>(\n state: TranslationState<C>,\n options?: Omit<TranslationStoreOptions<C>, 'locale' | 'catalogs'>,\n): TranslationStore<C> {\n if (state.version !== 3) {\n throw new LinguaInvalidStateError(`Unsupported lingua state version: ${String(state.version)}.`);\n }\n\n return createTranslationStore({ ...options, catalogs: state.catalogs, locale: state.locale });\n}\n"],"mappings":"6IA2BA,SAAgB,EAA0C,EAA0D,CAClH,IAAM,EAAW,EAAA,mBAAmB,EAAQ,QAAQ,EAC9C,EAAW,EAAQ,SACnB,GAAmB,MAAM,QAAQ,CAAQ,EAAI,EAAW,EAAW,CAAC,CAAQ,EAAI,CAAC,EAAA,CAAG,IAAI,EAAA,eAAe,EACvG,EAAa,IAAI,gBACjB,EAAc,IAAI,IACpB,EAAW,GACX,EAAS,EAAA,gBAAgB,EAAQ,QAAU,IAAI,EAC/C,EAAW,EAET,OAA+C,CACnD,SACA,WACA,WAAY,EAAA,6BAAgC,EAAS,WAAW,EAAG,CAAE,GAAG,EAAS,WAAU,QAAO,CAAC,CACrG,GACI,EAAW,EAAc,EAEvB,MAAyB,CAC7B,GAAI,EAAU,MAAM,IAAI,EAAA,mBAC1B,EAEM,MAAsB,CACtB,IAEJ,EAAW,GACX,EAAY,MAAM,EAClB,EAAW,MAAM,EACnB,EAEM,EAAY,GAA2D,CAC3E,GAAI,CACF,EAAS,CAAQ,CACnB,MAAgB,CAEhB,CACF,EAEM,MAAqB,CACzB,IACA,EAAW,EAAc,EAEzB,IAAK,IAAM,IAAY,CAAC,GAAG,CAAW,EAAG,EAAS,CAAQ,CAC5D,EAEM,EAAY,GAA+B,EAAA,YAAY,EAAQ,CAAe,CAAC,CAAC,SAAS,CAAS,EAExG,MAAO,CACL,IAAI,gBAAiB,CACnB,OAAO,EAAW,MACpB,EACA,UACA,IAAI,UAAW,CACb,OAAO,CACT,EACA,aAAc,CACZ,OAAO,CACT,EACA,SAAS,EAAa,CACpB,MAAO,CAAC,GAAY,EAAS,SAAS,GAAa,QAAU,CAAM,CACrE,EACA,MAAM,KAAK,EAAa,CACtB,EAAW,EAEX,IAAM,EAAe,EAAA,gBAAgB,GAAa,QAAU,CAAM,EAC5D,EAAU,MAAM,EAAS,KAAK,CAAY,EAE5C,CAAC,GAAY,GAAW,EAAS,CAAY,GAAG,EAAO,CAC7D,EACA,IAAI,QAAS,CACX,OAAO,CACT,EACA,SAAS,EAAa,EAAkB,CACtC,OAAO,EAAS,WAAW,gBAAgB,EAAK,CAAgB,CAClE,EACA,gBAAgB,EAAK,EAAkB,CACrC,OAAO,EAAS,WAAW,gBAAgB,EAAK,CAAgB,CAClE,EACA,WAAY,CAGV,OAFA,EAAW,EAEJ,EAAS,MAAM,CAAM,CAC9B,EACA,MAAM,UAAU,EAAY,CAC1B,EAAW,EAEX,IAAM,EAAO,EAAA,gBAAgB,CAAU,EAEnC,IAAS,IAEb,EAAS,EACT,EAAO,EACT,EACA,UAAU,EAAU,EAAkB,CAGpC,GAFA,EAAW,EAEP,GAAkB,QAAQ,QAAS,UAAa,CAAC,EAErD,IAAM,MAA0B,CAC9B,EAAY,OAAO,CAAQ,EAC3B,GAAkB,QAAQ,oBAAoB,QAAS,CAAW,CACpE,EAOA,OALA,GAAkB,QAAQ,iBAAiB,QAAS,EAAa,CAAE,KAAM,EAAK,CAAC,EAC/E,EAAY,IAAI,CAAQ,EAEpB,GAAkB,WAAW,EAAS,CAAQ,EAE3C,CACT,GACC,OAAO,SAAU,EAClB,UAAU,EAAa,EAAmB,CAAC,EAAG,CAC5C,OAAO,EAAS,WAAW,iBAAiB,EAAK,CAAgB,CACnE,EACA,iBAAiB,EAAK,EAAkB,CACtC,OAAO,EAAS,WAAW,iBAAiB,EAAK,CAAgB,CACnE,CACF,CACF,CAEA,SAAgB,EACd,EACA,EACqB,CACrB,GAAI,EAAM,UAAY,EACpB,MAAM,IAAI,EAAA,wBAAwB,qCAAqC,OAAO,EAAM,OAAO,EAAE,EAAE,EAGjG,OAAO,EAAuB,CAAE,GAAG,EAAS,SAAU,EAAM,SAAU,OAAQ,EAAM,MAAO,CAAC,CAC9F"}
1
+ {"version":3,"file":"i18n.cjs","names":[],"sources":["../src/i18n.ts"],"sourcesContent":["import { error as logError } from './_dev';\nimport { canonicalLocale, localeChain } from './_locale';\nimport { createCatalogStore } from './_resources';\nimport { LinguaDisposedError, LinguaInvalidStateError } from './errors';\nimport { createTranslatorFromCompiled, type Translator } from './translator';\nimport type { Catalog, Locale, SubscribeOptions, TranslationState, TranslationStoreOptions } from './types';\n\nexport type TranslationSnapshot<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n readonly revision: number;\n readonly translator: Translator<C>;\n};\n\nexport type TranslationStore<C extends Catalog = Catalog> = Translator<C> & {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n getSnapshot(): TranslationSnapshot<C>;\n isLoaded(options?: { locale?: Locale }): boolean;\n load(options?: { locale?: Locale }): Promise<void>;\n serialize(): TranslationState<C>;\n setLocale(locale: Locale): Promise<void>;\n subscribe(listener: (snapshot: TranslationSnapshot<C>) => void, options?: SubscribeOptions): () => void;\n};\n\nexport function createTranslationStore<C extends Catalog>(options: TranslationStoreOptions<C>): TranslationStore<C> {\n const catalogs = createCatalogStore(options.catalogs);\n const fallback = options.fallback;\n const fallbackLocales = (Array.isArray(fallback) ? fallback : fallback ? [fallback] : []).map(canonicalLocale);\n const controller = new AbortController();\n const subscribers = new Set<(snapshot: TranslationSnapshot<C>) => void>();\n let disposed = false;\n let locale = canonicalLocale(options.locale ?? 'en');\n let revision = 0;\n\n const buildSnapshot = (): TranslationSnapshot<C> => ({\n locale,\n revision,\n translator: createTranslatorFromCompiled<C>(catalogs.catalogMap(), { ...options, fallback, locale }),\n });\n let snapshot = buildSnapshot();\n\n const assertLive = (): void => {\n if (disposed) throw new LinguaDisposedError();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n subscribers.clear();\n controller.abort();\n };\n\n const dispatch = (listener: (next: TranslationSnapshot<C>) => void): void => {\n try {\n listener(snapshot);\n } catch (error) {\n logError('subscriber error', error);\n }\n };\n\n const notify = (): void => {\n revision++;\n snapshot = buildSnapshot();\n\n for (const listener of [...subscribers]) dispatch(listener);\n };\n\n const relevant = (candidate: Locale): boolean => localeChain(locale, fallbackLocales).includes(candidate);\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n getSnapshot() {\n return snapshot;\n },\n isLoaded(loadOptions) {\n return !disposed && catalogs.isLoaded(loadOptions?.locale ?? locale);\n },\n async load(loadOptions) {\n assertLive();\n\n const targetLocale = canonicalLocale(loadOptions?.locale ?? locale);\n const changed = await catalogs.load(targetLocale);\n\n if (!disposed && changed && relevant(targetLocale)) notify();\n },\n get locale() {\n return locale;\n },\n segments(key: string, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n segmentsDynamic(key, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n serialize() {\n assertLive();\n\n return catalogs.state(locale);\n },\n async setLocale(nextLocale) {\n assertLive();\n\n const next = canonicalLocale(nextLocale);\n\n if (next === locale) return;\n\n locale = next;\n notify();\n },\n subscribe(listener, subscribeOptions) {\n assertLive();\n\n if (subscribeOptions?.signal?.aborted) return () => {};\n\n const unsubscribe = (): void => {\n subscribers.delete(listener);\n subscribeOptions?.signal?.removeEventListener('abort', unsubscribe);\n };\n\n subscribeOptions?.signal?.addEventListener('abort', unsubscribe, { once: true });\n subscribers.add(listener);\n\n if (subscribeOptions?.immediate) dispatch(listener);\n\n return unsubscribe;\n },\n [Symbol.dispose]: dispose,\n translate(key: string, translateOptions = {}) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n translateDynamic(key, translateOptions) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n } as TranslationStore<C>;\n}\n\nexport function hydrateTranslationStore<C extends Catalog>(\n state: TranslationState<C>,\n options?: Omit<TranslationStoreOptions<C>, 'locale' | 'catalogs'>,\n): TranslationStore<C> {\n if (state.version !== 3) {\n throw new LinguaInvalidStateError(`Unsupported lingua state version: ${String(state.version)}.`);\n }\n\n return createTranslationStore({ ...options, catalogs: state.catalogs, locale: state.locale });\n}\n"],"mappings":"6IA0BA,SAAgB,EAA0C,EAA0D,CAClH,IAAM,EAAW,EAAA,mBAAmB,EAAQ,QAAQ,EAC9C,EAAW,EAAQ,SACnB,GAAmB,MAAM,QAAQ,CAAQ,EAAI,EAAW,EAAW,CAAC,CAAQ,EAAI,CAAC,EAAA,CAAG,IAAI,EAAA,eAAe,EACvG,EAAa,IAAI,gBACjB,EAAc,IAAI,IACpB,EAAW,GACX,EAAS,EAAA,gBAAgB,EAAQ,QAAU,IAAI,EAC/C,EAAW,EAET,OAA+C,CACnD,SACA,WACA,WAAY,EAAA,6BAAgC,EAAS,WAAW,EAAG,CAAE,GAAG,EAAS,WAAU,QAAO,CAAC,CACrG,GACI,EAAW,EAAc,EAEvB,MAAyB,CAC7B,GAAI,EAAU,MAAM,IAAI,EAAA,mBAC1B,EAEM,MAAsB,CACtB,IAEJ,EAAW,GACX,EAAY,MAAM,EAClB,EAAW,MAAM,EACnB,EAEM,EAAY,GAA2D,CAC3E,GAAI,CACF,EAAS,CAAQ,CACnB,MAAgB,CAEhB,CACF,EAEM,MAAqB,CACzB,IACA,EAAW,EAAc,EAEzB,IAAK,IAAM,IAAY,CAAC,GAAG,CAAW,EAAG,EAAS,CAAQ,CAC5D,EAEM,EAAY,GAA+B,EAAA,YAAY,EAAQ,CAAe,CAAC,CAAC,SAAS,CAAS,EAExG,MAAO,CACL,IAAI,gBAAiB,CACnB,OAAO,EAAW,MACpB,EACA,UACA,IAAI,UAAW,CACb,OAAO,CACT,EACA,aAAc,CACZ,OAAO,CACT,EACA,SAAS,EAAa,CACpB,MAAO,CAAC,GAAY,EAAS,SAAS,GAAa,QAAU,CAAM,CACrE,EACA,MAAM,KAAK,EAAa,CACtB,EAAW,EAEX,IAAM,EAAe,EAAA,gBAAgB,GAAa,QAAU,CAAM,EAC5D,EAAU,MAAM,EAAS,KAAK,CAAY,EAE5C,CAAC,GAAY,GAAW,EAAS,CAAY,GAAG,EAAO,CAC7D,EACA,IAAI,QAAS,CACX,OAAO,CACT,EACA,SAAS,EAAa,EAAkB,CACtC,OAAO,EAAS,WAAW,gBAAgB,EAAK,CAAgB,CAClE,EACA,gBAAgB,EAAK,EAAkB,CACrC,OAAO,EAAS,WAAW,gBAAgB,EAAK,CAAgB,CAClE,EACA,WAAY,CAGV,OAFA,EAAW,EAEJ,EAAS,MAAM,CAAM,CAC9B,EACA,MAAM,UAAU,EAAY,CAC1B,EAAW,EAEX,IAAM,EAAO,EAAA,gBAAgB,CAAU,EAEnC,IAAS,IAEb,EAAS,EACT,EAAO,EACT,EACA,UAAU,EAAU,EAAkB,CAGpC,GAFA,EAAW,EAEP,GAAkB,QAAQ,QAAS,UAAa,CAAC,EAErD,IAAM,MAA0B,CAC9B,EAAY,OAAO,CAAQ,EAC3B,GAAkB,QAAQ,oBAAoB,QAAS,CAAW,CACpE,EAOA,OALA,GAAkB,QAAQ,iBAAiB,QAAS,EAAa,CAAE,KAAM,EAAK,CAAC,EAC/E,EAAY,IAAI,CAAQ,EAEpB,GAAkB,WAAW,EAAS,CAAQ,EAE3C,CACT,GACC,OAAO,SAAU,EAClB,UAAU,EAAa,EAAmB,CAAC,EAAG,CAC5C,OAAO,EAAS,WAAW,iBAAiB,EAAK,CAAgB,CACnE,EACA,iBAAiB,EAAK,EAAkB,CACtC,OAAO,EAAS,WAAW,iBAAiB,EAAK,CAAgB,CACnE,CACF,CACF,CAEA,SAAgB,EACd,EACA,EACqB,CACrB,GAAI,EAAM,UAAY,EACpB,MAAM,IAAI,EAAA,wBAAwB,qCAAqC,OAAO,EAAM,OAAO,EAAE,EAAE,EAGjG,OAAO,EAAuB,CAAE,GAAG,EAAS,SAAU,EAAM,SAAU,OAAQ,EAAM,MAAO,CAAC,CAC9F"}
package/dist/i18n.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { Catalog, TranslationStoreOptions, TranslationState, Locale, SubscribeOptions } from './types';
2
1
  import { type Translator } from './translator';
2
+ import type { Catalog, Locale, SubscribeOptions, TranslationState, TranslationStoreOptions } from './types';
3
3
  export type TranslationSnapshot<C extends Catalog = Catalog> = {
4
4
  readonly locale: Locale;
5
5
  readonly revision: number;
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAM5G,OAAO,EAAE,KAAK,UAAU,EAAgC,MAAM,cAAc,CAAC;AAE7E,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,IAAI;IAC7D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG;IAC1E,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;IACzB,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC;IACrC,OAAO,IAAI,IAAI,CAAC;IAChB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,WAAW,IAAI,mBAAmB,CAAC,CAAC,CAAC,CAAC;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;IACjD,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,SAAS,IAAI,gBAAgB,CAAC,CAAC,CAAC,CAAC;IACjC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,SAAS,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,MAAM,IAAI,CAAC;CACzG,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,OAAO,EAAE,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAqHlH;AAED,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,OAAO,EACvD,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC1B,OAAO,CAAC,EAAE,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC,GAChE,gBAAgB,CAAC,CAAC,CAAC,CAMrB"}
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAIA,OAAO,EAAgC,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAC7E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAE5G,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,IAAI;IAC7D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG;IAC1E,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;IACzB,QAAQ,CAAC,cAAc,EAAE,WAAW,CAAC;IACrC,OAAO,IAAI,IAAI,CAAC;IAChB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,WAAW,IAAI,mBAAmB,CAAC,CAAC,CAAC,CAAC;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;IACjD,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,SAAS,IAAI,gBAAgB,CAAC,CAAC,CAAC,CAAC;IACjC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,SAAS,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,MAAM,IAAI,CAAC;CACzG,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,OAAO,EAAE,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAqHlH;AAED,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,OAAO,EACvD,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC1B,OAAO,CAAC,EAAE,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC,GAChE,gBAAgB,CAAC,CAAC,CAAC,CAMrB"}
package/dist/i18n.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.js","names":[],"sources":["../src/i18n.ts"],"sourcesContent":["import type { Catalog, TranslationStoreOptions, TranslationState, Locale, SubscribeOptions } from './types';\n\nimport { error as logError } from './_dev';\nimport { canonicalLocale, localeChain } from './_locale';\nimport { createCatalogStore } from './_resources';\nimport { LinguaDisposedError, LinguaInvalidStateError } from './errors';\nimport { type Translator, createTranslatorFromCompiled } from './translator';\n\nexport type TranslationSnapshot<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n readonly revision: number;\n readonly translator: Translator<C>;\n};\n\nexport type TranslationStore<C extends Catalog = Catalog> = Translator<C> & {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n getSnapshot(): TranslationSnapshot<C>;\n isLoaded(options?: { locale?: Locale }): boolean;\n load(options?: { locale?: Locale }): Promise<void>;\n serialize(): TranslationState<C>;\n setLocale(locale: Locale): Promise<void>;\n subscribe(listener: (snapshot: TranslationSnapshot<C>) => void, options?: SubscribeOptions): () => void;\n};\n\nexport function createTranslationStore<C extends Catalog>(options: TranslationStoreOptions<C>): TranslationStore<C> {\n const catalogs = createCatalogStore(options.catalogs);\n const fallback = options.fallback;\n const fallbackLocales = (Array.isArray(fallback) ? fallback : fallback ? [fallback] : []).map(canonicalLocale);\n const controller = new AbortController();\n const subscribers = new Set<(snapshot: TranslationSnapshot<C>) => void>();\n let disposed = false;\n let locale = canonicalLocale(options.locale ?? 'en');\n let revision = 0;\n\n const buildSnapshot = (): TranslationSnapshot<C> => ({\n locale,\n revision,\n translator: createTranslatorFromCompiled<C>(catalogs.catalogMap(), { ...options, fallback, locale }),\n });\n let snapshot = buildSnapshot();\n\n const assertLive = (): void => {\n if (disposed) throw new LinguaDisposedError();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n subscribers.clear();\n controller.abort();\n };\n\n const dispatch = (listener: (next: TranslationSnapshot<C>) => void): void => {\n try {\n listener(snapshot);\n } catch (error) {\n logError('subscriber error', error);\n }\n };\n\n const notify = (): void => {\n revision++;\n snapshot = buildSnapshot();\n\n for (const listener of [...subscribers]) dispatch(listener);\n };\n\n const relevant = (candidate: Locale): boolean => localeChain(locale, fallbackLocales).includes(candidate);\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n getSnapshot() {\n return snapshot;\n },\n isLoaded(loadOptions) {\n return !disposed && catalogs.isLoaded(loadOptions?.locale ?? locale);\n },\n async load(loadOptions) {\n assertLive();\n\n const targetLocale = canonicalLocale(loadOptions?.locale ?? locale);\n const changed = await catalogs.load(targetLocale);\n\n if (!disposed && changed && relevant(targetLocale)) notify();\n },\n get locale() {\n return locale;\n },\n segments(key: string, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n segmentsDynamic(key, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n serialize() {\n assertLive();\n\n return catalogs.state(locale);\n },\n async setLocale(nextLocale) {\n assertLive();\n\n const next = canonicalLocale(nextLocale);\n\n if (next === locale) return;\n\n locale = next;\n notify();\n },\n subscribe(listener, subscribeOptions) {\n assertLive();\n\n if (subscribeOptions?.signal?.aborted) return () => {};\n\n const unsubscribe = (): void => {\n subscribers.delete(listener);\n subscribeOptions?.signal?.removeEventListener('abort', unsubscribe);\n };\n\n subscribeOptions?.signal?.addEventListener('abort', unsubscribe, { once: true });\n subscribers.add(listener);\n\n if (subscribeOptions?.immediate) dispatch(listener);\n\n return unsubscribe;\n },\n [Symbol.dispose]: dispose,\n translate(key: string, translateOptions = {}) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n translateDynamic(key, translateOptions) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n } as TranslationStore<C>;\n}\n\nexport function hydrateTranslationStore<C extends Catalog>(\n state: TranslationState<C>,\n options?: Omit<TranslationStoreOptions<C>, 'locale' | 'catalogs'>,\n): TranslationStore<C> {\n if (state.version !== 3) {\n throw new LinguaInvalidStateError(`Unsupported lingua state version: ${String(state.version)}.`);\n }\n\n return createTranslationStore({ ...options, catalogs: state.catalogs, locale: state.locale });\n}\n"],"mappings":";;;;;;AA2BA,SAAgB,EAA0C,GAA0D;CAClH,IAAM,IAAW,EAAmB,EAAQ,QAAQ,GAC9C,IAAW,EAAQ,UACnB,KAAmB,MAAM,QAAQ,CAAQ,IAAI,IAAW,IAAW,CAAC,CAAQ,IAAI,CAAC,EAAA,CAAG,IAAI,CAAe,GACvG,IAAa,IAAI,gBAAgB,GACjC,oBAAc,IAAI,IAAgD,GACpE,IAAW,IACX,IAAS,EAAgB,EAAQ,UAAU,IAAI,GAC/C,IAAW,GAET,WAA+C;EACnD;EACA;EACA,YAAY,EAAgC,EAAS,WAAW,GAAG;GAAE,GAAG;GAAS;GAAU;EAAO,CAAC;CACrG,IACI,IAAW,EAAc,GAEvB,UAAyB;EAC7B,IAAI,GAAU,MAAM,IAAI,EAAoB;CAC9C,GAEM,UAAsB;EACtB,MAEJ,IAAW,IACX,EAAY,MAAM,GAClB,EAAW,MAAM;CACnB,GAEM,KAAY,MAA2D;EAC3E,IAAI;GACF,EAAS,CAAQ;EACnB,QAAgB,CAEhB;CACF,GAEM,UAAqB;EAEzB,AADA,KACA,IAAW,EAAc;EAEzB,KAAK,IAAM,KAAY,CAAC,GAAG,CAAW,GAAG,EAAS,CAAQ;CAC5D,GAEM,KAAY,MAA+B,EAAY,GAAQ,CAAe,CAAC,CAAC,SAAS,CAAS;CAExG,OAAO;EACL,IAAI,iBAAiB;GACnB,OAAO,EAAW;EACpB;EACA;EACA,IAAI,WAAW;GACb,OAAO;EACT;EACA,cAAc;GACZ,OAAO;EACT;EACA,SAAS,GAAa;GACpB,OAAO,CAAC,KAAY,EAAS,SAAS,GAAa,UAAU,CAAM;EACrE;EACA,MAAM,KAAK,GAAa;GACtB,EAAW;GAEX,IAAM,IAAe,EAAgB,GAAa,UAAU,CAAM,GAC5D,IAAU,MAAM,EAAS,KAAK,CAAY;GAEhD,AAAI,CAAC,KAAY,KAAW,EAAS,CAAY,KAAG,EAAO;EAC7D;EACA,IAAI,SAAS;GACX,OAAO;EACT;EACA,SAAS,GAAa,GAAkB;GACtC,OAAO,EAAS,WAAW,gBAAgB,GAAK,CAAgB;EAClE;EACA,gBAAgB,GAAK,GAAkB;GACrC,OAAO,EAAS,WAAW,gBAAgB,GAAK,CAAgB;EAClE;EACA,YAAY;GAGV,OAFA,EAAW,GAEJ,EAAS,MAAM,CAAM;EAC9B;EACA,MAAM,UAAU,GAAY;GAC1B,EAAW;GAEX,IAAM,IAAO,EAAgB,CAAU;GAEnC,MAAS,MAEb,IAAS,GACT,EAAO;EACT;EACA,UAAU,GAAU,GAAkB;GAGpC,IAFA,EAAW,GAEP,GAAkB,QAAQ,SAAS,aAAa,CAAC;GAErD,IAAM,UAA0B;IAE9B,AADA,EAAY,OAAO,CAAQ,GAC3B,GAAkB,QAAQ,oBAAoB,SAAS,CAAW;GACpE;GAOA,OALA,GAAkB,QAAQ,iBAAiB,SAAS,GAAa,EAAE,MAAM,GAAK,CAAC,GAC/E,EAAY,IAAI,CAAQ,GAEpB,GAAkB,aAAW,EAAS,CAAQ,GAE3C;EACT;GACC,OAAO,UAAU;EAClB,UAAU,GAAa,IAAmB,CAAC,GAAG;GAC5C,OAAO,EAAS,WAAW,iBAAiB,GAAK,CAAgB;EACnE;EACA,iBAAiB,GAAK,GAAkB;GACtC,OAAO,EAAS,WAAW,iBAAiB,GAAK,CAAgB;EACnE;CACF;AACF;AAEA,SAAgB,EACd,GACA,GACqB;CACrB,IAAI,EAAM,YAAY,GACpB,MAAM,IAAI,EAAwB,qCAAqC,OAAO,EAAM,OAAO,EAAE,EAAE;CAGjG,OAAO,EAAuB;EAAE,GAAG;EAAS,UAAU,EAAM;EAAU,QAAQ,EAAM;CAAO,CAAC;AAC9F"}
1
+ {"version":3,"file":"i18n.js","names":[],"sources":["../src/i18n.ts"],"sourcesContent":["import { error as logError } from './_dev';\nimport { canonicalLocale, localeChain } from './_locale';\nimport { createCatalogStore } from './_resources';\nimport { LinguaDisposedError, LinguaInvalidStateError } from './errors';\nimport { createTranslatorFromCompiled, type Translator } from './translator';\nimport type { Catalog, Locale, SubscribeOptions, TranslationState, TranslationStoreOptions } from './types';\n\nexport type TranslationSnapshot<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n readonly revision: number;\n readonly translator: Translator<C>;\n};\n\nexport type TranslationStore<C extends Catalog = Catalog> = Translator<C> & {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n getSnapshot(): TranslationSnapshot<C>;\n isLoaded(options?: { locale?: Locale }): boolean;\n load(options?: { locale?: Locale }): Promise<void>;\n serialize(): TranslationState<C>;\n setLocale(locale: Locale): Promise<void>;\n subscribe(listener: (snapshot: TranslationSnapshot<C>) => void, options?: SubscribeOptions): () => void;\n};\n\nexport function createTranslationStore<C extends Catalog>(options: TranslationStoreOptions<C>): TranslationStore<C> {\n const catalogs = createCatalogStore(options.catalogs);\n const fallback = options.fallback;\n const fallbackLocales = (Array.isArray(fallback) ? fallback : fallback ? [fallback] : []).map(canonicalLocale);\n const controller = new AbortController();\n const subscribers = new Set<(snapshot: TranslationSnapshot<C>) => void>();\n let disposed = false;\n let locale = canonicalLocale(options.locale ?? 'en');\n let revision = 0;\n\n const buildSnapshot = (): TranslationSnapshot<C> => ({\n locale,\n revision,\n translator: createTranslatorFromCompiled<C>(catalogs.catalogMap(), { ...options, fallback, locale }),\n });\n let snapshot = buildSnapshot();\n\n const assertLive = (): void => {\n if (disposed) throw new LinguaDisposedError();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n subscribers.clear();\n controller.abort();\n };\n\n const dispatch = (listener: (next: TranslationSnapshot<C>) => void): void => {\n try {\n listener(snapshot);\n } catch (error) {\n logError('subscriber error', error);\n }\n };\n\n const notify = (): void => {\n revision++;\n snapshot = buildSnapshot();\n\n for (const listener of [...subscribers]) dispatch(listener);\n };\n\n const relevant = (candidate: Locale): boolean => localeChain(locale, fallbackLocales).includes(candidate);\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n getSnapshot() {\n return snapshot;\n },\n isLoaded(loadOptions) {\n return !disposed && catalogs.isLoaded(loadOptions?.locale ?? locale);\n },\n async load(loadOptions) {\n assertLive();\n\n const targetLocale = canonicalLocale(loadOptions?.locale ?? locale);\n const changed = await catalogs.load(targetLocale);\n\n if (!disposed && changed && relevant(targetLocale)) notify();\n },\n get locale() {\n return locale;\n },\n segments(key: string, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n segmentsDynamic(key, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n serialize() {\n assertLive();\n\n return catalogs.state(locale);\n },\n async setLocale(nextLocale) {\n assertLive();\n\n const next = canonicalLocale(nextLocale);\n\n if (next === locale) return;\n\n locale = next;\n notify();\n },\n subscribe(listener, subscribeOptions) {\n assertLive();\n\n if (subscribeOptions?.signal?.aborted) return () => {};\n\n const unsubscribe = (): void => {\n subscribers.delete(listener);\n subscribeOptions?.signal?.removeEventListener('abort', unsubscribe);\n };\n\n subscribeOptions?.signal?.addEventListener('abort', unsubscribe, { once: true });\n subscribers.add(listener);\n\n if (subscribeOptions?.immediate) dispatch(listener);\n\n return unsubscribe;\n },\n [Symbol.dispose]: dispose,\n translate(key: string, translateOptions = {}) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n translateDynamic(key, translateOptions) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n } as TranslationStore<C>;\n}\n\nexport function hydrateTranslationStore<C extends Catalog>(\n state: TranslationState<C>,\n options?: Omit<TranslationStoreOptions<C>, 'locale' | 'catalogs'>,\n): TranslationStore<C> {\n if (state.version !== 3) {\n throw new LinguaInvalidStateError(`Unsupported lingua state version: ${String(state.version)}.`);\n }\n\n return createTranslationStore({ ...options, catalogs: state.catalogs, locale: state.locale });\n}\n"],"mappings":";;;;;;AA0BA,SAAgB,EAA0C,GAA0D;CAClH,IAAM,IAAW,EAAmB,EAAQ,QAAQ,GAC9C,IAAW,EAAQ,UACnB,KAAmB,MAAM,QAAQ,CAAQ,IAAI,IAAW,IAAW,CAAC,CAAQ,IAAI,CAAC,EAAA,CAAG,IAAI,CAAe,GACvG,IAAa,IAAI,gBAAgB,GACjC,oBAAc,IAAI,IAAgD,GACpE,IAAW,IACX,IAAS,EAAgB,EAAQ,UAAU,IAAI,GAC/C,IAAW,GAET,WAA+C;EACnD;EACA;EACA,YAAY,EAAgC,EAAS,WAAW,GAAG;GAAE,GAAG;GAAS;GAAU;EAAO,CAAC;CACrG,IACI,IAAW,EAAc,GAEvB,UAAyB;EAC7B,IAAI,GAAU,MAAM,IAAI,EAAoB;CAC9C,GAEM,UAAsB;EACtB,MAEJ,IAAW,IACX,EAAY,MAAM,GAClB,EAAW,MAAM;CACnB,GAEM,KAAY,MAA2D;EAC3E,IAAI;GACF,EAAS,CAAQ;EACnB,QAAgB,CAEhB;CACF,GAEM,UAAqB;EAEzB,AADA,KACA,IAAW,EAAc;EAEzB,KAAK,IAAM,KAAY,CAAC,GAAG,CAAW,GAAG,EAAS,CAAQ;CAC5D,GAEM,KAAY,MAA+B,EAAY,GAAQ,CAAe,CAAC,CAAC,SAAS,CAAS;CAExG,OAAO;EACL,IAAI,iBAAiB;GACnB,OAAO,EAAW;EACpB;EACA;EACA,IAAI,WAAW;GACb,OAAO;EACT;EACA,cAAc;GACZ,OAAO;EACT;EACA,SAAS,GAAa;GACpB,OAAO,CAAC,KAAY,EAAS,SAAS,GAAa,UAAU,CAAM;EACrE;EACA,MAAM,KAAK,GAAa;GACtB,EAAW;GAEX,IAAM,IAAe,EAAgB,GAAa,UAAU,CAAM,GAC5D,IAAU,MAAM,EAAS,KAAK,CAAY;GAEhD,AAAI,CAAC,KAAY,KAAW,EAAS,CAAY,KAAG,EAAO;EAC7D;EACA,IAAI,SAAS;GACX,OAAO;EACT;EACA,SAAS,GAAa,GAAkB;GACtC,OAAO,EAAS,WAAW,gBAAgB,GAAK,CAAgB;EAClE;EACA,gBAAgB,GAAK,GAAkB;GACrC,OAAO,EAAS,WAAW,gBAAgB,GAAK,CAAgB;EAClE;EACA,YAAY;GAGV,OAFA,EAAW,GAEJ,EAAS,MAAM,CAAM;EAC9B;EACA,MAAM,UAAU,GAAY;GAC1B,EAAW;GAEX,IAAM,IAAO,EAAgB,CAAU;GAEnC,MAAS,MAEb,IAAS,GACT,EAAO;EACT;EACA,UAAU,GAAU,GAAkB;GAGpC,IAFA,EAAW,GAEP,GAAkB,QAAQ,SAAS,aAAa,CAAC;GAErD,IAAM,UAA0B;IAE9B,AADA,EAAY,OAAO,CAAQ,GAC3B,GAAkB,QAAQ,oBAAoB,SAAS,CAAW;GACpE;GAOA,OALA,GAAkB,QAAQ,iBAAiB,SAAS,GAAa,EAAE,MAAM,GAAK,CAAC,GAC/E,EAAY,IAAI,CAAQ,GAEpB,GAAkB,aAAW,EAAS,CAAQ,GAE3C;EACT;GACC,OAAO,UAAU;EAClB,UAAU,GAAa,IAAmB,CAAC,GAAG;GAC5C,OAAO,EAAS,WAAW,iBAAiB,GAAK,CAAgB;EACnE;EACA,iBAAiB,GAAK,GAAkB;GACtC,OAAO,EAAS,WAAW,iBAAiB,GAAK,CAAgB;EACnE;CACF;AACF;AAEA,SAAgB,EACd,GACA,GACqB;CACrB,IAAI,EAAM,YAAY,GACpB,MAAM,IAAI,EAAwB,qCAAqC,OAAO,EAAM,OAAO,EAAE,EAAE;CAGjG,OAAO,EAAuB;EAAE,GAAG;EAAS,UAAU,EAAM;EAAU,QAAQ,EAAM;CAAO,CAAC;AAC9F"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { LinguaDisposedError, LinguaError, LinguaInvalidCatalogError, LinguaInvalidLocaleError, LinguaInvalidPluralCountError, LinguaInvalidStateError, LinguaMissingCatalogError, } from './errors';
2
2
  export { createTranslationStore, hydrateTranslationStore, type TranslationSnapshot, type TranslationStore, } from './i18n';
3
3
  export { createCatalogTranslator, createTranslator, type Translator } from './translator';
4
- export type { Catalog, CatalogLoader, CatalogTranslatorOptions, CatalogNode, Catalogs, CatalogSource, CatalogSources, TranslationState, TranslationStoreOptions, LoadedCatalogs, Locale, MessageKey, PluralCategory, PluralKey, PluralMessage, PluralOptions, SubscribeOptions, TextKey, TranslateOptions, TranslatorOptions, Values, } from './types';
4
+ export type { Catalog, CatalogLoader, CatalogNode, CatalogSource, CatalogSources, Catalogs, CatalogTranslatorOptions, Locale, MessageKey, PluralCategory, PluralKey, PluralMessage, PluralOptions, SubscribeOptions, TextKey, TranslateOptions, TranslationState, TranslationStoreOptions, TranslatorOptions, Values, } from './types';
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,WAAW,EACX,yBAAyB,EACzB,wBAAwB,EACxB,6BAA6B,EAC7B,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,GACtB,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1F,YAAY,EACV,OAAO,EACP,aAAa,EACb,wBAAwB,EACxB,WAAW,EACX,QAAQ,EACR,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,uBAAuB,EACvB,cAAc,EACd,MAAM,EACN,UAAU,EACV,cAAc,EACd,SAAS,EACT,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,OAAO,EACP,gBAAgB,EAChB,iBAAiB,EACjB,MAAM,GACP,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,WAAW,EACX,yBAAyB,EACzB,wBAAwB,EACxB,6BAA6B,EAC7B,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,sBAAsB,EACtB,uBAAuB,EACvB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,GACtB,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1F,YAAY,EACV,OAAO,EACP,aAAa,EACb,WAAW,EACX,aAAa,EACb,cAAc,EACd,QAAQ,EACR,wBAAwB,EACxB,MAAM,EACN,UAAU,EACV,cAAc,EACd,SAAS,EACT,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,OAAO,EACP,gBAAgB,EAChB,gBAAgB,EAChB,uBAAuB,EACvB,iBAAiB,EACjB,MAAM,GACP,MAAM,SAAS,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"lingua.cjs","names":[],"sources":["../src/errors.ts","../src/_dev.ts","../src/_locale.ts","../src/_template.ts","../src/_catalog.ts","../src/_resources.ts","../src/translator.ts","../src/i18n.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 static is(error: unknown): error is LinguaError {\n return error instanceof LinguaError;\n }\n}\n\nexport class LinguaDisposedError extends LinguaError {\n constructor() {\n super('Operation called on a disposed translation store.');\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 {}\n","const isDev = !(globalThis as { __LINGUA_PROD__?: boolean }).__LINGUA_PROD__;\n\n/** @internal @security Messages may include user-supplied data. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/lingua] ${msg}`);\n}\n\n/** @internal */\nexport function error(msg: string, ...args: unknown[]): void {\n if (isDev) console.error(`[@vielzeug/lingua] ${msg}`, ...args);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n","import type { Locale } from './types';\n\nimport { LinguaInvalidLocaleError } from './errors';\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","export 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 renderSegments<V>(\n parts: Template,\n values: Record<string, V | number>,\n missing: (name: string) => string,\n): Array<string | number | V> {\n const result: Array<string | number | V> = [];\n\n for (const part of parts) {\n if (typeof part === 'string') {\n if (part !== '') result.push(part);\n\n continue;\n }\n\n result.push(Object.hasOwn(values, part.value) ? values[part.value]! : missing(part.value));\n }\n\n return result;\n}\n","import type { Catalog, CatalogNode, PluralMessage } from './types';\n\nimport { compileTemplate, type Template } from './_template';\nimport { LinguaInvalidCatalogError } from './errors';\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\nfunction 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","import type { Catalog, CatalogSources, TranslationState, LoadedCatalogs, Locale } from './types';\n\nimport { type CompiledCatalog, compileCatalog } from './_catalog';\nimport { canonicalLocale } from './_locale';\nimport { LinguaMissingCatalogError } from './errors';\n\n/** One catalog state machine owns static sources, lazy sources, and in-flight work. */\nexport function createCatalogStore<C extends Catalog>(sources: CatalogSources<C>) {\n const definitions = new Map<Locale, C | (() => Promise<C>)>();\n const loaded = new Map<Locale, { readonly catalog: C; readonly compiled: CompiledCatalog }>();\n const tasks = new Map<Locale, Promise<void>>();\n\n for (const [locale, source] of Object.entries(sources)) definitions.set(canonicalLocale(locale), source);\n\n const add = (locale: Locale, catalog: C): void => {\n loaded.set(locale, { catalog, compiled: compileCatalog(catalog) });\n };\n\n for (const [locale, source] of definitions) {\n if (typeof source !== 'function') add(locale, source);\n }\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 source = definitions.get(locale);\n\n if (!source) throw new LinguaMissingCatalogError(`Catalog has no source for locale \"${locale}\".`);\n\n if (typeof source !== 'function') {\n add(locale, source);\n\n return true;\n }\n\n const existing = tasks.get(locale);\n\n if (existing) {\n await existing;\n\n return false;\n }\n\n const task = source().then(\n (catalog) => {\n add(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 isLoaded(locale: Locale): boolean {\n return loaded.has(canonicalLocale(locale));\n },\n load,\n state(locale: Locale): TranslationState<C> {\n const catalogs: LoadedCatalogs<C> = {};\n\n for (const [loadedLocale, { catalog }] of loaded) catalogs[loadedLocale] = catalog;\n\n return { catalogs, locale, version: 3 };\n },\n };\n}\n","import type {\n Catalog,\n Catalogs,\n CatalogTranslatorOptions,\n Locale,\n PluralKey,\n PluralOptions,\n TextKey,\n TranslateOptions,\n TranslatorOptions,\n} from './types';\n\nimport { type CompiledCatalog, type CompiledMessage, compileCatalog } from './_catalog';\nimport { canonicalLocale, localeChain, pluralCategory } from './_locale';\nimport { renderSegments, renderText, type Template } from './_template';\nimport { LinguaInvalidPluralCountError } from './errors';\n\nexport type Translator<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n segments<V>(key: TextKey<C>, options: TranslateOptions & { values: Record<string, V> }): Array<string | V>;\n segments<V>(key: PluralKey<C>, options: PluralOptions & { values?: Record<string, V> }): Array<string | number | V>;\n segmentsDynamic<V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V>;\n translate(key: TextKey<C>, options?: TranslateOptions): string;\n translate(key: PluralKey<C>, options: PluralOptions): string;\n translateDynamic(key: string, options?: TranslateOptions | PluralOptions): string;\n};\n\ntype ResolvedMessage = { readonly locale: Locale; readonly message: CompiledMessage };\n\nexport function createTranslatorFromCompiled<C extends Catalog>(\n catalogs: ReadonlyMap<Locale, CompiledCatalog>,\n options: TranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const fallback = (\n Array.isArray(options.fallback) ? options.fallback : options.fallback ? [options.fallback] : []\n ).map(canonicalLocale);\n const chain = localeChain(locale, fallback);\n const missingKey = options.onMissingKey ?? ((key: string) => key);\n const missingValue = options.onMissingValue ?? ((name: string) => `{${name}}`);\n\n const resolve = (key: string): ResolvedMessage | undefined => {\n for (const candidate of chain) {\n const message = catalogs.get(candidate)?.get(key);\n\n if (message) return { locale: candidate, message };\n }\n\n return undefined;\n };\n\n const templateFor = (\n key: string,\n options: TranslateOptions | PluralOptions,\n ): { key: string; template: Template } | undefined => {\n const found = resolve(key);\n\n if (!found) return undefined;\n\n if (found.message.kind === 'text') {\n if ('count' in options) return undefined;\n\n return { key, template: found.message.template };\n }\n\n if (!('count' in options) || !Number.isFinite(options.count)) {\n if ('count' in options) throw new LinguaInvalidPluralCountError('`count` must be a finite number.');\n\n return undefined;\n }\n\n const category =\n options.count === 0 && !options.ordinal\n ? 'zero'\n : pluralCategory(found.locale, options.count, options.ordinal ?? false);\n const template = found.message.forms.get(category) ?? found.message.forms.get('other');\n\n return template ? { key, template } : undefined;\n };\n\n const valuesFor = (options: TranslateOptions | PluralOptions): Record<string, unknown> =>\n 'count' in options ? { count: options.count, ...options.values } : (options.values ?? {});\n\n const segmentsDynamic = <V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V> => {\n const found = templateFor(key, options);\n\n if (!found) return [missingKey(key, locale)];\n\n return renderSegments(found.template, valuesFor(options) as Record<string, V | number>, (name) =>\n missingValue(name, found.key, locale),\n );\n };\n\n const translateDynamic = (key: string, options: TranslateOptions | PluralOptions = {}): string => {\n const found = templateFor(key, options);\n\n if (!found) return missingKey(key, locale);\n\n return renderText(found.template, valuesFor(options), (name) => missingValue(name, found.key, locale));\n };\n\n return {\n locale,\n segments(key: string, options: (TranslateOptions | PluralOptions) & { values?: Record<string, unknown> }) {\n return segmentsDynamic(key, options);\n },\n segmentsDynamic,\n translate(key: string, options: TranslateOptions | PluralOptions = {}) {\n return translateDynamic(key, options);\n },\n translateDynamic,\n } as Translator<C>;\n}\n\n/** Creates a fixed-locale translator from one catalog. Lingua snapshots catalog messages during construction. */\nexport function createCatalogTranslator<C extends Catalog>(\n catalog: C,\n options: CatalogTranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const compiled = new Map<Locale, CompiledCatalog>([[locale, compileCatalog(catalog)]]);\n\n return createTranslatorFromCompiled<C>(compiled, { ...options, locale });\n}\n\nexport function createTranslator<C extends Catalog>(catalogs: Catalogs<C>, options?: TranslatorOptions): Translator<C> {\n const compiled = new Map<Locale, CompiledCatalog>();\n\n for (const [locale, catalog] of Object.entries(catalogs)) {\n compiled.set(canonicalLocale(locale), compileCatalog(catalog));\n }\n\n return createTranslatorFromCompiled<C>(compiled, options);\n}\n","import type { Catalog, TranslationStoreOptions, TranslationState, Locale, SubscribeOptions } from './types';\n\nimport { error as logError } from './_dev';\nimport { canonicalLocale, localeChain } from './_locale';\nimport { createCatalogStore } from './_resources';\nimport { LinguaDisposedError, LinguaInvalidStateError } from './errors';\nimport { type Translator, createTranslatorFromCompiled } from './translator';\n\nexport type TranslationSnapshot<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n readonly revision: number;\n readonly translator: Translator<C>;\n};\n\nexport type TranslationStore<C extends Catalog = Catalog> = Translator<C> & {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n getSnapshot(): TranslationSnapshot<C>;\n isLoaded(options?: { locale?: Locale }): boolean;\n load(options?: { locale?: Locale }): Promise<void>;\n serialize(): TranslationState<C>;\n setLocale(locale: Locale): Promise<void>;\n subscribe(listener: (snapshot: TranslationSnapshot<C>) => void, options?: SubscribeOptions): () => void;\n};\n\nexport function createTranslationStore<C extends Catalog>(options: TranslationStoreOptions<C>): TranslationStore<C> {\n const catalogs = createCatalogStore(options.catalogs);\n const fallback = options.fallback;\n const fallbackLocales = (Array.isArray(fallback) ? fallback : fallback ? [fallback] : []).map(canonicalLocale);\n const controller = new AbortController();\n const subscribers = new Set<(snapshot: TranslationSnapshot<C>) => void>();\n let disposed = false;\n let locale = canonicalLocale(options.locale ?? 'en');\n let revision = 0;\n\n const buildSnapshot = (): TranslationSnapshot<C> => ({\n locale,\n revision,\n translator: createTranslatorFromCompiled<C>(catalogs.catalogMap(), { ...options, fallback, locale }),\n });\n let snapshot = buildSnapshot();\n\n const assertLive = (): void => {\n if (disposed) throw new LinguaDisposedError();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n subscribers.clear();\n controller.abort();\n };\n\n const dispatch = (listener: (next: TranslationSnapshot<C>) => void): void => {\n try {\n listener(snapshot);\n } catch (error) {\n logError('subscriber error', error);\n }\n };\n\n const notify = (): void => {\n revision++;\n snapshot = buildSnapshot();\n\n for (const listener of [...subscribers]) dispatch(listener);\n };\n\n const relevant = (candidate: Locale): boolean => localeChain(locale, fallbackLocales).includes(candidate);\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n getSnapshot() {\n return snapshot;\n },\n isLoaded(loadOptions) {\n return !disposed && catalogs.isLoaded(loadOptions?.locale ?? locale);\n },\n async load(loadOptions) {\n assertLive();\n\n const targetLocale = canonicalLocale(loadOptions?.locale ?? locale);\n const changed = await catalogs.load(targetLocale);\n\n if (!disposed && changed && relevant(targetLocale)) notify();\n },\n get locale() {\n return locale;\n },\n segments(key: string, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n segmentsDynamic(key, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n serialize() {\n assertLive();\n\n return catalogs.state(locale);\n },\n async setLocale(nextLocale) {\n assertLive();\n\n const next = canonicalLocale(nextLocale);\n\n if (next === locale) return;\n\n locale = next;\n notify();\n },\n subscribe(listener, subscribeOptions) {\n assertLive();\n\n if (subscribeOptions?.signal?.aborted) return () => {};\n\n const unsubscribe = (): void => {\n subscribers.delete(listener);\n subscribeOptions?.signal?.removeEventListener('abort', unsubscribe);\n };\n\n subscribeOptions?.signal?.addEventListener('abort', unsubscribe, { once: true });\n subscribers.add(listener);\n\n if (subscribeOptions?.immediate) dispatch(listener);\n\n return unsubscribe;\n },\n [Symbol.dispose]: dispose,\n translate(key: string, translateOptions = {}) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n translateDynamic(key, translateOptions) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n } as TranslationStore<C>;\n}\n\nexport function hydrateTranslationStore<C extends Catalog>(\n state: TranslationState<C>,\n options?: Omit<TranslationStoreOptions<C>, 'locale' | 'catalogs'>,\n): TranslationStore<C> {\n if (state.version !== 3) {\n throw new LinguaInvalidStateError(`Unsupported lingua state version: ${String(state.version)}.`);\n }\n\n return createTranslationStore({ ...options, catalogs: state.catalogs, locale: state.locale });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"lingua.cjs","names":[],"sources":["../src/errors.ts","../src/_dev.ts","../src/_locale.ts","../src/_template.ts","../src/_catalog.ts","../src/_resources.ts","../src/translator.ts","../src/i18n.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 static is(error: unknown): error is LinguaError {\n return error instanceof LinguaError;\n }\n}\n\nexport class LinguaDisposedError extends LinguaError {\n constructor() {\n super('Operation called on a disposed translation store.');\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 {}\n","const isDev = !(globalThis as { __LINGUA_PROD__?: boolean }).__LINGUA_PROD__;\n\n/** @internal @security Messages may include user-supplied data. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/lingua] ${msg}`);\n}\n\n/** @internal */\nexport function error(msg: string, ...args: unknown[]): void {\n if (isDev) console.error(`[@vielzeug/lingua] ${msg}`, ...args);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n","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","export 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 renderSegments<V>(\n parts: Template,\n values: Record<string, V | number>,\n missing: (name: string) => string,\n): Array<string | number | V> {\n const result: Array<string | number | V> = [];\n\n for (const part of parts) {\n if (typeof part === 'string') {\n if (part !== '') result.push(part);\n\n continue;\n }\n\n result.push(Object.hasOwn(values, part.value) ? values[part.value]! : missing(part.value));\n }\n\n return result;\n}\n","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\nfunction 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","import { type CompiledCatalog, compileCatalog } from './_catalog';\nimport { canonicalLocale } from './_locale';\nimport { LinguaMissingCatalogError } from './errors';\nimport type { Catalog, CatalogSources, Catalogs, Locale, TranslationState } from './types';\n\n/** One catalog state machine owns static sources, lazy sources, and in-flight work. */\nexport function createCatalogStore<C extends Catalog>(sources: CatalogSources<C>) {\n const definitions = new Map<Locale, C | (() => Promise<C>)>();\n const loaded = new Map<Locale, { readonly catalog: C; readonly compiled: CompiledCatalog }>();\n const tasks = new Map<Locale, Promise<void>>();\n\n for (const [locale, source] of Object.entries(sources)) definitions.set(canonicalLocale(locale), source);\n\n const add = (locale: Locale, catalog: C): void => {\n loaded.set(locale, { catalog, compiled: compileCatalog(catalog) });\n };\n\n for (const [locale, source] of definitions) {\n if (typeof source !== 'function') add(locale, source);\n }\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 source = definitions.get(locale);\n\n if (!source) throw new LinguaMissingCatalogError(`Catalog has no source for locale \"${locale}\".`);\n\n if (typeof source !== 'function') {\n add(locale, source);\n\n return true;\n }\n\n const existing = tasks.get(locale);\n\n if (existing) {\n await existing;\n\n return false;\n }\n\n const task = source().then(\n (catalog) => {\n add(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 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: 3 };\n },\n };\n}\n","import { type CompiledCatalog, type CompiledMessage, compileCatalog } from './_catalog';\nimport { canonicalLocale, localeChain, pluralCategory } from './_locale';\nimport { renderSegments, renderText, type Template } from './_template';\nimport { LinguaInvalidPluralCountError } from './errors';\nimport type {\n Catalog,\n Catalogs,\n CatalogTranslatorOptions,\n Locale,\n PluralKey,\n PluralOptions,\n TextKey,\n TranslateOptions,\n TranslatorOptions,\n} from './types';\n\nexport type Translator<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n segments<V>(key: TextKey<C>, options: TranslateOptions & { values: Record<string, V> }): Array<string | V>;\n segments<V>(key: PluralKey<C>, options: PluralOptions & { values?: Record<string, V> }): Array<string | number | V>;\n segmentsDynamic<V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V>;\n translate(key: TextKey<C>, options?: TranslateOptions): string;\n translate(key: PluralKey<C>, options: PluralOptions): string;\n translateDynamic(key: string, options?: TranslateOptions | PluralOptions): string;\n};\n\ntype ResolvedMessage = { readonly locale: Locale; readonly message: CompiledMessage };\n\nexport function createTranslatorFromCompiled<C extends Catalog>(\n catalogs: ReadonlyMap<Locale, CompiledCatalog>,\n options: TranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const fallback = (\n Array.isArray(options.fallback) ? options.fallback : options.fallback ? [options.fallback] : []\n ).map(canonicalLocale);\n const chain = localeChain(locale, fallback);\n const missingKey = options.onMissingKey ?? ((key: string) => key);\n const missingValue = options.onMissingValue ?? ((name: string) => `{${name}}`);\n\n const resolve = (key: string): ResolvedMessage | undefined => {\n for (const candidate of chain) {\n const message = catalogs.get(candidate)?.get(key);\n\n if (message) return { locale: candidate, message };\n }\n\n return undefined;\n };\n\n const templateFor = (\n key: string,\n options: TranslateOptions | PluralOptions,\n ): { key: string; template: Template } | undefined => {\n const found = resolve(key);\n\n if (!found) return undefined;\n\n if (found.message.kind === 'text') {\n if ('count' in options) return undefined;\n\n return { key, template: found.message.template };\n }\n\n if (!('count' in options) || !Number.isFinite(options.count)) {\n if ('count' in options) throw new LinguaInvalidPluralCountError('`count` must be a finite number.');\n\n return undefined;\n }\n\n const category =\n options.count === 0 && !options.ordinal\n ? 'zero'\n : pluralCategory(found.locale, options.count, options.ordinal ?? false);\n const template = found.message.forms.get(category) ?? found.message.forms.get('other');\n\n return template ? { key, template } : undefined;\n };\n\n const valuesFor = (options: TranslateOptions | PluralOptions): Record<string, unknown> =>\n 'count' in options ? { count: options.count, ...options.values } : (options.values ?? {});\n\n const segmentsDynamic = <V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V> => {\n const found = templateFor(key, options);\n\n if (!found) return [missingKey(key, locale)];\n\n return renderSegments(found.template, valuesFor(options) as Record<string, V | number>, (name) =>\n missingValue(name, found.key, locale),\n );\n };\n\n const translateDynamic = (key: string, options: TranslateOptions | PluralOptions = {}): string => {\n const found = templateFor(key, options);\n\n if (!found) return missingKey(key, locale);\n\n return renderText(found.template, valuesFor(options), (name) => missingValue(name, found.key, locale));\n };\n\n return {\n locale,\n segments(key: string, options: (TranslateOptions | PluralOptions) & { values?: Record<string, unknown> }) {\n return segmentsDynamic(key, options);\n },\n segmentsDynamic,\n translate(key: string, options: TranslateOptions | PluralOptions = {}) {\n return translateDynamic(key, options);\n },\n translateDynamic,\n } as Translator<C>;\n}\n\n/** Creates a fixed-locale translator from one catalog. Lingua snapshots catalog messages during construction. */\nexport function createCatalogTranslator<C extends Catalog>(\n catalog: C,\n options: CatalogTranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const compiled = new Map<Locale, CompiledCatalog>([[locale, compileCatalog(catalog)]]);\n\n return createTranslatorFromCompiled<C>(compiled, { ...options, locale });\n}\n\nexport function createTranslator<C extends Catalog>(catalogs: Catalogs<C>, options?: TranslatorOptions): Translator<C> {\n const compiled = new Map<Locale, CompiledCatalog>();\n\n for (const [locale, catalog] of Object.entries(catalogs)) {\n compiled.set(canonicalLocale(locale), compileCatalog(catalog));\n }\n\n return createTranslatorFromCompiled<C>(compiled, options);\n}\n","import { error as logError } from './_dev';\nimport { canonicalLocale, localeChain } from './_locale';\nimport { createCatalogStore } from './_resources';\nimport { LinguaDisposedError, LinguaInvalidStateError } from './errors';\nimport { createTranslatorFromCompiled, type Translator } from './translator';\nimport type { Catalog, Locale, SubscribeOptions, TranslationState, TranslationStoreOptions } from './types';\n\nexport type TranslationSnapshot<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n readonly revision: number;\n readonly translator: Translator<C>;\n};\n\nexport type TranslationStore<C extends Catalog = Catalog> = Translator<C> & {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n getSnapshot(): TranslationSnapshot<C>;\n isLoaded(options?: { locale?: Locale }): boolean;\n load(options?: { locale?: Locale }): Promise<void>;\n serialize(): TranslationState<C>;\n setLocale(locale: Locale): Promise<void>;\n subscribe(listener: (snapshot: TranslationSnapshot<C>) => void, options?: SubscribeOptions): () => void;\n};\n\nexport function createTranslationStore<C extends Catalog>(options: TranslationStoreOptions<C>): TranslationStore<C> {\n const catalogs = createCatalogStore(options.catalogs);\n const fallback = options.fallback;\n const fallbackLocales = (Array.isArray(fallback) ? fallback : fallback ? [fallback] : []).map(canonicalLocale);\n const controller = new AbortController();\n const subscribers = new Set<(snapshot: TranslationSnapshot<C>) => void>();\n let disposed = false;\n let locale = canonicalLocale(options.locale ?? 'en');\n let revision = 0;\n\n const buildSnapshot = (): TranslationSnapshot<C> => ({\n locale,\n revision,\n translator: createTranslatorFromCompiled<C>(catalogs.catalogMap(), { ...options, fallback, locale }),\n });\n let snapshot = buildSnapshot();\n\n const assertLive = (): void => {\n if (disposed) throw new LinguaDisposedError();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n subscribers.clear();\n controller.abort();\n };\n\n const dispatch = (listener: (next: TranslationSnapshot<C>) => void): void => {\n try {\n listener(snapshot);\n } catch (error) {\n logError('subscriber error', error);\n }\n };\n\n const notify = (): void => {\n revision++;\n snapshot = buildSnapshot();\n\n for (const listener of [...subscribers]) dispatch(listener);\n };\n\n const relevant = (candidate: Locale): boolean => localeChain(locale, fallbackLocales).includes(candidate);\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n getSnapshot() {\n return snapshot;\n },\n isLoaded(loadOptions) {\n return !disposed && catalogs.isLoaded(loadOptions?.locale ?? locale);\n },\n async load(loadOptions) {\n assertLive();\n\n const targetLocale = canonicalLocale(loadOptions?.locale ?? locale);\n const changed = await catalogs.load(targetLocale);\n\n if (!disposed && changed && relevant(targetLocale)) notify();\n },\n get locale() {\n return locale;\n },\n segments(key: string, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n segmentsDynamic(key, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n serialize() {\n assertLive();\n\n return catalogs.state(locale);\n },\n async setLocale(nextLocale) {\n assertLive();\n\n const next = canonicalLocale(nextLocale);\n\n if (next === locale) return;\n\n locale = next;\n notify();\n },\n subscribe(listener, subscribeOptions) {\n assertLive();\n\n if (subscribeOptions?.signal?.aborted) return () => {};\n\n const unsubscribe = (): void => {\n subscribers.delete(listener);\n subscribeOptions?.signal?.removeEventListener('abort', unsubscribe);\n };\n\n subscribeOptions?.signal?.addEventListener('abort', unsubscribe, { once: true });\n subscribers.add(listener);\n\n if (subscribeOptions?.immediate) dispatch(listener);\n\n return unsubscribe;\n },\n [Symbol.dispose]: dispose,\n translate(key: string, translateOptions = {}) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n translateDynamic(key, translateOptions) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n } as TranslationStore<C>;\n}\n\nexport function hydrateTranslationStore<C extends Catalog>(\n state: TranslationState<C>,\n options?: Omit<TranslationStoreOptions<C>, 'locale' | 'catalogs'>,\n): TranslationStore<C> {\n if (state.version !== 3) {\n throw new LinguaInvalidStateError(`Unsupported lingua state version: ${String(state.version)}.`);\n }\n\n return createTranslationStore({ ...options, catalogs: state.catalogs, locale: state.locale });\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"lingua.iife.js","names":[],"sources":["../src/errors.ts","../src/_dev.ts","../src/_locale.ts","../src/_template.ts","../src/_catalog.ts","../src/_resources.ts","../src/translator.ts","../src/i18n.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 static is(error: unknown): error is LinguaError {\n return error instanceof LinguaError;\n }\n}\n\nexport class LinguaDisposedError extends LinguaError {\n constructor() {\n super('Operation called on a disposed translation store.');\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 {}\n","const isDev = !(globalThis as { __LINGUA_PROD__?: boolean }).__LINGUA_PROD__;\n\n/** @internal @security Messages may include user-supplied data. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/lingua] ${msg}`);\n}\n\n/** @internal */\nexport function error(msg: string, ...args: unknown[]): void {\n if (isDev) console.error(`[@vielzeug/lingua] ${msg}`, ...args);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n","import type { Locale } from './types';\n\nimport { LinguaInvalidLocaleError } from './errors';\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","export 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 renderSegments<V>(\n parts: Template,\n values: Record<string, V | number>,\n missing: (name: string) => string,\n): Array<string | number | V> {\n const result: Array<string | number | V> = [];\n\n for (const part of parts) {\n if (typeof part === 'string') {\n if (part !== '') result.push(part);\n\n continue;\n }\n\n result.push(Object.hasOwn(values, part.value) ? values[part.value]! : missing(part.value));\n }\n\n return result;\n}\n","import type { Catalog, CatalogNode, PluralMessage } from './types';\n\nimport { compileTemplate, type Template } from './_template';\nimport { LinguaInvalidCatalogError } from './errors';\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\nfunction 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","import type { Catalog, CatalogSources, TranslationState, LoadedCatalogs, Locale } from './types';\n\nimport { type CompiledCatalog, compileCatalog } from './_catalog';\nimport { canonicalLocale } from './_locale';\nimport { LinguaMissingCatalogError } from './errors';\n\n/** One catalog state machine owns static sources, lazy sources, and in-flight work. */\nexport function createCatalogStore<C extends Catalog>(sources: CatalogSources<C>) {\n const definitions = new Map<Locale, C | (() => Promise<C>)>();\n const loaded = new Map<Locale, { readonly catalog: C; readonly compiled: CompiledCatalog }>();\n const tasks = new Map<Locale, Promise<void>>();\n\n for (const [locale, source] of Object.entries(sources)) definitions.set(canonicalLocale(locale), source);\n\n const add = (locale: Locale, catalog: C): void => {\n loaded.set(locale, { catalog, compiled: compileCatalog(catalog) });\n };\n\n for (const [locale, source] of definitions) {\n if (typeof source !== 'function') add(locale, source);\n }\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 source = definitions.get(locale);\n\n if (!source) throw new LinguaMissingCatalogError(`Catalog has no source for locale \"${locale}\".`);\n\n if (typeof source !== 'function') {\n add(locale, source);\n\n return true;\n }\n\n const existing = tasks.get(locale);\n\n if (existing) {\n await existing;\n\n return false;\n }\n\n const task = source().then(\n (catalog) => {\n add(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 isLoaded(locale: Locale): boolean {\n return loaded.has(canonicalLocale(locale));\n },\n load,\n state(locale: Locale): TranslationState<C> {\n const catalogs: LoadedCatalogs<C> = {};\n\n for (const [loadedLocale, { catalog }] of loaded) catalogs[loadedLocale] = catalog;\n\n return { catalogs, locale, version: 3 };\n },\n };\n}\n","import type {\n Catalog,\n Catalogs,\n CatalogTranslatorOptions,\n Locale,\n PluralKey,\n PluralOptions,\n TextKey,\n TranslateOptions,\n TranslatorOptions,\n} from './types';\n\nimport { type CompiledCatalog, type CompiledMessage, compileCatalog } from './_catalog';\nimport { canonicalLocale, localeChain, pluralCategory } from './_locale';\nimport { renderSegments, renderText, type Template } from './_template';\nimport { LinguaInvalidPluralCountError } from './errors';\n\nexport type Translator<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n segments<V>(key: TextKey<C>, options: TranslateOptions & { values: Record<string, V> }): Array<string | V>;\n segments<V>(key: PluralKey<C>, options: PluralOptions & { values?: Record<string, V> }): Array<string | number | V>;\n segmentsDynamic<V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V>;\n translate(key: TextKey<C>, options?: TranslateOptions): string;\n translate(key: PluralKey<C>, options: PluralOptions): string;\n translateDynamic(key: string, options?: TranslateOptions | PluralOptions): string;\n};\n\ntype ResolvedMessage = { readonly locale: Locale; readonly message: CompiledMessage };\n\nexport function createTranslatorFromCompiled<C extends Catalog>(\n catalogs: ReadonlyMap<Locale, CompiledCatalog>,\n options: TranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const fallback = (\n Array.isArray(options.fallback) ? options.fallback : options.fallback ? [options.fallback] : []\n ).map(canonicalLocale);\n const chain = localeChain(locale, fallback);\n const missingKey = options.onMissingKey ?? ((key: string) => key);\n const missingValue = options.onMissingValue ?? ((name: string) => `{${name}}`);\n\n const resolve = (key: string): ResolvedMessage | undefined => {\n for (const candidate of chain) {\n const message = catalogs.get(candidate)?.get(key);\n\n if (message) return { locale: candidate, message };\n }\n\n return undefined;\n };\n\n const templateFor = (\n key: string,\n options: TranslateOptions | PluralOptions,\n ): { key: string; template: Template } | undefined => {\n const found = resolve(key);\n\n if (!found) return undefined;\n\n if (found.message.kind === 'text') {\n if ('count' in options) return undefined;\n\n return { key, template: found.message.template };\n }\n\n if (!('count' in options) || !Number.isFinite(options.count)) {\n if ('count' in options) throw new LinguaInvalidPluralCountError('`count` must be a finite number.');\n\n return undefined;\n }\n\n const category =\n options.count === 0 && !options.ordinal\n ? 'zero'\n : pluralCategory(found.locale, options.count, options.ordinal ?? false);\n const template = found.message.forms.get(category) ?? found.message.forms.get('other');\n\n return template ? { key, template } : undefined;\n };\n\n const valuesFor = (options: TranslateOptions | PluralOptions): Record<string, unknown> =>\n 'count' in options ? { count: options.count, ...options.values } : (options.values ?? {});\n\n const segmentsDynamic = <V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V> => {\n const found = templateFor(key, options);\n\n if (!found) return [missingKey(key, locale)];\n\n return renderSegments(found.template, valuesFor(options) as Record<string, V | number>, (name) =>\n missingValue(name, found.key, locale),\n );\n };\n\n const translateDynamic = (key: string, options: TranslateOptions | PluralOptions = {}): string => {\n const found = templateFor(key, options);\n\n if (!found) return missingKey(key, locale);\n\n return renderText(found.template, valuesFor(options), (name) => missingValue(name, found.key, locale));\n };\n\n return {\n locale,\n segments(key: string, options: (TranslateOptions | PluralOptions) & { values?: Record<string, unknown> }) {\n return segmentsDynamic(key, options);\n },\n segmentsDynamic,\n translate(key: string, options: TranslateOptions | PluralOptions = {}) {\n return translateDynamic(key, options);\n },\n translateDynamic,\n } as Translator<C>;\n}\n\n/** Creates a fixed-locale translator from one catalog. Lingua snapshots catalog messages during construction. */\nexport function createCatalogTranslator<C extends Catalog>(\n catalog: C,\n options: CatalogTranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const compiled = new Map<Locale, CompiledCatalog>([[locale, compileCatalog(catalog)]]);\n\n return createTranslatorFromCompiled<C>(compiled, { ...options, locale });\n}\n\nexport function createTranslator<C extends Catalog>(catalogs: Catalogs<C>, options?: TranslatorOptions): Translator<C> {\n const compiled = new Map<Locale, CompiledCatalog>();\n\n for (const [locale, catalog] of Object.entries(catalogs)) {\n compiled.set(canonicalLocale(locale), compileCatalog(catalog));\n }\n\n return createTranslatorFromCompiled<C>(compiled, options);\n}\n","import type { Catalog, TranslationStoreOptions, TranslationState, Locale, SubscribeOptions } from './types';\n\nimport { error as logError } from './_dev';\nimport { canonicalLocale, localeChain } from './_locale';\nimport { createCatalogStore } from './_resources';\nimport { LinguaDisposedError, LinguaInvalidStateError } from './errors';\nimport { type Translator, createTranslatorFromCompiled } from './translator';\n\nexport type TranslationSnapshot<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n readonly revision: number;\n readonly translator: Translator<C>;\n};\n\nexport type TranslationStore<C extends Catalog = Catalog> = Translator<C> & {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n getSnapshot(): TranslationSnapshot<C>;\n isLoaded(options?: { locale?: Locale }): boolean;\n load(options?: { locale?: Locale }): Promise<void>;\n serialize(): TranslationState<C>;\n setLocale(locale: Locale): Promise<void>;\n subscribe(listener: (snapshot: TranslationSnapshot<C>) => void, options?: SubscribeOptions): () => void;\n};\n\nexport function createTranslationStore<C extends Catalog>(options: TranslationStoreOptions<C>): TranslationStore<C> {\n const catalogs = createCatalogStore(options.catalogs);\n const fallback = options.fallback;\n const fallbackLocales = (Array.isArray(fallback) ? fallback : fallback ? [fallback] : []).map(canonicalLocale);\n const controller = new AbortController();\n const subscribers = new Set<(snapshot: TranslationSnapshot<C>) => void>();\n let disposed = false;\n let locale = canonicalLocale(options.locale ?? 'en');\n let revision = 0;\n\n const buildSnapshot = (): TranslationSnapshot<C> => ({\n locale,\n revision,\n translator: createTranslatorFromCompiled<C>(catalogs.catalogMap(), { ...options, fallback, locale }),\n });\n let snapshot = buildSnapshot();\n\n const assertLive = (): void => {\n if (disposed) throw new LinguaDisposedError();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n subscribers.clear();\n controller.abort();\n };\n\n const dispatch = (listener: (next: TranslationSnapshot<C>) => void): void => {\n try {\n listener(snapshot);\n } catch (error) {\n logError('subscriber error', error);\n }\n };\n\n const notify = (): void => {\n revision++;\n snapshot = buildSnapshot();\n\n for (const listener of [...subscribers]) dispatch(listener);\n };\n\n const relevant = (candidate: Locale): boolean => localeChain(locale, fallbackLocales).includes(candidate);\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n getSnapshot() {\n return snapshot;\n },\n isLoaded(loadOptions) {\n return !disposed && catalogs.isLoaded(loadOptions?.locale ?? locale);\n },\n async load(loadOptions) {\n assertLive();\n\n const targetLocale = canonicalLocale(loadOptions?.locale ?? locale);\n const changed = await catalogs.load(targetLocale);\n\n if (!disposed && changed && relevant(targetLocale)) notify();\n },\n get locale() {\n return locale;\n },\n segments(key: string, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n segmentsDynamic(key, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n serialize() {\n assertLive();\n\n return catalogs.state(locale);\n },\n async setLocale(nextLocale) {\n assertLive();\n\n const next = canonicalLocale(nextLocale);\n\n if (next === locale) return;\n\n locale = next;\n notify();\n },\n subscribe(listener, subscribeOptions) {\n assertLive();\n\n if (subscribeOptions?.signal?.aborted) return () => {};\n\n const unsubscribe = (): void => {\n subscribers.delete(listener);\n subscribeOptions?.signal?.removeEventListener('abort', unsubscribe);\n };\n\n subscribeOptions?.signal?.addEventListener('abort', unsubscribe, { once: true });\n subscribers.add(listener);\n\n if (subscribeOptions?.immediate) dispatch(listener);\n\n return unsubscribe;\n },\n [Symbol.dispose]: dispose,\n translate(key: string, translateOptions = {}) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n translateDynamic(key, translateOptions) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n } as TranslationStore<C>;\n}\n\nexport function hydrateTranslationStore<C extends Catalog>(\n state: TranslationState<C>,\n options?: Omit<TranslationStoreOptions<C>, 'locale' | 'catalogs'>,\n): TranslationStore<C> {\n if (state.version !== 3) {\n throw new LinguaInvalidStateError(`Unsupported lingua state version: ${String(state.version)}.`);\n }\n\n return createTranslationStore({ ...options, catalogs: state.catalogs, locale: state.locale });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"lingua.iife.js","names":[],"sources":["../src/errors.ts","../src/_dev.ts","../src/_locale.ts","../src/_template.ts","../src/_catalog.ts","../src/_resources.ts","../src/translator.ts","../src/i18n.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 static is(error: unknown): error is LinguaError {\n return error instanceof LinguaError;\n }\n}\n\nexport class LinguaDisposedError extends LinguaError {\n constructor() {\n super('Operation called on a disposed translation store.');\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 {}\n","const isDev = !(globalThis as { __LINGUA_PROD__?: boolean }).__LINGUA_PROD__;\n\n/** @internal @security Messages may include user-supplied data. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/lingua] ${msg}`);\n}\n\n/** @internal */\nexport function error(msg: string, ...args: unknown[]): void {\n if (isDev) console.error(`[@vielzeug/lingua] ${msg}`, ...args);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n","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","export 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 renderSegments<V>(\n parts: Template,\n values: Record<string, V | number>,\n missing: (name: string) => string,\n): Array<string | number | V> {\n const result: Array<string | number | V> = [];\n\n for (const part of parts) {\n if (typeof part === 'string') {\n if (part !== '') result.push(part);\n\n continue;\n }\n\n result.push(Object.hasOwn(values, part.value) ? values[part.value]! : missing(part.value));\n }\n\n return result;\n}\n","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\nfunction 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","import { type CompiledCatalog, compileCatalog } from './_catalog';\nimport { canonicalLocale } from './_locale';\nimport { LinguaMissingCatalogError } from './errors';\nimport type { Catalog, CatalogSources, Catalogs, Locale, TranslationState } from './types';\n\n/** One catalog state machine owns static sources, lazy sources, and in-flight work. */\nexport function createCatalogStore<C extends Catalog>(sources: CatalogSources<C>) {\n const definitions = new Map<Locale, C | (() => Promise<C>)>();\n const loaded = new Map<Locale, { readonly catalog: C; readonly compiled: CompiledCatalog }>();\n const tasks = new Map<Locale, Promise<void>>();\n\n for (const [locale, source] of Object.entries(sources)) definitions.set(canonicalLocale(locale), source);\n\n const add = (locale: Locale, catalog: C): void => {\n loaded.set(locale, { catalog, compiled: compileCatalog(catalog) });\n };\n\n for (const [locale, source] of definitions) {\n if (typeof source !== 'function') add(locale, source);\n }\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 source = definitions.get(locale);\n\n if (!source) throw new LinguaMissingCatalogError(`Catalog has no source for locale \"${locale}\".`);\n\n if (typeof source !== 'function') {\n add(locale, source);\n\n return true;\n }\n\n const existing = tasks.get(locale);\n\n if (existing) {\n await existing;\n\n return false;\n }\n\n const task = source().then(\n (catalog) => {\n add(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 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: 3 };\n },\n };\n}\n","import { type CompiledCatalog, type CompiledMessage, compileCatalog } from './_catalog';\nimport { canonicalLocale, localeChain, pluralCategory } from './_locale';\nimport { renderSegments, renderText, type Template } from './_template';\nimport { LinguaInvalidPluralCountError } from './errors';\nimport type {\n Catalog,\n Catalogs,\n CatalogTranslatorOptions,\n Locale,\n PluralKey,\n PluralOptions,\n TextKey,\n TranslateOptions,\n TranslatorOptions,\n} from './types';\n\nexport type Translator<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n segments<V>(key: TextKey<C>, options: TranslateOptions & { values: Record<string, V> }): Array<string | V>;\n segments<V>(key: PluralKey<C>, options: PluralOptions & { values?: Record<string, V> }): Array<string | number | V>;\n segmentsDynamic<V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V>;\n translate(key: TextKey<C>, options?: TranslateOptions): string;\n translate(key: PluralKey<C>, options: PluralOptions): string;\n translateDynamic(key: string, options?: TranslateOptions | PluralOptions): string;\n};\n\ntype ResolvedMessage = { readonly locale: Locale; readonly message: CompiledMessage };\n\nexport function createTranslatorFromCompiled<C extends Catalog>(\n catalogs: ReadonlyMap<Locale, CompiledCatalog>,\n options: TranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const fallback = (\n Array.isArray(options.fallback) ? options.fallback : options.fallback ? [options.fallback] : []\n ).map(canonicalLocale);\n const chain = localeChain(locale, fallback);\n const missingKey = options.onMissingKey ?? ((key: string) => key);\n const missingValue = options.onMissingValue ?? ((name: string) => `{${name}}`);\n\n const resolve = (key: string): ResolvedMessage | undefined => {\n for (const candidate of chain) {\n const message = catalogs.get(candidate)?.get(key);\n\n if (message) return { locale: candidate, message };\n }\n\n return undefined;\n };\n\n const templateFor = (\n key: string,\n options: TranslateOptions | PluralOptions,\n ): { key: string; template: Template } | undefined => {\n const found = resolve(key);\n\n if (!found) return undefined;\n\n if (found.message.kind === 'text') {\n if ('count' in options) return undefined;\n\n return { key, template: found.message.template };\n }\n\n if (!('count' in options) || !Number.isFinite(options.count)) {\n if ('count' in options) throw new LinguaInvalidPluralCountError('`count` must be a finite number.');\n\n return undefined;\n }\n\n const category =\n options.count === 0 && !options.ordinal\n ? 'zero'\n : pluralCategory(found.locale, options.count, options.ordinal ?? false);\n const template = found.message.forms.get(category) ?? found.message.forms.get('other');\n\n return template ? { key, template } : undefined;\n };\n\n const valuesFor = (options: TranslateOptions | PluralOptions): Record<string, unknown> =>\n 'count' in options ? { count: options.count, ...options.values } : (options.values ?? {});\n\n const segmentsDynamic = <V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V> => {\n const found = templateFor(key, options);\n\n if (!found) return [missingKey(key, locale)];\n\n return renderSegments(found.template, valuesFor(options) as Record<string, V | number>, (name) =>\n missingValue(name, found.key, locale),\n );\n };\n\n const translateDynamic = (key: string, options: TranslateOptions | PluralOptions = {}): string => {\n const found = templateFor(key, options);\n\n if (!found) return missingKey(key, locale);\n\n return renderText(found.template, valuesFor(options), (name) => missingValue(name, found.key, locale));\n };\n\n return {\n locale,\n segments(key: string, options: (TranslateOptions | PluralOptions) & { values?: Record<string, unknown> }) {\n return segmentsDynamic(key, options);\n },\n segmentsDynamic,\n translate(key: string, options: TranslateOptions | PluralOptions = {}) {\n return translateDynamic(key, options);\n },\n translateDynamic,\n } as Translator<C>;\n}\n\n/** Creates a fixed-locale translator from one catalog. Lingua snapshots catalog messages during construction. */\nexport function createCatalogTranslator<C extends Catalog>(\n catalog: C,\n options: CatalogTranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const compiled = new Map<Locale, CompiledCatalog>([[locale, compileCatalog(catalog)]]);\n\n return createTranslatorFromCompiled<C>(compiled, { ...options, locale });\n}\n\nexport function createTranslator<C extends Catalog>(catalogs: Catalogs<C>, options?: TranslatorOptions): Translator<C> {\n const compiled = new Map<Locale, CompiledCatalog>();\n\n for (const [locale, catalog] of Object.entries(catalogs)) {\n compiled.set(canonicalLocale(locale), compileCatalog(catalog));\n }\n\n return createTranslatorFromCompiled<C>(compiled, options);\n}\n","import { error as logError } from './_dev';\nimport { canonicalLocale, localeChain } from './_locale';\nimport { createCatalogStore } from './_resources';\nimport { LinguaDisposedError, LinguaInvalidStateError } from './errors';\nimport { createTranslatorFromCompiled, type Translator } from './translator';\nimport type { Catalog, Locale, SubscribeOptions, TranslationState, TranslationStoreOptions } from './types';\n\nexport type TranslationSnapshot<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n readonly revision: number;\n readonly translator: Translator<C>;\n};\n\nexport type TranslationStore<C extends Catalog = Catalog> = Translator<C> & {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n getSnapshot(): TranslationSnapshot<C>;\n isLoaded(options?: { locale?: Locale }): boolean;\n load(options?: { locale?: Locale }): Promise<void>;\n serialize(): TranslationState<C>;\n setLocale(locale: Locale): Promise<void>;\n subscribe(listener: (snapshot: TranslationSnapshot<C>) => void, options?: SubscribeOptions): () => void;\n};\n\nexport function createTranslationStore<C extends Catalog>(options: TranslationStoreOptions<C>): TranslationStore<C> {\n const catalogs = createCatalogStore(options.catalogs);\n const fallback = options.fallback;\n const fallbackLocales = (Array.isArray(fallback) ? fallback : fallback ? [fallback] : []).map(canonicalLocale);\n const controller = new AbortController();\n const subscribers = new Set<(snapshot: TranslationSnapshot<C>) => void>();\n let disposed = false;\n let locale = canonicalLocale(options.locale ?? 'en');\n let revision = 0;\n\n const buildSnapshot = (): TranslationSnapshot<C> => ({\n locale,\n revision,\n translator: createTranslatorFromCompiled<C>(catalogs.catalogMap(), { ...options, fallback, locale }),\n });\n let snapshot = buildSnapshot();\n\n const assertLive = (): void => {\n if (disposed) throw new LinguaDisposedError();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n subscribers.clear();\n controller.abort();\n };\n\n const dispatch = (listener: (next: TranslationSnapshot<C>) => void): void => {\n try {\n listener(snapshot);\n } catch (error) {\n logError('subscriber error', error);\n }\n };\n\n const notify = (): void => {\n revision++;\n snapshot = buildSnapshot();\n\n for (const listener of [...subscribers]) dispatch(listener);\n };\n\n const relevant = (candidate: Locale): boolean => localeChain(locale, fallbackLocales).includes(candidate);\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n getSnapshot() {\n return snapshot;\n },\n isLoaded(loadOptions) {\n return !disposed && catalogs.isLoaded(loadOptions?.locale ?? locale);\n },\n async load(loadOptions) {\n assertLive();\n\n const targetLocale = canonicalLocale(loadOptions?.locale ?? locale);\n const changed = await catalogs.load(targetLocale);\n\n if (!disposed && changed && relevant(targetLocale)) notify();\n },\n get locale() {\n return locale;\n },\n segments(key: string, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n segmentsDynamic(key, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n serialize() {\n assertLive();\n\n return catalogs.state(locale);\n },\n async setLocale(nextLocale) {\n assertLive();\n\n const next = canonicalLocale(nextLocale);\n\n if (next === locale) return;\n\n locale = next;\n notify();\n },\n subscribe(listener, subscribeOptions) {\n assertLive();\n\n if (subscribeOptions?.signal?.aborted) return () => {};\n\n const unsubscribe = (): void => {\n subscribers.delete(listener);\n subscribeOptions?.signal?.removeEventListener('abort', unsubscribe);\n };\n\n subscribeOptions?.signal?.addEventListener('abort', unsubscribe, { once: true });\n subscribers.add(listener);\n\n if (subscribeOptions?.immediate) dispatch(listener);\n\n return unsubscribe;\n },\n [Symbol.dispose]: dispose,\n translate(key: string, translateOptions = {}) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n translateDynamic(key, translateOptions) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n } as TranslationStore<C>;\n}\n\nexport function hydrateTranslationStore<C extends Catalog>(\n state: TranslationState<C>,\n options?: Omit<TranslationStoreOptions<C>, 'locale' | 'catalogs'>,\n): TranslationStore<C> {\n if (state.version !== 3) {\n throw new LinguaInvalidStateError(`Unsupported lingua state version: ${String(state.version)}.`);\n }\n\n return createTranslationStore({ ...options, catalogs: state.catalogs, locale: state.locale });\n}\n"],"mappings":"qFAAA,IAAa,EAAb,MAAa,UAAoB,KAAM,CACrC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,WAAW,KACvB,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CAEA,OAAO,GAAG,EAAsC,CAC9C,OAAO,aAAiB,CAC1B,CACF,EAEa,EAAb,cAAyC,CAAY,CACnD,aAAc,CACZ,MAAM,mDAAmD,CAC3D,CACF,EAEa,EAAb,cAA+C,CAAY,CAAC,EAC/C,EAAb,cAA8C,CAAY,CAAC,EAC9C,EAAb,cAAmD,CAAY,CAAC,EACnD,EAAb,cAA6C,CAAY,CAAC,EAC7C,EAAb,cAA+C,CAAY,CAAC,EEnBtD,EAAc,IAAI,IAExB,SAAgB,EAAgB,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,EAAY,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,CCtCA,IAAM,EAAgB,8BAEtB,SAAgB,EAAgB,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,EACd,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,EACd,EACA,EACA,EAC4B,CAC5B,IAAM,EAAqC,CAAC,EAE5C,IAAK,IAAM,KAAQ,EAAO,CACxB,GAAI,OAAO,GAAS,SAAU,CACxB,IAAS,IAAI,EAAO,KAAK,CAAI,EAEjC,QACF,CAEA,EAAO,KAAK,OAAO,OAAO,EAAQ,EAAK,KAAK,EAAI,EAAO,EAAK,OAAU,EAAQ,EAAK,KAAK,CAAC,CAC3F,CAEA,OAAO,CACT,CCrDA,IAAM,EAAa,IAAI,IAAI,CAAC,YAAa,cAAe,WAAW,CAAC,EAOpE,SAAS,EAAgB,EAA0C,CACjE,OAAO,OAAO,GAAS,YAAY,GAAiB,OAAO,OAAO,EAAM,QAAQ,CAClF,CAGA,SAAgB,EAAe,EAAmC,CAChE,IAAM,EAAW,IAAI,IAEf,GAAS,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,EAAgB,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,EAAM,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,EAAM,EAAO,CAAG,CAClB,CAEA,OAAO,CACT,CChEA,SAAgB,EAAsC,EAA4B,CAChF,IAAM,EAAc,IAAI,IAClB,EAAS,IAAI,IACb,EAAQ,IAAI,IAElB,IAAK,GAAM,CAAC,EAAQ,KAAW,OAAO,QAAQ,CAAO,EAAG,EAAY,IAAI,EAAgB,CAAM,EAAG,CAAM,EAEvG,IAAM,GAAO,EAAgB,IAAqB,CAChD,EAAO,IAAI,EAAQ,CAAE,UAAS,SAAU,EAAe,CAAO,CAAE,CAAC,CACnE,EAEA,IAAK,GAAM,CAAC,EAAQ,KAAW,EACzB,OAAO,GAAW,YAAY,EAAI,EAAQ,CAAM,EA2CtD,MAAO,CACL,YAAmD,CACjD,OAAO,IAAI,IAAI,CAAC,GAAG,CAAM,CAAC,CAAC,KAAK,CAAC,EAAQ,CAAE,eAAgB,CAAC,EAAQ,CAAQ,CAAC,CAAC,CAChF,EACA,SAAS,EAAyB,CAChC,OAAO,EAAO,IAAI,EAAgB,CAAM,CAAC,CAC3C,EACA,UA/CkB,IAA8C,CAChE,IAAM,EAAS,EAAgB,CAAe,EAE9C,GAAI,EAAO,IAAI,CAAM,EAAG,MAAO,GAE/B,IAAM,EAAS,EAAY,IAAI,CAAM,EAErC,GAAI,CAAC,EAAQ,MAAM,IAAI,EAA0B,qCAAqC,EAAO,GAAG,EAEhG,GAAI,OAAO,GAAW,WAGpB,OAFA,EAAI,EAAQ,CAAM,EAEX,GAGT,IAAM,EAAW,EAAM,IAAI,CAAM,EAEjC,GAAI,EAGF,OAFA,MAAM,EAEC,GAGT,IAAM,EAAO,EAAO,CAAC,CAAC,KACnB,GAAY,CACX,EAAI,EAAQ,CAAO,EACnB,EAAM,OAAO,CAAM,CACrB,EACC,GAAmB,CAElB,MADA,EAAM,OAAO,CAAM,EACb,CACR,CACF,EAKA,OAHA,EAAM,IAAI,EAAQ,CAAI,EACtB,MAAM,EAEC,EACT,EAUE,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,CC9CA,SAAgB,EACd,EACA,EAA6B,CAAC,EACf,CACf,IAAM,EAAS,EAAgB,EAAQ,QAAU,IAAI,EAI/C,EAAQ,EAAY,GAFxB,MAAM,QAAQ,EAAQ,QAAQ,EAAI,EAAQ,SAAW,EAAQ,SAAW,CAAC,EAAQ,QAAQ,EAAI,CAAC,EAAA,CAC9F,IAAI,CAC4B,CAAQ,EACpC,EAAa,EAAQ,eAAkB,GAAgB,GACvD,EAAe,EAAQ,iBAAoB,GAAiB,IAAI,EAAK,IAErE,EAAW,GAA6C,CAC5D,IAAK,IAAM,KAAa,EAAO,CAC7B,IAAM,EAAU,EAAS,IAAI,CAAS,CAAC,EAAE,IAAI,CAAG,EAEhD,GAAI,EAAS,MAAO,CAAE,OAAQ,EAAW,SAAQ,CACnD,CAGF,EAEM,GACJ,EACA,IACoD,CACpD,IAAM,EAAQ,EAAQ,CAAG,EAEzB,GAAI,CAAC,EAAO,OAEZ,GAAI,EAAM,QAAQ,OAAS,OAGzB,MAFI,UAAW,EAAS,OAEjB,CAAE,MAAK,SAAU,EAAM,QAAQ,QAAS,EAGjD,GAAI,EAAE,UAAW,IAAY,CAAC,OAAO,SAAS,EAAQ,KAAK,EAAG,CAC5D,GAAI,UAAW,EAAS,MAAM,IAAI,EAA8B,kCAAkC,EAElG,MACF,CAEA,IAAM,EACJ,EAAQ,QAAU,GAAK,CAAC,EAAQ,QAC5B,OACA,EAAe,EAAM,OAAQ,EAAQ,MAAO,EAAQ,SAAW,EAAK,EACpE,EAAW,EAAM,QAAQ,MAAM,IAAI,CAAQ,GAAK,EAAM,QAAQ,MAAM,IAAI,OAAO,EAErF,OAAO,EAAW,CAAE,MAAK,UAAS,EAAI,IAAA,EACxC,EAEM,EAAa,GACjB,UAAW,EAAU,CAAE,MAAO,EAAQ,MAAO,GAAG,EAAQ,MAAO,EAAK,EAAQ,QAAU,CAAC,EAEnF,GACJ,EACA,IAC+B,CAC/B,IAAM,EAAQ,EAAY,EAAK,CAAO,EAItC,OAFK,EAEE,EAAe,EAAM,SAAU,EAAU,CAAO,EAAkC,GACvF,EAAa,EAAM,EAAM,IAAK,CAAM,CACtC,EAJmB,CAAC,EAAW,EAAK,CAAM,CAAC,CAK7C,EAEM,GAAoB,EAAa,EAA4C,CAAC,IAAc,CAChG,IAAM,EAAQ,EAAY,EAAK,CAAO,EAItC,OAFK,EAEE,EAAW,EAAM,SAAU,EAAU,CAAO,EAAI,GAAS,EAAa,EAAM,EAAM,IAAK,CAAM,CAAC,EAFlF,EAAW,EAAK,CAAM,CAG3C,EAEA,MAAO,CACL,SACA,SAAS,EAAa,EAAoF,CACxG,OAAO,EAAgB,EAAK,CAAO,CACrC,EACA,kBACA,UAAU,EAAa,EAA4C,CAAC,EAAG,CACrE,OAAO,EAAiB,EAAK,CAAO,CACtC,EACA,kBACF,CACF,CAGA,SAAgB,EACd,EACA,EAAoC,CAAC,EACtB,CACf,IAAM,EAAS,EAAgB,EAAQ,QAAU,IAAI,EAGrD,OAAO,EAAgC,IAFlB,IAA6B,CAAC,CAAC,EAAQ,EAAe,CAAO,CAAC,CAAC,CAE7C,EAAU,CAAE,GAAG,EAAS,QAAO,CAAC,CACzE,CAEA,SAAgB,EAAoC,EAAuB,EAA4C,CACrH,IAAM,EAAW,IAAI,IAErB,IAAK,GAAM,CAAC,EAAQ,KAAY,OAAO,QAAQ,CAAQ,EACrD,EAAS,IAAI,EAAgB,CAAM,EAAG,EAAe,CAAO,CAAC,EAG/D,OAAO,EAAgC,EAAU,CAAO,CAC1D,CChHA,SAAgB,EAA0C,EAA0D,CAClH,IAAM,EAAW,EAAmB,EAAQ,QAAQ,EAC9C,EAAW,EAAQ,SACnB,GAAmB,MAAM,QAAQ,CAAQ,EAAI,EAAW,EAAW,CAAC,CAAQ,EAAI,CAAC,EAAA,CAAG,IAAI,CAAe,EACvG,EAAa,IAAI,gBACjB,EAAc,IAAI,IACpB,EAAW,GACX,EAAS,EAAgB,EAAQ,QAAU,IAAI,EAC/C,EAAW,EAET,OAA+C,CACnD,SACA,WACA,WAAY,EAAgC,EAAS,WAAW,EAAG,CAAE,GAAG,EAAS,WAAU,QAAO,CAAC,CACrG,GACI,EAAW,EAAc,EAEvB,MAAyB,CAC7B,GAAI,EAAU,MAAM,IAAI,CAC1B,EAEM,MAAsB,CACtB,IAEJ,EAAW,GACX,EAAY,MAAM,EAClB,EAAW,MAAM,EACnB,EAEM,EAAY,GAA2D,CAC3E,GAAI,CACF,EAAS,CAAQ,CACnB,MAAgB,CAEhB,CACF,EAEM,MAAqB,CACzB,IACA,EAAW,EAAc,EAEzB,IAAK,IAAM,IAAY,CAAC,GAAG,CAAW,EAAG,EAAS,CAAQ,CAC5D,EAEM,EAAY,GAA+B,EAAY,EAAQ,CAAe,CAAC,CAAC,SAAS,CAAS,EAExG,MAAO,CACL,IAAI,gBAAiB,CACnB,OAAO,EAAW,MACpB,EACA,UACA,IAAI,UAAW,CACb,OAAO,CACT,EACA,aAAc,CACZ,OAAO,CACT,EACA,SAAS,EAAa,CACpB,MAAO,CAAC,GAAY,EAAS,SAAS,GAAa,QAAU,CAAM,CACrE,EACA,MAAM,KAAK,EAAa,CACtB,EAAW,EAEX,IAAM,EAAe,EAAgB,GAAa,QAAU,CAAM,EAC5D,EAAU,MAAM,EAAS,KAAK,CAAY,EAE5C,CAAC,GAAY,GAAW,EAAS,CAAY,GAAG,EAAO,CAC7D,EACA,IAAI,QAAS,CACX,OAAO,CACT,EACA,SAAS,EAAa,EAAkB,CACtC,OAAO,EAAS,WAAW,gBAAgB,EAAK,CAAgB,CAClE,EACA,gBAAgB,EAAK,EAAkB,CACrC,OAAO,EAAS,WAAW,gBAAgB,EAAK,CAAgB,CAClE,EACA,WAAY,CAGV,OAFA,EAAW,EAEJ,EAAS,MAAM,CAAM,CAC9B,EACA,MAAM,UAAU,EAAY,CAC1B,EAAW,EAEX,IAAM,EAAO,EAAgB,CAAU,EAEnC,IAAS,IAEb,EAAS,EACT,EAAO,EACT,EACA,UAAU,EAAU,EAAkB,CAGpC,GAFA,EAAW,EAEP,GAAkB,QAAQ,QAAS,UAAa,CAAC,EAErD,IAAM,MAA0B,CAC9B,EAAY,OAAO,CAAQ,EAC3B,GAAkB,QAAQ,oBAAoB,QAAS,CAAW,CACpE,EAOA,OALA,GAAkB,QAAQ,iBAAiB,QAAS,EAAa,CAAE,KAAM,EAAK,CAAC,EAC/E,EAAY,IAAI,CAAQ,EAEpB,GAAkB,WAAW,EAAS,CAAQ,EAE3C,CACT,GACC,OAAO,SAAU,EAClB,UAAU,EAAa,EAAmB,CAAC,EAAG,CAC5C,OAAO,EAAS,WAAW,iBAAiB,EAAK,CAAgB,CACnE,EACA,iBAAiB,EAAK,EAAkB,CACtC,OAAO,EAAS,WAAW,iBAAiB,EAAK,CAAgB,CACnE,CACF,CACF,CAEA,SAAgB,EACd,EACA,EACqB,CACrB,GAAI,EAAM,UAAY,EACpB,MAAM,IAAI,EAAwB,qCAAqC,OAAO,EAAM,OAAO,EAAE,EAAE,EAGjG,OAAO,EAAuB,CAAE,GAAG,EAAS,SAAU,EAAM,SAAU,OAAQ,EAAM,MAAO,CAAC,CAC9F"}
@@ -1 +1 @@
1
- {"version":3,"file":"lingua.js","names":[],"sources":["../src/errors.ts","../src/_dev.ts","../src/_locale.ts","../src/_template.ts","../src/_catalog.ts","../src/_resources.ts","../src/translator.ts","../src/i18n.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 static is(error: unknown): error is LinguaError {\n return error instanceof LinguaError;\n }\n}\n\nexport class LinguaDisposedError extends LinguaError {\n constructor() {\n super('Operation called on a disposed translation store.');\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 {}\n","const isDev = !(globalThis as { __LINGUA_PROD__?: boolean }).__LINGUA_PROD__;\n\n/** @internal @security Messages may include user-supplied data. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/lingua] ${msg}`);\n}\n\n/** @internal */\nexport function error(msg: string, ...args: unknown[]): void {\n if (isDev) console.error(`[@vielzeug/lingua] ${msg}`, ...args);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n","import type { Locale } from './types';\n\nimport { LinguaInvalidLocaleError } from './errors';\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","export 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 renderSegments<V>(\n parts: Template,\n values: Record<string, V | number>,\n missing: (name: string) => string,\n): Array<string | number | V> {\n const result: Array<string | number | V> = [];\n\n for (const part of parts) {\n if (typeof part === 'string') {\n if (part !== '') result.push(part);\n\n continue;\n }\n\n result.push(Object.hasOwn(values, part.value) ? values[part.value]! : missing(part.value));\n }\n\n return result;\n}\n","import type { Catalog, CatalogNode, PluralMessage } from './types';\n\nimport { compileTemplate, type Template } from './_template';\nimport { LinguaInvalidCatalogError } from './errors';\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\nfunction 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","import type { Catalog, CatalogSources, TranslationState, LoadedCatalogs, Locale } from './types';\n\nimport { type CompiledCatalog, compileCatalog } from './_catalog';\nimport { canonicalLocale } from './_locale';\nimport { LinguaMissingCatalogError } from './errors';\n\n/** One catalog state machine owns static sources, lazy sources, and in-flight work. */\nexport function createCatalogStore<C extends Catalog>(sources: CatalogSources<C>) {\n const definitions = new Map<Locale, C | (() => Promise<C>)>();\n const loaded = new Map<Locale, { readonly catalog: C; readonly compiled: CompiledCatalog }>();\n const tasks = new Map<Locale, Promise<void>>();\n\n for (const [locale, source] of Object.entries(sources)) definitions.set(canonicalLocale(locale), source);\n\n const add = (locale: Locale, catalog: C): void => {\n loaded.set(locale, { catalog, compiled: compileCatalog(catalog) });\n };\n\n for (const [locale, source] of definitions) {\n if (typeof source !== 'function') add(locale, source);\n }\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 source = definitions.get(locale);\n\n if (!source) throw new LinguaMissingCatalogError(`Catalog has no source for locale \"${locale}\".`);\n\n if (typeof source !== 'function') {\n add(locale, source);\n\n return true;\n }\n\n const existing = tasks.get(locale);\n\n if (existing) {\n await existing;\n\n return false;\n }\n\n const task = source().then(\n (catalog) => {\n add(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 isLoaded(locale: Locale): boolean {\n return loaded.has(canonicalLocale(locale));\n },\n load,\n state(locale: Locale): TranslationState<C> {\n const catalogs: LoadedCatalogs<C> = {};\n\n for (const [loadedLocale, { catalog }] of loaded) catalogs[loadedLocale] = catalog;\n\n return { catalogs, locale, version: 3 };\n },\n };\n}\n","import type {\n Catalog,\n Catalogs,\n CatalogTranslatorOptions,\n Locale,\n PluralKey,\n PluralOptions,\n TextKey,\n TranslateOptions,\n TranslatorOptions,\n} from './types';\n\nimport { type CompiledCatalog, type CompiledMessage, compileCatalog } from './_catalog';\nimport { canonicalLocale, localeChain, pluralCategory } from './_locale';\nimport { renderSegments, renderText, type Template } from './_template';\nimport { LinguaInvalidPluralCountError } from './errors';\n\nexport type Translator<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n segments<V>(key: TextKey<C>, options: TranslateOptions & { values: Record<string, V> }): Array<string | V>;\n segments<V>(key: PluralKey<C>, options: PluralOptions & { values?: Record<string, V> }): Array<string | number | V>;\n segmentsDynamic<V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V>;\n translate(key: TextKey<C>, options?: TranslateOptions): string;\n translate(key: PluralKey<C>, options: PluralOptions): string;\n translateDynamic(key: string, options?: TranslateOptions | PluralOptions): string;\n};\n\ntype ResolvedMessage = { readonly locale: Locale; readonly message: CompiledMessage };\n\nexport function createTranslatorFromCompiled<C extends Catalog>(\n catalogs: ReadonlyMap<Locale, CompiledCatalog>,\n options: TranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const fallback = (\n Array.isArray(options.fallback) ? options.fallback : options.fallback ? [options.fallback] : []\n ).map(canonicalLocale);\n const chain = localeChain(locale, fallback);\n const missingKey = options.onMissingKey ?? ((key: string) => key);\n const missingValue = options.onMissingValue ?? ((name: string) => `{${name}}`);\n\n const resolve = (key: string): ResolvedMessage | undefined => {\n for (const candidate of chain) {\n const message = catalogs.get(candidate)?.get(key);\n\n if (message) return { locale: candidate, message };\n }\n\n return undefined;\n };\n\n const templateFor = (\n key: string,\n options: TranslateOptions | PluralOptions,\n ): { key: string; template: Template } | undefined => {\n const found = resolve(key);\n\n if (!found) return undefined;\n\n if (found.message.kind === 'text') {\n if ('count' in options) return undefined;\n\n return { key, template: found.message.template };\n }\n\n if (!('count' in options) || !Number.isFinite(options.count)) {\n if ('count' in options) throw new LinguaInvalidPluralCountError('`count` must be a finite number.');\n\n return undefined;\n }\n\n const category =\n options.count === 0 && !options.ordinal\n ? 'zero'\n : pluralCategory(found.locale, options.count, options.ordinal ?? false);\n const template = found.message.forms.get(category) ?? found.message.forms.get('other');\n\n return template ? { key, template } : undefined;\n };\n\n const valuesFor = (options: TranslateOptions | PluralOptions): Record<string, unknown> =>\n 'count' in options ? { count: options.count, ...options.values } : (options.values ?? {});\n\n const segmentsDynamic = <V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V> => {\n const found = templateFor(key, options);\n\n if (!found) return [missingKey(key, locale)];\n\n return renderSegments(found.template, valuesFor(options) as Record<string, V | number>, (name) =>\n missingValue(name, found.key, locale),\n );\n };\n\n const translateDynamic = (key: string, options: TranslateOptions | PluralOptions = {}): string => {\n const found = templateFor(key, options);\n\n if (!found) return missingKey(key, locale);\n\n return renderText(found.template, valuesFor(options), (name) => missingValue(name, found.key, locale));\n };\n\n return {\n locale,\n segments(key: string, options: (TranslateOptions | PluralOptions) & { values?: Record<string, unknown> }) {\n return segmentsDynamic(key, options);\n },\n segmentsDynamic,\n translate(key: string, options: TranslateOptions | PluralOptions = {}) {\n return translateDynamic(key, options);\n },\n translateDynamic,\n } as Translator<C>;\n}\n\n/** Creates a fixed-locale translator from one catalog. Lingua snapshots catalog messages during construction. */\nexport function createCatalogTranslator<C extends Catalog>(\n catalog: C,\n options: CatalogTranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const compiled = new Map<Locale, CompiledCatalog>([[locale, compileCatalog(catalog)]]);\n\n return createTranslatorFromCompiled<C>(compiled, { ...options, locale });\n}\n\nexport function createTranslator<C extends Catalog>(catalogs: Catalogs<C>, options?: TranslatorOptions): Translator<C> {\n const compiled = new Map<Locale, CompiledCatalog>();\n\n for (const [locale, catalog] of Object.entries(catalogs)) {\n compiled.set(canonicalLocale(locale), compileCatalog(catalog));\n }\n\n return createTranslatorFromCompiled<C>(compiled, options);\n}\n","import type { Catalog, TranslationStoreOptions, TranslationState, Locale, SubscribeOptions } from './types';\n\nimport { error as logError } from './_dev';\nimport { canonicalLocale, localeChain } from './_locale';\nimport { createCatalogStore } from './_resources';\nimport { LinguaDisposedError, LinguaInvalidStateError } from './errors';\nimport { type Translator, createTranslatorFromCompiled } from './translator';\n\nexport type TranslationSnapshot<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n readonly revision: number;\n readonly translator: Translator<C>;\n};\n\nexport type TranslationStore<C extends Catalog = Catalog> = Translator<C> & {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n getSnapshot(): TranslationSnapshot<C>;\n isLoaded(options?: { locale?: Locale }): boolean;\n load(options?: { locale?: Locale }): Promise<void>;\n serialize(): TranslationState<C>;\n setLocale(locale: Locale): Promise<void>;\n subscribe(listener: (snapshot: TranslationSnapshot<C>) => void, options?: SubscribeOptions): () => void;\n};\n\nexport function createTranslationStore<C extends Catalog>(options: TranslationStoreOptions<C>): TranslationStore<C> {\n const catalogs = createCatalogStore(options.catalogs);\n const fallback = options.fallback;\n const fallbackLocales = (Array.isArray(fallback) ? fallback : fallback ? [fallback] : []).map(canonicalLocale);\n const controller = new AbortController();\n const subscribers = new Set<(snapshot: TranslationSnapshot<C>) => void>();\n let disposed = false;\n let locale = canonicalLocale(options.locale ?? 'en');\n let revision = 0;\n\n const buildSnapshot = (): TranslationSnapshot<C> => ({\n locale,\n revision,\n translator: createTranslatorFromCompiled<C>(catalogs.catalogMap(), { ...options, fallback, locale }),\n });\n let snapshot = buildSnapshot();\n\n const assertLive = (): void => {\n if (disposed) throw new LinguaDisposedError();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n subscribers.clear();\n controller.abort();\n };\n\n const dispatch = (listener: (next: TranslationSnapshot<C>) => void): void => {\n try {\n listener(snapshot);\n } catch (error) {\n logError('subscriber error', error);\n }\n };\n\n const notify = (): void => {\n revision++;\n snapshot = buildSnapshot();\n\n for (const listener of [...subscribers]) dispatch(listener);\n };\n\n const relevant = (candidate: Locale): boolean => localeChain(locale, fallbackLocales).includes(candidate);\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n getSnapshot() {\n return snapshot;\n },\n isLoaded(loadOptions) {\n return !disposed && catalogs.isLoaded(loadOptions?.locale ?? locale);\n },\n async load(loadOptions) {\n assertLive();\n\n const targetLocale = canonicalLocale(loadOptions?.locale ?? locale);\n const changed = await catalogs.load(targetLocale);\n\n if (!disposed && changed && relevant(targetLocale)) notify();\n },\n get locale() {\n return locale;\n },\n segments(key: string, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n segmentsDynamic(key, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n serialize() {\n assertLive();\n\n return catalogs.state(locale);\n },\n async setLocale(nextLocale) {\n assertLive();\n\n const next = canonicalLocale(nextLocale);\n\n if (next === locale) return;\n\n locale = next;\n notify();\n },\n subscribe(listener, subscribeOptions) {\n assertLive();\n\n if (subscribeOptions?.signal?.aborted) return () => {};\n\n const unsubscribe = (): void => {\n subscribers.delete(listener);\n subscribeOptions?.signal?.removeEventListener('abort', unsubscribe);\n };\n\n subscribeOptions?.signal?.addEventListener('abort', unsubscribe, { once: true });\n subscribers.add(listener);\n\n if (subscribeOptions?.immediate) dispatch(listener);\n\n return unsubscribe;\n },\n [Symbol.dispose]: dispose,\n translate(key: string, translateOptions = {}) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n translateDynamic(key, translateOptions) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n } as TranslationStore<C>;\n}\n\nexport function hydrateTranslationStore<C extends Catalog>(\n state: TranslationState<C>,\n options?: Omit<TranslationStoreOptions<C>, 'locale' | 'catalogs'>,\n): TranslationStore<C> {\n if (state.version !== 3) {\n throw new LinguaInvalidStateError(`Unsupported lingua state version: ${String(state.version)}.`);\n }\n\n return createTranslationStore({ ...options, catalogs: state.catalogs, locale: state.locale });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"lingua.js","names":[],"sources":["../src/errors.ts","../src/_dev.ts","../src/_locale.ts","../src/_template.ts","../src/_catalog.ts","../src/_resources.ts","../src/translator.ts","../src/i18n.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 static is(error: unknown): error is LinguaError {\n return error instanceof LinguaError;\n }\n}\n\nexport class LinguaDisposedError extends LinguaError {\n constructor() {\n super('Operation called on a disposed translation store.');\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 {}\n","const isDev = !(globalThis as { __LINGUA_PROD__?: boolean }).__LINGUA_PROD__;\n\n/** @internal @security Messages may include user-supplied data. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/lingua] ${msg}`);\n}\n\n/** @internal */\nexport function error(msg: string, ...args: unknown[]): void {\n if (isDev) console.error(`[@vielzeug/lingua] ${msg}`, ...args);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n","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","export 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 renderSegments<V>(\n parts: Template,\n values: Record<string, V | number>,\n missing: (name: string) => string,\n): Array<string | number | V> {\n const result: Array<string | number | V> = [];\n\n for (const part of parts) {\n if (typeof part === 'string') {\n if (part !== '') result.push(part);\n\n continue;\n }\n\n result.push(Object.hasOwn(values, part.value) ? values[part.value]! : missing(part.value));\n }\n\n return result;\n}\n","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\nfunction 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","import { type CompiledCatalog, compileCatalog } from './_catalog';\nimport { canonicalLocale } from './_locale';\nimport { LinguaMissingCatalogError } from './errors';\nimport type { Catalog, CatalogSources, Catalogs, Locale, TranslationState } from './types';\n\n/** One catalog state machine owns static sources, lazy sources, and in-flight work. */\nexport function createCatalogStore<C extends Catalog>(sources: CatalogSources<C>) {\n const definitions = new Map<Locale, C | (() => Promise<C>)>();\n const loaded = new Map<Locale, { readonly catalog: C; readonly compiled: CompiledCatalog }>();\n const tasks = new Map<Locale, Promise<void>>();\n\n for (const [locale, source] of Object.entries(sources)) definitions.set(canonicalLocale(locale), source);\n\n const add = (locale: Locale, catalog: C): void => {\n loaded.set(locale, { catalog, compiled: compileCatalog(catalog) });\n };\n\n for (const [locale, source] of definitions) {\n if (typeof source !== 'function') add(locale, source);\n }\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 source = definitions.get(locale);\n\n if (!source) throw new LinguaMissingCatalogError(`Catalog has no source for locale \"${locale}\".`);\n\n if (typeof source !== 'function') {\n add(locale, source);\n\n return true;\n }\n\n const existing = tasks.get(locale);\n\n if (existing) {\n await existing;\n\n return false;\n }\n\n const task = source().then(\n (catalog) => {\n add(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 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: 3 };\n },\n };\n}\n","import { type CompiledCatalog, type CompiledMessage, compileCatalog } from './_catalog';\nimport { canonicalLocale, localeChain, pluralCategory } from './_locale';\nimport { renderSegments, renderText, type Template } from './_template';\nimport { LinguaInvalidPluralCountError } from './errors';\nimport type {\n Catalog,\n Catalogs,\n CatalogTranslatorOptions,\n Locale,\n PluralKey,\n PluralOptions,\n TextKey,\n TranslateOptions,\n TranslatorOptions,\n} from './types';\n\nexport type Translator<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n segments<V>(key: TextKey<C>, options: TranslateOptions & { values: Record<string, V> }): Array<string | V>;\n segments<V>(key: PluralKey<C>, options: PluralOptions & { values?: Record<string, V> }): Array<string | number | V>;\n segmentsDynamic<V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V>;\n translate(key: TextKey<C>, options?: TranslateOptions): string;\n translate(key: PluralKey<C>, options: PluralOptions): string;\n translateDynamic(key: string, options?: TranslateOptions | PluralOptions): string;\n};\n\ntype ResolvedMessage = { readonly locale: Locale; readonly message: CompiledMessage };\n\nexport function createTranslatorFromCompiled<C extends Catalog>(\n catalogs: ReadonlyMap<Locale, CompiledCatalog>,\n options: TranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const fallback = (\n Array.isArray(options.fallback) ? options.fallback : options.fallback ? [options.fallback] : []\n ).map(canonicalLocale);\n const chain = localeChain(locale, fallback);\n const missingKey = options.onMissingKey ?? ((key: string) => key);\n const missingValue = options.onMissingValue ?? ((name: string) => `{${name}}`);\n\n const resolve = (key: string): ResolvedMessage | undefined => {\n for (const candidate of chain) {\n const message = catalogs.get(candidate)?.get(key);\n\n if (message) return { locale: candidate, message };\n }\n\n return undefined;\n };\n\n const templateFor = (\n key: string,\n options: TranslateOptions | PluralOptions,\n ): { key: string; template: Template } | undefined => {\n const found = resolve(key);\n\n if (!found) return undefined;\n\n if (found.message.kind === 'text') {\n if ('count' in options) return undefined;\n\n return { key, template: found.message.template };\n }\n\n if (!('count' in options) || !Number.isFinite(options.count)) {\n if ('count' in options) throw new LinguaInvalidPluralCountError('`count` must be a finite number.');\n\n return undefined;\n }\n\n const category =\n options.count === 0 && !options.ordinal\n ? 'zero'\n : pluralCategory(found.locale, options.count, options.ordinal ?? false);\n const template = found.message.forms.get(category) ?? found.message.forms.get('other');\n\n return template ? { key, template } : undefined;\n };\n\n const valuesFor = (options: TranslateOptions | PluralOptions): Record<string, unknown> =>\n 'count' in options ? { count: options.count, ...options.values } : (options.values ?? {});\n\n const segmentsDynamic = <V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V> => {\n const found = templateFor(key, options);\n\n if (!found) return [missingKey(key, locale)];\n\n return renderSegments(found.template, valuesFor(options) as Record<string, V | number>, (name) =>\n missingValue(name, found.key, locale),\n );\n };\n\n const translateDynamic = (key: string, options: TranslateOptions | PluralOptions = {}): string => {\n const found = templateFor(key, options);\n\n if (!found) return missingKey(key, locale);\n\n return renderText(found.template, valuesFor(options), (name) => missingValue(name, found.key, locale));\n };\n\n return {\n locale,\n segments(key: string, options: (TranslateOptions | PluralOptions) & { values?: Record<string, unknown> }) {\n return segmentsDynamic(key, options);\n },\n segmentsDynamic,\n translate(key: string, options: TranslateOptions | PluralOptions = {}) {\n return translateDynamic(key, options);\n },\n translateDynamic,\n } as Translator<C>;\n}\n\n/** Creates a fixed-locale translator from one catalog. Lingua snapshots catalog messages during construction. */\nexport function createCatalogTranslator<C extends Catalog>(\n catalog: C,\n options: CatalogTranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const compiled = new Map<Locale, CompiledCatalog>([[locale, compileCatalog(catalog)]]);\n\n return createTranslatorFromCompiled<C>(compiled, { ...options, locale });\n}\n\nexport function createTranslator<C extends Catalog>(catalogs: Catalogs<C>, options?: TranslatorOptions): Translator<C> {\n const compiled = new Map<Locale, CompiledCatalog>();\n\n for (const [locale, catalog] of Object.entries(catalogs)) {\n compiled.set(canonicalLocale(locale), compileCatalog(catalog));\n }\n\n return createTranslatorFromCompiled<C>(compiled, options);\n}\n","import { error as logError } from './_dev';\nimport { canonicalLocale, localeChain } from './_locale';\nimport { createCatalogStore } from './_resources';\nimport { LinguaDisposedError, LinguaInvalidStateError } from './errors';\nimport { createTranslatorFromCompiled, type Translator } from './translator';\nimport type { Catalog, Locale, SubscribeOptions, TranslationState, TranslationStoreOptions } from './types';\n\nexport type TranslationSnapshot<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n readonly revision: number;\n readonly translator: Translator<C>;\n};\n\nexport type TranslationStore<C extends Catalog = Catalog> = Translator<C> & {\n [Symbol.dispose](): void;\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n getSnapshot(): TranslationSnapshot<C>;\n isLoaded(options?: { locale?: Locale }): boolean;\n load(options?: { locale?: Locale }): Promise<void>;\n serialize(): TranslationState<C>;\n setLocale(locale: Locale): Promise<void>;\n subscribe(listener: (snapshot: TranslationSnapshot<C>) => void, options?: SubscribeOptions): () => void;\n};\n\nexport function createTranslationStore<C extends Catalog>(options: TranslationStoreOptions<C>): TranslationStore<C> {\n const catalogs = createCatalogStore(options.catalogs);\n const fallback = options.fallback;\n const fallbackLocales = (Array.isArray(fallback) ? fallback : fallback ? [fallback] : []).map(canonicalLocale);\n const controller = new AbortController();\n const subscribers = new Set<(snapshot: TranslationSnapshot<C>) => void>();\n let disposed = false;\n let locale = canonicalLocale(options.locale ?? 'en');\n let revision = 0;\n\n const buildSnapshot = (): TranslationSnapshot<C> => ({\n locale,\n revision,\n translator: createTranslatorFromCompiled<C>(catalogs.catalogMap(), { ...options, fallback, locale }),\n });\n let snapshot = buildSnapshot();\n\n const assertLive = (): void => {\n if (disposed) throw new LinguaDisposedError();\n };\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n subscribers.clear();\n controller.abort();\n };\n\n const dispatch = (listener: (next: TranslationSnapshot<C>) => void): void => {\n try {\n listener(snapshot);\n } catch (error) {\n logError('subscriber error', error);\n }\n };\n\n const notify = (): void => {\n revision++;\n snapshot = buildSnapshot();\n\n for (const listener of [...subscribers]) dispatch(listener);\n };\n\n const relevant = (candidate: Locale): boolean => localeChain(locale, fallbackLocales).includes(candidate);\n\n return {\n get disposalSignal() {\n return controller.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n getSnapshot() {\n return snapshot;\n },\n isLoaded(loadOptions) {\n return !disposed && catalogs.isLoaded(loadOptions?.locale ?? locale);\n },\n async load(loadOptions) {\n assertLive();\n\n const targetLocale = canonicalLocale(loadOptions?.locale ?? locale);\n const changed = await catalogs.load(targetLocale);\n\n if (!disposed && changed && relevant(targetLocale)) notify();\n },\n get locale() {\n return locale;\n },\n segments(key: string, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n segmentsDynamic(key, translateOptions) {\n return snapshot.translator.segmentsDynamic(key, translateOptions);\n },\n serialize() {\n assertLive();\n\n return catalogs.state(locale);\n },\n async setLocale(nextLocale) {\n assertLive();\n\n const next = canonicalLocale(nextLocale);\n\n if (next === locale) return;\n\n locale = next;\n notify();\n },\n subscribe(listener, subscribeOptions) {\n assertLive();\n\n if (subscribeOptions?.signal?.aborted) return () => {};\n\n const unsubscribe = (): void => {\n subscribers.delete(listener);\n subscribeOptions?.signal?.removeEventListener('abort', unsubscribe);\n };\n\n subscribeOptions?.signal?.addEventListener('abort', unsubscribe, { once: true });\n subscribers.add(listener);\n\n if (subscribeOptions?.immediate) dispatch(listener);\n\n return unsubscribe;\n },\n [Symbol.dispose]: dispose,\n translate(key: string, translateOptions = {}) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n translateDynamic(key, translateOptions) {\n return snapshot.translator.translateDynamic(key, translateOptions);\n },\n } as TranslationStore<C>;\n}\n\nexport function hydrateTranslationStore<C extends Catalog>(\n state: TranslationState<C>,\n options?: Omit<TranslationStoreOptions<C>, 'locale' | 'catalogs'>,\n): TranslationStore<C> {\n if (state.version !== 3) {\n throw new LinguaInvalidStateError(`Unsupported lingua state version: ${String(state.version)}.`);\n }\n\n return createTranslationStore({ ...options, catalogs: state.catalogs, locale: state.locale });\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"translator.cjs","names":[],"sources":["../src/translator.ts"],"sourcesContent":["import type {\n Catalog,\n Catalogs,\n CatalogTranslatorOptions,\n Locale,\n PluralKey,\n PluralOptions,\n TextKey,\n TranslateOptions,\n TranslatorOptions,\n} from './types';\n\nimport { type CompiledCatalog, type CompiledMessage, compileCatalog } from './_catalog';\nimport { canonicalLocale, localeChain, pluralCategory } from './_locale';\nimport { renderSegments, renderText, type Template } from './_template';\nimport { LinguaInvalidPluralCountError } from './errors';\n\nexport type Translator<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n segments<V>(key: TextKey<C>, options: TranslateOptions & { values: Record<string, V> }): Array<string | V>;\n segments<V>(key: PluralKey<C>, options: PluralOptions & { values?: Record<string, V> }): Array<string | number | V>;\n segmentsDynamic<V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V>;\n translate(key: TextKey<C>, options?: TranslateOptions): string;\n translate(key: PluralKey<C>, options: PluralOptions): string;\n translateDynamic(key: string, options?: TranslateOptions | PluralOptions): string;\n};\n\ntype ResolvedMessage = { readonly locale: Locale; readonly message: CompiledMessage };\n\nexport function createTranslatorFromCompiled<C extends Catalog>(\n catalogs: ReadonlyMap<Locale, CompiledCatalog>,\n options: TranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const fallback = (\n Array.isArray(options.fallback) ? options.fallback : options.fallback ? [options.fallback] : []\n ).map(canonicalLocale);\n const chain = localeChain(locale, fallback);\n const missingKey = options.onMissingKey ?? ((key: string) => key);\n const missingValue = options.onMissingValue ?? ((name: string) => `{${name}}`);\n\n const resolve = (key: string): ResolvedMessage | undefined => {\n for (const candidate of chain) {\n const message = catalogs.get(candidate)?.get(key);\n\n if (message) return { locale: candidate, message };\n }\n\n return undefined;\n };\n\n const templateFor = (\n key: string,\n options: TranslateOptions | PluralOptions,\n ): { key: string; template: Template } | undefined => {\n const found = resolve(key);\n\n if (!found) return undefined;\n\n if (found.message.kind === 'text') {\n if ('count' in options) return undefined;\n\n return { key, template: found.message.template };\n }\n\n if (!('count' in options) || !Number.isFinite(options.count)) {\n if ('count' in options) throw new LinguaInvalidPluralCountError('`count` must be a finite number.');\n\n return undefined;\n }\n\n const category =\n options.count === 0 && !options.ordinal\n ? 'zero'\n : pluralCategory(found.locale, options.count, options.ordinal ?? false);\n const template = found.message.forms.get(category) ?? found.message.forms.get('other');\n\n return template ? { key, template } : undefined;\n };\n\n const valuesFor = (options: TranslateOptions | PluralOptions): Record<string, unknown> =>\n 'count' in options ? { count: options.count, ...options.values } : (options.values ?? {});\n\n const segmentsDynamic = <V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V> => {\n const found = templateFor(key, options);\n\n if (!found) return [missingKey(key, locale)];\n\n return renderSegments(found.template, valuesFor(options) as Record<string, V | number>, (name) =>\n missingValue(name, found.key, locale),\n );\n };\n\n const translateDynamic = (key: string, options: TranslateOptions | PluralOptions = {}): string => {\n const found = templateFor(key, options);\n\n if (!found) return missingKey(key, locale);\n\n return renderText(found.template, valuesFor(options), (name) => missingValue(name, found.key, locale));\n };\n\n return {\n locale,\n segments(key: string, options: (TranslateOptions | PluralOptions) & { values?: Record<string, unknown> }) {\n return segmentsDynamic(key, options);\n },\n segmentsDynamic,\n translate(key: string, options: TranslateOptions | PluralOptions = {}) {\n return translateDynamic(key, options);\n },\n translateDynamic,\n } as Translator<C>;\n}\n\n/** Creates a fixed-locale translator from one catalog. Lingua snapshots catalog messages during construction. */\nexport function createCatalogTranslator<C extends Catalog>(\n catalog: C,\n options: CatalogTranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const compiled = new Map<Locale, CompiledCatalog>([[locale, compileCatalog(catalog)]]);\n\n return createTranslatorFromCompiled<C>(compiled, { ...options, locale });\n}\n\nexport function createTranslator<C extends Catalog>(catalogs: Catalogs<C>, options?: TranslatorOptions): Translator<C> {\n const compiled = new Map<Locale, CompiledCatalog>();\n\n for (const [locale, catalog] of Object.entries(catalogs)) {\n compiled.set(canonicalLocale(locale), compileCatalog(catalog));\n }\n\n return createTranslatorFromCompiled<C>(compiled, options);\n}\n"],"mappings":"oHAgCA,SAAgB,EACd,EACA,EAA6B,CAAC,EACf,CACf,IAAM,EAAS,EAAA,gBAAgB,EAAQ,QAAU,IAAI,EAC/C,GACJ,MAAM,QAAQ,EAAQ,QAAQ,EAAI,EAAQ,SAAW,EAAQ,SAAW,CAAC,EAAQ,QAAQ,EAAI,CAAC,EAAA,CAC9F,IAAI,EAAA,eAAe,EACf,EAAQ,EAAA,YAAY,EAAQ,CAAQ,EACpC,EAAa,EAAQ,eAAkB,GAAgB,GACvD,EAAe,EAAQ,iBAAoB,GAAiB,IAAI,EAAK,IAErE,EAAW,GAA6C,CAC5D,IAAK,IAAM,KAAa,EAAO,CAC7B,IAAM,EAAU,EAAS,IAAI,CAAS,CAAC,EAAE,IAAI,CAAG,EAEhD,GAAI,EAAS,MAAO,CAAE,OAAQ,EAAW,SAAQ,CACnD,CAGF,EAEM,GACJ,EACA,IACoD,CACpD,IAAM,EAAQ,EAAQ,CAAG,EAEzB,GAAI,CAAC,EAAO,OAEZ,GAAI,EAAM,QAAQ,OAAS,OAGzB,MAFI,UAAW,EAAS,OAEjB,CAAE,MAAK,SAAU,EAAM,QAAQ,QAAS,EAGjD,GAAI,EAAE,UAAW,IAAY,CAAC,OAAO,SAAS,EAAQ,KAAK,EAAG,CAC5D,GAAI,UAAW,EAAS,MAAM,IAAI,EAAA,8BAA8B,kCAAkC,EAElG,MACF,CAEA,IAAM,EACJ,EAAQ,QAAU,GAAK,CAAC,EAAQ,QAC5B,OACA,EAAA,eAAe,EAAM,OAAQ,EAAQ,MAAO,EAAQ,SAAW,EAAK,EACpE,EAAW,EAAM,QAAQ,MAAM,IAAI,CAAQ,GAAK,EAAM,QAAQ,MAAM,IAAI,OAAO,EAErF,OAAO,EAAW,CAAE,MAAK,UAAS,EAAI,IAAA,EACxC,EAEM,EAAa,GACjB,UAAW,EAAU,CAAE,MAAO,EAAQ,MAAO,GAAG,EAAQ,MAAO,EAAK,EAAQ,QAAU,CAAC,EAEnF,GACJ,EACA,IAC+B,CAC/B,IAAM,EAAQ,EAAY,EAAK,CAAO,EAItC,OAFK,EAEE,EAAA,eAAe,EAAM,SAAU,EAAU,CAAO,EAAkC,GACvF,EAAa,EAAM,EAAM,IAAK,CAAM,CACtC,EAJmB,CAAC,EAAW,EAAK,CAAM,CAAC,CAK7C,EAEM,GAAoB,EAAa,EAA4C,CAAC,IAAc,CAChG,IAAM,EAAQ,EAAY,EAAK,CAAO,EAItC,OAFK,EAEE,EAAA,WAAW,EAAM,SAAU,EAAU,CAAO,EAAI,GAAS,EAAa,EAAM,EAAM,IAAK,CAAM,CAAC,EAFlF,EAAW,EAAK,CAAM,CAG3C,EAEA,MAAO,CACL,SACA,SAAS,EAAa,EAAoF,CACxG,OAAO,EAAgB,EAAK,CAAO,CACrC,EACA,kBACA,UAAU,EAAa,EAA4C,CAAC,EAAG,CACrE,OAAO,EAAiB,EAAK,CAAO,CACtC,EACA,kBACF,CACF,CAGA,SAAgB,EACd,EACA,EAAoC,CAAC,EACtB,CACf,IAAM,EAAS,EAAA,gBAAgB,EAAQ,QAAU,IAAI,EAGrD,OAAO,EAAgC,IAFlB,IAA6B,CAAC,CAAC,EAAQ,EAAA,eAAe,CAAO,CAAC,CAAC,CAE7C,EAAU,CAAE,GAAG,EAAS,QAAO,CAAC,CACzE,CAEA,SAAgB,EAAoC,EAAuB,EAA4C,CACrH,IAAM,EAAW,IAAI,IAErB,IAAK,GAAM,CAAC,EAAQ,KAAY,OAAO,QAAQ,CAAQ,EACrD,EAAS,IAAI,EAAA,gBAAgB,CAAM,EAAG,EAAA,eAAe,CAAO,CAAC,EAG/D,OAAO,EAAgC,EAAU,CAAO,CAC1D"}
1
+ {"version":3,"file":"translator.cjs","names":[],"sources":["../src/translator.ts"],"sourcesContent":["import { type CompiledCatalog, type CompiledMessage, compileCatalog } from './_catalog';\nimport { canonicalLocale, localeChain, pluralCategory } from './_locale';\nimport { renderSegments, renderText, type Template } from './_template';\nimport { LinguaInvalidPluralCountError } from './errors';\nimport type {\n Catalog,\n Catalogs,\n CatalogTranslatorOptions,\n Locale,\n PluralKey,\n PluralOptions,\n TextKey,\n TranslateOptions,\n TranslatorOptions,\n} from './types';\n\nexport type Translator<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n segments<V>(key: TextKey<C>, options: TranslateOptions & { values: Record<string, V> }): Array<string | V>;\n segments<V>(key: PluralKey<C>, options: PluralOptions & { values?: Record<string, V> }): Array<string | number | V>;\n segmentsDynamic<V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V>;\n translate(key: TextKey<C>, options?: TranslateOptions): string;\n translate(key: PluralKey<C>, options: PluralOptions): string;\n translateDynamic(key: string, options?: TranslateOptions | PluralOptions): string;\n};\n\ntype ResolvedMessage = { readonly locale: Locale; readonly message: CompiledMessage };\n\nexport function createTranslatorFromCompiled<C extends Catalog>(\n catalogs: ReadonlyMap<Locale, CompiledCatalog>,\n options: TranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const fallback = (\n Array.isArray(options.fallback) ? options.fallback : options.fallback ? [options.fallback] : []\n ).map(canonicalLocale);\n const chain = localeChain(locale, fallback);\n const missingKey = options.onMissingKey ?? ((key: string) => key);\n const missingValue = options.onMissingValue ?? ((name: string) => `{${name}}`);\n\n const resolve = (key: string): ResolvedMessage | undefined => {\n for (const candidate of chain) {\n const message = catalogs.get(candidate)?.get(key);\n\n if (message) return { locale: candidate, message };\n }\n\n return undefined;\n };\n\n const templateFor = (\n key: string,\n options: TranslateOptions | PluralOptions,\n ): { key: string; template: Template } | undefined => {\n const found = resolve(key);\n\n if (!found) return undefined;\n\n if (found.message.kind === 'text') {\n if ('count' in options) return undefined;\n\n return { key, template: found.message.template };\n }\n\n if (!('count' in options) || !Number.isFinite(options.count)) {\n if ('count' in options) throw new LinguaInvalidPluralCountError('`count` must be a finite number.');\n\n return undefined;\n }\n\n const category =\n options.count === 0 && !options.ordinal\n ? 'zero'\n : pluralCategory(found.locale, options.count, options.ordinal ?? false);\n const template = found.message.forms.get(category) ?? found.message.forms.get('other');\n\n return template ? { key, template } : undefined;\n };\n\n const valuesFor = (options: TranslateOptions | PluralOptions): Record<string, unknown> =>\n 'count' in options ? { count: options.count, ...options.values } : (options.values ?? {});\n\n const segmentsDynamic = <V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V> => {\n const found = templateFor(key, options);\n\n if (!found) return [missingKey(key, locale)];\n\n return renderSegments(found.template, valuesFor(options) as Record<string, V | number>, (name) =>\n missingValue(name, found.key, locale),\n );\n };\n\n const translateDynamic = (key: string, options: TranslateOptions | PluralOptions = {}): string => {\n const found = templateFor(key, options);\n\n if (!found) return missingKey(key, locale);\n\n return renderText(found.template, valuesFor(options), (name) => missingValue(name, found.key, locale));\n };\n\n return {\n locale,\n segments(key: string, options: (TranslateOptions | PluralOptions) & { values?: Record<string, unknown> }) {\n return segmentsDynamic(key, options);\n },\n segmentsDynamic,\n translate(key: string, options: TranslateOptions | PluralOptions = {}) {\n return translateDynamic(key, options);\n },\n translateDynamic,\n } as Translator<C>;\n}\n\n/** Creates a fixed-locale translator from one catalog. Lingua snapshots catalog messages during construction. */\nexport function createCatalogTranslator<C extends Catalog>(\n catalog: C,\n options: CatalogTranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const compiled = new Map<Locale, CompiledCatalog>([[locale, compileCatalog(catalog)]]);\n\n return createTranslatorFromCompiled<C>(compiled, { ...options, locale });\n}\n\nexport function createTranslator<C extends Catalog>(catalogs: Catalogs<C>, options?: TranslatorOptions): Translator<C> {\n const compiled = new Map<Locale, CompiledCatalog>();\n\n for (const [locale, catalog] of Object.entries(catalogs)) {\n compiled.set(canonicalLocale(locale), compileCatalog(catalog));\n }\n\n return createTranslatorFromCompiled<C>(compiled, options);\n}\n"],"mappings":"oHA+BA,SAAgB,EACd,EACA,EAA6B,CAAC,EACf,CACf,IAAM,EAAS,EAAA,gBAAgB,EAAQ,QAAU,IAAI,EAC/C,GACJ,MAAM,QAAQ,EAAQ,QAAQ,EAAI,EAAQ,SAAW,EAAQ,SAAW,CAAC,EAAQ,QAAQ,EAAI,CAAC,EAAA,CAC9F,IAAI,EAAA,eAAe,EACf,EAAQ,EAAA,YAAY,EAAQ,CAAQ,EACpC,EAAa,EAAQ,eAAkB,GAAgB,GACvD,EAAe,EAAQ,iBAAoB,GAAiB,IAAI,EAAK,IAErE,EAAW,GAA6C,CAC5D,IAAK,IAAM,KAAa,EAAO,CAC7B,IAAM,EAAU,EAAS,IAAI,CAAS,CAAC,EAAE,IAAI,CAAG,EAEhD,GAAI,EAAS,MAAO,CAAE,OAAQ,EAAW,SAAQ,CACnD,CAGF,EAEM,GACJ,EACA,IACoD,CACpD,IAAM,EAAQ,EAAQ,CAAG,EAEzB,GAAI,CAAC,EAAO,OAEZ,GAAI,EAAM,QAAQ,OAAS,OAGzB,MAFI,UAAW,EAAS,OAEjB,CAAE,MAAK,SAAU,EAAM,QAAQ,QAAS,EAGjD,GAAI,EAAE,UAAW,IAAY,CAAC,OAAO,SAAS,EAAQ,KAAK,EAAG,CAC5D,GAAI,UAAW,EAAS,MAAM,IAAI,EAAA,8BAA8B,kCAAkC,EAElG,MACF,CAEA,IAAM,EACJ,EAAQ,QAAU,GAAK,CAAC,EAAQ,QAC5B,OACA,EAAA,eAAe,EAAM,OAAQ,EAAQ,MAAO,EAAQ,SAAW,EAAK,EACpE,EAAW,EAAM,QAAQ,MAAM,IAAI,CAAQ,GAAK,EAAM,QAAQ,MAAM,IAAI,OAAO,EAErF,OAAO,EAAW,CAAE,MAAK,UAAS,EAAI,IAAA,EACxC,EAEM,EAAa,GACjB,UAAW,EAAU,CAAE,MAAO,EAAQ,MAAO,GAAG,EAAQ,MAAO,EAAK,EAAQ,QAAU,CAAC,EAEnF,GACJ,EACA,IAC+B,CAC/B,IAAM,EAAQ,EAAY,EAAK,CAAO,EAItC,OAFK,EAEE,EAAA,eAAe,EAAM,SAAU,EAAU,CAAO,EAAkC,GACvF,EAAa,EAAM,EAAM,IAAK,CAAM,CACtC,EAJmB,CAAC,EAAW,EAAK,CAAM,CAAC,CAK7C,EAEM,GAAoB,EAAa,EAA4C,CAAC,IAAc,CAChG,IAAM,EAAQ,EAAY,EAAK,CAAO,EAItC,OAFK,EAEE,EAAA,WAAW,EAAM,SAAU,EAAU,CAAO,EAAI,GAAS,EAAa,EAAM,EAAM,IAAK,CAAM,CAAC,EAFlF,EAAW,EAAK,CAAM,CAG3C,EAEA,MAAO,CACL,SACA,SAAS,EAAa,EAAoF,CACxG,OAAO,EAAgB,EAAK,CAAO,CACrC,EACA,kBACA,UAAU,EAAa,EAA4C,CAAC,EAAG,CACrE,OAAO,EAAiB,EAAK,CAAO,CACtC,EACA,kBACF,CACF,CAGA,SAAgB,EACd,EACA,EAAoC,CAAC,EACtB,CACf,IAAM,EAAS,EAAA,gBAAgB,EAAQ,QAAU,IAAI,EAGrD,OAAO,EAAgC,IAFlB,IAA6B,CAAC,CAAC,EAAQ,EAAA,eAAe,CAAO,CAAC,CAAC,CAE7C,EAAU,CAAE,GAAG,EAAS,QAAO,CAAC,CACzE,CAEA,SAAgB,EAAoC,EAAuB,EAA4C,CACrH,IAAM,EAAW,IAAI,IAErB,IAAK,GAAM,CAAC,EAAQ,KAAY,OAAO,QAAQ,CAAQ,EACrD,EAAS,IAAI,EAAA,gBAAgB,CAAM,EAAG,EAAA,eAAe,CAAO,CAAC,EAG/D,OAAO,EAAgC,EAAU,CAAO,CAC1D"}
@@ -1,5 +1,5 @@
1
- import type { Catalog, Catalogs, CatalogTranslatorOptions, Locale, PluralKey, PluralOptions, TextKey, TranslateOptions, TranslatorOptions } from './types';
2
1
  import { type CompiledCatalog } from './_catalog';
2
+ import type { Catalog, Catalogs, CatalogTranslatorOptions, Locale, PluralKey, PluralOptions, TextKey, TranslateOptions, TranslatorOptions } from './types';
3
3
  export type Translator<C extends Catalog = Catalog> = {
4
4
  readonly locale: Locale;
5
5
  segments<V>(key: TextKey<C>, options: TranslateOptions & {
@@ -1 +1 @@
1
- {"version":3,"file":"translator.d.ts","sourceRoot":"","sources":["../src/translator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,QAAQ,EACR,wBAAwB,EACxB,MAAM,EACN,SAAS,EACT,aAAa,EACb,OAAO,EACP,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,KAAK,eAAe,EAAwC,MAAM,YAAY,CAAC;AAKxF,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,IAAI;IACpD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,gBAAgB,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;KAAE,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3G,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;KAAE,GAAG,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC;IACpH,eAAe,CAAC,CAAC,EACf,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,CAAC,gBAAgB,GAAG,aAAa,CAAC,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;KAAE,GAC3E,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC;IAC9B,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAAC;IAC/D,SAAS,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CAAC;IAC7D,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,aAAa,GAAG,MAAM,CAAC;CACnF,CAAC;AAIF,wBAAgB,4BAA4B,CAAC,CAAC,SAAS,OAAO,EAC5D,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,EAC9C,OAAO,GAAE,iBAAsB,GAC9B,UAAU,CAAC,CAAC,CAAC,CAmFf;AAED,iHAAiH;AACjH,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,OAAO,EACvD,OAAO,EAAE,CAAC,EACV,OAAO,GAAE,wBAA6B,GACrC,UAAU,CAAC,CAAC,CAAC,CAKf;AAED,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,UAAU,CAAC,CAAC,CAAC,CAQrH"}
1
+ {"version":3,"file":"translator.d.ts","sourceRoot":"","sources":["../src/translator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,eAAe,EAAwC,MAAM,YAAY,CAAC;AAIxF,OAAO,KAAK,EACV,OAAO,EACP,QAAQ,EACR,wBAAwB,EACxB,MAAM,EACN,SAAS,EACT,aAAa,EACb,OAAO,EACP,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAEjB,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,IAAI;IACpD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,gBAAgB,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;KAAE,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3G,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;KAAE,GAAG,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC;IACpH,eAAe,CAAC,CAAC,EACf,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,CAAC,gBAAgB,GAAG,aAAa,CAAC,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;KAAE,GAC3E,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC;IAC9B,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAAC;IAC/D,SAAS,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CAAC;IAC7D,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,aAAa,GAAG,MAAM,CAAC;CACnF,CAAC;AAIF,wBAAgB,4BAA4B,CAAC,CAAC,SAAS,OAAO,EAC5D,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,EAC9C,OAAO,GAAE,iBAAsB,GAC9B,UAAU,CAAC,CAAC,CAAC,CAmFf;AAED,iHAAiH;AACjH,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,OAAO,EACvD,OAAO,EAAE,CAAC,EACV,OAAO,GAAE,wBAA6B,GACrC,UAAU,CAAC,CAAC,CAAC,CAKf;AAED,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,UAAU,CAAC,CAAC,CAAC,CAQrH"}
@@ -1 +1 @@
1
- {"version":3,"file":"translator.js","names":[],"sources":["../src/translator.ts"],"sourcesContent":["import type {\n Catalog,\n Catalogs,\n CatalogTranslatorOptions,\n Locale,\n PluralKey,\n PluralOptions,\n TextKey,\n TranslateOptions,\n TranslatorOptions,\n} from './types';\n\nimport { type CompiledCatalog, type CompiledMessage, compileCatalog } from './_catalog';\nimport { canonicalLocale, localeChain, pluralCategory } from './_locale';\nimport { renderSegments, renderText, type Template } from './_template';\nimport { LinguaInvalidPluralCountError } from './errors';\n\nexport type Translator<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n segments<V>(key: TextKey<C>, options: TranslateOptions & { values: Record<string, V> }): Array<string | V>;\n segments<V>(key: PluralKey<C>, options: PluralOptions & { values?: Record<string, V> }): Array<string | number | V>;\n segmentsDynamic<V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V>;\n translate(key: TextKey<C>, options?: TranslateOptions): string;\n translate(key: PluralKey<C>, options: PluralOptions): string;\n translateDynamic(key: string, options?: TranslateOptions | PluralOptions): string;\n};\n\ntype ResolvedMessage = { readonly locale: Locale; readonly message: CompiledMessage };\n\nexport function createTranslatorFromCompiled<C extends Catalog>(\n catalogs: ReadonlyMap<Locale, CompiledCatalog>,\n options: TranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const fallback = (\n Array.isArray(options.fallback) ? options.fallback : options.fallback ? [options.fallback] : []\n ).map(canonicalLocale);\n const chain = localeChain(locale, fallback);\n const missingKey = options.onMissingKey ?? ((key: string) => key);\n const missingValue = options.onMissingValue ?? ((name: string) => `{${name}}`);\n\n const resolve = (key: string): ResolvedMessage | undefined => {\n for (const candidate of chain) {\n const message = catalogs.get(candidate)?.get(key);\n\n if (message) return { locale: candidate, message };\n }\n\n return undefined;\n };\n\n const templateFor = (\n key: string,\n options: TranslateOptions | PluralOptions,\n ): { key: string; template: Template } | undefined => {\n const found = resolve(key);\n\n if (!found) return undefined;\n\n if (found.message.kind === 'text') {\n if ('count' in options) return undefined;\n\n return { key, template: found.message.template };\n }\n\n if (!('count' in options) || !Number.isFinite(options.count)) {\n if ('count' in options) throw new LinguaInvalidPluralCountError('`count` must be a finite number.');\n\n return undefined;\n }\n\n const category =\n options.count === 0 && !options.ordinal\n ? 'zero'\n : pluralCategory(found.locale, options.count, options.ordinal ?? false);\n const template = found.message.forms.get(category) ?? found.message.forms.get('other');\n\n return template ? { key, template } : undefined;\n };\n\n const valuesFor = (options: TranslateOptions | PluralOptions): Record<string, unknown> =>\n 'count' in options ? { count: options.count, ...options.values } : (options.values ?? {});\n\n const segmentsDynamic = <V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V> => {\n const found = templateFor(key, options);\n\n if (!found) return [missingKey(key, locale)];\n\n return renderSegments(found.template, valuesFor(options) as Record<string, V | number>, (name) =>\n missingValue(name, found.key, locale),\n );\n };\n\n const translateDynamic = (key: string, options: TranslateOptions | PluralOptions = {}): string => {\n const found = templateFor(key, options);\n\n if (!found) return missingKey(key, locale);\n\n return renderText(found.template, valuesFor(options), (name) => missingValue(name, found.key, locale));\n };\n\n return {\n locale,\n segments(key: string, options: (TranslateOptions | PluralOptions) & { values?: Record<string, unknown> }) {\n return segmentsDynamic(key, options);\n },\n segmentsDynamic,\n translate(key: string, options: TranslateOptions | PluralOptions = {}) {\n return translateDynamic(key, options);\n },\n translateDynamic,\n } as Translator<C>;\n}\n\n/** Creates a fixed-locale translator from one catalog. Lingua snapshots catalog messages during construction. */\nexport function createCatalogTranslator<C extends Catalog>(\n catalog: C,\n options: CatalogTranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const compiled = new Map<Locale, CompiledCatalog>([[locale, compileCatalog(catalog)]]);\n\n return createTranslatorFromCompiled<C>(compiled, { ...options, locale });\n}\n\nexport function createTranslator<C extends Catalog>(catalogs: Catalogs<C>, options?: TranslatorOptions): Translator<C> {\n const compiled = new Map<Locale, CompiledCatalog>();\n\n for (const [locale, catalog] of Object.entries(catalogs)) {\n compiled.set(canonicalLocale(locale), compileCatalog(catalog));\n }\n\n return createTranslatorFromCompiled<C>(compiled, options);\n}\n"],"mappings":";;;;;AAgCA,SAAgB,EACd,GACA,IAA6B,CAAC,GACf;CACf,IAAM,IAAS,EAAgB,EAAQ,UAAU,IAAI,GAC/C,KACJ,MAAM,QAAQ,EAAQ,QAAQ,IAAI,EAAQ,WAAW,EAAQ,WAAW,CAAC,EAAQ,QAAQ,IAAI,CAAC,EAAA,CAC9F,IAAI,CAAe,GACf,IAAQ,EAAY,GAAQ,CAAQ,GACpC,IAAa,EAAQ,kBAAkB,MAAgB,IACvD,IAAe,EAAQ,oBAAoB,MAAiB,IAAI,EAAK,KAErE,KAAW,MAA6C;EAC5D,KAAK,IAAM,KAAa,GAAO;GAC7B,IAAM,IAAU,EAAS,IAAI,CAAS,CAAC,EAAE,IAAI,CAAG;GAEhD,IAAI,GAAS,OAAO;IAAE,QAAQ;IAAW;GAAQ;EACnD;CAGF,GAEM,KACJ,GACA,MACoD;EACpD,IAAM,IAAQ,EAAQ,CAAG;EAEzB,IAAI,CAAC,GAAO;EAEZ,IAAI,EAAM,QAAQ,SAAS,QAGzB,OAFI,WAAW,IAAS,SAEjB;GAAE;GAAK,UAAU,EAAM,QAAQ;EAAS;EAGjD,IAAI,EAAE,WAAW,MAAY,CAAC,OAAO,SAAS,EAAQ,KAAK,GAAG;GAC5D,IAAI,WAAW,GAAS,MAAM,IAAI,EAA8B,kCAAkC;GAElG;EACF;EAEA,IAAM,IACJ,EAAQ,UAAU,KAAK,CAAC,EAAQ,UAC5B,SACA,EAAe,EAAM,QAAQ,EAAQ,OAAO,EAAQ,WAAW,EAAK,GACpE,IAAW,EAAM,QAAQ,MAAM,IAAI,CAAQ,KAAK,EAAM,QAAQ,MAAM,IAAI,OAAO;EAErF,OAAO,IAAW;GAAE;GAAK;EAAS,IAAI,KAAA;CACxC,GAEM,KAAa,MACjB,WAAW,IAAU;EAAE,OAAO,EAAQ;EAAO,GAAG,EAAQ;CAAO,IAAK,EAAQ,UAAU,CAAC,GAEnF,KACJ,GACA,MAC+B;EAC/B,IAAM,IAAQ,EAAY,GAAK,CAAO;EAItC,OAFK,IAEE,EAAe,EAAM,UAAU,EAAU,CAAO,IAAkC,MACvF,EAAa,GAAM,EAAM,KAAK,CAAM,CACtC,IAJmB,CAAC,EAAW,GAAK,CAAM,CAAC;CAK7C,GAEM,KAAoB,GAAa,IAA4C,CAAC,MAAc;EAChG,IAAM,IAAQ,EAAY,GAAK,CAAO;EAItC,OAFK,IAEE,EAAW,EAAM,UAAU,EAAU,CAAO,IAAI,MAAS,EAAa,GAAM,EAAM,KAAK,CAAM,CAAC,IAFlF,EAAW,GAAK,CAAM;CAG3C;CAEA,OAAO;EACL;EACA,SAAS,GAAa,GAAoF;GACxG,OAAO,EAAgB,GAAK,CAAO;EACrC;EACA;EACA,UAAU,GAAa,IAA4C,CAAC,GAAG;GACrE,OAAO,EAAiB,GAAK,CAAO;EACtC;EACA;CACF;AACF;AAGA,SAAgB,EACd,GACA,IAAoC,CAAC,GACtB;CACf,IAAM,IAAS,EAAgB,EAAQ,UAAU,IAAI;CAGrD,OAAO,kBAAgC,IAFlB,IAA6B,CAAC,CAAC,GAAQ,EAAe,CAAO,CAAC,CAAC,CAE7C,GAAU;EAAE,GAAG;EAAS;CAAO,CAAC;AACzE;AAEA,SAAgB,EAAoC,GAAuB,GAA4C;CACrH,IAAM,oBAAW,IAAI,IAA6B;CAElD,KAAK,IAAM,CAAC,GAAQ,MAAY,OAAO,QAAQ,CAAQ,GACrD,EAAS,IAAI,EAAgB,CAAM,GAAG,EAAe,CAAO,CAAC;CAG/D,OAAO,EAAgC,GAAU,CAAO;AAC1D"}
1
+ {"version":3,"file":"translator.js","names":[],"sources":["../src/translator.ts"],"sourcesContent":["import { type CompiledCatalog, type CompiledMessage, compileCatalog } from './_catalog';\nimport { canonicalLocale, localeChain, pluralCategory } from './_locale';\nimport { renderSegments, renderText, type Template } from './_template';\nimport { LinguaInvalidPluralCountError } from './errors';\nimport type {\n Catalog,\n Catalogs,\n CatalogTranslatorOptions,\n Locale,\n PluralKey,\n PluralOptions,\n TextKey,\n TranslateOptions,\n TranslatorOptions,\n} from './types';\n\nexport type Translator<C extends Catalog = Catalog> = {\n readonly locale: Locale;\n segments<V>(key: TextKey<C>, options: TranslateOptions & { values: Record<string, V> }): Array<string | V>;\n segments<V>(key: PluralKey<C>, options: PluralOptions & { values?: Record<string, V> }): Array<string | number | V>;\n segmentsDynamic<V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V>;\n translate(key: TextKey<C>, options?: TranslateOptions): string;\n translate(key: PluralKey<C>, options: PluralOptions): string;\n translateDynamic(key: string, options?: TranslateOptions | PluralOptions): string;\n};\n\ntype ResolvedMessage = { readonly locale: Locale; readonly message: CompiledMessage };\n\nexport function createTranslatorFromCompiled<C extends Catalog>(\n catalogs: ReadonlyMap<Locale, CompiledCatalog>,\n options: TranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const fallback = (\n Array.isArray(options.fallback) ? options.fallback : options.fallback ? [options.fallback] : []\n ).map(canonicalLocale);\n const chain = localeChain(locale, fallback);\n const missingKey = options.onMissingKey ?? ((key: string) => key);\n const missingValue = options.onMissingValue ?? ((name: string) => `{${name}}`);\n\n const resolve = (key: string): ResolvedMessage | undefined => {\n for (const candidate of chain) {\n const message = catalogs.get(candidate)?.get(key);\n\n if (message) return { locale: candidate, message };\n }\n\n return undefined;\n };\n\n const templateFor = (\n key: string,\n options: TranslateOptions | PluralOptions,\n ): { key: string; template: Template } | undefined => {\n const found = resolve(key);\n\n if (!found) return undefined;\n\n if (found.message.kind === 'text') {\n if ('count' in options) return undefined;\n\n return { key, template: found.message.template };\n }\n\n if (!('count' in options) || !Number.isFinite(options.count)) {\n if ('count' in options) throw new LinguaInvalidPluralCountError('`count` must be a finite number.');\n\n return undefined;\n }\n\n const category =\n options.count === 0 && !options.ordinal\n ? 'zero'\n : pluralCategory(found.locale, options.count, options.ordinal ?? false);\n const template = found.message.forms.get(category) ?? found.message.forms.get('other');\n\n return template ? { key, template } : undefined;\n };\n\n const valuesFor = (options: TranslateOptions | PluralOptions): Record<string, unknown> =>\n 'count' in options ? { count: options.count, ...options.values } : (options.values ?? {});\n\n const segmentsDynamic = <V>(\n key: string,\n options: (TranslateOptions | PluralOptions) & { values?: Record<string, V> },\n ): Array<string | number | V> => {\n const found = templateFor(key, options);\n\n if (!found) return [missingKey(key, locale)];\n\n return renderSegments(found.template, valuesFor(options) as Record<string, V | number>, (name) =>\n missingValue(name, found.key, locale),\n );\n };\n\n const translateDynamic = (key: string, options: TranslateOptions | PluralOptions = {}): string => {\n const found = templateFor(key, options);\n\n if (!found) return missingKey(key, locale);\n\n return renderText(found.template, valuesFor(options), (name) => missingValue(name, found.key, locale));\n };\n\n return {\n locale,\n segments(key: string, options: (TranslateOptions | PluralOptions) & { values?: Record<string, unknown> }) {\n return segmentsDynamic(key, options);\n },\n segmentsDynamic,\n translate(key: string, options: TranslateOptions | PluralOptions = {}) {\n return translateDynamic(key, options);\n },\n translateDynamic,\n } as Translator<C>;\n}\n\n/** Creates a fixed-locale translator from one catalog. Lingua snapshots catalog messages during construction. */\nexport function createCatalogTranslator<C extends Catalog>(\n catalog: C,\n options: CatalogTranslatorOptions = {},\n): Translator<C> {\n const locale = canonicalLocale(options.locale ?? 'en');\n const compiled = new Map<Locale, CompiledCatalog>([[locale, compileCatalog(catalog)]]);\n\n return createTranslatorFromCompiled<C>(compiled, { ...options, locale });\n}\n\nexport function createTranslator<C extends Catalog>(catalogs: Catalogs<C>, options?: TranslatorOptions): Translator<C> {\n const compiled = new Map<Locale, CompiledCatalog>();\n\n for (const [locale, catalog] of Object.entries(catalogs)) {\n compiled.set(canonicalLocale(locale), compileCatalog(catalog));\n }\n\n return createTranslatorFromCompiled<C>(compiled, options);\n}\n"],"mappings":";;;;;AA+BA,SAAgB,EACd,GACA,IAA6B,CAAC,GACf;CACf,IAAM,IAAS,EAAgB,EAAQ,UAAU,IAAI,GAC/C,KACJ,MAAM,QAAQ,EAAQ,QAAQ,IAAI,EAAQ,WAAW,EAAQ,WAAW,CAAC,EAAQ,QAAQ,IAAI,CAAC,EAAA,CAC9F,IAAI,CAAe,GACf,IAAQ,EAAY,GAAQ,CAAQ,GACpC,IAAa,EAAQ,kBAAkB,MAAgB,IACvD,IAAe,EAAQ,oBAAoB,MAAiB,IAAI,EAAK,KAErE,KAAW,MAA6C;EAC5D,KAAK,IAAM,KAAa,GAAO;GAC7B,IAAM,IAAU,EAAS,IAAI,CAAS,CAAC,EAAE,IAAI,CAAG;GAEhD,IAAI,GAAS,OAAO;IAAE,QAAQ;IAAW;GAAQ;EACnD;CAGF,GAEM,KACJ,GACA,MACoD;EACpD,IAAM,IAAQ,EAAQ,CAAG;EAEzB,IAAI,CAAC,GAAO;EAEZ,IAAI,EAAM,QAAQ,SAAS,QAGzB,OAFI,WAAW,IAAS,SAEjB;GAAE;GAAK,UAAU,EAAM,QAAQ;EAAS;EAGjD,IAAI,EAAE,WAAW,MAAY,CAAC,OAAO,SAAS,EAAQ,KAAK,GAAG;GAC5D,IAAI,WAAW,GAAS,MAAM,IAAI,EAA8B,kCAAkC;GAElG;EACF;EAEA,IAAM,IACJ,EAAQ,UAAU,KAAK,CAAC,EAAQ,UAC5B,SACA,EAAe,EAAM,QAAQ,EAAQ,OAAO,EAAQ,WAAW,EAAK,GACpE,IAAW,EAAM,QAAQ,MAAM,IAAI,CAAQ,KAAK,EAAM,QAAQ,MAAM,IAAI,OAAO;EAErF,OAAO,IAAW;GAAE;GAAK;EAAS,IAAI,KAAA;CACxC,GAEM,KAAa,MACjB,WAAW,IAAU;EAAE,OAAO,EAAQ;EAAO,GAAG,EAAQ;CAAO,IAAK,EAAQ,UAAU,CAAC,GAEnF,KACJ,GACA,MAC+B;EAC/B,IAAM,IAAQ,EAAY,GAAK,CAAO;EAItC,OAFK,IAEE,EAAe,EAAM,UAAU,EAAU,CAAO,IAAkC,MACvF,EAAa,GAAM,EAAM,KAAK,CAAM,CACtC,IAJmB,CAAC,EAAW,GAAK,CAAM,CAAC;CAK7C,GAEM,KAAoB,GAAa,IAA4C,CAAC,MAAc;EAChG,IAAM,IAAQ,EAAY,GAAK,CAAO;EAItC,OAFK,IAEE,EAAW,EAAM,UAAU,EAAU,CAAO,IAAI,MAAS,EAAa,GAAM,EAAM,KAAK,CAAM,CAAC,IAFlF,EAAW,GAAK,CAAM;CAG3C;CAEA,OAAO;EACL;EACA,SAAS,GAAa,GAAoF;GACxG,OAAO,EAAgB,GAAK,CAAO;EACrC;EACA;EACA,UAAU,GAAa,IAA4C,CAAC,GAAG;GACrE,OAAO,EAAiB,GAAK,CAAO;EACtC;EACA;CACF;AACF;AAGA,SAAgB,EACd,GACA,IAAoC,CAAC,GACtB;CACf,IAAM,IAAS,EAAgB,EAAQ,UAAU,IAAI;CAGrD,OAAO,kBAAgC,IAFlB,IAA6B,CAAC,CAAC,GAAQ,EAAe,CAAO,CAAC,CAAC,CAE7C,GAAU;EAAE,GAAG;EAAS;CAAO,CAAC;AACzE;AAEA,SAAgB,EAAoC,GAAuB,GAA4C;CACrH,IAAM,oBAAW,IAAI,IAA6B;CAElD,KAAK,IAAM,CAAC,GAAQ,MAAY,OAAO,QAAQ,CAAQ,GACrD,EAAS,IAAI,EAAgB,CAAM,GAAG,EAAe,CAAO,CAAC;CAG/D,OAAO,EAAgC,GAAU,CAAO;AAC1D"}
package/dist/types.d.ts CHANGED
@@ -13,8 +13,6 @@ export type CatalogLoader<C extends Catalog = Catalog> = () => Promise<C>;
13
13
  export type CatalogSource<C extends Catalog = Catalog> = C | CatalogLoader<C>;
14
14
  /** Locale declarations may contain static catalogs or lazy loaders. */
15
15
  export type CatalogSources<C extends Catalog = Catalog> = Record<Locale, CatalogSource<C>>;
16
- /** Resolved catalog payload used for SSR serialization and hydration. */
17
- export type LoadedCatalogs<C extends Catalog = Catalog> = Catalogs<C>;
18
16
  export type MessageKey<C, Prefix extends string = '', Depth extends readonly unknown[] = readonly [1, 1, 1, 1, 1, 1]> = Depth extends readonly [unknown, ...infer Rest] ? C extends string | PluralMessage ? Prefix : C extends Catalog ? {
19
17
  [K in string & keyof C]: MessageKey<C[K], Prefix extends '' ? K : `${Prefix}.${K}`, Rest>;
20
18
  }[string & keyof C] : never : never;
@@ -48,7 +46,7 @@ export type TranslationStoreOptions<C extends Catalog = Catalog> = TranslatorOpt
48
46
  catalogs: CatalogSources<C>;
49
47
  };
50
48
  export type TranslationState<C extends Catalog = Catalog> = {
51
- readonly catalogs: LoadedCatalogs<C>;
49
+ readonly catalogs: Catalogs<C>;
52
50
  readonly locale: Locale;
53
51
  readonly version: 3;
54
52
  };
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"validate.cjs","names":[],"sources":["../src/validate.ts"],"sourcesContent":["import type { Catalog, CatalogNode, Locale, PluralMessage } from './types';\n\nimport { compileCatalog } from './_catalog';\nimport { canonicalLocale } from './_locale';\n\nexport type ValidationIssue = {\n key: string;\n locale: Locale;\n missing: Intl.LDMLPluralRule;\n};\n\nfunction isPluralMessage(node: CatalogNode): node is PluralMessage {\n return typeof node === 'object' && node !== null && Object.hasOwn(node, 'plural');\n}\n\n/** Explicit tooling API. Runtime never loads validation code or emits asynchronous catalog warnings. */\nexport function validateCatalog(catalog: Catalog, locale: Locale): ValidationIssue[] {\n compileCatalog(catalog);\n\n const canonical = canonicalLocale(locale);\n const categories = new Intl.PluralRules(canonical).resolvedOptions().pluralCategories;\n const issues: ValidationIssue[] = [];\n\n const visit = (node: CatalogNode, key: string): void => {\n if (typeof node === 'string') return;\n\n if (isPluralMessage(node)) {\n for (const missing of categories) {\n if (!Object.hasOwn(node.plural, missing)) issues.push({ key, locale: canonical, missing });\n }\n\n return;\n }\n\n for (const [childKey, child] of Object.entries(node)) visit(child, key ? `${key}.${childKey}` : childKey);\n };\n\n for (const [key, node] of Object.entries(catalog)) visit(node, key);\n\n return issues;\n}\n"],"mappings":"gIAWA,SAAS,EAAgB,EAA0C,CACjE,OAAO,OAAO,GAAS,YAAY,GAAiB,OAAO,OAAO,EAAM,QAAQ,CAClF,CAGA,SAAgB,EAAgB,EAAkB,EAAmC,CACnF,EAAA,eAAe,CAAO,EAEtB,IAAM,EAAY,EAAA,gBAAgB,CAAM,EAClC,EAAa,IAAI,KAAK,YAAY,CAAS,CAAC,CAAC,gBAAgB,CAAC,CAAC,iBAC/D,EAA4B,CAAC,EAE7B,GAAS,EAAmB,IAAsB,CAClD,UAAO,GAAS,SAEpB,IAAI,EAAgB,CAAI,EAAG,CACzB,IAAK,IAAM,KAAW,EACf,OAAO,OAAO,EAAK,OAAQ,CAAO,GAAG,EAAO,KAAK,CAAE,MAAK,OAAQ,EAAW,SAAQ,CAAC,EAG3F,MACF,CAEA,IAAK,GAAM,CAAC,EAAU,KAAU,OAAO,QAAQ,CAAI,EAAG,EAAM,EAAO,EAAM,GAAG,EAAI,GAAG,IAAa,CAAQ,CAFxG,CAGF,EAEA,IAAK,GAAM,CAAC,EAAK,KAAS,OAAO,QAAQ,CAAO,EAAG,EAAM,EAAM,CAAG,EAElE,OAAO,CACT"}
1
+ {"version":3,"file":"validate.cjs","names":[],"sources":["../src/validate.ts"],"sourcesContent":["import { compileCatalog } from './_catalog';\nimport { canonicalLocale } from './_locale';\nimport type { Catalog, CatalogNode, Locale, PluralMessage } from './types';\n\nexport type ValidationIssue = {\n key: string;\n locale: Locale;\n missing: Intl.LDMLPluralRule;\n};\n\nfunction isPluralMessage(node: CatalogNode): node is PluralMessage {\n return typeof node === 'object' && node !== null && Object.hasOwn(node, 'plural');\n}\n\n/** Explicit tooling API. Runtime never loads validation code or emits asynchronous catalog warnings. */\nexport function validateCatalog(catalog: Catalog, locale: Locale): ValidationIssue[] {\n compileCatalog(catalog);\n\n const canonical = canonicalLocale(locale);\n const categories = new Intl.PluralRules(canonical).resolvedOptions().pluralCategories;\n const issues: ValidationIssue[] = [];\n\n const visit = (node: CatalogNode, key: string): void => {\n if (typeof node === 'string') return;\n\n if (isPluralMessage(node)) {\n for (const missing of categories) {\n if (!Object.hasOwn(node.plural, missing)) issues.push({ key, locale: canonical, missing });\n }\n\n return;\n }\n\n for (const [childKey, child] of Object.entries(node)) visit(child, key ? `${key}.${childKey}` : childKey);\n };\n\n for (const [key, node] of Object.entries(catalog)) visit(node, key);\n\n return issues;\n}\n"],"mappings":"gIAUA,SAAS,EAAgB,EAA0C,CACjE,OAAO,OAAO,GAAS,YAAY,GAAiB,OAAO,OAAO,EAAM,QAAQ,CAClF,CAGA,SAAgB,EAAgB,EAAkB,EAAmC,CACnF,EAAA,eAAe,CAAO,EAEtB,IAAM,EAAY,EAAA,gBAAgB,CAAM,EAClC,EAAa,IAAI,KAAK,YAAY,CAAS,CAAC,CAAC,gBAAgB,CAAC,CAAC,iBAC/D,EAA4B,CAAC,EAE7B,GAAS,EAAmB,IAAsB,CAClD,UAAO,GAAS,SAEpB,IAAI,EAAgB,CAAI,EAAG,CACzB,IAAK,IAAM,KAAW,EACf,OAAO,OAAO,EAAK,OAAQ,CAAO,GAAG,EAAO,KAAK,CAAE,MAAK,OAAQ,EAAW,SAAQ,CAAC,EAG3F,MACF,CAEA,IAAK,GAAM,CAAC,EAAU,KAAU,OAAO,QAAQ,CAAI,EAAG,EAAM,EAAO,EAAM,GAAG,EAAI,GAAG,IAAa,CAAQ,CAFxG,CAGF,EAEA,IAAK,GAAM,CAAC,EAAK,KAAS,OAAO,QAAQ,CAAO,EAAG,EAAM,EAAM,CAAG,EAElE,OAAO,CACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAe,MAAM,EAAiB,MAAM,SAAS,CAAC;AAK3E,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC;CAC9B,CAAC;AAMF,wGAAwG;AACxG,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,eAAe,EAAE,CAwBnF"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAe,MAAM,EAAiB,MAAM,SAAS,CAAC;AAE3E,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC;CAC9B,CAAC;AAMF,wGAAwG;AACxG,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,eAAe,EAAE,CAwBnF"}
@@ -1 +1 @@
1
- {"version":3,"file":"validate.js","names":[],"sources":["../src/validate.ts"],"sourcesContent":["import type { Catalog, CatalogNode, Locale, PluralMessage } from './types';\n\nimport { compileCatalog } from './_catalog';\nimport { canonicalLocale } from './_locale';\n\nexport type ValidationIssue = {\n key: string;\n locale: Locale;\n missing: Intl.LDMLPluralRule;\n};\n\nfunction isPluralMessage(node: CatalogNode): node is PluralMessage {\n return typeof node === 'object' && node !== null && Object.hasOwn(node, 'plural');\n}\n\n/** Explicit tooling API. Runtime never loads validation code or emits asynchronous catalog warnings. */\nexport function validateCatalog(catalog: Catalog, locale: Locale): ValidationIssue[] {\n compileCatalog(catalog);\n\n const canonical = canonicalLocale(locale);\n const categories = new Intl.PluralRules(canonical).resolvedOptions().pluralCategories;\n const issues: ValidationIssue[] = [];\n\n const visit = (node: CatalogNode, key: string): void => {\n if (typeof node === 'string') return;\n\n if (isPluralMessage(node)) {\n for (const missing of categories) {\n if (!Object.hasOwn(node.plural, missing)) issues.push({ key, locale: canonical, missing });\n }\n\n return;\n }\n\n for (const [childKey, child] of Object.entries(node)) visit(child, key ? `${key}.${childKey}` : childKey);\n };\n\n for (const [key, node] of Object.entries(catalog)) visit(node, key);\n\n return issues;\n}\n"],"mappings":";;;AAWA,SAAS,EAAgB,GAA0C;CACjE,OAAO,OAAO,KAAS,cAAY,KAAiB,OAAO,OAAO,GAAM,QAAQ;AAClF;AAGA,SAAgB,EAAgB,GAAkB,GAAmC;CACnF,EAAe,CAAO;CAEtB,IAAM,IAAY,EAAgB,CAAM,GAClC,IAAa,IAAI,KAAK,YAAY,CAAS,CAAC,CAAC,gBAAgB,CAAC,CAAC,kBAC/D,IAA4B,CAAC,GAE7B,KAAS,GAAmB,MAAsB;EAClD,WAAO,KAAS,UAEpB;OAAI,EAAgB,CAAI,GAAG;IACzB,KAAK,IAAM,KAAW,GACpB,AAAK,OAAO,OAAO,EAAK,QAAQ,CAAO,KAAG,EAAO,KAAK;KAAE;KAAK,QAAQ;KAAW;IAAQ,CAAC;IAG3F;GACF;GAEA,KAAK,IAAM,CAAC,GAAU,MAAU,OAAO,QAAQ,CAAI,GAAG,EAAM,GAAO,IAAM,GAAG,EAAI,GAAG,MAAa,CAAQ;EAFxG;CAGF;CAEA,KAAK,IAAM,CAAC,GAAK,MAAS,OAAO,QAAQ,CAAO,GAAG,EAAM,GAAM,CAAG;CAElE,OAAO;AACT"}
1
+ {"version":3,"file":"validate.js","names":[],"sources":["../src/validate.ts"],"sourcesContent":["import { compileCatalog } from './_catalog';\nimport { canonicalLocale } from './_locale';\nimport type { Catalog, CatalogNode, Locale, PluralMessage } from './types';\n\nexport type ValidationIssue = {\n key: string;\n locale: Locale;\n missing: Intl.LDMLPluralRule;\n};\n\nfunction isPluralMessage(node: CatalogNode): node is PluralMessage {\n return typeof node === 'object' && node !== null && Object.hasOwn(node, 'plural');\n}\n\n/** Explicit tooling API. Runtime never loads validation code or emits asynchronous catalog warnings. */\nexport function validateCatalog(catalog: Catalog, locale: Locale): ValidationIssue[] {\n compileCatalog(catalog);\n\n const canonical = canonicalLocale(locale);\n const categories = new Intl.PluralRules(canonical).resolvedOptions().pluralCategories;\n const issues: ValidationIssue[] = [];\n\n const visit = (node: CatalogNode, key: string): void => {\n if (typeof node === 'string') return;\n\n if (isPluralMessage(node)) {\n for (const missing of categories) {\n if (!Object.hasOwn(node.plural, missing)) issues.push({ key, locale: canonical, missing });\n }\n\n return;\n }\n\n for (const [childKey, child] of Object.entries(node)) visit(child, key ? `${key}.${childKey}` : childKey);\n };\n\n for (const [key, node] of Object.entries(catalog)) visit(node, key);\n\n return issues;\n}\n"],"mappings":";;;AAUA,SAAS,EAAgB,GAA0C;CACjE,OAAO,OAAO,KAAS,cAAY,KAAiB,OAAO,OAAO,GAAM,QAAQ;AAClF;AAGA,SAAgB,EAAgB,GAAkB,GAAmC;CACnF,EAAe,CAAO;CAEtB,IAAM,IAAY,EAAgB,CAAM,GAClC,IAAa,IAAI,KAAK,YAAY,CAAS,CAAC,CAAC,gBAAgB,CAAC,CAAC,kBAC/D,IAA4B,CAAC,GAE7B,KAAS,GAAmB,MAAsB;EAClD,WAAO,KAAS,UAEpB;OAAI,EAAgB,CAAI,GAAG;IACzB,KAAK,IAAM,KAAW,GACpB,AAAK,OAAO,OAAO,EAAK,QAAQ,CAAO,KAAG,EAAO,KAAK;KAAE;KAAK,QAAQ;KAAW;IAAQ,CAAC;IAG3F;GACF;GAEA,KAAK,IAAM,CAAC,GAAU,MAAU,OAAO,QAAQ,CAAI,GAAG,EAAM,GAAO,IAAM,GAAG,EAAI,GAAG,MAAa,CAAQ;EAFxG;CAGF;CAEA,KAAK,IAAM,CAAC,GAAK,MAAS,OAAO,QAAQ,CAAO,GAAG,EAAM,GAAM,CAAG;CAElE,OAAO;AACT"}
package/package.json CHANGED
@@ -1,65 +1,64 @@
1
1
  {
2
2
  "name": "@vielzeug/lingua",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "Explicit typed localization with pluralization, lazy locale catalogs, and SSR hydration",
5
5
  "type": "module",
6
+ "engines": {
7
+ "node": ">=22"
8
+ },
6
9
  "files": [
7
10
  "dist"
8
11
  ],
9
12
  "main": "./dist/index.cjs",
10
13
  "module": "./dist/index.js",
11
14
  "types": "dist/index.d.ts",
12
- "typesVersions": {
13
- "*": {
14
- "format": [
15
- "dist/format.d.ts"
16
- ],
17
- "validate": [
18
- "dist/validate.d.ts"
19
- ]
20
- }
21
- },
22
15
  "exports": {
23
16
  ".": {
24
- "types": "./dist/index.d.ts",
25
17
  "import": "./dist/index.js",
26
- "require": "./dist/index.cjs"
18
+ "require": "./dist/index.cjs",
19
+ "types": "./dist/index.d.ts"
27
20
  },
28
21
  "./format": {
29
- "types": "./dist/format.d.ts",
30
22
  "import": "./dist/format.js",
31
- "require": "./dist/format.cjs"
23
+ "require": "./dist/format.cjs",
24
+ "types": "./dist/format.d.ts"
32
25
  },
33
26
  "./validate": {
34
- "types": "./dist/validate.d.ts",
35
27
  "import": "./dist/validate.js",
36
- "require": "./dist/validate.cjs"
28
+ "require": "./dist/validate.cjs",
29
+ "types": "./dist/validate.d.ts"
30
+ }
31
+ },
32
+ "typesVersions": {
33
+ "*": {
34
+ "format": [
35
+ "dist/format.d.ts"
36
+ ],
37
+ "validate": [
38
+ "dist/validate.d.ts"
39
+ ]
37
40
  }
38
41
  },
42
+ "publishConfig": {
43
+ "access": "public",
44
+ "registry": "https://registry.npmjs.org/"
45
+ },
39
46
  "scripts": {
40
- "build": "pnpm run typecheck && vite build && pnpm run build:bundle && pnpm run build:types && pnpm run verify:exports && pnpm run verify:package",
47
+ "build": "pnpm run typecheck && vite build && pnpm run build:bundle && pnpm run build:types && pnpm run verify:exports",
48
+ "build:bundle": "vite build --config vite.bundle.config.ts",
41
49
  "build:types": "tsc -p tsconfig.declarations.json",
42
- "fix": "eslint --fix src",
43
- "lint": "eslint src",
50
+ "fix": "biome check --write src",
51
+ "lint": "biome ci src",
44
52
  "prepublishOnly": "pnpm run build",
45
53
  "preview": "vite preview",
46
54
  "test": "pnpm run typecheck && vitest",
47
55
  "typecheck": "tsc -p tsconfig.json --noEmit",
48
- "build:bundle": "vite build --config vite.bundle.config.ts",
49
- "verify:exports": "node ./scripts/verify-exports.mjs",
50
- "verify:package": "node ./scripts/verify-package.mjs"
51
- },
52
- "publishConfig": {
53
- "access": "public",
54
- "registry": "https://registry.npmjs.org/"
55
- },
56
- "engines": {
57
- "node": ">=22"
56
+ "verify:exports": "node ./scripts/verify-exports.mjs"
58
57
  },
59
58
  "devDependencies": {
60
- "@types/node": "^26.1.2",
59
+ "@types/node": "^26.2.0",
61
60
  "typescript": "^6.0.3",
62
- "vite": "^8.2.0",
61
+ "vite": "^8.2.1",
63
62
  "vitest": "^4.1.10"
64
63
  }
65
64
  }