@intlayer/lingui 9.0.0-canary.7 → 9.0.0-canary.9

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,22 +1,44 @@
1
1
  import { EventEmitter } from "./eventEmitter.mjs";
2
- import { linguiMessageToIcu, navigateCatalog } from "./linguiCatalog.mjs";
2
+ import { linguiMessageToIcu, navigateLinguiCatalog, unwrapLinguiCatalog } from "./linguiCatalog.mjs";
3
3
  import { getIntlayer } from "@intlayer/core/interpreter";
4
4
  import { resolveMessage } from "@intlayer/core/messageFormat";
5
+ import { getDictionaries } from "@intlayer/dictionaries-entry";
5
6
 
6
7
  //#region src/I18nClass.ts
7
8
  /**
8
- * Looks up a lingui message from the `messages` intlayer dictionary.
9
+ * Keys of every intlayer dictionary available at runtime (the namespaces).
9
10
  *
10
- * The entire lingui catalog is stored in a single `messages` dictionary.
11
- * Both flat dotted ids (`'results-table.bundleSize'`, lingui's own format)
12
- * and genuinely nested paths (`'home.title'`) are supported.
11
+ * The bundler-injected `@intlayer/dictionaries-entry` exposes the full registry;
12
+ * outside a bundle (e.g. unit tests) it resolves to an empty map, in which case
13
+ * resolution falls back to the runtime catalogs loaded via `load()`.
13
14
  */
14
- const lookupDictionaryMessage = (id, locale) => {
15
+ const getDictionaryKeys = () => {
15
16
  try {
16
- const value = navigateCatalog(getIntlayer("messages", locale), id);
17
- return value === void 0 ? void 0 : linguiMessageToIcu(value);
17
+ return Object.keys(getDictionaries());
18
18
  } catch {
19
- return;
19
+ return [];
20
+ }
21
+ };
22
+ /**
23
+ * Looks up a lingui message across every intlayer dictionary.
24
+ *
25
+ * lingui ids are flat, namespace-less keys (`'hero.title'`), but the matching
26
+ * content may live in any dictionary — a single centralized catalog, or one of
27
+ * many namespaced catalogs (`home`, `shared`, …) produced by `syncJSON` from
28
+ * split lingui catalogs. Each dictionary is searched in turn, supporting both
29
+ * the flat/nested key shapes and the lingui `{ messages: {…} }` wrapper. The
30
+ * first match wins.
31
+ */
32
+ const lookupDictionaryMessage = (id, locale) => {
33
+ for (const key of getDictionaryKeys()) {
34
+ let dictionary;
35
+ try {
36
+ dictionary = getIntlayer(key, locale);
37
+ } catch {
38
+ continue;
39
+ }
40
+ const value = navigateLinguiCatalog(dictionary, id);
41
+ if (value !== void 0) return linguiMessageToIcu(value);
20
42
  }
21
43
  };
22
44
  /**
@@ -54,12 +76,10 @@ var I18nClass = class extends EventEmitter {
54
76
  return this._locales;
55
77
  }
56
78
  get messages() {
57
- let dictionary = {};
58
- try {
59
- dictionary = getIntlayer("messages", this._locale);
60
- } catch {
61
- dictionary = {};
62
- }
79
+ const dictionary = {};
80
+ for (const key of getDictionaryKeys()) try {
81
+ Object.assign(dictionary, unwrapLinguiCatalog(getIntlayer(key, this._locale)));
82
+ } catch {}
63
83
  return {
64
84
  ...this._catalogs[this._locale] ?? {},
65
85
  ...dictionary
@@ -130,7 +150,7 @@ var I18nClass = class extends EventEmitter {
130
150
  if (fromDictionary !== void 0) return fromDictionary;
131
151
  const catalog = this._catalogs[this._locale];
132
152
  if (catalog) {
133
- const raw = navigateCatalog(catalog, id);
153
+ const raw = navigateLinguiCatalog(catalog, id);
134
154
  if (raw !== void 0) return linguiMessageToIcu(raw);
135
155
  }
136
156
  }
@@ -1 +1 @@
1
- {"version":3,"file":"I18nClass.mjs","names":[],"sources":["../../src/I18nClass.ts"],"sourcesContent":["import { getIntlayer } from '@intlayer/core/interpreter';\nimport { resolveMessage } from '@intlayer/core/messageFormat';\nimport type {\n DictionaryKeys,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type {\n AllMessages,\n Locale,\n Locales,\n MessageDescriptor,\n MessageId,\n MessageOptions,\n Messages,\n} from '@lingui/core';\nimport { EventEmitter } from './eventEmitter';\nimport { linguiMessageToIcu, navigateCatalog } from './linguiCatalog';\n\n/** Mirrors the unexported `Values` type from `@lingui/core`. */\ntype Values = Record<string, unknown>;\n\n/** Mirrors the unexported `MessageCompiler` type from `@lingui/core`. */\ntype MessageCompiler = (message: string) => unknown;\n\n/** Mirrors the unexported `Events` type from `@lingui/core`. */\ntype LinguiEvents = {\n change: () => void;\n missing: (event: { locale: Locale; id: MessageId }) => void;\n};\n\n/** Mirrors the unexported `I18nProps` type from `@lingui/core`. */\ntype I18nProps = {\n locale?: Locale;\n locales?: Locales;\n messages?: AllMessages;\n missing?: string | ((locale: string, id: string) => string);\n};\n\n/**\n * Looks up a lingui message from the `messages` intlayer dictionary.\n *\n * The entire lingui catalog is stored in a single `messages` dictionary.\n * Both flat dotted ids (`'results-table.bundleSize'`, lingui's own format)\n * and genuinely nested paths (`'home.title'`) are supported.\n */\nconst lookupDictionaryMessage = (\n id: string,\n locale: LocalesValues\n): string | undefined => {\n try {\n const dictionary = getIntlayer('messages' as DictionaryKeys, locale);\n const value = navigateCatalog(dictionary, id);\n return value === undefined ? undefined : linguiMessageToIcu(value);\n } catch {\n return undefined;\n }\n};\n\n/**\n * Intlayer-backed implementation of `@lingui/core`'s `I18n` class.\n *\n * - Messages are read from the `messages` intlayer dictionary.\n * - ICU MessageFormat syntax is resolved via `@intlayer/core/messageFormat`.\n * - `load()` / `loadAndActivate()` / `setMessagesCompiler()` are no-ops —\n * messages are served by intlayer's compiled dictionaries.\n * - `activate(locale)` emits `'change'` so that React consumers re-render.\n */\nexport class I18nClass extends EventEmitter<LinguiEvents> {\n private _locale: string;\n private _locales?: Locales;\n /**\n * Per-locale catalogs supplied at runtime via the constructor, `load()` or\n * `loadAndActivate()`. Used as a fallback when a key is absent from the\n * compiled intlayer `messages` dictionary, so an unmodified lingui codebase\n * (which loads its compiled `.mjs`/`.json` catalogs) keeps working as a\n * drop-in. For optimal bundle size, compile catalogs into intlayer\n * dictionaries instead — see the dev warning emitted by `load()`.\n */\n private _catalogs: Record<string, Messages> = {};\n private _loadFallbackWarned = false;\n\n constructor({ locale = 'en', locales, messages }: I18nProps = {}) {\n super();\n this._locale = typeof locale === 'string' ? locale : 'en';\n this._locales = locales;\n if (messages) this.mergeAllCatalogs(messages);\n }\n\n get locale(): string {\n return this._locale;\n }\n\n get locales(): Locales | undefined {\n return this._locales;\n }\n\n get messages(): Messages {\n let dictionary: Messages = {};\n try {\n dictionary = getIntlayer(\n 'messages' as DictionaryKeys,\n this._locale as LocalesValues\n ) as Messages;\n } catch {\n dictionary = {};\n }\n // The compiled dictionary wins over the runtime fallback catalog.\n return { ...(this._catalogs[this._locale] ?? {}), ...dictionary };\n }\n\n /** Merges a single-locale catalog into the in-memory fallback store. */\n private mergeLocaleCatalog(locale: string, catalog: Messages) {\n this._catalogs[locale] = { ...this._catalogs[locale], ...catalog };\n }\n\n /**\n * Merges a `{ [locale]: catalog }` map (lingui's `AllMessages`) into the\n * in-memory fallback store.\n */\n private mergeAllCatalogs(messages: AllMessages) {\n for (const [locale, catalog] of Object.entries(messages)) {\n if (catalog && typeof catalog === 'object') {\n this.mergeLocaleCatalog(locale, catalog as Messages);\n }\n }\n }\n\n /**\n * No-op: intlayer handles message compilation at build time.\n */\n setMessagesCompiler(_compiler: MessageCompiler): this {\n if (process.env.NODE_ENV === 'development') {\n console.warn(\n '@intlayer/lingui: i18n.setMessagesCompiler() is a no-op — ' +\n 'message compilation is handled at build time by intlayer.'\n );\n }\n return this;\n }\n\n /**\n * Loads message catalogs into the runtime fallback store, supporting both\n * lingui signatures: `load(locale, messages)` and `load(allMessages)`.\n *\n * These messages are a compatibility fallback — keys present in the compiled\n * intlayer `messages` dictionary take precedence, and only those keys can be\n * pruned/optimized at build time.\n */\n load(localeOrAll: Locale | AllMessages, messages?: Messages): void {\n if (typeof localeOrAll === 'string') {\n this.mergeLocaleCatalog(localeOrAll, messages ?? {});\n } else {\n this.mergeAllCatalogs(localeOrAll);\n }\n\n if (process.env.NODE_ENV === 'development' && !this._loadFallbackWarned) {\n this._loadFallbackWarned = true;\n console.warn(\n '@intlayer/lingui: i18n.load() messages are used as a runtime ' +\n 'fallback. For optimal bundle size, compile your catalogs into ' +\n 'intlayer dictionaries instead of importing lingui locale files.'\n );\n }\n }\n\n /**\n * Loads the given catalog (fallback store) and activates the locale\n * (emits `'change'`).\n */\n loadAndActivate({\n locale,\n locales,\n messages,\n }: {\n locale: Locale;\n locales?: Locales;\n messages?: Messages;\n }): void {\n if (messages) this.mergeLocaleCatalog(locale, messages);\n this.activate(locale, locales);\n }\n\n /**\n * Sets the active locale and emits `'change'` to notify React consumers.\n */\n activate(locale: Locale, locales?: Locales): void {\n this._locale = locale;\n this._locales = locales;\n this.emit('change');\n }\n\n /**\n * Resolves the raw message template for an id (before interpolation).\n *\n * Resolution order:\n * 1. compiled intlayer `messages` dictionary\n * 2. runtime fallback catalog (constructor / `load()` / `loadAndActivate()`)\n */\n private resolveTemplate(id: string): string | undefined {\n const fromDictionary = lookupDictionaryMessage(\n id,\n this._locale as LocalesValues\n );\n if (fromDictionary !== undefined) return fromDictionary;\n\n const catalog = this._catalogs[this._locale];\n if (catalog) {\n const raw = navigateCatalog(catalog, id);\n if (raw !== undefined) return linguiMessageToIcu(raw);\n }\n\n return undefined;\n }\n\n /**\n * Translates a message descriptor or a plain ID.\n *\n * Resolution order:\n * 1. `messages` intlayer dictionary (flat dotted key or nested path)\n * 2. runtime fallback catalog loaded via `load()` / `loadAndActivate()`\n * 3. `descriptor.message` or `options.message` (original source string)\n * 4. The raw `id` as fallback\n */\n _(descriptor: MessageDescriptor): string;\n _(id: MessageId, values?: Values, options?: MessageOptions): string;\n _(\n descriptorOrId: MessageDescriptor | MessageId,\n values?: Values,\n options?: MessageOptions\n ): string {\n const isDescriptor =\n typeof descriptorOrId === 'object' && descriptorOrId !== null;\n const id = isDescriptor\n ? (descriptorOrId as MessageDescriptor).id\n : (descriptorOrId as MessageId);\n const defaultMessage = isDescriptor\n ? ((descriptorOrId as MessageDescriptor).message ?? options?.message)\n : options?.message;\n const resolvedValues: Values = isDescriptor\n ? {\n ...((descriptorOrId as MessageDescriptor).values ?? {}),\n ...(values ?? {}),\n }\n : (values ?? {});\n\n const rawValue = this.resolveTemplate(id);\n const template = rawValue ?? defaultMessage ?? id;\n\n return (\n resolveMessage(\n template,\n resolvedValues as Record<string, string | number>,\n this._locale as LocalesValues,\n 'icu'\n ) ?? id\n );\n }\n\n /**\n * Alias for `_`. Provided for lingui API compatibility.\n */\n t = (\n descriptorOrId: MessageDescriptor | MessageId,\n values?: Values,\n options?: MessageOptions\n ): string => this._(descriptorOrId as MessageId, values, options);\n\n /**\n * @deprecated Use `Intl.DateTimeFormat` directly.\n */\n date(\n value?: string | Date | number,\n format?: Intl.DateTimeFormatOptions\n ): string {\n if (value === undefined || value === null) return '';\n const dateValue =\n value instanceof Date\n ? value\n : new Date(typeof value === 'string' ? value : value);\n return new Intl.DateTimeFormat(this._locale, format).format(dateValue);\n }\n\n /**\n * @deprecated Use `Intl.NumberFormat` directly.\n */\n number(value: number | bigint, format?: Intl.NumberFormatOptions): string {\n return new Intl.NumberFormat(this._locale, format).format(value);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"I18nClass.mjs","names":[],"sources":["../../src/I18nClass.ts"],"sourcesContent":["import { getIntlayer } from '@intlayer/core/interpreter';\nimport { resolveMessage } from '@intlayer/core/messageFormat';\nimport { getDictionaries } from '@intlayer/dictionaries-entry';\nimport type {\n DictionaryKeys,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type {\n AllMessages,\n Locale,\n Locales,\n MessageDescriptor,\n MessageId,\n MessageOptions,\n Messages,\n} from '@lingui/core';\nimport { EventEmitter } from './eventEmitter';\nimport {\n linguiMessageToIcu,\n navigateLinguiCatalog,\n unwrapLinguiCatalog,\n} from './linguiCatalog';\n\n/** Mirrors the unexported `Values` type from `@lingui/core`. */\ntype Values = Record<string, unknown>;\n\n/** Mirrors the unexported `MessageCompiler` type from `@lingui/core`. */\ntype MessageCompiler = (message: string) => unknown;\n\n/** Mirrors the unexported `Events` type from `@lingui/core`. */\ntype LinguiEvents = {\n change: () => void;\n missing: (event: { locale: Locale; id: MessageId }) => void;\n};\n\n/** Mirrors the unexported `I18nProps` type from `@lingui/core`. */\ntype I18nProps = {\n locale?: Locale;\n locales?: Locales;\n messages?: AllMessages;\n missing?: string | ((locale: string, id: string) => string);\n};\n\n/**\n * Keys of every intlayer dictionary available at runtime (the namespaces).\n *\n * The bundler-injected `@intlayer/dictionaries-entry` exposes the full registry;\n * outside a bundle (e.g. unit tests) it resolves to an empty map, in which case\n * resolution falls back to the runtime catalogs loaded via `load()`.\n */\nconst getDictionaryKeys = (): DictionaryKeys[] => {\n try {\n return Object.keys(getDictionaries()) as DictionaryKeys[];\n } catch {\n return [];\n }\n};\n\n/**\n * Looks up a lingui message across every intlayer dictionary.\n *\n * lingui ids are flat, namespace-less keys (`'hero.title'`), but the matching\n * content may live in any dictionary — a single centralized catalog, or one of\n * many namespaced catalogs (`home`, `shared`, …) produced by `syncJSON` from\n * split lingui catalogs. Each dictionary is searched in turn, supporting both\n * the flat/nested key shapes and the lingui `{ messages: {…} }` wrapper. The\n * first match wins.\n */\nconst lookupDictionaryMessage = (\n id: string,\n locale: LocalesValues\n): string | undefined => {\n for (const key of getDictionaryKeys()) {\n let dictionary: unknown;\n try {\n dictionary = getIntlayer(key, locale);\n } catch {\n continue;\n }\n const value = navigateLinguiCatalog(dictionary, id);\n if (value !== undefined) return linguiMessageToIcu(value);\n }\n return undefined;\n};\n\n/**\n * Intlayer-backed implementation of `@lingui/core`'s `I18n` class.\n *\n * - Messages are read from the `messages` intlayer dictionary.\n * - ICU MessageFormat syntax is resolved via `@intlayer/core/messageFormat`.\n * - `load()` / `loadAndActivate()` / `setMessagesCompiler()` are no-ops —\n * messages are served by intlayer's compiled dictionaries.\n * - `activate(locale)` emits `'change'` so that React consumers re-render.\n */\nexport class I18nClass extends EventEmitter<LinguiEvents> {\n private _locale: string;\n private _locales?: Locales;\n /**\n * Per-locale catalogs supplied at runtime via the constructor, `load()` or\n * `loadAndActivate()`. Used as a fallback when a key is absent from the\n * compiled intlayer `messages` dictionary, so an unmodified lingui codebase\n * (which loads its compiled `.mjs`/`.json` catalogs) keeps working as a\n * drop-in. For optimal bundle size, compile catalogs into intlayer\n * dictionaries instead — see the dev warning emitted by `load()`.\n */\n private _catalogs: Record<string, Messages> = {};\n private _loadFallbackWarned = false;\n\n constructor({ locale = 'en', locales, messages }: I18nProps = {}) {\n super();\n this._locale = typeof locale === 'string' ? locale : 'en';\n this._locales = locales;\n if (messages) this.mergeAllCatalogs(messages);\n }\n\n get locale(): string {\n return this._locale;\n }\n\n get locales(): Locales | undefined {\n return this._locales;\n }\n\n get messages(): Messages {\n // Merge every intlayer dictionary (namespace) for the active locale into a\n // single flat catalog, unwrapping the lingui `{ messages: {…} }` wrapper.\n const dictionary: Messages = {};\n for (const key of getDictionaryKeys()) {\n try {\n Object.assign(\n dictionary,\n unwrapLinguiCatalog(getIntlayer(key, this._locale as LocalesValues))\n );\n } catch {\n // Skip dictionaries that fail to resolve for this locale.\n }\n }\n // The compiled dictionaries win over the runtime fallback catalog.\n return { ...(this._catalogs[this._locale] ?? {}), ...dictionary };\n }\n\n /** Merges a single-locale catalog into the in-memory fallback store. */\n private mergeLocaleCatalog(locale: string, catalog: Messages) {\n this._catalogs[locale] = { ...this._catalogs[locale], ...catalog };\n }\n\n /**\n * Merges a `{ [locale]: catalog }` map (lingui's `AllMessages`) into the\n * in-memory fallback store.\n */\n private mergeAllCatalogs(messages: AllMessages) {\n for (const [locale, catalog] of Object.entries(messages)) {\n if (catalog && typeof catalog === 'object') {\n this.mergeLocaleCatalog(locale, catalog as Messages);\n }\n }\n }\n\n /**\n * No-op: intlayer handles message compilation at build time.\n */\n setMessagesCompiler(_compiler: MessageCompiler): this {\n if (process.env.NODE_ENV === 'development') {\n console.warn(\n '@intlayer/lingui: i18n.setMessagesCompiler() is a no-op — ' +\n 'message compilation is handled at build time by intlayer.'\n );\n }\n return this;\n }\n\n /**\n * Loads message catalogs into the runtime fallback store, supporting both\n * lingui signatures: `load(locale, messages)` and `load(allMessages)`.\n *\n * These messages are a compatibility fallback — keys present in the compiled\n * intlayer `messages` dictionary take precedence, and only those keys can be\n * pruned/optimized at build time.\n */\n load(localeOrAll: Locale | AllMessages, messages?: Messages): void {\n if (typeof localeOrAll === 'string') {\n this.mergeLocaleCatalog(localeOrAll, messages ?? {});\n } else {\n this.mergeAllCatalogs(localeOrAll);\n }\n\n if (process.env.NODE_ENV === 'development' && !this._loadFallbackWarned) {\n this._loadFallbackWarned = true;\n console.warn(\n '@intlayer/lingui: i18n.load() messages are used as a runtime ' +\n 'fallback. For optimal bundle size, compile your catalogs into ' +\n 'intlayer dictionaries instead of importing lingui locale files.'\n );\n }\n }\n\n /**\n * Loads the given catalog (fallback store) and activates the locale\n * (emits `'change'`).\n */\n loadAndActivate({\n locale,\n locales,\n messages,\n }: {\n locale: Locale;\n locales?: Locales;\n messages?: Messages;\n }): void {\n if (messages) this.mergeLocaleCatalog(locale, messages);\n this.activate(locale, locales);\n }\n\n /**\n * Sets the active locale and emits `'change'` to notify React consumers.\n */\n activate(locale: Locale, locales?: Locales): void {\n this._locale = locale;\n this._locales = locales;\n this.emit('change');\n }\n\n /**\n * Resolves the raw message template for an id (before interpolation).\n *\n * Resolution order:\n * 1. compiled intlayer `messages` dictionary\n * 2. runtime fallback catalog (constructor / `load()` / `loadAndActivate()`)\n */\n private resolveTemplate(id: string): string | undefined {\n const fromDictionary = lookupDictionaryMessage(\n id,\n this._locale as LocalesValues\n );\n if (fromDictionary !== undefined) return fromDictionary;\n\n const catalog = this._catalogs[this._locale];\n if (catalog) {\n const raw = navigateLinguiCatalog(catalog, id);\n if (raw !== undefined) return linguiMessageToIcu(raw);\n }\n\n return undefined;\n }\n\n /**\n * Translates a message descriptor or a plain ID.\n *\n * Resolution order:\n * 1. `messages` intlayer dictionary (flat dotted key or nested path)\n * 2. runtime fallback catalog loaded via `load()` / `loadAndActivate()`\n * 3. `descriptor.message` or `options.message` (original source string)\n * 4. The raw `id` as fallback\n */\n _(descriptor: MessageDescriptor): string;\n _(id: MessageId, values?: Values, options?: MessageOptions): string;\n _(\n descriptorOrId: MessageDescriptor | MessageId,\n values?: Values,\n options?: MessageOptions\n ): string {\n const isDescriptor =\n typeof descriptorOrId === 'object' && descriptorOrId !== null;\n const id = isDescriptor\n ? (descriptorOrId as MessageDescriptor).id\n : (descriptorOrId as MessageId);\n const defaultMessage = isDescriptor\n ? ((descriptorOrId as MessageDescriptor).message ?? options?.message)\n : options?.message;\n const resolvedValues: Values = isDescriptor\n ? {\n ...((descriptorOrId as MessageDescriptor).values ?? {}),\n ...(values ?? {}),\n }\n : (values ?? {});\n\n const rawValue = this.resolveTemplate(id);\n const template = rawValue ?? defaultMessage ?? id;\n\n return (\n resolveMessage(\n template,\n resolvedValues as Record<string, string | number>,\n this._locale as LocalesValues,\n 'icu'\n ) ?? id\n );\n }\n\n /**\n * Alias for `_`. Provided for lingui API compatibility.\n */\n t = (\n descriptorOrId: MessageDescriptor | MessageId,\n values?: Values,\n options?: MessageOptions\n ): string => this._(descriptorOrId as MessageId, values, options);\n\n /**\n * @deprecated Use `Intl.DateTimeFormat` directly.\n */\n date(\n value?: string | Date | number,\n format?: Intl.DateTimeFormatOptions\n ): string {\n if (value === undefined || value === null) return '';\n const dateValue =\n value instanceof Date\n ? value\n : new Date(typeof value === 'string' ? value : value);\n return new Intl.DateTimeFormat(this._locale, format).format(dateValue);\n }\n\n /**\n * @deprecated Use `Intl.NumberFormat` directly.\n */\n number(value: number | bigint, format?: Intl.NumberFormatOptions): string {\n return new Intl.NumberFormat(this._locale, format).format(value);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAkDA,MAAM,0BAA4C;CAChD,IAAI;EACF,OAAO,OAAO,KAAK,gBAAgB,CAAC;CACtC,QAAQ;EACN,OAAO,CAAC;CACV;AACF;;;;;;;;;;;AAYA,MAAM,2BACJ,IACA,WACuB;CACvB,KAAK,MAAM,OAAO,kBAAkB,GAAG;EACrC,IAAI;EACJ,IAAI;GACF,aAAa,YAAY,KAAK,MAAM;EACtC,QAAQ;GACN;EACF;EACA,MAAM,QAAQ,sBAAsB,YAAY,EAAE;EAClD,IAAI,UAAU,QAAW,OAAO,mBAAmB,KAAK;CAC1D;AAEF;;;;;;;;;;AAWA,IAAa,YAAb,cAA+B,aAA2B;CACxD,AAAQ;CACR,AAAQ;;;;;;;;;CASR,AAAQ,YAAsC,CAAC;CAC/C,AAAQ,sBAAsB;CAE9B,YAAY,EAAE,SAAS,MAAM,SAAS,aAAwB,CAAC,GAAG;EAChE,MAAM;EACN,KAAK,UAAU,OAAO,WAAW,WAAW,SAAS;EACrD,KAAK,WAAW;EAChB,IAAI,UAAU,KAAK,iBAAiB,QAAQ;CAC9C;CAEA,IAAI,SAAiB;EACnB,OAAO,KAAK;CACd;CAEA,IAAI,UAA+B;EACjC,OAAO,KAAK;CACd;CAEA,IAAI,WAAqB;EAGvB,MAAM,aAAuB,CAAC;EAC9B,KAAK,MAAM,OAAO,kBAAkB,GAClC,IAAI;GACF,OAAO,OACL,YACA,oBAAoB,YAAY,KAAK,KAAK,OAAwB,CAAC,CACrE;EACF,QAAQ,CAER;EAGF,OAAO;GAAE,GAAI,KAAK,UAAU,KAAK,YAAY,CAAC;GAAI,GAAG;EAAW;CAClE;;CAGA,AAAQ,mBAAmB,QAAgB,SAAmB;EAC5D,KAAK,UAAU,UAAU;GAAE,GAAG,KAAK,UAAU;GAAS,GAAG;EAAQ;CACnE;;;;;CAMA,AAAQ,iBAAiB,UAAuB;EAC9C,KAAK,MAAM,CAAC,QAAQ,YAAY,OAAO,QAAQ,QAAQ,GACrD,IAAI,WAAW,OAAO,YAAY,UAChC,KAAK,mBAAmB,QAAQ,OAAmB;CAGzD;;;;CAKA,oBAAoB,WAAkC;EAElD,QAAQ,KACN,qHAEF;EAEF,OAAO;CACT;;;;;;;;;CAUA,KAAK,aAAmC,UAA2B;EACjE,IAAI,OAAO,gBAAgB,UACzB,KAAK,mBAAmB,aAAa,YAAY,CAAC,CAAC;OAEnD,KAAK,iBAAiB,WAAW;EAGnC,IAA8C,CAAC,KAAK,qBAAqB;GACvE,KAAK,sBAAsB;GAC3B,QAAQ,KACN,4LAGF;EACF;CACF;;;;;CAMA,gBAAgB,EACd,QACA,SACA,YAKO;EACP,IAAI,UAAU,KAAK,mBAAmB,QAAQ,QAAQ;EACtD,KAAK,SAAS,QAAQ,OAAO;CAC/B;;;;CAKA,SAAS,QAAgB,SAAyB;EAChD,KAAK,UAAU;EACf,KAAK,WAAW;EAChB,KAAK,KAAK,QAAQ;CACpB;;;;;;;;CASA,AAAQ,gBAAgB,IAAgC;EACtD,MAAM,iBAAiB,wBACrB,IACA,KAAK,OACP;EACA,IAAI,mBAAmB,QAAW,OAAO;EAEzC,MAAM,UAAU,KAAK,UAAU,KAAK;EACpC,IAAI,SAAS;GACX,MAAM,MAAM,sBAAsB,SAAS,EAAE;GAC7C,IAAI,QAAQ,QAAW,OAAO,mBAAmB,GAAG;EACtD;CAGF;CAaA,EACE,gBACA,QACA,SACQ;EACR,MAAM,eACJ,OAAO,mBAAmB,YAAY,mBAAmB;EAC3D,MAAM,KAAK,eACN,eAAqC,KACrC;EACL,MAAM,iBAAiB,eACjB,eAAqC,WAAW,SAAS,UAC3D,SAAS;EACb,MAAM,iBAAyB,eAC3B;GACE,GAAK,eAAqC,UAAU,CAAC;GACrD,GAAI,UAAU,CAAC;EACjB,IACC,UAAU,CAAC;EAKhB,OACE,eAJe,KAAK,gBAAgB,EACd,KAAK,kBAAkB,IAK3C,gBACA,KAAK,SACL,KACF,KAAK;CAET;;;;CAKA,KACE,gBACA,QACA,YACW,KAAK,EAAE,gBAA6B,QAAQ,OAAO;;;;CAKhE,KACE,OACA,QACQ;EACR,IAAI,UAAU,UAAa,UAAU,MAAM,OAAO;EAClD,MAAM,YACJ,iBAAiB,OACb,QACA,IAAI,KAAK,OAAO,UAAU,WAAW,QAAQ,KAAK;EACxD,OAAO,IAAI,KAAK,eAAe,KAAK,SAAS,MAAM,CAAC,CAAC,OAAO,SAAS;CACvE;;;;CAKA,OAAO,OAAwB,QAA2C;EACxE,OAAO,IAAI,KAAK,aAAa,KAAK,SAAS,MAAM,CAAC,CAAC,OAAO,KAAK;CACjE;AACF"}
@@ -34,6 +34,38 @@ const navigateCatalog = (catalog, id) => {
34
34
  return current;
35
35
  };
36
36
  /**
37
+ * Returns the flat id→message map of a catalog, transparently unwrapping the
38
+ * lingui `{ messages: {…} }` wrapper when present.
39
+ *
40
+ * Compiled lingui catalogs (`.po`/`.mjs`/`.json`) nest the id→message map under
41
+ * a top-level `messages` key, and syncJSON-backed intlayer dictionaries
42
+ * preserve that wrapper (`{ messages: { 'hero.title': […] } }`). Centralized
43
+ * intlayer dictionaries instead store the map at the top level
44
+ * (`{ 'hero.title': '…' }`). Both shapes are supported.
45
+ */
46
+ const unwrapLinguiCatalog = (catalog) => {
47
+ if (!catalog || typeof catalog !== "object") return {};
48
+ const wrapped = catalog.messages;
49
+ if (wrapped && typeof wrapped === "object") return wrapped;
50
+ return catalog;
51
+ };
52
+ /**
53
+ * Reads a value from a catalog by id, accepting both the flat/nested shapes
54
+ * handled by {@link navigateCatalog} and the lingui `{ messages: {…} }` wrapper.
55
+ *
56
+ * The direct lookup is tried first so a centralized dictionary that genuinely
57
+ * stores content at the top level keeps working; only on a miss does it look
58
+ * inside the `messages` wrapper used by namespaced lingui catalogs.
59
+ */
60
+ const navigateLinguiCatalog = (catalog, id) => {
61
+ const direct = navigateCatalog(catalog, id);
62
+ if (direct !== void 0) return direct;
63
+ if (catalog && typeof catalog === "object") {
64
+ const wrapped = catalog.messages;
65
+ if (wrapped && typeof wrapped === "object") return navigateCatalog(wrapped, id);
66
+ }
67
+ };
68
+ /**
37
69
  * Converts a single compiled lingui token to its ICU MessageFormat equivalent.
38
70
  *
39
71
  * Token shapes (from `@lingui/message-utils`):
@@ -83,5 +115,5 @@ const linguiMessageToIcu = (compiled) => {
83
115
  };
84
116
 
85
117
  //#endregion
86
- export { linguiMessageToIcu, navigateCatalog };
118
+ export { linguiMessageToIcu, navigateCatalog, navigateLinguiCatalog, unwrapLinguiCatalog };
87
119
  //# sourceMappingURL=linguiCatalog.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"linguiCatalog.mjs","names":[],"sources":["../../src/linguiCatalog.ts"],"sourcesContent":["/**\n * Helpers for reading lingui message catalogs.\n *\n * lingui catalogs are flat maps whose keys are dotted strings\n * (`'results-table.bundleSize'`) rather than nested objects, and whose\n * compiled (`.mjs`) values are token arrays rather than plain strings. These\n * helpers bridge that format onto intlayer's ICU-based `resolveMessage`.\n */\n\n/**\n * Reads a value from a catalog by id.\n *\n * lingui ids are flat keys that themselves contain dots\n * (`'results-table.bundleSize'`), so the flat key is tried first. When that\n * misses, the id is treated as a nested path (`'home.title'` →\n * `catalog.home.title`) to also support genuinely nested intlayer\n * dictionaries.\n *\n * @example\n * navigateCatalog({ 'a.b': 'X' }, 'a.b'); // 'X' (flat key)\n * navigateCatalog({ a: { b: 'X' } }, 'a.b'); // 'X' (nested path)\n */\nexport const navigateCatalog = (catalog: unknown, id: string): unknown => {\n if (!id) return catalog;\n if (catalog === null || typeof catalog !== 'object') return undefined;\n\n const flatValue = (catalog as Record<string, unknown>)[id];\n if (flatValue !== undefined) return flatValue;\n\n if (!id.includes('.')) return undefined;\n\n let current: unknown = catalog;\n for (const part of id.split('.')) {\n if (\n current === null ||\n current === undefined ||\n typeof current !== 'object'\n ) {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n return current;\n};\n\n/**\n * Converts a single compiled lingui token to its ICU MessageFormat equivalent.\n *\n * Token shapes (from `@lingui/message-utils`):\n * - `string` → literal text\n * - `[name]` → `{name}`\n * - `[name, 'number' | 'date' | 'time', format?]` → `{name, number, format}`\n * - `[name, 'plural' | 'select' | 'selectordinal', options]` → ICU block,\n * where each option value is itself a compiled sub-message.\n */\nconst tokenToIcu = (token: unknown): string => {\n if (typeof token === 'string') return token;\n if (!Array.isArray(token)) return '';\n\n const [name, type, format] = token as [string, string?, unknown?];\n\n if (type === undefined) return `{${String(name)}}`;\n\n if (type === 'plural' || type === 'select' || type === 'selectordinal') {\n const options = (format ?? {}) as Record<string, unknown>;\n const segments: string[] = [];\n let offsetSegment = '';\n\n for (const [category, value] of Object.entries(options)) {\n if (category === 'offset') {\n offsetSegment = `offset:${String(value)} `;\n continue;\n }\n segments.push(`${category} {${linguiMessageToIcu(value)}}`);\n }\n\n return `{${String(name)}, ${type}, ${offsetSegment}${segments.join(' ')}}`;\n }\n\n return format !== undefined\n ? `{${String(name)}, ${type}, ${String(format)}}`\n : `{${String(name)}, ${type}}`;\n};\n\n/**\n * Converts a compiled lingui message into an ICU MessageFormat string that\n * `@intlayer/core`'s `resolveMessage(…, 'icu')` can interpolate.\n *\n * Plain strings (uncompiled `.json` catalogs) pass through unchanged; token\n * arrays (compiled `.mjs` catalogs) are flattened, including nested\n * plural/select blocks and `{name}` placeholders.\n *\n * @example\n * linguiMessageToIcu(['Bundle Size']); // 'Bundle Size'\n * linguiMessageToIcu(['Hello ', ['name']]); // 'Hello {name}'\n * linguiMessageToIcu('Already ICU {count}'); // 'Already ICU {count}'\n */\nexport const linguiMessageToIcu = (compiled: unknown): string => {\n if (typeof compiled === 'string') return compiled;\n if (!Array.isArray(compiled)) return String(compiled ?? '');\n return compiled.map(tokenToIcu).join('');\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAsBA,MAAa,mBAAmB,SAAkB,OAAwB;CACxE,IAAI,CAAC,IAAI,OAAO;CAChB,IAAI,YAAY,QAAQ,OAAO,YAAY,UAAU,OAAO;CAE5D,MAAM,YAAa,QAAoC;CACvD,IAAI,cAAc,QAAW,OAAO;CAEpC,IAAI,CAAC,GAAG,SAAS,GAAG,GAAG,OAAO;CAE9B,IAAI,UAAmB;CACvB,KAAK,MAAM,QAAQ,GAAG,MAAM,GAAG,GAAG;EAChC,IACE,YAAY,QACZ,YAAY,UACZ,OAAO,YAAY,UAEnB;EAEF,UAAW,QAAoC;CACjD;CACA,OAAO;AACT;;;;;;;;;;;AAYA,MAAM,cAAc,UAA2B;CAC7C,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO;CAElC,MAAM,CAAC,MAAM,MAAM,UAAU;CAE7B,IAAI,SAAS,QAAW,OAAO,IAAI,OAAO,IAAI,EAAE;CAEhD,IAAI,SAAS,YAAY,SAAS,YAAY,SAAS,iBAAiB;EACtE,MAAM,UAAW,UAAU,CAAC;EAC5B,MAAM,WAAqB,CAAC;EAC5B,IAAI,gBAAgB;EAEpB,KAAK,MAAM,CAAC,UAAU,UAAU,OAAO,QAAQ,OAAO,GAAG;GACvD,IAAI,aAAa,UAAU;IACzB,gBAAgB,UAAU,OAAO,KAAK,EAAE;IACxC;GACF;GACA,SAAS,KAAK,GAAG,SAAS,IAAI,mBAAmB,KAAK,EAAE,EAAE;EAC5D;EAEA,OAAO,IAAI,OAAO,IAAI,EAAE,IAAI,KAAK,IAAI,gBAAgB,SAAS,KAAK,GAAG,EAAE;CAC1E;CAEA,OAAO,WAAW,SACd,IAAI,OAAO,IAAI,EAAE,IAAI,KAAK,IAAI,OAAO,MAAM,EAAE,KAC7C,IAAI,OAAO,IAAI,EAAE,IAAI,KAAK;AAChC;;;;;;;;;;;;;;AAeA,MAAa,sBAAsB,aAA8B;CAC/D,IAAI,OAAO,aAAa,UAAU,OAAO;CACzC,IAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG,OAAO,OAAO,YAAY,EAAE;CAC1D,OAAO,SAAS,IAAI,UAAU,CAAC,CAAC,KAAK,EAAE;AACzC"}
1
+ {"version":3,"file":"linguiCatalog.mjs","names":[],"sources":["../../src/linguiCatalog.ts"],"sourcesContent":["/**\n * Helpers for reading lingui message catalogs.\n *\n * lingui catalogs are flat maps whose keys are dotted strings\n * (`'results-table.bundleSize'`) rather than nested objects, and whose\n * compiled (`.mjs`) values are token arrays rather than plain strings. These\n * helpers bridge that format onto intlayer's ICU-based `resolveMessage`.\n */\n\n/**\n * Reads a value from a catalog by id.\n *\n * lingui ids are flat keys that themselves contain dots\n * (`'results-table.bundleSize'`), so the flat key is tried first. When that\n * misses, the id is treated as a nested path (`'home.title'` →\n * `catalog.home.title`) to also support genuinely nested intlayer\n * dictionaries.\n *\n * @example\n * navigateCatalog({ 'a.b': 'X' }, 'a.b'); // 'X' (flat key)\n * navigateCatalog({ a: { b: 'X' } }, 'a.b'); // 'X' (nested path)\n */\nexport const navigateCatalog = (catalog: unknown, id: string): unknown => {\n if (!id) return catalog;\n if (catalog === null || typeof catalog !== 'object') return undefined;\n\n const flatValue = (catalog as Record<string, unknown>)[id];\n if (flatValue !== undefined) return flatValue;\n\n if (!id.includes('.')) return undefined;\n\n let current: unknown = catalog;\n for (const part of id.split('.')) {\n if (\n current === null ||\n current === undefined ||\n typeof current !== 'object'\n ) {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n return current;\n};\n\n/**\n * Returns the flat id→message map of a catalog, transparently unwrapping the\n * lingui `{ messages: {…} }` wrapper when present.\n *\n * Compiled lingui catalogs (`.po`/`.mjs`/`.json`) nest the id→message map under\n * a top-level `messages` key, and syncJSON-backed intlayer dictionaries\n * preserve that wrapper (`{ messages: { 'hero.title': […] } }`). Centralized\n * intlayer dictionaries instead store the map at the top level\n * (`{ 'hero.title': '…' }`). Both shapes are supported.\n */\nexport const unwrapLinguiCatalog = (\n catalog: unknown\n): Record<string, unknown> => {\n if (!catalog || typeof catalog !== 'object') return {};\n const wrapped = (catalog as Record<string, unknown>).messages;\n if (wrapped && typeof wrapped === 'object') {\n return wrapped as Record<string, unknown>;\n }\n return catalog as Record<string, unknown>;\n};\n\n/**\n * Reads a value from a catalog by id, accepting both the flat/nested shapes\n * handled by {@link navigateCatalog} and the lingui `{ messages: {…} }` wrapper.\n *\n * The direct lookup is tried first so a centralized dictionary that genuinely\n * stores content at the top level keeps working; only on a miss does it look\n * inside the `messages` wrapper used by namespaced lingui catalogs.\n */\nexport const navigateLinguiCatalog = (\n catalog: unknown,\n id: string\n): unknown => {\n const direct = navigateCatalog(catalog, id);\n if (direct !== undefined) return direct;\n\n if (catalog && typeof catalog === 'object') {\n const wrapped = (catalog as Record<string, unknown>).messages;\n if (wrapped && typeof wrapped === 'object') {\n return navigateCatalog(wrapped, id);\n }\n }\n\n return undefined;\n};\n\n/**\n * Converts a single compiled lingui token to its ICU MessageFormat equivalent.\n *\n * Token shapes (from `@lingui/message-utils`):\n * - `string` → literal text\n * - `[name]` → `{name}`\n * - `[name, 'number' | 'date' | 'time', format?]` → `{name, number, format}`\n * - `[name, 'plural' | 'select' | 'selectordinal', options]` → ICU block,\n * where each option value is itself a compiled sub-message.\n */\nconst tokenToIcu = (token: unknown): string => {\n if (typeof token === 'string') return token;\n if (!Array.isArray(token)) return '';\n\n const [name, type, format] = token as [string, string?, unknown?];\n\n if (type === undefined) return `{${String(name)}}`;\n\n if (type === 'plural' || type === 'select' || type === 'selectordinal') {\n const options = (format ?? {}) as Record<string, unknown>;\n const segments: string[] = [];\n let offsetSegment = '';\n\n for (const [category, value] of Object.entries(options)) {\n if (category === 'offset') {\n offsetSegment = `offset:${String(value)} `;\n continue;\n }\n segments.push(`${category} {${linguiMessageToIcu(value)}}`);\n }\n\n return `{${String(name)}, ${type}, ${offsetSegment}${segments.join(' ')}}`;\n }\n\n return format !== undefined\n ? `{${String(name)}, ${type}, ${String(format)}}`\n : `{${String(name)}, ${type}}`;\n};\n\n/**\n * Converts a compiled lingui message into an ICU MessageFormat string that\n * `@intlayer/core`'s `resolveMessage(…, 'icu')` can interpolate.\n *\n * Plain strings (uncompiled `.json` catalogs) pass through unchanged; token\n * arrays (compiled `.mjs` catalogs) are flattened, including nested\n * plural/select blocks and `{name}` placeholders.\n *\n * @example\n * linguiMessageToIcu(['Bundle Size']); // 'Bundle Size'\n * linguiMessageToIcu(['Hello ', ['name']]); // 'Hello {name}'\n * linguiMessageToIcu('Already ICU {count}'); // 'Already ICU {count}'\n */\nexport const linguiMessageToIcu = (compiled: unknown): string => {\n if (typeof compiled === 'string') return compiled;\n if (!Array.isArray(compiled)) return String(compiled ?? '');\n return compiled.map(tokenToIcu).join('');\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAsBA,MAAa,mBAAmB,SAAkB,OAAwB;CACxE,IAAI,CAAC,IAAI,OAAO;CAChB,IAAI,YAAY,QAAQ,OAAO,YAAY,UAAU,OAAO;CAE5D,MAAM,YAAa,QAAoC;CACvD,IAAI,cAAc,QAAW,OAAO;CAEpC,IAAI,CAAC,GAAG,SAAS,GAAG,GAAG,OAAO;CAE9B,IAAI,UAAmB;CACvB,KAAK,MAAM,QAAQ,GAAG,MAAM,GAAG,GAAG;EAChC,IACE,YAAY,QACZ,YAAY,UACZ,OAAO,YAAY,UAEnB;EAEF,UAAW,QAAoC;CACjD;CACA,OAAO;AACT;;;;;;;;;;;AAYA,MAAa,uBACX,YAC4B;CAC5B,IAAI,CAAC,WAAW,OAAO,YAAY,UAAU,OAAO,CAAC;CACrD,MAAM,UAAW,QAAoC;CACrD,IAAI,WAAW,OAAO,YAAY,UAChC,OAAO;CAET,OAAO;AACT;;;;;;;;;AAUA,MAAa,yBACX,SACA,OACY;CACZ,MAAM,SAAS,gBAAgB,SAAS,EAAE;CAC1C,IAAI,WAAW,QAAW,OAAO;CAEjC,IAAI,WAAW,OAAO,YAAY,UAAU;EAC1C,MAAM,UAAW,QAAoC;EACrD,IAAI,WAAW,OAAO,YAAY,UAChC,OAAO,gBAAgB,SAAS,EAAE;CAEtC;AAGF;;;;;;;;;;;AAYA,MAAM,cAAc,UAA2B;CAC7C,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO;CAElC,MAAM,CAAC,MAAM,MAAM,UAAU;CAE7B,IAAI,SAAS,QAAW,OAAO,IAAI,OAAO,IAAI,EAAE;CAEhD,IAAI,SAAS,YAAY,SAAS,YAAY,SAAS,iBAAiB;EACtE,MAAM,UAAW,UAAU,CAAC;EAC5B,MAAM,WAAqB,CAAC;EAC5B,IAAI,gBAAgB;EAEpB,KAAK,MAAM,CAAC,UAAU,UAAU,OAAO,QAAQ,OAAO,GAAG;GACvD,IAAI,aAAa,UAAU;IACzB,gBAAgB,UAAU,OAAO,KAAK,EAAE;IACxC;GACF;GACA,SAAS,KAAK,GAAG,SAAS,IAAI,mBAAmB,KAAK,EAAE,EAAE;EAC5D;EAEA,OAAO,IAAI,OAAO,IAAI,EAAE,IAAI,KAAK,IAAI,gBAAgB,SAAS,KAAK,GAAG,EAAE;CAC1E;CAEA,OAAO,WAAW,SACd,IAAI,OAAO,IAAI,EAAE,IAAI,KAAK,IAAI,OAAO,MAAM,EAAE,KAC7C,IAAI,OAAO,IAAI,EAAE,IAAI,KAAK;AAChC;;;;;;;;;;;;;;AAeA,MAAa,sBAAsB,aAA8B;CAC/D,IAAI,OAAO,aAAa,UAAU,OAAO;CACzC,IAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG,OAAO,OAAO,YAAY,EAAE;CAC1D,OAAO,SAAS,IAAI,UAAU,CAAC,CAAC,KAAK,EAAE;AACzC"}
@@ -1,6 +1,93 @@
1
- import "node:path";
2
- import "@intlayer/chokidar/utils";
3
- import "@intlayer/config/colors";
4
- import "@intlayer/config/logger";
5
- import "@intlayer/config/node";
6
- import "vite-intlayer";
1
+ import { join } from "node:path";
2
+ import { runOnce } from "@intlayer/chokidar/utils";
3
+ import * as ANSIColors from "@intlayer/config/colors";
4
+ import { colorize, getAppLogger } from "@intlayer/config/logger";
5
+ import { getConfiguration } from "@intlayer/config/node";
6
+ import { intlayer } from "vite-intlayer";
7
+
8
+ //#region src/plugin/index.ts
9
+ /**
10
+ * Caller configurations for lingui.
11
+ *
12
+ * After `@lingui/babel-plugin-lingui-macro` / `@lingui/swc-plugin` compiles
13
+ * macros (`` t`Hello ${name}` `` → `i18n._(id, values)`) the intlayer field
14
+ * usage analyser sees these method calls and records which top-level fields of
15
+ * the `messages` dictionary are consumed, enabling accurate pruning.
16
+ *
17
+ * Two call forms are tracked:
18
+ * - `i18n._('home.title', values)` — string id
19
+ * - `i18n._({ id: 'home.title', message: '...' }, values)` — descriptor
20
+ * - `i18n.t('home.title', values)` — alias for `_`
21
+ *
22
+ * Because lingui projects may also use hashed IDs (generated from the default
23
+ * message string) that cannot be statically mapped to dictionary keys, a
24
+ * separate `'all'`-mode caller is not needed here: when the first argument is
25
+ * not a static string or descriptor, the `'self'` handler falls back to `'all'`
26
+ * automatically.
27
+ */
28
+ const LINGUI_COMPAT_CALLERS = [{
29
+ callerName: "_",
30
+ importSources: ["@lingui/core", "@intlayer/lingui"],
31
+ matchAsMethod: true,
32
+ namespace: {
33
+ from: "fixed",
34
+ value: "messages"
35
+ },
36
+ translationFunction: "self",
37
+ flatKey: true
38
+ }, {
39
+ callerName: "t",
40
+ importSources: ["@lingui/core", "@intlayer/lingui"],
41
+ matchAsMethod: true,
42
+ namespace: {
43
+ from: "fixed",
44
+ value: "messages"
45
+ },
46
+ translationFunction: "self",
47
+ flatKey: true
48
+ }];
49
+ /**
50
+ * A Vite plugin for the lingui compat adapter.
51
+ *
52
+ * Wraps `vite-intlayer` and adds resolve aliases so that both
53
+ * `@lingui/core` **and** `@lingui/react` are redirected to
54
+ * `@intlayer/lingui` at bundle time.
55
+ *
56
+ * @example
57
+ * ```ts
58
+ * // vite.config.ts
59
+ * import { lingui } from '@intlayer/lingui/plugin';
60
+ *
61
+ * export default defineConfig({
62
+ * plugins: [lingui()],
63
+ * });
64
+ * ```
65
+ */
66
+ const lingui = (options) => {
67
+ const intlayerConfig = getConfiguration();
68
+ const appLogger = getAppLogger(intlayerConfig);
69
+ runOnce(join(intlayerConfig.system.baseDir, ".intlayer", "cache", "intlayer-issues-invitation.lock"), () => {
70
+ appLogger([colorize("Please report any issues you met on GitHub:", ANSIColors.GREY), colorize("https://github.com/aymericzip/intlayer/issues", ANSIColors.GREY_LIGHT)]);
71
+ }, { cacheTimeoutMs: 1e3 * 60 * 60 });
72
+ const basePlugins = intlayer({
73
+ ...options,
74
+ compatCallers: [...options?.compatCallers ?? [], ...LINGUI_COMPAT_CALLERS]
75
+ });
76
+ const compatPlugin = {
77
+ name: "vite-lingui-compat-plugin",
78
+ config: () => ({ resolve: { alias: {
79
+ "@lingui/core": "@intlayer/lingui",
80
+ "@lingui/react": "@intlayer/lingui"
81
+ } } })
82
+ };
83
+ return [...Array.isArray(basePlugins) ? basePlugins : [basePlugins], compatPlugin];
84
+ };
85
+ /**
86
+ * Backwards-compatible alias for {@link lingui}, matching the naming used by the
87
+ * other compat adapters' Vite plugins (e.g. `i18nextVitePlugin`).
88
+ */
89
+ const linguiVitePlugin = lingui;
90
+
91
+ //#endregion
92
+ export { lingui as default, lingui, linguiVitePlugin };
93
+ //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugin/index.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { runOnce } from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport { getConfiguration } from '@intlayer/config/node';\nimport type { PluginOption } from 'vite';\nimport { type CompatCallerConfig, intlayer } from 'vite-intlayer';\n\n/**\n * Caller configurations for lingui.\n *\n * After `@lingui/babel-plugin-lingui-macro` / `@lingui/swc-plugin` compiles\n * macros (`` t`Hello ${name}` `` → `i18n._(id, values)`) the intlayer field\n * usage analyser sees these method calls and records which top-level fields of\n * the `messages` dictionary are consumed, enabling accurate pruning.\n *\n * Two call forms are tracked:\n * - `i18n._('home.title', values)` — string id\n * - `i18n._({ id: 'home.title', message: '...' }, values)` — descriptor\n * - `i18n.t('home.title', values)` — alias for `_`\n *\n * Because lingui projects may also use hashed IDs (generated from the default\n * message string) that cannot be statically mapped to dictionary keys, a\n * separate `'all'`-mode caller is not needed here: when the first argument is\n * not a static string or descriptor, the `'self'` handler falls back to `'all'`\n * automatically.\n */\nconst LINGUI_COMPAT_CALLERS: CompatCallerConfig[] = [\n {\n callerName: '_',\n importSources: ['@lingui/core', '@intlayer/lingui'],\n matchAsMethod: true,\n namespace: { from: 'fixed', value: 'messages' },\n translationFunction: 'self',\n },\n {\n callerName: 't',\n importSources: ['@lingui/core', '@intlayer/lingui'],\n matchAsMethod: true,\n namespace: { from: 'fixed', value: 'messages' },\n translationFunction: 'self',\n },\n];\n\n/**\n * A Vite plugin for the lingui compat adapter.\n *\n * Wraps `vite-intlayer` and adds resolve aliases so that both\n * `@lingui/core` **and** `@lingui/react` are redirected to\n * `@intlayer/lingui` at bundle time.\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { lingui } from '@intlayer/lingui/plugin';\n *\n * export default defineConfig({\n * plugins: [lingui()],\n * });\n * ```\n */\nexport const linguiVitePlugin = (\n options?: Parameters<typeof intlayer>[0]\n): PluginOption[] => {\n const intlayerConfig = getConfiguration();\n const appLogger = getAppLogger(intlayerConfig);\n\n runOnce(\n join(\n intlayerConfig.system.baseDir,\n '.intlayer',\n 'cache',\n 'intlayer-issues-invitation.lock'\n ),\n () => {\n appLogger([\n colorize(\n 'Please report any issues you met on GitHub:',\n ANSIColors.GREY\n ),\n colorize(\n 'https://github.com/aymericzip/intlayer/issues',\n ANSIColors.GREY_LIGHT\n ),\n ]);\n },\n {\n cacheTimeoutMs: 1000 * 60 * 60, // 1 hour\n }\n );\n\n const basePlugins = intlayer({\n ...options,\n compatCallers: [\n ...(options?.compatCallers ?? []),\n ...LINGUI_COMPAT_CALLERS,\n ],\n });\n\n const compatPlugin: PluginOption = {\n name: 'vite-lingui-compat-plugin',\n config: () => ({\n resolve: {\n alias: {\n '@lingui/core': '@intlayer/lingui',\n '@lingui/react': '@intlayer/lingui',\n },\n },\n }),\n };\n\n return [\n ...(Array.isArray(basePlugins) ? basePlugins : [basePlugins]),\n compatPlugin,\n ];\n};\n\n/**\n * Drop-in replacement alias for `@lingui/vite-plugin`'s `lingui` export, so an\n * existing `import { lingui } from '@lingui/vite-plugin'` only needs its source\n * swapped to `@intlayer/lingui/plugin` the call site stays unchanged.\n */\nexport const lingui = linguiVitePlugin;\n\nexport default linguiVitePlugin;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,MAAM,wBAA8C,CAClD;CACE,YAAY;CACZ,eAAe,CAAC,gBAAgB,kBAAkB;CAClD,eAAe;CACf,WAAW;EAAE,MAAM;EAAS,OAAO;CAAW;CAC9C,qBAAqB;AACvB,GACA;CACE,YAAY;CACZ,eAAe,CAAC,gBAAgB,kBAAkB;CAClD,eAAe;CACf,WAAW;EAAE,MAAM;EAAS,OAAO;CAAW;CAC9C,qBAAqB;AACvB,CACF;;;;;;;;;;;;;;;;;;AAmBA,MAAa,oBACX,YACmB;CACnB,MAAM,iBAAiB,iBAAiB;CACxC,MAAM,YAAY,aAAa,cAAc;CAE7C,QACE,KACE,eAAe,OAAO,SACtB,aACA,SACA,iCACF,SACM;EACJ,UAAU,CACR,SACE,+CACA,WAAW,IACb,GACA,SACE,iDACA,WAAW,UACb,CACF,CAAC;CACH,GACA,EACE,gBAAgB,MAAO,KAAK,GAC9B,CACF;CAEA,MAAM,cAAc,SAAS;EAC3B,GAAG;EACH,eAAe,CACb,GAAI,SAAS,iBAAiB,CAAC,GAC/B,GAAG,qBACL;CACF,CAAC;CAED,MAAM,eAA6B;EACjC,MAAM;EACN,eAAe,EACb,SAAS,EACP,OAAO;GACL,gBAAgB;GAChB,iBAAiB;EACnB,EACF,EACF;CACF;CAEA,OAAO,CACL,GAAI,MAAM,QAAQ,WAAW,IAAI,cAAc,CAAC,WAAW,GAC3D,YACF;AACF;;;;;;AAOA,MAAa,SAAS"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugin/index.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { runOnce } from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport { getConfiguration } from '@intlayer/config/node';\nimport type { PluginOption } from 'vite';\nimport { type CompatCallerConfig, intlayer } from 'vite-intlayer';\n\n/**\n * Caller configurations for lingui.\n *\n * After `@lingui/babel-plugin-lingui-macro` / `@lingui/swc-plugin` compiles\n * macros (`` t`Hello ${name}` `` → `i18n._(id, values)`) the intlayer field\n * usage analyser sees these method calls and records which top-level fields of\n * the `messages` dictionary are consumed, enabling accurate pruning.\n *\n * Two call forms are tracked:\n * - `i18n._('home.title', values)` — string id\n * - `i18n._({ id: 'home.title', message: '...' }, values)` — descriptor\n * - `i18n.t('home.title', values)` — alias for `_`\n *\n * Because lingui projects may also use hashed IDs (generated from the default\n * message string) that cannot be statically mapped to dictionary keys, a\n * separate `'all'`-mode caller is not needed here: when the first argument is\n * not a static string or descriptor, the `'self'` handler falls back to `'all'`\n * automatically.\n */\nconst LINGUI_COMPAT_CALLERS: CompatCallerConfig[] = [\n {\n callerName: '_',\n importSources: ['@lingui/core', '@intlayer/lingui'],\n matchAsMethod: true,\n namespace: { from: 'fixed', value: 'messages' },\n translationFunction: 'self',\n // lingui catalogs are flat: `i18n._('results-table.bundleSize')` reads the\n // literal `'results-table.bundleSize'` key, so the whole id is the field.\n flatKey: true,\n },\n {\n callerName: 't',\n importSources: ['@lingui/core', '@intlayer/lingui'],\n matchAsMethod: true,\n namespace: { from: 'fixed', value: 'messages' },\n translationFunction: 'self',\n flatKey: true,\n },\n];\n\n/**\n * A Vite plugin for the lingui compat adapter.\n *\n * Wraps `vite-intlayer` and adds resolve aliases so that both\n * `@lingui/core` **and** `@lingui/react` are redirected to\n * `@intlayer/lingui` at bundle time.\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { lingui } from '@intlayer/lingui/plugin';\n *\n * export default defineConfig({\n * plugins: [lingui()],\n * });\n * ```\n */\nexport const lingui = (\n options?: Parameters<typeof intlayer>[0]\n): PluginOption[] => {\n const intlayerConfig = getConfiguration();\n const appLogger = getAppLogger(intlayerConfig);\n\n runOnce(\n join(\n intlayerConfig.system.baseDir,\n '.intlayer',\n 'cache',\n 'intlayer-issues-invitation.lock'\n ),\n () => {\n appLogger([\n colorize(\n 'Please report any issues you met on GitHub:',\n ANSIColors.GREY\n ),\n colorize(\n 'https://github.com/aymericzip/intlayer/issues',\n ANSIColors.GREY_LIGHT\n ),\n ]);\n },\n {\n cacheTimeoutMs: 1000 * 60 * 60, // 1 hour\n }\n );\n\n const basePlugins = intlayer({\n ...options,\n compatCallers: [\n ...(options?.compatCallers ?? []),\n ...LINGUI_COMPAT_CALLERS,\n ],\n });\n\n const compatPlugin: PluginOption = {\n name: 'vite-lingui-compat-plugin',\n config: () => ({\n resolve: {\n alias: {\n '@lingui/core': '@intlayer/lingui',\n '@lingui/react': '@intlayer/lingui',\n },\n },\n }),\n };\n\n return [\n ...(Array.isArray(basePlugins) ? basePlugins : [basePlugins]),\n compatPlugin,\n ];\n};\n\n/**\n * Backwards-compatible alias for {@link lingui}, matching the naming used by the\n * other compat adapters' Vite plugins (e.g. `i18nextVitePlugin`).\n */\nexport const linguiVitePlugin = lingui;\n\nexport default lingui;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,MAAM,wBAA8C,CAClD;CACE,YAAY;CACZ,eAAe,CAAC,gBAAgB,kBAAkB;CAClD,eAAe;CACf,WAAW;EAAE,MAAM;EAAS,OAAO;CAAW;CAC9C,qBAAqB;CAGrB,SAAS;AACX,GACA;CACE,YAAY;CACZ,eAAe,CAAC,gBAAgB,kBAAkB;CAClD,eAAe;CACf,WAAW;EAAE,MAAM;EAAS,OAAO;CAAW;CAC9C,qBAAqB;CACrB,SAAS;AACX,CACF;;;;;;;;;;;;;;;;;;AAmBA,MAAa,UACX,YACmB;CACnB,MAAM,iBAAiB,iBAAiB;CACxC,MAAM,YAAY,aAAa,cAAc;CAE7C,QACE,KACE,eAAe,OAAO,SACtB,aACA,SACA,iCACF,SACM;EACJ,UAAU,CACR,SACE,+CACA,WAAW,IACb,GACA,SACE,iDACA,WAAW,UACb,CACF,CAAC;CACH,GACA,EACE,gBAAgB,MAAO,KAAK,GAC9B,CACF;CAEA,MAAM,cAAc,SAAS;EAC3B,GAAG;EACH,eAAe,CACb,GAAI,SAAS,iBAAiB,CAAC,GAC/B,GAAG,qBACL;CACF,CAAC;CAED,MAAM,eAA6B;EACjC,MAAM;EACN,eAAe,EACb,SAAS,EACP,OAAO;GACL,gBAAgB;GAChB,iBAAiB;EACnB,EACF,EACF;CACF;CAEA,OAAO,CACL,GAAI,MAAM,QAAQ,WAAW,IAAI,cAAc,CAAC,WAAW,GAC3D,YACF;AACF;;;;;AAMA,MAAa,mBAAmB"}
@@ -1 +1 @@
1
- {"version":3,"file":"I18nClass.d.ts","names":[],"sources":["../../src/I18nClass.ts"],"mappings":";;;;;KAmBK,MAAA,GAAS,MAAM;AAJ0B;AAAA,KAOzC,eAAA,IAAmB,OAAe;;KAGlC,YAAA;EACH,MAAA;EACA,OAAA,GAAU,KAAA;IAAS,MAAA,EAAQ,MAAA;IAAQ,EAAA,EAAI,SAAS;EAAA;AAAA;AALX;AAAA,KASlC,SAAA;EACH,MAAA,GAAS,MAAA;EACT,OAAA,GAAU,OAAA;EACV,QAAA,GAAW,WAAA;EACX,OAAA,cAAqB,MAAA,UAAgB,EAAA;AAAA;;;;;;AARa;AAAA;;;cAwCvC,SAAA,SAAkB,YAAA,CAAa,YAAA;EAAA,QAClC,OAAA;EAAA,QACA,QAAA;EAnCc;;;;;;;;EAAA,QA4Cd,SAAA;EAAA,QACA,mBAAA;;IAEM,MAAA;IAAe,OAAA;IAAS;EAAA,IAAY,SAAA;EAAA,IAO9C,MAAA;EAAA,IAIA,OAAA,IAAW,OAAA;EAAA,IAIX,QAAA,IAAY,QAAA;EA7BK;EAAA,QA4Cb,kBAAA;EA5CkC;;;;EAAA,QAoDlC,gBAAA;EA3BO;;;EAsCf,mBAAA,CAAoB,SAAA,EAAW,eAAA;EAkBJ;;;;;;;;EAA3B,IAAA,CAAK,WAAA,EAAa,MAAA,GAAS,WAAA,EAAa,QAAA,GAAW,QAAA;EAqChB;;;;EAhBnC,eAAA;IACE,MAAA;IACA,OAAA;IACA;EAAA;IAEA,MAAA,EAAQ,MAAA;IACR,OAAA,GAAU,OAAA;IACV,QAAA,GAAW,QAAA;EAAA;EA+FM;;;EAtFnB,QAAA,CAAS,MAAA,EAAQ,MAAA,EAAQ,OAAA,GAAU,OAAA;EAtHM;;;;;;;EAAA,QAmIjC,eAAA;;;;;;;;;;EAyBR,CAAA,CAAE,UAAA,EAAY,iBAAA;EACd,CAAA,CAAE,EAAA,EAAI,SAAA,EAAW,MAAA,GAAS,MAAA,EAAQ,OAAA,GAAU,cAAA;EAhIxC;;;EAqKJ,CAAA,GACE,cAAA,EAAgB,iBAAA,GAAoB,SAAA,EACpC,MAAA,GAAS,MAAA,EACT,OAAA,GAAU,cAAA;EAtIZ;;;EA4IA,IAAA,CACE,KAAA,YAAiB,IAAA,WACjB,MAAA,GAAS,IAAA,CAAK,qBAAA;EA5HE;;;EAyIlB,MAAA,CAAO,KAAA,mBAAwB,MAAA,GAAS,IAAA,CAAK,mBAAA;AAAA"}
1
+ {"version":3,"file":"I18nClass.d.ts","names":[],"sources":["../../src/I18nClass.ts"],"mappings":";;;;;KAwBK,MAAA,GAAS,MAAM;AAR0B;AAAA,KAWzC,eAAA,IAAmB,OAAe;;KAGlC,YAAA;EACH,MAAA;EACA,OAAA,GAAU,KAAA;IAAS,MAAA,EAAQ,MAAA;IAAQ,EAAA,EAAI,SAAS;EAAA;AAAA;AALX;AAAA,KASlC,SAAA;EACH,MAAA,GAAS,MAAA;EACT,OAAA,GAAU,OAAA;EACV,QAAA,GAAW,WAAA;EACX,OAAA,cAAqB,MAAA,UAAgB,EAAA;AAAA;;;;;;AARa;AAAA;;;cA8DvC,SAAA,SAAkB,YAAA,CAAa,YAAA;EAAA,QAClC,OAAA;EAAA,QACA,QAAA;EAzDc;;;;;;;;EAAA,QAkEd,SAAA;EAAA,QACA,mBAAA;;IAEM,MAAA;IAAe,OAAA;IAAS;EAAA,IAAY,SAAA;EAAA,IAO9C,MAAA;EAAA,IAIA,OAAA,IAAW,OAAA;EAAA,IAIX,QAAA,IAAY,QAAA;EA7BK;EAAA,QAgDb,kBAAA;EAhDkC;;;;EAAA,QAwDlC,gBAAA;EA/BO;;;EA0Cf,mBAAA,CAAoB,SAAA,EAAW,eAAA;EAkBJ;;;;;;;;EAA3B,IAAA,CAAK,WAAA,EAAa,MAAA,GAAS,WAAA,EAAa,QAAA,GAAW,QAAA;EAqChB;;;;EAhBnC,eAAA;IACE,MAAA;IACA,OAAA;IACA;EAAA;IAEA,MAAA,EAAQ,MAAA;IACR,OAAA,GAAU,OAAA;IACV,QAAA,GAAW,QAAA;EAAA;EA+FM;;;EAtFnB,QAAA,CAAS,MAAA,EAAQ,MAAA,EAAQ,OAAA,GAAU,OAAA;EA1HM;;;;;;;EAAA,QAuIjC,eAAA;;;;;;;;;;EAyBR,CAAA,CAAE,UAAA,EAAY,iBAAA;EACd,CAAA,CAAE,EAAA,EAAI,SAAA,EAAW,MAAA,GAAS,MAAA,EAAQ,OAAA,GAAU,cAAA;EApIxC;;;EAyKJ,CAAA,GACE,cAAA,EAAgB,iBAAA,GAAoB,SAAA,EACpC,MAAA,GAAS,MAAA,EACT,OAAA,GAAU,cAAA;EAtIZ;;;EA4IA,IAAA,CACE,KAAA,YAAiB,IAAA,WACjB,MAAA,GAAS,IAAA,CAAK,qBAAA;EA5HE;;;EAyIlB,MAAA,CAAO,KAAA,mBAAwB,MAAA,GAAS,IAAA,CAAK,mBAAA;AAAA"}
@@ -21,6 +21,26 @@
21
21
  * navigateCatalog({ a: { b: 'X' } }, 'a.b'); // 'X' (nested path)
22
22
  */
23
23
  declare const navigateCatalog: (catalog: unknown, id: string) => unknown;
24
+ /**
25
+ * Returns the flat id→message map of a catalog, transparently unwrapping the
26
+ * lingui `{ messages: {…} }` wrapper when present.
27
+ *
28
+ * Compiled lingui catalogs (`.po`/`.mjs`/`.json`) nest the id→message map under
29
+ * a top-level `messages` key, and syncJSON-backed intlayer dictionaries
30
+ * preserve that wrapper (`{ messages: { 'hero.title': […] } }`). Centralized
31
+ * intlayer dictionaries instead store the map at the top level
32
+ * (`{ 'hero.title': '…' }`). Both shapes are supported.
33
+ */
34
+ declare const unwrapLinguiCatalog: (catalog: unknown) => Record<string, unknown>;
35
+ /**
36
+ * Reads a value from a catalog by id, accepting both the flat/nested shapes
37
+ * handled by {@link navigateCatalog} and the lingui `{ messages: {…} }` wrapper.
38
+ *
39
+ * The direct lookup is tried first so a centralized dictionary that genuinely
40
+ * stores content at the top level keeps working; only on a miss does it look
41
+ * inside the `messages` wrapper used by namespaced lingui catalogs.
42
+ */
43
+ declare const navigateLinguiCatalog: (catalog: unknown, id: string) => unknown;
24
44
  /**
25
45
  * Converts a compiled lingui message into an ICU MessageFormat string that
26
46
  * `@intlayer/core`'s `resolveMessage(…, 'icu')` can interpolate.
@@ -36,5 +56,5 @@ declare const navigateCatalog: (catalog: unknown, id: string) => unknown;
36
56
  */
37
57
  declare const linguiMessageToIcu: (compiled: unknown) => string;
38
58
  //#endregion
39
- export { linguiMessageToIcu, navigateCatalog };
59
+ export { linguiMessageToIcu, navigateCatalog, navigateLinguiCatalog, unwrapLinguiCatalog };
40
60
  //# sourceMappingURL=linguiCatalog.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"linguiCatalog.d.ts","names":[],"sources":["../../src/linguiCatalog.ts"],"mappings":";;AAsBA;;;;AAA4D;AA2E5D;;;;AAAoD;;;;;;;;;;;cA3EvC,eAAA,GAAmB,OAAA,WAAkB,EAAU;;;;;;;;;;;;;;cA2E/C,kBAAA,GAAsB,QAAiB"}
1
+ {"version":3,"file":"linguiCatalog.d.ts","names":[],"sources":["../../src/linguiCatalog.ts"],"mappings":";;AAsBA;;;;AAA4D;AAiC5D;;;;AAES;AAiBT;;;;AAEY;AAmEZ;;;;AAAoD;cAzHvC,eAAA,GAAmB,OAAA,WAAkB,EAAU;;;;;;;;;;;cAiC/C,mBAAA,GACX,OAAA,cACC,MAAM;;;;;;;;;cAiBI,qBAAA,GACX,OAAA,WACA,EAAU;;;;;;;;;;;;;;cAmEC,kBAAA,GAAsB,QAAiB"}
@@ -1 +1,30 @@
1
- export { };
1
+ import { PluginOption } from "vite";
2
+ import { intlayer } from "vite-intlayer";
3
+
4
+ //#region src/plugin/index.d.ts
5
+ /**
6
+ * A Vite plugin for the lingui compat adapter.
7
+ *
8
+ * Wraps `vite-intlayer` and adds resolve aliases so that both
9
+ * `@lingui/core` **and** `@lingui/react` are redirected to
10
+ * `@intlayer/lingui` at bundle time.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * // vite.config.ts
15
+ * import { lingui } from '@intlayer/lingui/plugin';
16
+ *
17
+ * export default defineConfig({
18
+ * plugins: [lingui()],
19
+ * });
20
+ * ```
21
+ */
22
+ declare const lingui: (options?: Parameters<typeof intlayer>[0]) => PluginOption[];
23
+ /**
24
+ * Backwards-compatible alias for {@link lingui}, matching the naming used by the
25
+ * other compat adapters' Vite plugins (e.g. `i18nextVitePlugin`).
26
+ */
27
+ declare const linguiVitePlugin: (options?: Parameters<typeof intlayer>[0]) => PluginOption[];
28
+ //#endregion
29
+ export { lingui as default, lingui, linguiVitePlugin };
30
+ //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/plugin/index.ts"],"mappings":";;;;;;AA6DA;;;;;;;;;;;;;AAEe;AA2Df;cA7Da,gBAAA,GACX,OAAA,GAAU,UAAA,QAAkB,QAAA,SAC3B,YAAA;;;;;;cA2DU,MAAA,GAAM,OAAA,GA5DP,UAAA,QAAkB,QAAA,SAC3B,YAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/plugin/index.ts"],"mappings":";;;;;;AAiEA;;;;;;;;;;;;;AAEe;AA0Df;cA5Da,MAAA,GACX,OAAA,GAAU,UAAA,QAAkB,QAAA,SAC3B,YAAA;;;;;cA0DU,gBAAA,GAAgB,OAAA,GA3DjB,UAAA,QAAkB,QAAA,SAC3B,YAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intlayer/lingui",
3
- "version": "9.0.0-canary.7",
3
+ "version": "9.0.0-canary.9",
4
4
  "private": false,
5
5
  "description": "lingui API adapter for intlayer — drop-in compatibility layer",
6
6
  "keywords": [
@@ -74,13 +74,13 @@
74
74
  "typecheck": "tsc --noEmit --project tsconfig.types.json"
75
75
  },
76
76
  "dependencies": {
77
- "@intlayer/chokidar": "9.0.0-canary.7",
78
- "@intlayer/config": "9.0.0-canary.7",
79
- "@intlayer/core": "9.0.0-canary.7",
80
- "@intlayer/dictionaries-entry": "9.0.0-canary.7",
81
- "@intlayer/types": "9.0.0-canary.7",
82
- "react-intlayer": "9.0.0-canary.7",
83
- "vite-intlayer": "9.0.0-canary.7"
77
+ "@intlayer/chokidar": "9.0.0-canary.9",
78
+ "@intlayer/config": "9.0.0-canary.9",
79
+ "@intlayer/core": "9.0.0-canary.9",
80
+ "@intlayer/dictionaries-entry": "9.0.0-canary.9",
81
+ "@intlayer/types": "9.0.0-canary.9",
82
+ "react-intlayer": "9.0.0-canary.9",
83
+ "vite-intlayer": "9.0.0-canary.9"
84
84
  },
85
85
  "devDependencies": {
86
86
  "@lingui/core": "^6.3.0",