@vielzeug/lingua 2.1.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/_catalog.cjs +1 -1
  2. package/dist/_catalog.cjs.map +1 -1
  3. package/dist/_catalog.d.ts +2 -1
  4. package/dist/_catalog.d.ts.map +1 -1
  5. package/dist/_catalog.js +15 -15
  6. package/dist/_catalog.js.map +1 -1
  7. package/dist/_locale.cjs.map +1 -1
  8. package/dist/_locale.d.ts.map +1 -1
  9. package/dist/_locale.js.map +1 -1
  10. package/dist/_resources.cjs +1 -1
  11. package/dist/_resources.cjs.map +1 -1
  12. package/dist/_resources.d.ts +1 -1
  13. package/dist/_resources.d.ts.map +1 -1
  14. package/dist/_resources.js +9 -9
  15. package/dist/_resources.js.map +1 -1
  16. package/dist/catalog.cjs +2 -0
  17. package/dist/catalog.cjs.map +1 -0
  18. package/dist/catalog.d.ts +27 -0
  19. package/dist/catalog.d.ts.map +1 -0
  20. package/dist/catalog.js +10 -0
  21. package/dist/catalog.js.map +1 -0
  22. package/dist/i18n.cjs.map +1 -1
  23. package/dist/i18n.d.ts +1 -1
  24. package/dist/i18n.d.ts.map +1 -1
  25. package/dist/i18n.js.map +1 -1
  26. package/dist/index.cjs +1 -1
  27. package/dist/index.d.ts +2 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +4 -3
  30. package/dist/lingua.cjs +1 -1
  31. package/dist/lingua.cjs.map +1 -1
  32. package/dist/lingua.iife.js +1 -1
  33. package/dist/lingua.iife.js.map +1 -1
  34. package/dist/lingua.js +1 -1
  35. package/dist/lingua.js.map +1 -1
  36. package/dist/translator.cjs +1 -1
  37. package/dist/translator.cjs.map +1 -1
  38. package/dist/translator.d.ts +1 -1
  39. package/dist/translator.d.ts.map +1 -1
  40. package/dist/translator.js +34 -34
  41. package/dist/translator.js.map +1 -1
  42. package/dist/types.d.ts +8 -11
  43. package/dist/types.d.ts.map +1 -1
  44. package/dist/validate.cjs +1 -1
  45. package/dist/validate.cjs.map +1 -1
  46. package/dist/validate.d.ts +13 -1
  47. package/dist/validate.d.ts.map +1 -1
  48. package/dist/validate.js +31 -13
  49. package/dist/validate.js.map +1 -1
  50. package/package.json +36 -32
@@ -1,42 +1,42 @@
1
- import { LinguaInvalidPluralCountError as e } from "./errors.js";
2
- import { canonicalLocale as t, localeChain as n, pluralCategory as r } from "./_locale.js";
3
- import { renderSegments as i, renderText as a } from "./_template.js";
4
- import { compileCatalog as o } from "./_catalog.js";
1
+ import { renderSegments as e, renderText as t } from "./_template.js";
2
+ import { LinguaInvalidPluralCountError as n } from "./errors.js";
3
+ import { compileCatalog as r } from "./_catalog.js";
4
+ import { canonicalLocale as i, localeChain as a, pluralCategory as o } from "./_locale.js";
5
5
  //#region src/translator.ts
6
- function s(o, s = {}) {
7
- let c = t(s.locale ?? "en"), l = (Array.isArray(s.fallback) ? s.fallback : s.fallback ? [s.fallback] : []).map(t), u = n(c, l), d = s.onMissingKey ?? ((e) => e), f = s.onMissingValue ?? ((e) => `{${e}}`), p = (e) => {
6
+ function s(r, s = {}) {
7
+ let c = i(s.locale ?? "en"), l = (Array.isArray(s.fallback) ? s.fallback : s.fallback ? [s.fallback] : []).map(i), u = a(c, l), d = s.onMissingKey ?? ((e) => e), f = s.onMissingValue ?? ((e) => `{${e}}`), p = (e) => {
8
8
  for (let t of u) {
9
- let n = o.get(t)?.get(e);
9
+ let n = r.get(t)?.get(e);
10
10
  if (n) return {
11
11
  locale: t,
12
12
  message: n
13
13
  };
14
14
  }
15
- }, m = (t, n) => {
16
- let i = p(t);
17
- if (!i) return;
18
- if (i.message.kind === "text") return "count" in n ? void 0 : {
19
- key: t,
20
- template: i.message.template
15
+ }, m = (e, t) => {
16
+ let r = p(e);
17
+ if (!r) return;
18
+ if (r.message.kind === "text") return "count" in t ? void 0 : {
19
+ key: e,
20
+ template: r.message.template
21
21
  };
22
- if (!("count" in n) || !Number.isFinite(n.count)) {
23
- if ("count" in n) throw new e("`count` must be a finite number.");
22
+ if (!("count" in t) || !Number.isFinite(t.count)) {
23
+ if ("count" in t) throw new n("`count` must be a finite number.");
24
24
  return;
25
25
  }
26
- let a = n.count === 0 && !n.ordinal ? "zero" : r(i.locale, n.count, n.ordinal ?? !1), o = i.message.forms.get(a) ?? i.message.forms.get("other");
27
- return o ? {
28
- key: t,
29
- template: o
26
+ let i = t.count === 0 && !t.ordinal ? "zero" : o(r.locale, t.count, t.ordinal ?? !1), a = r.message.forms.get(i) ?? r.message.forms.get("other");
27
+ return a ? {
28
+ key: e,
29
+ template: a
30
30
  } : void 0;
31
31
  }, h = (e) => "count" in e ? {
32
32
  count: e.count,
33
33
  ...e.values
34
- } : e.values ?? {}, g = (e, t) => {
35
- let n = m(e, t);
36
- return n ? i(n.template, h(t), (e) => f(e, n.key, c)) : [d(e, c)];
37
- }, _ = (e, t = {}) => {
38
- let n = m(e, t);
39
- return n ? a(n.template, h(t), (e) => f(e, n.key, c)) : d(e, c);
34
+ } : e.values ?? {}, g = (t, n) => {
35
+ let r = m(t, n);
36
+ return r ? e(r.template, h(n), (e) => f(e, r.key, c)) : [d(t, c)];
37
+ }, _ = (e, n = {}) => {
38
+ let r = m(e, n);
39
+ return r ? t(r.template, h(n), (e) => f(e, r.key, c)) : d(e, c);
40
40
  };
41
41
  return {
42
42
  locale: c,
@@ -50,17 +50,17 @@ function s(o, s = {}) {
50
50
  translateDynamic: _
51
51
  };
52
52
  }
53
- function c(e, n = {}) {
54
- let r = t(n.locale ?? "en");
55
- return s(/* @__PURE__ */ new Map([[r, o(e)]]), {
56
- ...n,
57
- locale: r
53
+ function c(e, t = {}) {
54
+ let n = i(t.locale ?? "en");
55
+ return s(/* @__PURE__ */ new Map([[n, r(e)]]), {
56
+ ...t,
57
+ locale: n
58
58
  });
59
59
  }
60
- function l(e, n) {
61
- let r = /* @__PURE__ */ new Map();
62
- for (let [n, i] of Object.entries(e)) r.set(t(n), o(i));
63
- return s(r, n);
60
+ function l(e, t) {
61
+ let n = /* @__PURE__ */ new Map();
62
+ for (let [t, a] of Object.entries(e)) n.set(i(t), r(a));
63
+ return s(n, t);
64
64
  }
65
65
  //#endregion
66
66
  export { c as createCatalogTranslator, l as createTranslator, s as createTranslatorFromCompiled };
@@ -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,17 +13,13 @@ 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
- 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
- [K in string & keyof C]: MessageKey<C[K], Prefix extends '' ? K : `${Prefix}.${K}`, Rest>;
20
- }[string & keyof C] : never : never;
21
- export type TextKey<C, Prefix extends string = '', Depth extends readonly unknown[] = readonly [1, 1, 1, 1, 1, 1]> = Depth extends readonly [unknown, ...infer Rest] ? C extends string ? Prefix : C extends Catalog ? {
22
- [K in string & keyof C]: TextKey<C[K], Prefix extends '' ? K : `${Prefix}.${K}`, Rest>;
23
- }[string & keyof C] : never : never;
24
- export type PluralKey<C, Prefix extends string = '', Depth extends readonly unknown[] = readonly [1, 1, 1, 1, 1, 1]> = Depth extends readonly [unknown, ...infer Rest] ? C extends PluralMessage ? Prefix : C extends Catalog ? {
25
- [K in string & keyof C]: PluralKey<C[K], Prefix extends '' ? K : `${Prefix}.${K}`, Rest>;
16
+ /** Traverses a catalog type and collects dotted paths to nodes matching `Leaf`. */
17
+ type CatalogPaths<C, Leaf, Prefix extends string = '', Depth extends readonly unknown[] = readonly [1, 1, 1, 1, 1, 1]> = Depth extends readonly [unknown, ...infer Rest] ? C extends Leaf ? Prefix : C extends Catalog ? {
18
+ [K in string & keyof C]: CatalogPaths<C[K], Leaf, Prefix extends '' ? K : `${Prefix}.${K}`, Rest>;
26
19
  }[string & keyof C] : never : never;
20
+ export type MessageKey<C> = CatalogPaths<C, string | PluralMessage>;
21
+ export type TextKey<C> = CatalogPaths<C, string>;
22
+ export type PluralKey<C> = CatalogPaths<C, PluralMessage>;
27
23
  export type Values = Record<string, unknown>;
28
24
  export type TranslateOptions = {
29
25
  values?: Values;
@@ -48,8 +44,9 @@ export type TranslationStoreOptions<C extends Catalog = Catalog> = TranslatorOpt
48
44
  catalogs: CatalogSources<C>;
49
45
  };
50
46
  export type TranslationState<C extends Catalog = Catalog> = {
51
- readonly catalogs: LoadedCatalogs<C>;
47
+ readonly catalogs: Catalogs<C>;
52
48
  readonly locale: Locale;
53
49
  readonly version: 3;
54
50
  };
51
+ export {};
55
52
  //# sourceMappingURL=types.d.ts.map
@@ -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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"}
package/dist/validate.cjs CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./_locale.cjs"),t=require("./_catalog.cjs");function n(e){return typeof e==`object`&&!!e&&Object.hasOwn(e,`plural`)}function r(r,i){t.compileCatalog(r);let a=e.canonicalLocale(i),o=new Intl.PluralRules(a).resolvedOptions().pluralCategories,s=[],c=(e,t)=>{if(typeof e!=`string`){if(n(e)){for(let n of o)Object.hasOwn(e.plural,n)||s.push({key:t,locale:a,missing:n});return}for(let[n,r]of Object.entries(e))c(r,t?`${t}.${n}`:n)}};for(let[e,t]of Object.entries(r))c(t,e);return s}exports.validateCatalog=r;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./_catalog.cjs"),t=require("./_locale.cjs");function n(n,r){e.compileCatalog(n);let i=t.canonicalLocale(r),a=new Intl.PluralRules(i).resolvedOptions().pluralCategories,o=[],s=(t,n)=>{if(typeof t!=`string`){if(e.isPluralMessage(t)){for(let e of a)Object.hasOwn(t.plural,e)||o.push({key:n,locale:i,missing:e});return}for(let[e,r]of Object.entries(t))s(r,n?`${n}.${e}`:e)}};for(let[e,t]of Object.entries(n))s(t,e);return o}function r(t){let n=Object.keys(t),r=new Map,i=[],a=[];for(let i of n)r.set(i,new Set(e.compileCatalog(t[i]).keys()));let o=n[0],s=r.get(o);for(let e of n){if(e===o)continue;let t=r.get(e);for(let n of s)t.has(n)||i.push({key:n,locale:e});for(let n of t)s.has(n)||a.push({key:n,locale:e})}return{extra:a,missing:i}}exports.compareCatalogs=r,exports.validateCatalog=n;
2
2
  //# sourceMappingURL=validate.cjs.map
@@ -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, isPluralMessage } from './_catalog';\nimport { canonicalLocale } from './_locale';\nimport type { Catalog, CatalogNode, Catalogs, Locale } from './types';\n\nexport type ValidationIssue = {\n key: string;\n locale: Locale;\n missing: Intl.LDMLPluralRule;\n};\n\nexport type CatalogComparison = {\n readonly missing: ReadonlyArray<{ key: string; locale: Locale }>;\n readonly extra: ReadonlyArray<{ key: string; locale: Locale }>;\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\n/** Compares catalog key sets across locales. Reports keys missing in each target locale and keys present in targets but absent from the base. */\nexport function compareCatalogs<C extends Catalog>(catalogs: Catalogs<C>): CatalogComparison {\n const locales = Object.keys(catalogs);\n const keySets = new Map<Locale, Set<string>>();\n const missing: Array<{ key: string; locale: Locale }> = [];\n const extra: Array<{ key: string; locale: Locale }> = [];\n\n for (const locale of locales) {\n keySets.set(locale, new Set(compileCatalog(catalogs[locale]).keys()));\n }\n\n const base = locales[0];\n const baseKeys = keySets.get(base)!;\n\n for (const locale of locales) {\n if (locale === base) continue;\n const targetKeys = keySets.get(locale)!;\n\n for (const key of baseKeys) {\n if (!targetKeys.has(key)) missing.push({ key, locale });\n }\n\n for (const key of targetKeys) {\n if (!baseKeys.has(key)) extra.push({ key, locale });\n }\n }\n\n return { extra, missing };\n}\n"],"mappings":"gIAgBA,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,EAAA,gBAAgB,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,CAGA,SAAgB,EAAmC,EAA0C,CAC3F,IAAM,EAAU,OAAO,KAAK,CAAQ,EAC9B,EAAU,IAAI,IACd,EAAkD,CAAC,EACnD,EAAgD,CAAC,EAEvD,IAAK,IAAM,KAAU,EACnB,EAAQ,IAAI,EAAQ,IAAI,IAAI,EAAA,eAAe,EAAS,EAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAGtE,IAAM,EAAO,EAAQ,GACf,EAAW,EAAQ,IAAI,CAAI,EAEjC,IAAK,IAAM,KAAU,EAAS,CAC5B,GAAI,IAAW,EAAM,SACrB,IAAM,EAAa,EAAQ,IAAI,CAAM,EAErC,IAAK,IAAM,KAAO,EACX,EAAW,IAAI,CAAG,GAAG,EAAQ,KAAK,CAAE,MAAK,QAAO,CAAC,EAGxD,IAAK,IAAM,KAAO,EACX,EAAS,IAAI,CAAG,GAAG,EAAM,KAAK,CAAE,MAAK,QAAO,CAAC,CAEtD,CAEA,MAAO,CAAE,QAAO,SAAQ,CAC1B"}
@@ -1,9 +1,21 @@
1
- import type { Catalog, Locale } from './types';
1
+ import type { Catalog, Catalogs, Locale } from './types';
2
2
  export type ValidationIssue = {
3
3
  key: string;
4
4
  locale: Locale;
5
5
  missing: Intl.LDMLPluralRule;
6
6
  };
7
+ export type CatalogComparison = {
8
+ readonly missing: ReadonlyArray<{
9
+ key: string;
10
+ locale: Locale;
11
+ }>;
12
+ readonly extra: ReadonlyArray<{
13
+ key: string;
14
+ locale: Locale;
15
+ }>;
16
+ };
7
17
  /** Explicit tooling API. Runtime never loads validation code or emits asynchronous catalog warnings. */
8
18
  export declare function validateCatalog(catalog: Catalog, locale: Locale): ValidationIssue[];
19
+ /** Compares catalog key sets across locales. Reports keys missing in each target locale and keys present in targets but absent from the base. */
20
+ export declare function compareCatalogs<C extends Catalog>(catalogs: Catalogs<C>): CatalogComparison;
9
21
  //# sourceMappingURL=validate.d.ts.map
@@ -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,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtE,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjE,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChE,CAAC;AAEF,wGAAwG;AACxG,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,eAAe,EAAE,CAwBnF;AAED,iJAAiJ;AACjJ,wBAAgB,eAAe,CAAC,CAAC,SAAS,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,iBAAiB,CA2B3F"}
package/dist/validate.js CHANGED
@@ -1,28 +1,46 @@
1
- import { canonicalLocale as e } from "./_locale.js";
2
- import { compileCatalog as t } from "./_catalog.js";
1
+ import { compileCatalog as e, isPluralMessage as t } from "./_catalog.js";
2
+ import { canonicalLocale as n } from "./_locale.js";
3
3
  //#region src/validate.ts
4
- function n(e) {
5
- return typeof e == "object" && !!e && Object.hasOwn(e, "plural");
6
- }
7
4
  function r(r, i) {
8
- t(r);
9
- let a = e(i), o = new Intl.PluralRules(a).resolvedOptions().pluralCategories, s = [], c = (e, t) => {
5
+ e(r);
6
+ let a = n(i), o = new Intl.PluralRules(a).resolvedOptions().pluralCategories, s = [], c = (e, n) => {
10
7
  if (typeof e != "string") {
11
- if (n(e)) {
12
- for (let n of o) Object.hasOwn(e.plural, n) || s.push({
13
- key: t,
8
+ if (t(e)) {
9
+ for (let t of o) Object.hasOwn(e.plural, t) || s.push({
10
+ key: n,
14
11
  locale: a,
15
- missing: n
12
+ missing: t
16
13
  });
17
14
  return;
18
15
  }
19
- for (let [n, r] of Object.entries(e)) c(r, t ? `${t}.${n}` : n);
16
+ for (let [t, r] of Object.entries(e)) c(r, n ? `${n}.${t}` : t);
20
17
  }
21
18
  };
22
19
  for (let [e, t] of Object.entries(r)) c(t, e);
23
20
  return s;
24
21
  }
22
+ function i(t) {
23
+ let n = Object.keys(t), r = /* @__PURE__ */ new Map(), i = [], a = [];
24
+ for (let i of n) r.set(i, new Set(e(t[i]).keys()));
25
+ let o = n[0], s = r.get(o);
26
+ for (let e of n) {
27
+ if (e === o) continue;
28
+ let t = r.get(e);
29
+ for (let n of s) t.has(n) || i.push({
30
+ key: n,
31
+ locale: e
32
+ });
33
+ for (let n of t) s.has(n) || a.push({
34
+ key: n,
35
+ locale: e
36
+ });
37
+ }
38
+ return {
39
+ extra: a,
40
+ missing: i
41
+ };
42
+ }
25
43
  //#endregion
26
- export { r as validateCatalog };
44
+ export { i as compareCatalogs, r as validateCatalog };
27
45
 
28
46
  //# sourceMappingURL=validate.js.map
@@ -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, isPluralMessage } from './_catalog';\nimport { canonicalLocale } from './_locale';\nimport type { Catalog, CatalogNode, Catalogs, Locale } from './types';\n\nexport type ValidationIssue = {\n key: string;\n locale: Locale;\n missing: Intl.LDMLPluralRule;\n};\n\nexport type CatalogComparison = {\n readonly missing: ReadonlyArray<{ key: string; locale: Locale }>;\n readonly extra: ReadonlyArray<{ key: string; locale: Locale }>;\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\n/** Compares catalog key sets across locales. Reports keys missing in each target locale and keys present in targets but absent from the base. */\nexport function compareCatalogs<C extends Catalog>(catalogs: Catalogs<C>): CatalogComparison {\n const locales = Object.keys(catalogs);\n const keySets = new Map<Locale, Set<string>>();\n const missing: Array<{ key: string; locale: Locale }> = [];\n const extra: Array<{ key: string; locale: Locale }> = [];\n\n for (const locale of locales) {\n keySets.set(locale, new Set(compileCatalog(catalogs[locale]).keys()));\n }\n\n const base = locales[0];\n const baseKeys = keySets.get(base)!;\n\n for (const locale of locales) {\n if (locale === base) continue;\n const targetKeys = keySets.get(locale)!;\n\n for (const key of baseKeys) {\n if (!targetKeys.has(key)) missing.push({ key, locale });\n }\n\n for (const key of targetKeys) {\n if (!baseKeys.has(key)) extra.push({ key, locale });\n }\n }\n\n return { extra, missing };\n}\n"],"mappings":";;;AAgBA,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;AAGA,SAAgB,EAAmC,GAA0C;CAC3F,IAAM,IAAU,OAAO,KAAK,CAAQ,GAC9B,oBAAU,IAAI,IAAyB,GACvC,IAAkD,CAAC,GACnD,IAAgD,CAAC;CAEvD,KAAK,IAAM,KAAU,GACnB,EAAQ,IAAI,GAAQ,IAAI,IAAI,EAAe,EAAS,EAAO,CAAC,CAAC,KAAK,CAAC,CAAC;CAGtE,IAAM,IAAO,EAAQ,IACf,IAAW,EAAQ,IAAI,CAAI;CAEjC,KAAK,IAAM,KAAU,GAAS;EAC5B,IAAI,MAAW,GAAM;EACrB,IAAM,IAAa,EAAQ,IAAI,CAAM;EAErC,KAAK,IAAM,KAAO,GAChB,AAAK,EAAW,IAAI,CAAG,KAAG,EAAQ,KAAK;GAAE;GAAK;EAAO,CAAC;EAGxD,KAAK,IAAM,KAAO,GAChB,AAAK,EAAS,IAAI,CAAG,KAAG,EAAM,KAAK;GAAE;GAAK;EAAO,CAAC;CAEtD;CAEA,OAAO;EAAE;EAAO;CAAQ;AAC1B"}
package/package.json CHANGED
@@ -1,65 +1,69 @@
1
1
  {
2
2
  "name": "@vielzeug/lingua",
3
- "version": "2.1.0",
3
+ "version": "2.3.0",
4
4
  "description": "Explicit typed localization with pluralization, lazy locale catalogs, and SSR hydration",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/helmuthdu/vielzeug",
8
+ "directory": "packages/lingua"
9
+ },
5
10
  "type": "module",
11
+ "engines": {
12
+ "node": ">=22"
13
+ },
6
14
  "files": [
7
15
  "dist"
8
16
  ],
9
17
  "main": "./dist/index.cjs",
10
18
  "module": "./dist/index.js",
11
19
  "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
20
  "exports": {
23
21
  ".": {
24
- "types": "./dist/index.d.ts",
25
22
  "import": "./dist/index.js",
26
- "require": "./dist/index.cjs"
23
+ "require": "./dist/index.cjs",
24
+ "types": "./dist/index.d.ts"
27
25
  },
28
26
  "./format": {
29
- "types": "./dist/format.d.ts",
30
27
  "import": "./dist/format.js",
31
- "require": "./dist/format.cjs"
28
+ "require": "./dist/format.cjs",
29
+ "types": "./dist/format.d.ts"
32
30
  },
33
31
  "./validate": {
34
- "types": "./dist/validate.d.ts",
35
32
  "import": "./dist/validate.js",
36
- "require": "./dist/validate.cjs"
33
+ "require": "./dist/validate.cjs",
34
+ "types": "./dist/validate.d.ts"
37
35
  }
38
36
  },
37
+ "typesVersions": {
38
+ "*": {
39
+ "format": [
40
+ "dist/format.d.ts"
41
+ ],
42
+ "validate": [
43
+ "dist/validate.d.ts"
44
+ ]
45
+ }
46
+ },
47
+ "publishConfig": {
48
+ "access": "public",
49
+ "registry": "https://registry.npmjs.org/"
50
+ },
39
51
  "scripts": {
40
- "build": "pnpm run typecheck && vite build && pnpm run build:bundle && pnpm run build:types && pnpm run verify:exports && pnpm run verify:package",
52
+ "build": "pnpm run typecheck && vite build && pnpm run build:bundle && pnpm run build:types && pnpm run verify:exports",
53
+ "build:bundle": "vite build --config vite.bundle.config.ts",
41
54
  "build:types": "tsc -p tsconfig.declarations.json",
42
- "fix": "eslint --fix src",
43
- "lint": "eslint src",
55
+ "fix": "biome check --write src",
56
+ "lint": "biome ci src",
44
57
  "prepublishOnly": "pnpm run build",
45
58
  "preview": "vite preview",
46
59
  "test": "pnpm run typecheck && vitest",
47
60
  "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"
61
+ "verify:exports": "node ./scripts/verify-exports.mjs"
58
62
  },
59
63
  "devDependencies": {
60
- "@types/node": "^26.1.2",
64
+ "@types/node": "^26.2.0",
61
65
  "typescript": "^6.0.3",
62
- "vite": "^8.2.0",
66
+ "vite": "^8.2.1",
63
67
  "vitest": "^4.1.10"
64
68
  }
65
69
  }