@intlayer/i18next 9.0.0-canary.9 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,20 +1,11 @@
1
1
  import { getInterpolationValues, resolveTranslation } from "./resolveTranslation.mjs";
2
2
  import { internationalization, log } from "@intlayer/config/built";
3
+ import { getIntlayer } from "@intlayer/core/interpreter";
4
+ import { navigatePath, resolveMessage } from "@intlayer/core/messageFormat";
3
5
  import * as ANSIColors from "@intlayer/config/colors";
4
6
  import { colorize, getAppLogger } from "@intlayer/config/logger";
5
- import { getIntlayer } from "@intlayer/core/interpreter";
6
- import { resolveMessage } from "@intlayer/core/messageFormat";
7
7
 
8
8
  //#region src/createInstance.ts
9
- const navigatePath = (obj, path) => {
10
- if (!path) return obj;
11
- let current = obj;
12
- for (const part of path.split(".")) {
13
- if (current === null || current === void 0 || typeof current !== "object") return;
14
- current = current[part];
15
- }
16
- return current;
17
- };
18
9
  const warnIgnoredResources = (location) => {
19
10
  getAppLogger({ log })(`${colorize(location, ANSIColors.CYAN)}: the ${colorize("`resources`", ANSIColors.CYAN)} option is ignored when using ${colorize("@intlayer/i18next", ANSIColors.MAGENTA)} — translations are served from the compiled intlayer dictionaries instead. Remove the resource imports and the ${colorize("`resources`", ANSIColors.CYAN)} option to reduce your bundle size.`);
20
11
  };
@@ -127,21 +118,24 @@ const createInstance = (instanceOptions = {}) => {
127
118
  * Returns a `t()` function bound to a fixed locale and namespace.
128
119
  * When `ns` matches a registered intlayer dictionary key, the returned
129
120
  * function's `key` parameter is typed to only accept valid dot-notation
130
- * paths for that dictionary.
121
+ * paths for that dictionary, and its return type is resolved from the
122
+ * content at that path. With a `keyPrefix`, keys are relative dot-paths
123
+ * under the prefix.
131
124
  *
132
125
  * @example
133
126
  * ```ts
134
127
  * const tAbout = i18n.getFixedT(null, 'about');
135
- * tAbout('counter.label'); // ✓ typed
128
+ * tAbout('counter.label'); // ✓ typed key and return value
136
129
  * ```
137
130
  */
138
- getFixedT(lng, ns, keyPrefix) {
131
+ getFixedT: ((lng, ns, keyPrefix) => {
139
132
  const fixedLng = Array.isArray(lng) ? lng[0] ?? currentLanguage : lng ?? currentLanguage;
140
133
  const fixedNS = ns ?? defaultNS;
141
134
  return (key, opts) => {
142
- return resolveKey(fixedLng, fixedNS, keyPrefix ? `${keyPrefix}.${String(key)}` : String(key), opts);
135
+ const fullKey = keyPrefix ? `${keyPrefix}.${key}` : key;
136
+ return resolveKey(fixedLng, fixedNS, fullKey, opts);
143
137
  };
144
- },
138
+ }),
145
139
  use(module) {
146
140
  module?.init?.(instance);
147
141
  return instance;
@@ -1 +1 @@
1
- {"version":3,"file":"createInstance.mjs","names":[],"sources":["../../src/createInstance.ts"],"sourcesContent":["import { internationalization, log } from '@intlayer/config/built';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport { getIntlayer } from '@intlayer/core/interpreter';\nimport { resolveMessage } from '@intlayer/core/messageFormat';\nimport type { ValidDotPathsFor } from '@intlayer/core/transpiler';\nimport type {\n DictionaryKeys,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type {\n createInstance as _createInstance,\n i18n as I18nInterface,\n InitOptions,\n TOptions,\n} from 'i18next';\nimport {\n getInterpolationValues,\n resolveTranslation,\n} from './resolveTranslation';\n\ntype EventHandler = (...args: unknown[]) => void;\n\nconst navigatePath = (obj: unknown, path: string): unknown => {\n if (!path) return obj;\n let current: unknown = obj;\n for (const part of path.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\nconst warnIgnoredResources = (location: string) => {\n const appLogger = getAppLogger({ log });\n appLogger(\n `${colorize(location, ANSIColors.CYAN)}: the ${colorize('`resources`', ANSIColors.CYAN)} option is ignored when using ${colorize('@intlayer/i18next', ANSIColors.MAGENTA)} — translations are served from the compiled intlayer dictionaries instead. Remove the resource imports and the ${colorize('`resources`', ANSIColors.CYAN)} option to reduce your bundle size.`\n );\n};\n\nexport const createInstance: typeof _createInstance = (\n instanceOptions: InitOptions = {}\n): I18nInterface => {\n if ((instanceOptions as Record<string, unknown>).resources !== undefined) {\n warnIgnoredResources('createInstance');\n }\n\n const config = internationalization;\n\n let currentLanguage: string =\n (instanceOptions.lng as string) ?? config?.defaultLocale ?? 'en';\n\n let defaultNS: string =\n (instanceOptions.defaultNS as string) ??\n (Array.isArray(instanceOptions.ns)\n ? (instanceOptions.ns[0] as string)\n : (instanceOptions.ns as string)) ??\n 'translation';\n\n const listeners = new Map<string, Set<EventHandler>>();\n let initialized = false;\n\n const emit = (event: string, ...args: unknown[]) => {\n listeners.get(event)?.forEach((h) => {\n h(...args);\n });\n };\n\n const getSeparators = () => ({\n keySeparator:\n (instanceOptions.keySeparator as string | false | undefined) ?? '.',\n nsSeparator:\n (instanceOptions.nsSeparator as string | false | undefined) ?? ':',\n });\n\n /**\n * Resolves a key through the full i18next pipeline (namespace prefix,\n * `ns` option, plural/context suffixes, `$t()` nesting, interpolation).\n * Falls back to the interpolated `defaultValue`, then to the key itself.\n */\n const resolveKey = (\n lang: string,\n ns: string,\n key: string,\n opts?: TOptions | string\n ): string => {\n const options =\n typeof opts === 'string' ? { defaultValue: opts } : (opts as TOptions);\n\n const resolved = resolveTranslation({\n locale: lang as LocalesValues,\n namespace: ns,\n key,\n options,\n ...getSeparators(),\n });\n\n if (resolved !== undefined) return resolved as string;\n\n const defaultValue = (options as Record<string, unknown> | undefined)\n ?.defaultValue;\n if (typeof defaultValue === 'string') {\n return resolveMessage(\n defaultValue,\n getInterpolationValues(options),\n lang as LocalesValues,\n 'i18next'\n );\n }\n\n return key;\n };\n\n const instance = {\n get language() {\n return currentLanguage;\n },\n get languages() {\n return (config?.locales?.map(String) ?? [\n currentLanguage,\n ]) as readonly string[];\n },\n get resolvedLanguage() {\n return currentLanguage;\n },\n get isInitialized() {\n return initialized;\n },\n isInitializing: false,\n initializedStoreOnce: false,\n initializedLanguageOnce: false,\n options: instanceOptions,\n modules: {} as I18nInterface['modules'],\n services: {} as I18nInterface['services'],\n store: {} as I18nInterface['store'],\n format: ((value: unknown) => String(value)) as I18nInterface['format'],\n\n async init(optionsOrCb?: unknown, cb?: unknown) {\n const opts =\n typeof optionsOrCb === 'function'\n ? {}\n : ((optionsOrCb ?? {}) as Record<string, unknown>);\n if (opts.resources !== undefined) {\n warnIgnoredResources('i18next.init');\n }\n if (opts.lng) currentLanguage = opts.lng as string;\n if (opts.defaultNS) defaultNS = opts.defaultNS as string;\n else if (opts.ns)\n defaultNS = Array.isArray(opts.ns)\n ? (opts.ns[0] as string)\n : (opts.ns as string);\n initialized = true;\n emit('initialized', opts);\n const t = instance.t.bind(instance);\n const callback = typeof optionsOrCb === 'function' ? optionsOrCb : cb;\n (callback as ((err: unknown, t: unknown) => void) | undefined)?.(null, t);\n return t as unknown as Promise<I18nInterface['t']>;\n },\n\n t(\n key: unknown,\n optionsOrDefaultValue?: unknown,\n extraOpts?: unknown\n ): unknown {\n const options =\n typeof optionsOrDefaultValue === 'string'\n ? {\n defaultValue: optionsOrDefaultValue,\n ...((extraOpts ?? {}) as Record<string, unknown>),\n }\n : (optionsOrDefaultValue as TOptions | undefined);\n const keys: string[] = Array.isArray(key)\n ? (key as string[])\n : [String(key)];\n for (const candidateKey of keys) {\n const result = resolveTranslation({\n locale: currentLanguage as LocalesValues,\n namespace: defaultNS,\n key: candidateKey,\n options,\n ...getSeparators(),\n });\n if (result !== undefined) return result;\n }\n\n const defaultValue = (options as Record<string, unknown> | undefined)\n ?.defaultValue;\n if (typeof defaultValue === 'string') {\n return resolveMessage(\n defaultValue,\n getInterpolationValues(options),\n currentLanguage as LocalesValues,\n 'i18next'\n );\n }\n\n return defaultValue ?? (Array.isArray(key) ? key[key.length - 1] : key);\n },\n\n async changeLanguage(lng?: string, cb?: unknown) {\n const prev = currentLanguage;\n if (lng) currentLanguage = lng;\n emit('languageChanged', currentLanguage, prev);\n const t = instance.t.bind(instance);\n (cb as ((err: unknown, t: unknown) => void) | undefined)?.(null, t);\n return t as unknown as Promise<I18nInterface['t']>;\n },\n\n exists(key: string, options?: unknown): boolean {\n return (\n resolveTranslation({\n locale: currentLanguage as LocalesValues,\n namespace: defaultNS,\n key,\n options: options as TOptions,\n ...getSeparators(),\n }) !== undefined\n );\n },\n\n /**\n * Returns a `t()` function bound to a fixed locale and namespace.\n * When `ns` matches a registered intlayer dictionary key, the returned\n * function's `key` parameter is typed to only accept valid dot-notation\n * paths for that dictionary.\n *\n * @example\n * ```ts\n * const tAbout = i18n.getFixedT(null, 'about');\n * tAbout('counter.label'); // ✓ typed\n * ```\n */\n getFixedT<N extends DictionaryKeys>(\n lng: string | readonly string[] | null,\n ns?: N | null,\n keyPrefix?: string\n ): <P extends ValidDotPathsFor<N>>(key: P, opts?: TOptions) => string {\n const fixedLng = Array.isArray(lng)\n ? ((lng[0] as string) ?? currentLanguage)\n : ((lng as string) ?? currentLanguage);\n const fixedNS = (ns as string) ?? defaultNS;\n return <P extends ValidDotPathsFor<N>>(\n key: P,\n opts?: TOptions\n ): string => {\n const fullKey = keyPrefix ? `${keyPrefix}.${String(key)}` : String(key);\n return resolveKey(fixedLng, fixedNS, fullKey, opts);\n };\n },\n\n use(module: unknown) {\n (module as { init?: (i18n: I18nInterface) => void })?.init?.(\n instance as unknown as I18nInterface\n );\n return instance as unknown as I18nInterface;\n },\n\n on(event: string, handler: EventHandler) {\n if (!listeners.has(event)) listeners.set(event, new Set());\n listeners.get(event)!.add(handler);\n return instance as unknown as I18nInterface;\n },\n\n once(event: string, handler: EventHandler) {\n const wrapper: EventHandler = (...args) => {\n handler(...args);\n instance.off(event, wrapper);\n };\n instance.on(event, wrapper);\n return instance as unknown as I18nInterface;\n },\n\n off(event: string, handler?: EventHandler) {\n if (!handler) listeners.delete(event);\n else listeners.get(event)?.delete(handler);\n },\n\n emit(eventName: string, ...args: unknown[]) {\n emit(eventName, ...args);\n },\n\n createInstance(opts?: InitOptions, _cb?: unknown) {\n return createInstance({ ...instanceOptions, ...opts });\n },\n\n cloneInstance(opts?: Record<string, unknown>, _cb?: unknown) {\n return createInstance({ ...instanceOptions, ...opts });\n },\n\n dir(lng?: string): 'ltr' | 'rtl' {\n const rtl = ['ar', 'he', 'fa', 'ur', 'ps', 'yi', 'dv', 'ug'];\n return rtl.some((l) => (lng ?? currentLanguage).startsWith(l))\n ? 'rtl'\n : 'ltr';\n },\n\n setDefaultNamespace(ns: string) {\n defaultNS = ns;\n },\n\n hasLoadedNamespace(ns: string | readonly string[]): boolean {\n try {\n getIntlayer(\n (Array.isArray(ns) ? ns[0] : ns) as DictionaryKeys,\n currentLanguage as LocalesValues\n );\n return true;\n } catch {\n return false;\n }\n },\n\n async loadNamespaces(_ns: unknown) {},\n async loadLanguages(_lngs: unknown) {},\n loadResources(_cb?: unknown) {},\n async reloadResources() {},\n\n getDataByLanguage(_lng: string) {\n return undefined;\n },\n\n getResource(lng: string, ns: string, key: string): unknown {\n try {\n return navigatePath(\n getIntlayer(ns as DictionaryKeys, lng as LocalesValues),\n key\n );\n } catch {\n return undefined;\n }\n },\n\n addResource: () => instance as unknown as I18nInterface,\n addResources: () => instance as unknown as I18nInterface,\n addResourceBundle: () => instance as unknown as I18nInterface,\n hasResourceBundle: () => false,\n getResourceBundle: () => undefined,\n removeResourceBundle: () => instance as unknown as I18nInterface,\n\n toJSON() {\n return {\n options: instanceOptions,\n store: {} as I18nInterface['store'],\n language: currentLanguage,\n languages: (config?.locales?.map(String) ?? [\n currentLanguage,\n ]) as readonly string[],\n resolvedLanguage: currentLanguage,\n };\n },\n };\n\n return instance as unknown as I18nInterface;\n};\n\n/** Typed variant of i18next's `getFixedT`, scoped to an intlayer dictionary namespace. */\nexport type TypedGetFixedT = <N extends DictionaryKeys>(\n lng: string | readonly string[] | null,\n ns?: N | null,\n keyPrefix?: string\n) => <P extends ValidDotPathsFor<N>>(key: P, opts?: TOptions) => string;\n"],"mappings":"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"}
1
+ {"version":3,"file":"createInstance.mjs","names":[],"sources":["../../src/createInstance.ts"],"sourcesContent":["import { internationalization, log } from '@intlayer/config/built';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport { getIntlayer } from '@intlayer/core/interpreter';\nimport { navigatePath, resolveMessage } from '@intlayer/core/messageFormat';\nimport type {\n DictionaryKeys,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type {\n createInstance as _createInstance,\n i18n as I18nInterface,\n InitOptions,\n TOptions,\n} from 'i18next';\nimport {\n getInterpolationValues,\n resolveTranslation,\n} from './resolveTranslation';\nimport type { TypedGetFixedT } from './typedTranslation';\n\nexport type { TypedGetFixedT } from './typedTranslation';\n\ntype EventHandler = (...args: unknown[]) => void;\n\nconst warnIgnoredResources = (location: string) => {\n const appLogger = getAppLogger({ log });\n appLogger(\n `${colorize(location, ANSIColors.CYAN)}: the ${colorize('`resources`', ANSIColors.CYAN)} option is ignored when using ${colorize('@intlayer/i18next', ANSIColors.MAGENTA)} — translations are served from the compiled intlayer dictionaries instead. Remove the resource imports and the ${colorize('`resources`', ANSIColors.CYAN)} option to reduce your bundle size.`\n );\n};\n\nexport const createInstance: typeof _createInstance = (\n instanceOptions: InitOptions = {}\n): I18nInterface => {\n if ((instanceOptions as Record<string, unknown>).resources !== undefined) {\n warnIgnoredResources('createInstance');\n }\n\n const config = internationalization;\n\n let currentLanguage: string =\n (instanceOptions.lng as string) ?? config?.defaultLocale ?? 'en';\n\n let defaultNS: string =\n (instanceOptions.defaultNS as string) ??\n (Array.isArray(instanceOptions.ns)\n ? (instanceOptions.ns[0] as string)\n : (instanceOptions.ns as string)) ??\n 'translation';\n\n const listeners = new Map<string, Set<EventHandler>>();\n let initialized = false;\n\n const emit = (event: string, ...args: unknown[]) => {\n listeners.get(event)?.forEach((h) => {\n h(...args);\n });\n };\n\n const getSeparators = () => ({\n keySeparator:\n (instanceOptions.keySeparator as string | false | undefined) ?? '.',\n nsSeparator:\n (instanceOptions.nsSeparator as string | false | undefined) ?? ':',\n });\n\n /**\n * Resolves a key through the full i18next pipeline (namespace prefix,\n * `ns` option, plural/context suffixes, `$t()` nesting, interpolation).\n * Falls back to the interpolated `defaultValue`, then to the key itself.\n */\n const resolveKey = (\n lang: string,\n ns: string,\n key: string,\n opts?: TOptions | string\n ): string => {\n const options =\n typeof opts === 'string' ? { defaultValue: opts } : (opts as TOptions);\n\n const resolved = resolveTranslation({\n locale: lang as LocalesValues,\n namespace: ns,\n key,\n options,\n ...getSeparators(),\n });\n\n if (resolved !== undefined) return resolved as string;\n\n const defaultValue = (options as Record<string, unknown> | undefined)\n ?.defaultValue;\n if (typeof defaultValue === 'string') {\n return resolveMessage(\n defaultValue,\n getInterpolationValues(options),\n lang as LocalesValues,\n 'i18next'\n );\n }\n\n return key;\n };\n\n const instance = {\n get language() {\n return currentLanguage;\n },\n get languages() {\n return (config?.locales?.map(String) ?? [\n currentLanguage,\n ]) as readonly string[];\n },\n get resolvedLanguage() {\n return currentLanguage;\n },\n get isInitialized() {\n return initialized;\n },\n isInitializing: false,\n initializedStoreOnce: false,\n initializedLanguageOnce: false,\n options: instanceOptions,\n modules: {} as I18nInterface['modules'],\n services: {} as I18nInterface['services'],\n store: {} as I18nInterface['store'],\n format: ((value: unknown) => String(value)) as I18nInterface['format'],\n\n async init(optionsOrCb?: unknown, cb?: unknown) {\n const opts =\n typeof optionsOrCb === 'function'\n ? {}\n : ((optionsOrCb ?? {}) as Record<string, unknown>);\n if (opts.resources !== undefined) {\n warnIgnoredResources('i18next.init');\n }\n if (opts.lng) currentLanguage = opts.lng as string;\n if (opts.defaultNS) defaultNS = opts.defaultNS as string;\n else if (opts.ns)\n defaultNS = Array.isArray(opts.ns)\n ? (opts.ns[0] as string)\n : (opts.ns as string);\n initialized = true;\n emit('initialized', opts);\n const t = instance.t.bind(instance);\n const callback = typeof optionsOrCb === 'function' ? optionsOrCb : cb;\n (callback as ((err: unknown, t: unknown) => void) | undefined)?.(null, t);\n return t as unknown as Promise<I18nInterface['t']>;\n },\n\n t(\n key: unknown,\n optionsOrDefaultValue?: unknown,\n extraOpts?: unknown\n ): unknown {\n const options =\n typeof optionsOrDefaultValue === 'string'\n ? {\n defaultValue: optionsOrDefaultValue,\n ...((extraOpts ?? {}) as Record<string, unknown>),\n }\n : (optionsOrDefaultValue as TOptions | undefined);\n const keys: string[] = Array.isArray(key)\n ? (key as string[])\n : [String(key)];\n for (const candidateKey of keys) {\n const result = resolveTranslation({\n locale: currentLanguage as LocalesValues,\n namespace: defaultNS,\n key: candidateKey,\n options,\n ...getSeparators(),\n });\n if (result !== undefined) return result;\n }\n\n const defaultValue = (options as Record<string, unknown> | undefined)\n ?.defaultValue;\n if (typeof defaultValue === 'string') {\n return resolveMessage(\n defaultValue,\n getInterpolationValues(options),\n currentLanguage as LocalesValues,\n 'i18next'\n );\n }\n\n return defaultValue ?? (Array.isArray(key) ? key[key.length - 1] : key);\n },\n\n async changeLanguage(lng?: string, cb?: unknown) {\n const prev = currentLanguage;\n if (lng) currentLanguage = lng;\n emit('languageChanged', currentLanguage, prev);\n const t = instance.t.bind(instance);\n (cb as ((err: unknown, t: unknown) => void) | undefined)?.(null, t);\n return t as unknown as Promise<I18nInterface['t']>;\n },\n\n exists(key: string, options?: unknown): boolean {\n return (\n resolveTranslation({\n locale: currentLanguage as LocalesValues,\n namespace: defaultNS,\n key,\n options: options as TOptions,\n ...getSeparators(),\n }) !== undefined\n );\n },\n\n /**\n * Returns a `t()` function bound to a fixed locale and namespace.\n * When `ns` matches a registered intlayer dictionary key, the returned\n * function's `key` parameter is typed to only accept valid dot-notation\n * paths for that dictionary, and its return type is resolved from the\n * content at that path. With a `keyPrefix`, keys are relative dot-paths\n * under the prefix.\n *\n * @example\n * ```ts\n * const tAbout = i18n.getFixedT(null, 'about');\n * tAbout('counter.label'); // ✓ typed key and return value\n * ```\n */\n getFixedT: ((\n lng: string | readonly string[] | null,\n ns?: string | null,\n keyPrefix?: string\n ) => {\n const fixedLng = Array.isArray(lng)\n ? ((lng[0] as string) ?? currentLanguage)\n : ((lng as string) ?? currentLanguage);\n const fixedNS = ns ?? defaultNS;\n return (key: string, opts?: TOptions): string => {\n const fullKey = keyPrefix ? `${keyPrefix}.${key}` : key;\n return resolveKey(fixedLng, fixedNS, fullKey, opts);\n };\n }) as TypedGetFixedT,\n\n use(module: unknown) {\n (module as { init?: (i18n: I18nInterface) => void })?.init?.(\n instance as unknown as I18nInterface\n );\n return instance as unknown as I18nInterface;\n },\n\n on(event: string, handler: EventHandler) {\n if (!listeners.has(event)) listeners.set(event, new Set());\n listeners.get(event)!.add(handler);\n return instance as unknown as I18nInterface;\n },\n\n once(event: string, handler: EventHandler) {\n const wrapper: EventHandler = (...args) => {\n handler(...args);\n instance.off(event, wrapper);\n };\n instance.on(event, wrapper);\n return instance as unknown as I18nInterface;\n },\n\n off(event: string, handler?: EventHandler) {\n if (!handler) listeners.delete(event);\n else listeners.get(event)?.delete(handler);\n },\n\n emit(eventName: string, ...args: unknown[]) {\n emit(eventName, ...args);\n },\n\n createInstance(opts?: InitOptions, _cb?: unknown) {\n return createInstance({ ...instanceOptions, ...opts });\n },\n\n cloneInstance(opts?: Record<string, unknown>, _cb?: unknown) {\n return createInstance({ ...instanceOptions, ...opts });\n },\n\n dir(lng?: string): 'ltr' | 'rtl' {\n const rtl = ['ar', 'he', 'fa', 'ur', 'ps', 'yi', 'dv', 'ug'];\n return rtl.some((l) => (lng ?? currentLanguage).startsWith(l))\n ? 'rtl'\n : 'ltr';\n },\n\n setDefaultNamespace(ns: string) {\n defaultNS = ns;\n },\n\n hasLoadedNamespace(ns: string | readonly string[]): boolean {\n try {\n getIntlayer(\n (Array.isArray(ns) ? ns[0] : ns) as DictionaryKeys,\n currentLanguage as LocalesValues\n );\n return true;\n } catch {\n return false;\n }\n },\n\n async loadNamespaces(_ns: unknown) {},\n async loadLanguages(_lngs: unknown) {},\n loadResources(_cb?: unknown) {},\n async reloadResources() {},\n\n getDataByLanguage(_lng: string) {\n return undefined;\n },\n\n getResource(lng: string, ns: string, key: string): unknown {\n try {\n return navigatePath(\n getIntlayer(ns as DictionaryKeys, lng as LocalesValues),\n key\n );\n } catch {\n return undefined;\n }\n },\n\n addResource: () => instance as unknown as I18nInterface,\n addResources: () => instance as unknown as I18nInterface,\n addResourceBundle: () => instance as unknown as I18nInterface,\n hasResourceBundle: () => false,\n getResourceBundle: () => undefined,\n removeResourceBundle: () => instance as unknown as I18nInterface,\n\n toJSON() {\n return {\n options: instanceOptions,\n store: {} as I18nInterface['store'],\n language: currentLanguage,\n languages: (config?.locales?.map(String) ?? [\n currentLanguage,\n ]) as readonly string[],\n resolvedLanguage: currentLanguage,\n };\n },\n };\n\n return instance as unknown as I18nInterface;\n};\n"],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import { resolveTranslation } from "./resolveTranslation.mjs";
2
+ import { internationalization } from "@intlayer/config/built";
3
+ import { getDictionary as getDictionary$1 } from "@intlayer/core/interpreter";
4
+
5
+ //#region src/getDictionary.ts
6
+ /**
7
+ * Dictionary-accepting variant of `getFixedT`.
8
+ *
9
+ * Used by the build-time optimization (and available for manual use): instead
10
+ * of resolving the namespace from the runtime registry, the dictionary is
11
+ * supplied directly — enabling tree-shaking of unused locale content.
12
+ *
13
+ * The returned `t()` matches the fixed translator produced by
14
+ * `getFixedT(lng, ns, keyPrefix)`: plural and context suffixes, `$t()`
15
+ * nesting, `defaultValue` and `{{var}}` interpolation are all supported.
16
+ *
17
+ * @example
18
+ * import aboutDictionary from './about.content';
19
+ * const t = getDictionary(aboutDictionary, 'fr');
20
+ * t('counter.label');
21
+ */
22
+ const getDictionary = ((dictionary, locale, keyPrefix) => {
23
+ const targetLocale = locale ?? internationalization?.defaultLocale;
24
+ const dictionaryContent = getDictionary$1(dictionary, targetLocale);
25
+ return (key, options) => {
26
+ const resolved = resolveTranslation({
27
+ locale: targetLocale,
28
+ namespace: dictionary.key,
29
+ key: keyPrefix ? `${keyPrefix}.${key}` : key,
30
+ options,
31
+ dictionaryContent
32
+ });
33
+ return resolved !== void 0 ? resolved : key;
34
+ };
35
+ });
36
+
37
+ //#endregion
38
+ export { getDictionary };
39
+ //# sourceMappingURL=getDictionary.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getDictionary.mjs","names":["getDictionaryCore"],"sources":["../../src/getDictionary.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport { getDictionary as getDictionaryCore } from '@intlayer/core/interpreter';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport type {\n DictionaryKeys,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type { TOptions } from 'i18next';\nimport { resolveTranslation } from './resolveTranslation';\nimport type { ScopedTFunction, TypedTFunction } from './typedTranslation';\n\n/**\n * Overload set for {@link getDictionary}: without a key prefix the returned\n * `t()` is typed against the dictionary's dot-paths; with a prefix the keys\n * are relative dot-paths under that scope.\n */\ntype GetDictionary = {\n <T extends Dictionary>(\n dictionary: T,\n locale?: LocalesValues\n ): TypedTFunction<T['key'] & DictionaryKeys>;\n <T extends Dictionary, Prefix extends string>(\n dictionary: T,\n locale: LocalesValues | undefined,\n keyPrefix: Prefix\n ): ScopedTFunction<T['key'] & DictionaryKeys, Prefix>;\n};\n\n/**\n * Dictionary-accepting variant of `getFixedT`.\n *\n * Used by the build-time optimization (and available for manual use): instead\n * of resolving the namespace from the runtime registry, the dictionary is\n * supplied directly — enabling tree-shaking of unused locale content.\n *\n * The returned `t()` matches the fixed translator produced by\n * `getFixedT(lng, ns, keyPrefix)`: plural and context suffixes, `$t()`\n * nesting, `defaultValue` and `{{var}}` interpolation are all supported.\n *\n * @example\n * import aboutDictionary from './about.content';\n * const t = getDictionary(aboutDictionary, 'fr');\n * t('counter.label');\n */\nexport const getDictionary = (<T extends Dictionary>(\n dictionary: T,\n locale?: LocalesValues,\n keyPrefix?: string\n) => {\n const targetLocale = (locale ??\n internationalization?.defaultLocale) as LocalesValues;\n const dictionaryContent = getDictionaryCore(dictionary, targetLocale);\n\n return (key: string, options?: TOptions): unknown => {\n const resolved = resolveTranslation({\n locale: targetLocale,\n namespace: dictionary.key,\n key: keyPrefix ? `${keyPrefix}.${key}` : key,\n options,\n dictionaryContent,\n });\n return resolved !== undefined ? resolved : key;\n };\n}) as GetDictionary;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA4CA,MAAa,kBACX,YACA,QACA,cACG;CACH,MAAM,eAAgB,UACpB,sBAAsB;CACxB,MAAM,oBAAoBA,gBAAkB,YAAY,YAAY;CAEpE,QAAQ,KAAa,YAAgC;EACnD,MAAM,WAAW,mBAAmB;GAClC,QAAQ;GACR,WAAW,WAAW;GACtB,KAAK,YAAY,GAAG,UAAU,GAAG,QAAQ;GACzC;GACA;EACF,CAAC;EACD,OAAO,aAAa,SAAY,WAAW;CAC7C;AACF"}
@@ -0,0 +1,36 @@
1
+ import { resolveTranslation } from "./resolveTranslation.mjs";
2
+ import { internationalization } from "@intlayer/config/built";
3
+ import { getDictionary } from "@intlayer/core/interpreter";
4
+
5
+ //#region src/getDictionaryDynamic.ts
6
+ /**
7
+ * Dynamic dictionary-accepting variant of `getFixedT`.
8
+ *
9
+ * Counterpart to {@link getDictionary} for dictionaries imported lazily per
10
+ * locale: only the JSON of the resolved locale is loaded. Returns a promise
11
+ * of the fixed `t()` function.
12
+ *
13
+ * @example
14
+ * const t = await getDictionaryDynamic(aboutLoaders, 'about', 'fr');
15
+ * t('counter.label');
16
+ */
17
+ const getDictionaryDynamic = (async (dictionaryPromise, key, locale, keyPrefix) => {
18
+ const targetLocale = locale ?? internationalization?.defaultLocale;
19
+ const loadDictionary = dictionaryPromise[targetLocale];
20
+ const dictionary = loadDictionary ? await loadDictionary() : void 0;
21
+ const dictionaryContent = dictionary ? getDictionary(dictionary, targetLocale) : void 0;
22
+ return (lookupKey, options) => {
23
+ const resolved = resolveTranslation({
24
+ locale: targetLocale,
25
+ namespace: key,
26
+ key: keyPrefix ? `${keyPrefix}.${lookupKey}` : lookupKey,
27
+ options,
28
+ dictionaryContent
29
+ });
30
+ return resolved !== void 0 ? resolved : lookupKey;
31
+ };
32
+ });
33
+
34
+ //#endregion
35
+ export { getDictionaryDynamic };
36
+ //# sourceMappingURL=getDictionaryDynamic.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getDictionaryDynamic.mjs","names":["getDictionaryCore"],"sources":["../../src/getDictionaryDynamic.ts"],"sourcesContent":["import { internationalization } from '@intlayer/config/built';\nimport { getDictionary as getDictionaryCore } from '@intlayer/core/interpreter';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport type {\n DictionaryKeys,\n LocalesValues,\n StrictModeLocaleMap,\n} from '@intlayer/types/module_augmentation';\nimport type { TOptions } from 'i18next';\nimport { resolveTranslation } from './resolveTranslation';\nimport type { ScopedTFunction, TypedTFunction } from './typedTranslation';\n\n/**\n * Overload set for {@link getDictionaryDynamic}: without a key prefix the\n * returned `t()` is typed against the dictionary's dot-paths; with a prefix\n * the keys are relative dot-paths under that scope.\n */\ntype GetDictionaryDynamic = {\n <T extends Dictionary, K extends DictionaryKeys>(\n dictionaryPromise: StrictModeLocaleMap<() => Promise<T>>,\n key: K,\n locale?: LocalesValues\n ): Promise<TypedTFunction<K>>;\n <T extends Dictionary, K extends DictionaryKeys, Prefix extends string>(\n dictionaryPromise: StrictModeLocaleMap<() => Promise<T>>,\n key: K,\n locale: LocalesValues | undefined,\n keyPrefix: Prefix\n ): Promise<ScopedTFunction<K, Prefix>>;\n};\n\n/**\n * Dynamic dictionary-accepting variant of `getFixedT`.\n *\n * Counterpart to {@link getDictionary} for dictionaries imported lazily per\n * locale: only the JSON of the resolved locale is loaded. Returns a promise\n * of the fixed `t()` function.\n *\n * @example\n * const t = await getDictionaryDynamic(aboutLoaders, 'about', 'fr');\n * t('counter.label');\n */\nexport const getDictionaryDynamic = (async <\n const T extends Dictionary,\n const K extends DictionaryKeys,\n>(\n dictionaryPromise: StrictModeLocaleMap<() => Promise<T>>,\n key: K,\n locale?: LocalesValues,\n keyPrefix?: string\n) => {\n const targetLocale = (locale ??\n internationalization?.defaultLocale) as LocalesValues;\n const loadDictionary = (\n dictionaryPromise as Record<string, () => Promise<T>>\n )[targetLocale as string];\n const dictionary = loadDictionary ? await loadDictionary() : undefined;\n const dictionaryContent = dictionary\n ? getDictionaryCore(dictionary, targetLocale)\n : undefined;\n\n return (lookupKey: string, options?: TOptions): unknown => {\n const resolved = resolveTranslation({\n locale: targetLocale,\n namespace: key,\n key: keyPrefix ? `${keyPrefix}.${lookupKey}` : lookupKey,\n options,\n dictionaryContent,\n });\n return resolved !== undefined ? resolved : lookupKey;\n };\n}) as GetDictionaryDynamic;\n"],"mappings":";;;;;;;;;;;;;;;;AA0CA,MAAa,wBAAwB,OAInC,mBACA,KACA,QACA,cACG;CACH,MAAM,eAAgB,UACpB,sBAAsB;CACxB,MAAM,iBACJ,kBACA;CACF,MAAM,aAAa,iBAAiB,MAAM,eAAe,IAAI;CAC7D,MAAM,oBAAoB,aACtBA,cAAkB,YAAY,YAAY,IAC1C;CAEJ,QAAQ,WAAmB,YAAgC;EACzD,MAAM,WAAW,mBAAmB;GAClC,QAAQ;GACR,WAAW;GACX,KAAK,YAAY,GAAG,UAAU,GAAG,cAAc;GAC/C;GACA;EACF,CAAC;EACD,OAAO,aAAa,SAAY,WAAW;CAC7C;AACF"}
@@ -1,4 +1,6 @@
1
1
  import { getInterpolationValues, resolveTranslation } from "./resolveTranslation.mjs";
2
+ import { getDictionary } from "./getDictionary.mjs";
3
+ import { getDictionaryDynamic } from "./getDictionaryDynamic.mjs";
2
4
  import { createInstance } from "./createInstance.mjs";
3
5
 
4
6
  //#region src/index.ts
@@ -36,5 +38,5 @@ const loadLanguages = i18next.loadLanguages.bind(i18next);
36
38
  const keyFromSelector = (selector) => selector;
37
39
 
38
40
  //#endregion
39
- export { changeLanguage, createInstance, i18next as default, i18next, dir, exists, getFixedT, getInterpolationValues, hasLoadedNamespace, init, keyFromSelector, loadLanguages, loadNamespaces, loadResources, reloadResources, resolveTranslation, setDefaultNamespace, t, use };
41
+ export { changeLanguage, createInstance, i18next as default, i18next, dir, exists, getDictionary, getDictionaryDynamic, getFixedT, getInterpolationValues, hasLoadedNamespace, init, keyFromSelector, loadLanguages, loadNamespaces, loadResources, reloadResources, resolveTranslation, setDefaultNamespace, t, use };
40
42
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/index.ts"],"sourcesContent":["import type {\n changeLanguage as _changeLanguage,\n dir as _dir,\n exists as _exists,\n hasLoadedNamespace as _hasLoadedNamespace,\n init as _init,\n loadLanguages as _loadLanguages,\n loadNamespaces as _loadNamespaces,\n loadResources as _loadResources,\n reloadResources as _reloadResources,\n setDefaultNamespace as _setDefaultNamespace,\n t as _t,\n use as _use,\n i18n,\n} from 'i18next';\nimport { createInstance, type TypedGetFixedT } from './createInstance';\n\nexport {\n getInterpolationValues,\n type ResolveTranslationParams,\n resolveTranslation,\n} from './resolveTranslation';\n\nconst i18next: i18n = createInstance();\n\nexport { createInstance };\nexport default i18next;\nexport { i18next };\n\nexport const dir: typeof _dir = i18next.dir.bind(i18next);\nexport const init: typeof _init = i18next.init.bind(i18next);\nexport const loadResources: typeof _loadResources =\n i18next.loadResources.bind(i18next);\nexport const reloadResources: typeof _reloadResources =\n i18next.reloadResources.bind(i18next);\nexport const use: typeof _use = i18next.use.bind(i18next);\nexport const changeLanguage: typeof _changeLanguage =\n i18next.changeLanguage.bind(i18next);\n\n/**\n * Returns a `t()` function bound to a fixed locale and namespace.\n * When `ns` matches a registered intlayer dictionary key, the returned\n * function's `key` parameter is typed to only accept valid dot-notation\n * paths for that dictionary.\n *\n * @example\n * ```ts\n * const tAbout = getFixedT(null, 'about');\n * tAbout('counter.label'); // ✓ typed\n * ```\n */\nexport const getFixedT: TypedGetFixedT = i18next.getFixedT.bind(\n i18next\n) as TypedGetFixedT;\n\nexport const t: typeof _t = i18next.t.bind(i18next);\nexport const exists: typeof _exists = i18next.exists.bind(i18next);\nexport const setDefaultNamespace: typeof _setDefaultNamespace =\n i18next.setDefaultNamespace.bind(i18next);\nexport const hasLoadedNamespace: typeof _hasLoadedNamespace =\n i18next.hasLoadedNamespace.bind(i18next);\nexport const loadNamespaces: typeof _loadNamespaces =\n i18next.loadNamespaces.bind(i18next);\nexport const loadLanguages: typeof _loadLanguages =\n i18next.loadLanguages.bind(i18next);\n\n/**\n * No-op shim for i18next's `keyFromSelector`. This helper is not exposed by\n * every supported i18next version, so a permissive identity function is\n * provided to keep `.keyFromSelector(...)` call-sites working.\n */\nexport const keyFromSelector = (selector: unknown): unknown => selector;\n\nexport type { InitOptions, i18n, TFunction, TOptions } from 'i18next';\n"],"mappings":";;;;AAuBA,MAAM,UAAgB,eAAe;AAMrC,MAAa,MAAmB,QAAQ,IAAI,KAAK,OAAO;AACxD,MAAa,OAAqB,QAAQ,KAAK,KAAK,OAAO;AAC3D,MAAa,gBACX,QAAQ,cAAc,KAAK,OAAO;AACpC,MAAa,kBACX,QAAQ,gBAAgB,KAAK,OAAO;AACtC,MAAa,MAAmB,QAAQ,IAAI,KAAK,OAAO;AACxD,MAAa,iBACX,QAAQ,eAAe,KAAK,OAAO;;;;;;;;;;;;;AAcrC,MAAa,YAA4B,QAAQ,UAAU,KACzD,OACF;AAEA,MAAa,IAAe,QAAQ,EAAE,KAAK,OAAO;AAClD,MAAa,SAAyB,QAAQ,OAAO,KAAK,OAAO;AACjE,MAAa,sBACX,QAAQ,oBAAoB,KAAK,OAAO;AAC1C,MAAa,qBACX,QAAQ,mBAAmB,KAAK,OAAO;AACzC,MAAa,iBACX,QAAQ,eAAe,KAAK,OAAO;AACrC,MAAa,gBACX,QAAQ,cAAc,KAAK,OAAO;;;;;;AAOpC,MAAa,mBAAmB,aAA+B"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/index.ts"],"sourcesContent":["import type {\n changeLanguage as _changeLanguage,\n dir as _dir,\n exists as _exists,\n hasLoadedNamespace as _hasLoadedNamespace,\n init as _init,\n loadLanguages as _loadLanguages,\n loadNamespaces as _loadNamespaces,\n loadResources as _loadResources,\n reloadResources as _reloadResources,\n setDefaultNamespace as _setDefaultNamespace,\n t as _t,\n use as _use,\n i18n,\n} from 'i18next';\nimport { createInstance, type TypedGetFixedT } from './createInstance';\n\nexport { getDictionary } from './getDictionary';\nexport { getDictionaryDynamic } from './getDictionaryDynamic';\nexport {\n getInterpolationValues,\n type ResolveTranslationParams,\n resolveTranslation,\n} from './resolveTranslation';\nexport type {\n ContentAtPath,\n ScopedDotPaths,\n ScopedTFunction,\n TranslatedValue,\n TypedGetFixedT,\n TypedTFunction,\n} from './typedTranslation';\n\nconst i18next: i18n = createInstance();\n\nexport { createInstance };\nexport default i18next;\nexport { i18next };\n\nexport const dir: typeof _dir = i18next.dir.bind(i18next);\nexport const init: typeof _init = i18next.init.bind(i18next);\nexport const loadResources: typeof _loadResources =\n i18next.loadResources.bind(i18next);\nexport const reloadResources: typeof _reloadResources =\n i18next.reloadResources.bind(i18next);\nexport const use: typeof _use = i18next.use.bind(i18next);\nexport const changeLanguage: typeof _changeLanguage =\n i18next.changeLanguage.bind(i18next);\n\n/**\n * Returns a `t()` function bound to a fixed locale and namespace.\n * When `ns` matches a registered intlayer dictionary key, the returned\n * function's `key` parameter is typed to only accept valid dot-notation\n * paths for that dictionary.\n *\n * @example\n * ```ts\n * const tAbout = getFixedT(null, 'about');\n * tAbout('counter.label'); // ✓ typed\n * ```\n */\nexport const getFixedT: TypedGetFixedT = i18next.getFixedT.bind(\n i18next\n) as TypedGetFixedT;\n\nexport const t: typeof _t = i18next.t.bind(i18next);\nexport const exists: typeof _exists = i18next.exists.bind(i18next);\nexport const setDefaultNamespace: typeof _setDefaultNamespace =\n i18next.setDefaultNamespace.bind(i18next);\nexport const hasLoadedNamespace: typeof _hasLoadedNamespace =\n i18next.hasLoadedNamespace.bind(i18next);\nexport const loadNamespaces: typeof _loadNamespaces =\n i18next.loadNamespaces.bind(i18next);\nexport const loadLanguages: typeof _loadLanguages =\n i18next.loadLanguages.bind(i18next);\n\n/**\n * No-op shim for i18next's `keyFromSelector`. This helper is not exposed by\n * every supported i18next version, so a permissive identity function is\n * provided to keep `.keyFromSelector(...)` call-sites working.\n */\nexport const keyFromSelector = (selector: unknown): unknown => selector;\n\nexport type { InitOptions, i18n, TFunction, TOptions } from 'i18next';\n"],"mappings":";;;;;;AAiCA,MAAM,UAAgB,eAAe;AAMrC,MAAa,MAAmB,QAAQ,IAAI,KAAK,OAAO;AACxD,MAAa,OAAqB,QAAQ,KAAK,KAAK,OAAO;AAC3D,MAAa,gBACX,QAAQ,cAAc,KAAK,OAAO;AACpC,MAAa,kBACX,QAAQ,gBAAgB,KAAK,OAAO;AACtC,MAAa,MAAmB,QAAQ,IAAI,KAAK,OAAO;AACxD,MAAa,iBACX,QAAQ,eAAe,KAAK,OAAO;;;;;;;;;;;;;AAcrC,MAAa,YAA4B,QAAQ,UAAU,KACzD,OACF;AAEA,MAAa,IAAe,QAAQ,EAAE,KAAK,OAAO;AAClD,MAAa,SAAyB,QAAQ,OAAO,KAAK,OAAO;AACjE,MAAa,sBACX,QAAQ,oBAAoB,KAAK,OAAO;AAC1C,MAAa,qBACX,QAAQ,mBAAmB,KAAK,OAAO;AACzC,MAAa,iBACX,QAAQ,eAAe,KAAK,OAAO;AACrC,MAAa,gBACX,QAAQ,cAAc,KAAK,OAAO;;;;;;AAOpC,MAAa,mBAAmB,aAA+B"}
@@ -1,51 +1,12 @@
1
1
  import * as ANSIColors from "@intlayer/config/colors";
2
2
  import { colorize, getAppLogger } from "@intlayer/config/logger";
3
3
  import { join } from "node:path";
4
- import { runOnce } from "@intlayer/chokidar/utils";
4
+ import { I18NEXT_CALLERS } from "@intlayer/config/callers";
5
5
  import { getConfiguration } from "@intlayer/config/node";
6
+ import { runOnce } from "@intlayer/engine/utils";
6
7
  import { intlayer } from "vite-intlayer";
7
8
 
8
9
  //#region src/plugin/index.ts
9
- /**
10
- * A Vite plugin for the i18next compat adapter that wraps `vite-intlayer`
11
- * and registers a resolve alias mapping `i18next` to `@intlayer/i18next`.
12
- *
13
- * This lets an existing i18next codebase migrate to intlayer without
14
- * rewriting any `import ... from 'i18next'` statements — they are
15
- * transparently redirected to the compat adapter at build time.
16
- *
17
- * @example
18
- * ```ts
19
- * // vite.config.ts
20
- * import i18nextVitePlugin from '@intlayer/i18next/plugin';
21
- *
22
- * export default defineConfig({
23
- * plugins: [i18nextVitePlugin()],
24
- * });
25
- * ```
26
- */
27
- /**
28
- * Caller configurations for i18next's `getFixedT` method.
29
- *
30
- * Tells the intlayer field-usage analyser how to extract the dictionary key
31
- * (namespace) and optional key prefix from `i18n.getFixedT(lng, ns, prefix)`
32
- * call sites, enabling accurate dictionary pruning for projects using
33
- * `@intlayer/i18next`.
34
- */
35
- const I18NEXT_COMPAT_CALLERS = [{
36
- callerName: "getFixedT",
37
- importSources: ["i18next", "@intlayer/i18next"],
38
- matchAsMethod: true,
39
- namespace: {
40
- from: "argument",
41
- index: 1
42
- },
43
- keyPrefix: {
44
- from: "argument",
45
- index: 2
46
- },
47
- translationFunction: "return-value"
48
- }];
49
10
  const i18nextVitePlugin = (options) => {
50
11
  const intlayerConfig = getConfiguration();
51
12
  const appLogger = getAppLogger(intlayerConfig);
@@ -54,7 +15,7 @@ const i18nextVitePlugin = (options) => {
54
15
  }, { cacheTimeoutMs: 1e3 * 60 * 60 });
55
16
  const basePlugins = intlayer({
56
17
  ...options,
57
- compatCallers: [...options?.compatCallers ?? [], ...I18NEXT_COMPAT_CALLERS]
18
+ compatCallers: [...options?.compatCallers ?? [], ...I18NEXT_CALLERS]
58
19
  });
59
20
  const compatPlugin = {
60
21
  name: "vite-i18next-compat-plugin",
@@ -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 * A Vite plugin for the i18next compat adapter that wraps `vite-intlayer`\n * and registers a resolve alias mapping `i18next` to `@intlayer/i18next`.\n *\n * This lets an existing i18next codebase migrate to intlayer without\n * rewriting any `import ... from 'i18next'` statements — they are\n * transparently redirected to the compat adapter at build time.\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import i18nextVitePlugin from '@intlayer/i18next/plugin';\n *\n * export default defineConfig({\n * plugins: [i18nextVitePlugin()],\n * });\n * ```\n */\n\n/**\n * Caller configurations for i18next's `getFixedT` method.\n *\n * Tells the intlayer field-usage analyser how to extract the dictionary key\n * (namespace) and optional key prefix from `i18n.getFixedT(lng, ns, prefix)`\n * call sites, enabling accurate dictionary pruning for projects using\n * `@intlayer/i18next`.\n */\nconst I18NEXT_COMPAT_CALLERS: CompatCallerConfig[] = [\n {\n callerName: 'getFixedT',\n importSources: ['i18next', '@intlayer/i18next'],\n matchAsMethod: true,\n namespace: { from: 'argument', index: 1 },\n keyPrefix: { from: 'argument', index: 2 },\n translationFunction: 'return-value',\n },\n];\n\nexport const i18nextVitePlugin = (\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 ...I18NEXT_COMPAT_CALLERS,\n ],\n });\n\n const compatPlugin: PluginOption = {\n name: 'vite-i18next-compat-plugin',\n config: () => {\n return {\n resolve: {\n alias: {\n i18next: '@intlayer/i18next',\n },\n },\n };\n },\n };\n\n return [\n ...(Array.isArray(basePlugins) ? basePlugins : [basePlugins]),\n compatPlugin,\n ];\n};\n\nexport default i18nextVitePlugin;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,MAAM,yBAA+C,CACnD;CACE,YAAY;CACZ,eAAe,CAAC,WAAW,mBAAmB;CAC9C,eAAe;CACf,WAAW;EAAE,MAAM;EAAY,OAAO;CAAE;CACxC,WAAW;EAAE,MAAM;EAAY,OAAO;CAAE;CACxC,qBAAqB;AACvB,CACF;AAEA,MAAa,qBACX,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,sBACL;CACF,CAAC;CAED,MAAM,eAA6B;EACjC,MAAM;EACN,cAAc;GACZ,OAAO,EACL,SAAS,EACP,OAAO,EACL,SAAS,oBACX,EACF,EACF;EACF;CACF;CAEA,OAAO,CACL,GAAI,MAAM,QAAQ,WAAW,IAAI,cAAc,CAAC,WAAW,GAC3D,YACF;AACF"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugin/index.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { I18NEXT_CALLERS } from '@intlayer/config/callers';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { colorize, getAppLogger } from '@intlayer/config/logger';\nimport { getConfiguration } from '@intlayer/config/node';\nimport { runOnce } from '@intlayer/engine/utils';\nimport type { PluginOption } from 'vite';\nimport { intlayer } from 'vite-intlayer';\n\nexport const i18nextVitePlugin = (\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: [...(options?.compatCallers ?? []), ...I18NEXT_CALLERS],\n });\n\n const compatPlugin: PluginOption = {\n name: 'vite-i18next-compat-plugin',\n config: () => {\n return {\n resolve: {\n alias: {\n i18next: '@intlayer/i18next',\n },\n },\n };\n },\n };\n\n return [\n ...(Array.isArray(basePlugins) ? basePlugins : [basePlugins]),\n compatPlugin,\n ];\n};\n\nexport default i18nextVitePlugin;\n"],"mappings":";;;;;;;;;AASA,MAAa,qBACX,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,CAAC,GAAI,SAAS,iBAAiB,CAAC,GAAI,GAAG,eAAe;CACvE,CAAC;CAED,MAAM,eAA6B;EACjC,MAAM;EACN,cAAc;GACZ,OAAO,EACL,SAAS,EACP,OAAO,EACL,SAAS,oBACX,EACF,EACF;EACF;CACF;CAEA,OAAO,CACL,GAAI,MAAM,QAAQ,WAAW,IAAI,cAAc,CAAC,WAAW,GAC3D,YACF;AACF"}
@@ -1,5 +1,6 @@
1
1
  import { getIntlayer } from "@intlayer/core/interpreter";
2
- import { resolveMessage } from "@intlayer/core/messageFormat";
2
+ import { navigatePath, resolveMessage } from "@intlayer/core/messageFormat";
3
+ import { getDictionaries } from "@intlayer/dictionaries-entry";
3
4
 
4
5
  //#region src/resolveTranslation.ts
5
6
  /**
@@ -14,7 +15,7 @@ import { resolveMessage } from "@intlayer/core/messageFormat";
14
15
  * (`useTranslation`, `<Trans>`).
15
16
  */
16
17
  /** Option keys that are control flags, never interpolation values. */
17
- const CONTROL_OPTION_KEYS = new Set([
18
+ const CONTROL_OPTION_KEYS = /* @__PURE__ */ new Set([
18
19
  "defaultValue",
19
20
  "ns",
20
21
  "lng",
@@ -35,19 +36,25 @@ const CONTROL_OPTION_KEYS = new Set([
35
36
  ]);
36
37
  /** Maximum `$t()` nesting recursion depth. */
37
38
  const MAX_NESTING_DEPTH = 5;
38
- const navigatePath = (objectValue, path, keySeparator = ".") => {
39
- if (!path) return objectValue;
40
- if (keySeparator !== false && path.includes(keySeparator) && objectValue !== null && objectValue !== void 0 && typeof objectValue === "object") {
41
- const flatValue = objectValue[path];
42
- if (flatValue !== void 0) return flatValue;
43
- }
44
- const parts = keySeparator === false ? [path] : path.split(keySeparator);
45
- let current = objectValue;
46
- for (const part of parts) {
47
- if (current === null || current === void 0 || typeof current !== "object") return;
48
- current = current[part];
49
- }
50
- return current;
39
+ /**
40
+ * Canonical key of the single dictionary produced when a JSON source pattern
41
+ * has no `{{key}}` segment (one file holds the whole namespace, e.g.
42
+ * `./src/i18n/{{locale}}.json`). Used as the fallback namespace so i18next's
43
+ * default `translation` namespace resolves against the whole-file dictionary.
44
+ */
45
+ const ROOT_DICTIONARY_KEY = "index";
46
+ /**
47
+ * Reads a dictionary from the runtime registry, returning `undefined` when the
48
+ * namespace is not a registered dictionary.
49
+ *
50
+ * `getIntlayer` never throws for a missing key — in development it returns a
51
+ * path-stringifying fallback proxy — so a plain `getIntlayer` call cannot tell
52
+ * "missing namespace" apart from "resolved content". The registry membership
53
+ * check makes the distinction explicit before resolving.
54
+ */
55
+ const getDictionaryOrUndefined = (namespace, locale) => {
56
+ if (!(namespace in getDictionaries())) return void 0;
57
+ return getIntlayer(namespace, locale);
51
58
  };
52
59
  /**
53
60
  * Builds the ordered list of key candidates following i18next's resolution
@@ -95,7 +102,7 @@ const getInterpolationValues = (options) => {
95
102
  * cannot be resolved (caller decides between `defaultValue`, fallback keys
96
103
  * and key echo).
97
104
  */
98
- const resolveTranslation = ({ locale, namespace, key, options, keySeparator = ".", nsSeparator = ":", depth = 0 }) => {
105
+ const resolveTranslation = ({ locale, namespace, key, options, keySeparator = ".", nsSeparator = ":", depth = 0, dictionaryContent }) => {
99
106
  let targetNamespace = namespace;
100
107
  let path = key;
101
108
  if (nsSeparator !== false && key.includes(nsSeparator)) {
@@ -106,11 +113,13 @@ const resolveTranslation = ({ locale, namespace, key, options, keySeparator = ".
106
113
  const count = typeof options?.count === "number" ? options.count : void 0;
107
114
  const context = options?.context !== void 0 ? String(options.context) : void 0;
108
115
  const ordinal = options?.ordinal === true;
116
+ const resolvedLocale = options?.lng ?? locale;
109
117
  let dictionary;
110
- try {
111
- dictionary = getIntlayer(targetNamespace, options?.lng ?? locale);
112
- } catch {
113
- return;
118
+ if (dictionaryContent !== void 0 && targetNamespace === namespace && options?.lng === void 0) dictionary = dictionaryContent;
119
+ else {
120
+ dictionary = getDictionaryOrUndefined(targetNamespace, resolvedLocale);
121
+ if (dictionary === void 0 && targetNamespace === namespace && targetNamespace !== ROOT_DICTIONARY_KEY) dictionary = getDictionaryOrUndefined(ROOT_DICTIONARY_KEY, resolvedLocale);
122
+ if (dictionary === void 0) return void 0;
114
123
  }
115
124
  let resolvedValue;
116
125
  for (const candidate of buildKeyCandidates(path, options?.lng ?? locale, count, context, ordinal)) {
@@ -132,7 +141,8 @@ const resolveTranslation = ({ locale, namespace, key, options, keySeparator = ".
132
141
  options,
133
142
  keySeparator,
134
143
  nsSeparator,
135
- depth: depth + 1
144
+ depth: depth + 1,
145
+ dictionaryContent: targetNamespace === namespace ? dictionaryContent : void 0
136
146
  });
137
147
  return typeof nestedValue === "string" ? nestedValue : match;
138
148
  });
@@ -1 +1 @@
1
- {"version":3,"file":"resolveTranslation.mjs","names":[],"sources":["../../src/resolveTranslation.ts"],"sourcesContent":["import { getIntlayer } from '@intlayer/core/interpreter';\nimport {\n type MessageValues,\n resolveMessage,\n} from '@intlayer/core/messageFormat';\nimport type {\n DictionaryKeys,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type { TOptions } from 'i18next';\n\n/**\n * Shared i18next-dialect translation resolution.\n *\n * Implements the i18next lookup pipeline on top of intlayer dictionaries:\n * namespace prefix (`ns:key`), `ns` option override, plural suffixes\n * (`key_one`, `key_other`, …) via `Intl.PluralRules`, context suffixes\n * (`key_male`), `$t()` nesting, `defaultValue` and `{{var}}` interpolation.\n *\n * Used by `@intlayer/i18next` (instance `t`) and `@intlayer/react-i18next`\n * (`useTranslation`, `<Trans>`).\n */\n\n/** Option keys that are control flags, never interpolation values. */\nconst CONTROL_OPTION_KEYS = new Set([\n 'defaultValue',\n 'ns',\n 'lng',\n 'lngs',\n 'fallbackLng',\n 'returnObjects',\n 'returnDetails',\n 'keySeparator',\n 'nsSeparator',\n 'ordinal',\n 'postProcess',\n 'postProcessPassResolved',\n 'interpolation',\n 'replace',\n 'joinArrays',\n 'nsMode',\n 'keyPrefix',\n]);\n\n/** Maximum `$t()` nesting recursion depth. */\nconst MAX_NESTING_DEPTH = 5;\n\nconst navigatePath = (\n objectValue: unknown,\n path: string,\n keySeparator: string | false = '.'\n): unknown => {\n if (!path) return objectValue;\n\n // Try the full key as a flat property first (supports i18next flat\n // JSON files that use dotted keys like \"section.title\": \"value\").\n if (\n keySeparator !== false &&\n path.includes(keySeparator) &&\n objectValue !== null &&\n objectValue !== undefined &&\n typeof objectValue === 'object'\n ) {\n const flatValue = (objectValue as Record<string, unknown>)[path];\n if (flatValue !== undefined) {\n return flatValue;\n }\n }\n\n const parts = keySeparator === false ? [path] : path.split(keySeparator);\n\n let current: unknown = objectValue;\n for (const part of parts) {\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\n return current;\n};\n\n/**\n * Builds the ordered list of key candidates following i18next's resolution\n * order: context + plural → context → plural → exact key.\n */\nconst buildKeyCandidates = (\n path: string,\n locale: string,\n count: number | undefined,\n context: string | undefined,\n ordinal: boolean\n): string[] => {\n const candidates: string[] = [];\n\n const pluralCategory =\n count === undefined\n ? undefined\n : new Intl.PluralRules(locale, {\n type: ordinal ? 'ordinal' : 'cardinal',\n }).select(count);\n\n if (context) {\n if (pluralCategory) {\n if (ordinal) {\n candidates.push(`${path}_${context}_ordinal_${pluralCategory}`);\n }\n candidates.push(`${path}_${context}_${pluralCategory}`);\n if (count !== 1) candidates.push(`${path}_${context}_plural`);\n }\n candidates.push(`${path}_${context}`);\n }\n\n if (pluralCategory) {\n if (ordinal) candidates.push(`${path}_ordinal_${pluralCategory}`);\n candidates.push(`${path}_${pluralCategory}`);\n // Legacy i18next v3 JSON suffix\n if (count !== 1) candidates.push(`${path}_plural`);\n }\n\n candidates.push(path);\n\n return candidates;\n};\n\n/** Extracts interpolation values from i18next `t()` options. */\nexport const getInterpolationValues = (options?: TOptions): MessageValues => {\n if (!options || typeof options !== 'object') return {};\n\n const replace = (options as { replace?: MessageValues }).replace;\n if (replace) {\n // `count` and `context` are always interpolatable, even with `replace`\n const values: MessageValues = { ...replace };\n if (options.count !== undefined) values.count ??= options.count;\n if (options.context !== undefined) values.context ??= options.context;\n return values;\n }\n\n const values: MessageValues = {};\n for (const [optionKey, optionValue] of Object.entries(options)) {\n if (!CONTROL_OPTION_KEYS.has(optionKey)) values[optionKey] = optionValue;\n }\n return values;\n};\n\nexport type ResolveTranslationParams = {\n /** Locale to resolve against. */\n locale: LocalesValues;\n /** Default namespace (dictionary key) when the key has no `ns:` prefix. */\n namespace: string;\n /** The translation key, possibly `ns:path.to.key`. */\n key: string;\n /** i18next `t()` options (interpolation values, count, context, …). */\n options?: TOptions;\n /** Custom key separator (`init({ keySeparator })`). */\n keySeparator?: string | false;\n /** Custom namespace separator (`init({ nsSeparator })`). */\n nsSeparator?: string | false;\n /** Internal `$t()` nesting recursion depth. */\n depth?: number;\n};\n\n/**\n * Resolves a single translation key the i18next way against intlayer\n * dictionaries.\n *\n * Returns the resolved value: a string in the common case, or an\n * object/array when `returnObjects: true`. Returns `undefined` when the key\n * cannot be resolved (caller decides between `defaultValue`, fallback keys\n * and key echo).\n */\nexport const resolveTranslation = ({\n locale,\n namespace,\n key,\n options,\n keySeparator = '.',\n nsSeparator = ':',\n depth = 0,\n}: ResolveTranslationParams): unknown => {\n // Namespace resolution: `ns:` prefix > `ns` option > default namespace\n let targetNamespace = namespace;\n let path = key;\n\n if (nsSeparator !== false && key.includes(nsSeparator)) {\n const separatorIndex = key.indexOf(nsSeparator);\n targetNamespace = key.slice(0, separatorIndex);\n path = key.slice(separatorIndex + nsSeparator.length);\n } else if (options?.ns) {\n targetNamespace = Array.isArray(options.ns)\n ? (options.ns[0] as string)\n : (options.ns as string);\n }\n\n const count = typeof options?.count === 'number' ? options.count : undefined;\n const context =\n options?.context !== undefined ? String(options.context) : undefined;\n const ordinal = options?.ordinal === true;\n\n let dictionary: unknown;\n try {\n dictionary = getIntlayer(\n targetNamespace as DictionaryKeys,\n ((options?.lng as string) ?? locale) as LocalesValues\n );\n } catch {\n return undefined;\n }\n\n let resolvedValue: unknown;\n for (const candidate of buildKeyCandidates(\n path,\n (options?.lng as string) ?? (locale as string),\n count,\n context,\n ordinal\n )) {\n const value = navigatePath(dictionary, candidate, keySeparator);\n if (value !== null && value !== undefined) {\n resolvedValue = value;\n break;\n }\n }\n\n if (resolvedValue === null || resolvedValue === undefined) return undefined;\n\n // `returnObjects: true` — return the raw subtree\n if (\n options?.returnObjects &&\n typeof resolvedValue === 'object' &&\n resolvedValue !== null\n ) {\n return resolvedValue;\n }\n\n const values = getInterpolationValues(options);\n\n let resolved = resolveMessage(\n resolvedValue,\n values,\n ((options?.lng as string) ?? locale) as LocalesValues,\n 'i18next'\n );\n\n // `$t(key)` nesting\n if (depth < MAX_NESTING_DEPTH && resolved.includes('$t(')) {\n resolved = resolved.replace(\n /\\$t\\(\\s*([^),]+?)\\s*(?:,[^)]*)?\\)/g,\n (match, nestedKey: string) => {\n const nestedValue = resolveTranslation({\n locale,\n namespace: targetNamespace,\n key: nestedKey.trim(),\n options,\n keySeparator,\n nsSeparator,\n depth: depth + 1,\n });\n return typeof nestedValue === 'string' ? nestedValue : match;\n }\n );\n }\n\n return resolved;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"resolveTranslation.mjs","names":[],"sources":["../../src/resolveTranslation.ts"],"sourcesContent":["import { getIntlayer } from '@intlayer/core/interpreter';\nimport {\n type MessageValues,\n navigatePath,\n resolveMessage,\n} from '@intlayer/core/messageFormat';\nimport { getDictionaries } from '@intlayer/dictionaries-entry';\nimport type {\n DictionaryKeys,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type { TOptions } from 'i18next';\n\n/**\n * Shared i18next-dialect translation resolution.\n *\n * Implements the i18next lookup pipeline on top of intlayer dictionaries:\n * namespace prefix (`ns:key`), `ns` option override, plural suffixes\n * (`key_one`, `key_other`, …) via `Intl.PluralRules`, context suffixes\n * (`key_male`), `$t()` nesting, `defaultValue` and `{{var}}` interpolation.\n *\n * Used by `@intlayer/i18next` (instance `t`) and `@intlayer/react-i18next`\n * (`useTranslation`, `<Trans>`).\n */\n\n/** Option keys that are control flags, never interpolation values. */\nconst CONTROL_OPTION_KEYS = new Set([\n 'defaultValue',\n 'ns',\n 'lng',\n 'lngs',\n 'fallbackLng',\n 'returnObjects',\n 'returnDetails',\n 'keySeparator',\n 'nsSeparator',\n 'ordinal',\n 'postProcess',\n 'postProcessPassResolved',\n 'interpolation',\n 'replace',\n 'joinArrays',\n 'nsMode',\n 'keyPrefix',\n]);\n\n/** Maximum `$t()` nesting recursion depth. */\nconst MAX_NESTING_DEPTH = 5;\n\n/**\n * Canonical key of the single dictionary produced when a JSON source pattern\n * has no `{{key}}` segment (one file holds the whole namespace, e.g.\n * `./src/i18n/{{locale}}.json`). Used as the fallback namespace so i18next's\n * default `translation` namespace resolves against the whole-file dictionary.\n */\nconst ROOT_DICTIONARY_KEY = 'index';\n\n/**\n * Reads a dictionary from the runtime registry, returning `undefined` when the\n * namespace is not a registered dictionary.\n *\n * `getIntlayer` never throws for a missing key — in development it returns a\n * path-stringifying fallback proxy — so a plain `getIntlayer` call cannot tell\n * \"missing namespace\" apart from \"resolved content\". The registry membership\n * check makes the distinction explicit before resolving.\n */\nconst getDictionaryOrUndefined = (\n namespace: DictionaryKeys,\n locale: LocalesValues\n): unknown => {\n if (!(namespace in getDictionaries())) return undefined;\n\n return getIntlayer(namespace, locale);\n};\n\n/**\n * Builds the ordered list of key candidates following i18next's resolution\n * order: context + plural → context → plural → exact key.\n */\nconst buildKeyCandidates = (\n path: string,\n locale: string,\n count: number | undefined,\n context: string | undefined,\n ordinal: boolean\n): string[] => {\n const candidates: string[] = [];\n\n const pluralCategory =\n count === undefined\n ? undefined\n : new Intl.PluralRules(locale, {\n type: ordinal ? 'ordinal' : 'cardinal',\n }).select(count);\n\n if (context) {\n if (pluralCategory) {\n if (ordinal) {\n candidates.push(`${path}_${context}_ordinal_${pluralCategory}`);\n }\n candidates.push(`${path}_${context}_${pluralCategory}`);\n if (count !== 1) candidates.push(`${path}_${context}_plural`);\n }\n candidates.push(`${path}_${context}`);\n }\n\n if (pluralCategory) {\n if (ordinal) candidates.push(`${path}_ordinal_${pluralCategory}`);\n candidates.push(`${path}_${pluralCategory}`);\n // Legacy i18next v3 JSON suffix\n if (count !== 1) candidates.push(`${path}_plural`);\n }\n\n candidates.push(path);\n\n return candidates;\n};\n\n/** Extracts interpolation values from i18next `t()` options. */\nexport const getInterpolationValues = (options?: TOptions): MessageValues => {\n if (!options || typeof options !== 'object') return {};\n\n const replace = (options as { replace?: MessageValues }).replace;\n if (replace) {\n // `count` and `context` are always interpolatable, even with `replace`\n const values: MessageValues = { ...replace };\n if (options.count !== undefined) values.count ??= options.count;\n if (options.context !== undefined) values.context ??= options.context;\n return values;\n }\n\n const values: MessageValues = {};\n for (const [optionKey, optionValue] of Object.entries(options)) {\n if (!CONTROL_OPTION_KEYS.has(optionKey)) values[optionKey] = optionValue;\n }\n return values;\n};\n\nexport type ResolveTranslationParams = {\n /** Locale to resolve against. */\n locale: LocalesValues;\n /** Default namespace (dictionary key) when the key has no `ns:` prefix. */\n namespace: string;\n /** The translation key, possibly `ns:path.to.key`. */\n key: string;\n /** i18next `t()` options (interpolation values, count, context, …). */\n options?: TOptions;\n /** Custom key separator (`init({ keySeparator })`). */\n keySeparator?: string | false;\n /** Custom namespace separator (`init({ nsSeparator })`). */\n nsSeparator?: string | false;\n /** Internal `$t()` nesting recursion depth. */\n depth?: number;\n /**\n * Pre-resolved content of the `namespace` dictionary for `locale`.\n *\n * Supplied by the build-optimized `useDictionary` / `getDictionary`\n * variants, where the dictionary is imported at build time instead of read\n * from the runtime registry. Only used when the call resolves to the\n * default `namespace` without a locale override — cross-namespace\n * (`other:key`, `{ ns }`) and `{ lng }` lookups still go through\n * `getIntlayer`.\n */\n dictionaryContent?: unknown;\n};\n\n/**\n * Resolves a single translation key the i18next way against intlayer\n * dictionaries.\n *\n * Returns the resolved value: a string in the common case, or an\n * object/array when `returnObjects: true`. Returns `undefined` when the key\n * cannot be resolved (caller decides between `defaultValue`, fallback keys\n * and key echo).\n */\nexport const resolveTranslation = ({\n locale,\n namespace,\n key,\n options,\n keySeparator = '.',\n nsSeparator = ':',\n depth = 0,\n dictionaryContent,\n}: ResolveTranslationParams): unknown => {\n // Namespace resolution: `ns:` prefix > `ns` option > default namespace\n let targetNamespace = namespace;\n let path = key;\n\n if (nsSeparator !== false && key.includes(nsSeparator)) {\n const separatorIndex = key.indexOf(nsSeparator);\n targetNamespace = key.slice(0, separatorIndex);\n path = key.slice(separatorIndex + nsSeparator.length);\n } else if (options?.ns) {\n targetNamespace = Array.isArray(options.ns)\n ? (options.ns[0] as string)\n : (options.ns as string);\n }\n\n const count = typeof options?.count === 'number' ? options.count : undefined;\n const context =\n options?.context !== undefined ? String(options.context) : undefined;\n const ordinal = options?.ordinal === true;\n\n const resolvedLocale = ((options?.lng as string) ?? locale) as LocalesValues;\n\n let dictionary: unknown;\n if (\n dictionaryContent !== undefined &&\n targetNamespace === namespace &&\n options?.lng === undefined\n ) {\n dictionary = dictionaryContent;\n } else {\n dictionary = getDictionaryOrUndefined(\n targetNamespace as DictionaryKeys,\n resolvedLocale\n );\n\n // i18next's default namespace is `translation`, but a single-file JSON\n // source (no `{{key}}` segment) is loaded as the root `index` dictionary.\n // When the *default* namespace is not itself a registered dictionary, fall\n // back to `index` so `t('login.heroSubtitle')` resolves against the\n // whole-file dictionary. Explicit `ns:` prefixes / `ns` options never fall\n // back, so a genuinely missing namespace still returns `undefined`.\n if (\n dictionary === undefined &&\n targetNamespace === namespace &&\n targetNamespace !== ROOT_DICTIONARY_KEY\n ) {\n dictionary = getDictionaryOrUndefined(\n ROOT_DICTIONARY_KEY as DictionaryKeys,\n resolvedLocale\n );\n }\n\n if (dictionary === undefined) return undefined;\n }\n\n let resolvedValue: unknown;\n for (const candidate of buildKeyCandidates(\n path,\n (options?.lng as string) ?? (locale as string),\n count,\n context,\n ordinal\n )) {\n const value = navigatePath(dictionary, candidate, keySeparator);\n if (value !== null && value !== undefined) {\n resolvedValue = value;\n break;\n }\n }\n\n if (resolvedValue === null || resolvedValue === undefined) return undefined;\n\n // `returnObjects: true` — return the raw subtree\n if (\n options?.returnObjects &&\n typeof resolvedValue === 'object' &&\n resolvedValue !== null\n ) {\n return resolvedValue;\n }\n\n const values = getInterpolationValues(options);\n\n let resolved = resolveMessage(\n resolvedValue,\n values,\n ((options?.lng as string) ?? locale) as LocalesValues,\n 'i18next'\n );\n\n // `$t(key)` nesting\n if (depth < MAX_NESTING_DEPTH && resolved.includes('$t(')) {\n resolved = resolved.replace(\n /\\$t\\(\\s*([^),]+?)\\s*(?:,[^)]*)?\\)/g,\n (match, nestedKey: string) => {\n const nestedValue = resolveTranslation({\n locale,\n namespace: targetNamespace,\n key: nestedKey.trim(),\n options,\n keySeparator,\n nsSeparator,\n depth: depth + 1,\n dictionaryContent:\n targetNamespace === namespace ? dictionaryContent : undefined,\n });\n return typeof nestedValue === 'string' ? nestedValue : match;\n }\n );\n }\n\n return resolved;\n};\n"],"mappings":"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"}
File without changes
@@ -1,11 +1,7 @@
1
- import { ValidDotPathsFor } from "@intlayer/core/transpiler";
2
- import { DictionaryKeys } from "@intlayer/types/module_augmentation";
3
- import { TOptions, createInstance as createInstance$1 } from "i18next";
4
-
1
+ import { TypedGetFixedT } from "./typedTranslation.js";
2
+ import { createInstance as createInstance$1 } from "i18next";
5
3
  //#region src/createInstance.d.ts
6
4
  declare const createInstance: typeof createInstance$1;
7
- /** Typed variant of i18next's `getFixedT`, scoped to an intlayer dictionary namespace. */
8
- type TypedGetFixedT = <N extends DictionaryKeys>(lng: string | readonly string[] | null, ns?: N | null, keyPrefix?: string) => <P extends ValidDotPathsFor<N>>(key: P, opts?: TOptions) => string;
9
5
  //#endregion
10
- export { TypedGetFixedT, createInstance };
6
+ export { type TypedGetFixedT, createInstance };
11
7
  //# sourceMappingURL=createInstance.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createInstance.d.ts","names":[],"sources":["../../src/createInstance.ts"],"mappings":";;;;;cA8Ca,cAAA,SAAuB,gBAyTnC;;KAGW,cAAA,cAA4B,cAAA,EACtC,GAAA,qCACA,EAAA,GAAK,CAAA,SACL,SAAA,yBACc,gBAAA,CAAiB,CAAA,GAAI,GAAA,EAAK,CAAA,EAAG,IAAA,GAAO,QAAA"}
1
+ {"version":3,"file":"createInstance.d.ts","names":[],"sources":["../../src/createInstance.ts"],"mappings":";;;cAgCa,uBAAuB"}
@@ -0,0 +1,33 @@
1
+ import { ScopedTFunction, TypedTFunction } from "./typedTranslation.js";
2
+ import { DictionaryKeys, LocalesValues } from "@intlayer/types/module_augmentation";
3
+ import { Dictionary } from "@intlayer/types/dictionary";
4
+ //#region src/getDictionary.d.ts
5
+ /**
6
+ * Overload set for {@link getDictionary}: without a key prefix the returned
7
+ * `t()` is typed against the dictionary's dot-paths; with a prefix the keys
8
+ * are relative dot-paths under that scope.
9
+ */
10
+ type GetDictionary = {
11
+ <T extends Dictionary>(dictionary: T, locale?: LocalesValues): TypedTFunction<T['key'] & DictionaryKeys>;
12
+ <T extends Dictionary, Prefix extends string>(dictionary: T, locale: LocalesValues | undefined, keyPrefix: Prefix): ScopedTFunction<T['key'] & DictionaryKeys, Prefix>;
13
+ };
14
+ /**
15
+ * Dictionary-accepting variant of `getFixedT`.
16
+ *
17
+ * Used by the build-time optimization (and available for manual use): instead
18
+ * of resolving the namespace from the runtime registry, the dictionary is
19
+ * supplied directly — enabling tree-shaking of unused locale content.
20
+ *
21
+ * The returned `t()` matches the fixed translator produced by
22
+ * `getFixedT(lng, ns, keyPrefix)`: plural and context suffixes, `$t()`
23
+ * nesting, `defaultValue` and `{{var}}` interpolation are all supported.
24
+ *
25
+ * @example
26
+ * import aboutDictionary from './about.content';
27
+ * const t = getDictionary(aboutDictionary, 'fr');
28
+ * t('counter.label');
29
+ */
30
+ declare const getDictionary: GetDictionary;
31
+ //#endregion
32
+ export { getDictionary };
33
+ //# sourceMappingURL=getDictionary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getDictionary.d.ts","names":[],"sources":["../../src/getDictionary.ts"],"mappings":";;;;;;;;;KAgBK;GACF,UAAU,YACT,YAAY,GACZ,SAAS,gBACR,eAAe,WAAW;GAC5B,UAAU,YAAY,uBACrB,YAAY,GACZ,QAAQ,2BACR,WAAW,SACV,gBAAgB,WAAW,gBAAgB;;;;;;;;;;;;;;;;;;cAmBnC,eAmBP"}
@@ -0,0 +1,28 @@
1
+ import { ScopedTFunction, TypedTFunction } from "./typedTranslation.js";
2
+ import { DictionaryKeys, LocalesValues, StrictModeLocaleMap } from "@intlayer/types/module_augmentation";
3
+ import { Dictionary } from "@intlayer/types/dictionary";
4
+ //#region src/getDictionaryDynamic.d.ts
5
+ /**
6
+ * Overload set for {@link getDictionaryDynamic}: without a key prefix the
7
+ * returned `t()` is typed against the dictionary's dot-paths; with a prefix
8
+ * the keys are relative dot-paths under that scope.
9
+ */
10
+ type GetDictionaryDynamic = {
11
+ <T extends Dictionary, K extends DictionaryKeys>(dictionaryPromise: StrictModeLocaleMap<() => Promise<T>>, key: K, locale?: LocalesValues): Promise<TypedTFunction<K>>;
12
+ <T extends Dictionary, K extends DictionaryKeys, Prefix extends string>(dictionaryPromise: StrictModeLocaleMap<() => Promise<T>>, key: K, locale: LocalesValues | undefined, keyPrefix: Prefix): Promise<ScopedTFunction<K, Prefix>>;
13
+ };
14
+ /**
15
+ * Dynamic dictionary-accepting variant of `getFixedT`.
16
+ *
17
+ * Counterpart to {@link getDictionary} for dictionaries imported lazily per
18
+ * locale: only the JSON of the resolved locale is loaded. Returns a promise
19
+ * of the fixed `t()` function.
20
+ *
21
+ * @example
22
+ * const t = await getDictionaryDynamic(aboutLoaders, 'about', 'fr');
23
+ * t('counter.label');
24
+ */
25
+ declare const getDictionaryDynamic: GetDictionaryDynamic;
26
+ //#endregion
27
+ export { getDictionaryDynamic };
28
+ //# sourceMappingURL=getDictionaryDynamic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getDictionaryDynamic.d.ts","names":[],"sources":["../../src/getDictionaryDynamic.ts"],"mappings":";;;;;;;;;KAiBK;GACF,UAAU,YAAY,UAAU,gBAC/B,mBAAmB,0BAA0B,QAAQ,KACrD,KAAK,GACL,SAAS,gBACR,QAAQ,eAAe;GACzB,UAAU,YAAY,UAAU,gBAAgB,uBAC/C,mBAAmB,0BAA0B,QAAQ,KACrD,KAAK,GACL,QAAQ,2BACR,WAAW,SACV,QAAQ,gBAAgB,GAAG;;;;;;;;;;;;;cAcnB,sBA6BP"}
@@ -1,7 +1,9 @@
1
- import { TypedGetFixedT, createInstance } from "./createInstance.js";
1
+ import { ContentAtPath, ScopedDotPaths, ScopedTFunction, TranslatedValue, TypedGetFixedT, TypedTFunction } from "./typedTranslation.js";
2
+ import { createInstance } from "./createInstance.js";
3
+ import { getDictionary } from "./getDictionary.js";
4
+ import { getDictionaryDynamic } from "./getDictionaryDynamic.js";
2
5
  import { ResolveTranslationParams, getInterpolationValues, resolveTranslation } from "./resolveTranslation.js";
3
6
  import { InitOptions, TFunction, TOptions, changeLanguage as changeLanguage$1, dir as dir$1, exists as exists$1, hasLoadedNamespace as hasLoadedNamespace$1, i18n, i18n as i18n$1, init as init$1, loadLanguages as loadLanguages$1, loadNamespaces as loadNamespaces$1, loadResources as loadResources$1, reloadResources as reloadResources$1, setDefaultNamespace as setDefaultNamespace$1, t as t$1, use as use$1 } from "i18next";
4
-
5
7
  //#region src/index.d.ts
6
8
  declare const i18next: i18n$1;
7
9
  declare const dir: typeof dir$1;
@@ -36,5 +38,5 @@ declare const loadLanguages: typeof loadLanguages$1;
36
38
  */
37
39
  declare const keyFromSelector: (selector: unknown) => unknown;
38
40
  //#endregion
39
- export { type InitOptions, type ResolveTranslationParams, type TFunction, type TOptions, changeLanguage, createInstance, i18next as default, i18next, dir, exists, getFixedT, getInterpolationValues, hasLoadedNamespace, type i18n, init, keyFromSelector, loadLanguages, loadNamespaces, loadResources, reloadResources, resolveTranslation, setDefaultNamespace, t, use };
41
+ export { type ContentAtPath, type InitOptions, type ResolveTranslationParams, type ScopedDotPaths, type ScopedTFunction, type TFunction, type TOptions, type TranslatedValue, type TypedGetFixedT, type TypedTFunction, changeLanguage, createInstance, i18next as default, i18next, dir, exists, getDictionary, getDictionaryDynamic, getFixedT, getInterpolationValues, hasLoadedNamespace, type i18n, init, keyFromSelector, loadLanguages, loadNamespaces, loadResources, reloadResources, resolveTranslation, setDefaultNamespace, t, use };
40
42
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/index.ts"],"mappings":";;;;;cAuBM,OAAA,EAAS,MAAuB;AAAA,cAMzB,GAAA,SAAY,KAAgC;AAAA,cAC5C,IAAA,SAAa,MAAkC;AAAA,cAC/C,aAAA,SAAsB,eACE;AAAA,cACxB,eAAA,SAAwB,iBACE;AAAA,cAC1B,GAAA,SAAY,KAAgC;AAAA,cAC5C,cAAA,SAAuB,gBACE;;AARmB;AACzD;;;;AAA4D;AAC5D;;;;AACqC;cAmBxB,SAAA,EAAW,cAEL;AAAA,cAEN,CAAA,SAAU,GAA4B;AAAA,cACtC,MAAA,SAAe,QAAsC;AAAA,cACrD,mBAAA,SAA4B,qBACE;AAAA,cAC9B,kBAAA,SAA2B,oBACE;AAAA,cAC7B,cAAA,SAAuB,gBACE;AAAA,cACzB,aAAA,SAAsB,eACE;;;AA7BoB;AACzD;;cAmCa,eAAA,GAAmB,QAAiB"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/index.ts"],"mappings":";;;;;;;cAiCM,SAAS;cAMF,YAAY;cACZ,aAAa;cACb,sBAAsB;cAEtB,wBAAwB;cAExB,YAAY;cACZ,uBAAuB;;;;;;;;;;;;;cAevB,WAAW;cAIX,UAAU;cACV,eAAe;cACf,4BAA4B;cAE5B,2BAA2B;cAE3B,uBAAuB;cAEvB,sBAAsB;;;;;;cAQtB,kBAAe"}
@@ -1,6 +1,5 @@
1
1
  import { PluginOption } from "vite";
2
2
  import { intlayer } from "vite-intlayer";
3
-
4
3
  //#region src/plugin/index.d.ts
5
4
  declare const i18nextVitePlugin: (options?: Parameters<typeof intlayer>[0]) => PluginOption[];
6
5
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/plugin/index.ts"],"mappings":";;;;cA8Ca,iBAAA,GACX,OAAA,GAAU,UAAA,QAAkB,QAAA,SAC3B,YAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/plugin/index.ts"],"mappings":";;;cASa,oBAAiB,UAClB,kBAAkB,iBAC3B"}
@@ -1,18 +1,35 @@
1
- import { LocalesValues } from "@intlayer/types/module_augmentation";
2
1
  import { TOptions } from "i18next";
2
+ import { LocalesValues } from "@intlayer/types/module_augmentation";
3
3
  import { MessageValues } from "@intlayer/core/messageFormat";
4
-
5
4
  //#region src/resolveTranslation.d.ts
6
5
  /** Extracts interpolation values from i18next `t()` options. */
7
6
  declare const getInterpolationValues: (options?: TOptions) => MessageValues;
8
7
  type ResolveTranslationParams = {
9
- /** Locale to resolve against. */locale: LocalesValues; /** Default namespace (dictionary key) when the key has no `ns:` prefix. */
10
- namespace: string; /** The translation key, possibly `ns:path.to.key`. */
11
- key: string; /** i18next `t()` options (interpolation values, count, context, …). */
12
- options?: TOptions; /** Custom key separator (`init({ keySeparator })`). */
13
- keySeparator?: string | false; /** Custom namespace separator (`init({ nsSeparator })`). */
14
- nsSeparator?: string | false; /** Internal `$t()` nesting recursion depth. */
8
+ /** Locale to resolve against. */
9
+ locale: LocalesValues;
10
+ /** Default namespace (dictionary key) when the key has no `ns:` prefix. */
11
+ namespace: string;
12
+ /** The translation key, possibly `ns:path.to.key`. */
13
+ key: string;
14
+ /** i18next `t()` options (interpolation values, count, context, …). */
15
+ options?: TOptions;
16
+ /** Custom key separator (`init({ keySeparator })`). */
17
+ keySeparator?: string | false;
18
+ /** Custom namespace separator (`init({ nsSeparator })`). */
19
+ nsSeparator?: string | false;
20
+ /** Internal `$t()` nesting recursion depth. */
15
21
  depth?: number;
22
+ /**
23
+ * Pre-resolved content of the `namespace` dictionary for `locale`.
24
+ *
25
+ * Supplied by the build-optimized `useDictionary` / `getDictionary`
26
+ * variants, where the dictionary is imported at build time instead of read
27
+ * from the runtime registry. Only used when the call resolves to the
28
+ * default `namespace` without a locale override — cross-namespace
29
+ * (`other:key`, `{ ns }`) and `{ lng }` lookups still go through
30
+ * `getIntlayer`.
31
+ */
32
+ dictionaryContent?: unknown;
16
33
  };
17
34
  /**
18
35
  * Resolves a single translation key the i18next way against intlayer
@@ -23,15 +40,7 @@ type ResolveTranslationParams = {
23
40
  * cannot be resolved (caller decides between `defaultValue`, fallback keys
24
41
  * and key echo).
25
42
  */
26
- declare const resolveTranslation: ({
27
- locale,
28
- namespace,
29
- key,
30
- options,
31
- keySeparator,
32
- nsSeparator,
33
- depth
34
- }: ResolveTranslationParams) => unknown;
43
+ declare const resolveTranslation: ({ locale, namespace, key, options, keySeparator, nsSeparator, depth, dictionaryContent }: ResolveTranslationParams) => unknown;
35
44
  //#endregion
36
45
  export { ResolveTranslationParams, getInterpolationValues, resolveTranslation };
37
46
  //# sourceMappingURL=resolveTranslation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolveTranslation.d.ts","names":[],"sources":["../../src/resolveTranslation.ts"],"mappings":";;;;;;cAkIa,sBAAA,GAA0B,OAAA,GAAU,QAAA,KAAW,aAiB3D;AAAA,KAEW,wBAAA;EAFX,iCAIC,MAAA,EAAQ,aAAA,EAJT;EAMC,SAAA,UAvBqC;EAyBrC,GAAA,UARD;EAUC,OAAA,GAAU,QAAQ,EARR;EAUV,YAAA;EAEA,WAAA,mBAVA;EAYA,KAAA;AAAA;;;;;;;;AAAK;AAYP;cAAa,kBAAA;EAAsB,MAAA;EAAA,SAAA;EAAA,GAAA;EAAA,OAAA;EAAA,YAAA;EAAA,WAAA;EAAA;AAAA,GAQhC,wBAAA"}
1
+ {"version":3,"file":"resolveTranslation.d.ts","names":[],"sources":["../../src/resolveTranslation.ts"],"mappings":";;;;;cAuHa,yBAAsB,UAAc,aAAW;KAmBhD;;EAEV,QAAQ;;EAER;;EAEA;;EAEA,UAAU;;EAEV;;EAEA;;EAEA;;;;;;;;;;;EAWA;;;;;;;;;;;cAYW,uBAAkB,QAAA,WAAA,KAAA,SAAA,cAAA,aAAA,OAAA,qBAS5B"}
@@ -0,0 +1,60 @@
1
+ import { TOptions } from "i18next";
2
+ import { GetNestingResult } from "@intlayer/core/interpreter";
3
+ import { ValidDotPathsFor } from "@intlayer/core/transpiler";
4
+ import { DictionaryKeys } from "@intlayer/types/module_augmentation";
5
+ //#region src/typedTranslation.d.ts
6
+ /**
7
+ * The interpreter-resolved content type at dot-path `P` of dictionary `N` —
8
+ * the same type strength as the base `useIntlayer` hook.
9
+ */
10
+ type ContentAtPath<N extends DictionaryKeys, P> = GetNestingResult<N, P>;
11
+ /**
12
+ * The value returned by `t()` for key `P` of dictionary `N`: string literals
13
+ * declared in the dictionary keep their literal type (matching the strength of
14
+ * `useIntlayer`), every other node resolves to `string` at runtime.
15
+ */
16
+ type TranslatedValue<N extends DictionaryKeys, P> = ContentAtPath<N, P> extends string ? ContentAtPath<N, P> : string;
17
+ /**
18
+ * The dot-paths of dictionary `N` relative to the key prefix `Prefix`
19
+ * (`getFixedT(null, 'about', 'counter')` → paths under `about.counter`).
20
+ */
21
+ type ScopedDotPaths<N extends DictionaryKeys, Prefix extends string> = ValidDotPathsFor<N> extends (infer AllPaths) ? AllPaths extends `${Prefix}.${infer RelativePath}` ? RelativePath : never : never;
22
+ /**
23
+ * Fully-typed i18next `t()` bound to the dictionary namespace `N`.
24
+ *
25
+ * Keys are validated against the dictionary's dot-paths; the return type is
26
+ * resolved from the content at that path. With `returnObjects: true` the raw
27
+ * content subtree is returned instead of a string.
28
+ */
29
+ type TypedTFunction<N extends DictionaryKeys> = {
30
+ /** Returns the raw content subtree at `key` (i18next `returnObjects`). */
31
+ <P extends ValidDotPathsFor<N>>(key: P | P[], options: TOptions & {
32
+ returnObjects: true;
33
+ }): ContentAtPath<N, P>;
34
+ /** Translate a key, with optional default value and interpolation options. */
35
+ <P extends ValidDotPathsFor<N>>(key: P | P[], optionsOrDefaultValue?: TOptions | string, extraOptions?: TOptions): TranslatedValue<N, P>;
36
+ };
37
+ /**
38
+ * Fully-typed i18next `t()` bound to the dictionary namespace `N` and the key
39
+ * prefix `Prefix`: keys are relative dot-paths under the prefix, and return
40
+ * types are resolved against the absolute path in the dictionary.
41
+ */
42
+ type ScopedTFunction<N extends DictionaryKeys, Prefix extends string> = {
43
+ /** Returns the raw content subtree at `key` (i18next `returnObjects`). */
44
+ <P extends ScopedDotPaths<N, Prefix>>(key: P | P[], options: TOptions & {
45
+ returnObjects: true;
46
+ }): ContentAtPath<N, `${Prefix}.${P}`>;
47
+ /** Translate a scoped key, with optional default value and options. */
48
+ <P extends ScopedDotPaths<N, Prefix>>(key: P | P[], optionsOrDefaultValue?: TOptions | string, extraOptions?: TOptions): TranslatedValue<N, `${Prefix}.${P}`>;
49
+ };
50
+ /**
51
+ * Typed variant of i18next's `getFixedT`, scoped to an intlayer dictionary
52
+ * namespace. With a `keyPrefix`, keys become relative dot-paths under it.
53
+ */
54
+ type TypedGetFixedT = {
55
+ <N extends DictionaryKeys, Prefix extends string>(lng: string | readonly string[] | null, ns: N | null | undefined, keyPrefix: Prefix): ScopedTFunction<N, Prefix>;
56
+ <N extends DictionaryKeys>(lng: string | readonly string[] | null, ns?: N | null): TypedTFunction<N>;
57
+ };
58
+ //#endregion
59
+ export { ContentAtPath, ScopedDotPaths, ScopedTFunction, TranslatedValue, TypedGetFixedT, TypedTFunction };
60
+ //# sourceMappingURL=typedTranslation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typedTranslation.d.ts","names":[],"sources":["../../src/typedTranslation.ts"],"mappings":";;;;;;;;;KASY,cAAc,UAAU,gBAAgB,KAAK,iBAAiB,GAAG;;;;;;KAOjE,gBAAgB,UAAU,gBAAgB,KACpD,cAAc,GAAG,oBAAoB,cAAc,GAAG;;;;;KAM5C,eAAe,UAAU,gBAAgB,yBACnD,iBAAiB,kBAAiB,YAC9B,oBAAoB,gBAAgB,iBAClC;;;;;;;;KAWI,eAAe,UAAU;;GAElC,UAAU,iBAAiB,IAC1B,KAAK,IAAI,KACT,SAAS;IAAa;MACrB,cAAc,GAAG;;GAEnB,UAAU,iBAAiB,IAC1B,KAAK,IAAI,KACT,wBAAwB,mBACxB,eAAe,WACd,gBAAgB,GAAG;;;;;;;KAQZ,gBAAgB,UAAU,gBAAgB;;GAEnD,UAAU,eAAe,GAAG,SAC3B,KAAK,IAAI,KACT,SAAS;IAAa;MACrB,cAAc,MAAM,UAAU;;GAEhC,UAAU,eAAe,GAAG,SAC3B,KAAK,IAAI,KACT,wBAAwB,mBACxB,eAAe,WACd,gBAAgB,MAAM,UAAU;;;;;;KAOzB;GACT,UAAU,gBAAgB,uBACzB,wCACA,IAAI,sBACJ,WAAW,SACV,gBAAgB,GAAG;GACrB,UAAU,gBACT,wCACA,KAAK,WACJ,eAAe"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intlayer/i18next",
3
- "version": "9.0.0-canary.9",
3
+ "version": "9.0.0",
4
4
  "private": false,
5
5
  "description": "i18next API adapter for intlayer — drop-in compatibility layer that exposes the i18next interface while using @intlayer/core under the hood",
6
6
  "keywords": [
@@ -74,24 +74,24 @@
74
74
  "typecheck": "tsc --noEmit --project tsconfig.types.json"
75
75
  },
76
76
  "dependencies": {
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
- "vite-intlayer": "9.0.0-canary.9"
77
+ "@intlayer/config": "9.0.0",
78
+ "@intlayer/core": "9.0.0",
79
+ "@intlayer/dictionaries-entry": "9.0.0",
80
+ "@intlayer/engine": "9.0.0",
81
+ "@intlayer/types": "9.0.0",
82
+ "vite-intlayer": "9.0.0"
83
83
  },
84
84
  "devDependencies": {
85
- "@types/node": "25.9.4",
85
+ "@types/node": "26.1.1",
86
86
  "@utils/ts-config": "1.0.4",
87
87
  "@utils/ts-config-types": "1.0.4",
88
88
  "@utils/tsdown-config": "1.0.4",
89
- "i18next": "26.3.1",
89
+ "i18next": "26.3.6",
90
90
  "rimraf": "6.1.3",
91
- "tsdown": "0.22.2",
92
- "typescript": "6.0.3",
93
- "vite": "8.1.0",
94
- "vitest": "4.1.9"
91
+ "tsdown": "0.22.13",
92
+ "typescript": "7.0.2",
93
+ "vite": "8.1.5",
94
+ "vitest": "4.1.10"
95
95
  },
96
96
  "peerDependencies": {
97
97
  "i18next": ">=20.0.0",