@intlayer/lingui 9.0.0-canary.7 → 9.0.0-canary.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/I18nClass.mjs +36 -16
- package/dist/esm/I18nClass.mjs.map +1 -1
- package/dist/esm/linguiCatalog.mjs +33 -1
- package/dist/esm/linguiCatalog.mjs.map +1 -1
- package/dist/esm/plugin/index.mjs +93 -6
- package/dist/esm/plugin/index.mjs.map +1 -1
- package/dist/types/I18nClass.d.ts.map +1 -1
- package/dist/types/linguiCatalog.d.ts +21 -1
- package/dist/types/linguiCatalog.d.ts.map +1 -1
- package/dist/types/plugin/index.d.ts +30 -1
- package/dist/types/plugin/index.d.ts.map +1 -1
- package/package.json +8 -8
package/dist/esm/I18nClass.mjs
CHANGED
|
@@ -1,22 +1,44 @@
|
|
|
1
1
|
import { EventEmitter } from "./eventEmitter.mjs";
|
|
2
|
-
import { linguiMessageToIcu,
|
|
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
|
-
*
|
|
9
|
+
* Keys of every intlayer dictionary available at runtime (the namespaces).
|
|
9
10
|
*
|
|
10
|
-
* The
|
|
11
|
-
*
|
|
12
|
-
*
|
|
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
|
|
15
|
+
const getDictionaryKeys = () => {
|
|
15
16
|
try {
|
|
16
|
-
|
|
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
|
-
|
|
58
|
-
try {
|
|
59
|
-
dictionary
|
|
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 =
|
|
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":"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"}
|
|
@@ -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
|
|
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":";;;;;
|
|
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;
|
|
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
|
-
|
|
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":";;;;;;
|
|
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.
|
|
3
|
+
"version": "9.0.0-canary.8",
|
|
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.
|
|
78
|
-
"@intlayer/config": "9.0.0-canary.
|
|
79
|
-
"@intlayer/core": "9.0.0-canary.
|
|
80
|
-
"@intlayer/dictionaries-entry": "9.0.0-canary.
|
|
81
|
-
"@intlayer/types": "9.0.0-canary.
|
|
82
|
-
"react-intlayer": "9.0.0-canary.
|
|
83
|
-
"vite-intlayer": "9.0.0-canary.
|
|
77
|
+
"@intlayer/chokidar": "9.0.0-canary.8",
|
|
78
|
+
"@intlayer/config": "9.0.0-canary.8",
|
|
79
|
+
"@intlayer/core": "9.0.0-canary.8",
|
|
80
|
+
"@intlayer/dictionaries-entry": "9.0.0-canary.8",
|
|
81
|
+
"@intlayer/types": "9.0.0-canary.8",
|
|
82
|
+
"react-intlayer": "9.0.0-canary.8",
|
|
83
|
+
"vite-intlayer": "9.0.0-canary.8"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
86
|
"@lingui/core": "^6.3.0",
|