@intlayer/core 9.0.0-canary.1 → 9.0.0-canary.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/cjs/dictionaryManipulator/index.cjs +1 -0
  2. package/dist/cjs/dictionaryManipulator/mergeQualifiedDictionaries.cjs +1 -5
  3. package/dist/cjs/dictionaryManipulator/mergeQualifiedDictionaries.cjs.map +1 -1
  4. package/dist/cjs/dictionaryManipulator/qualifiedDictionary.cjs +48 -74
  5. package/dist/cjs/dictionaryManipulator/qualifiedDictionary.cjs.map +1 -1
  6. package/dist/cjs/index.cjs +4 -0
  7. package/dist/cjs/interpreter/getContent/plugins.cjs +8 -8
  8. package/dist/cjs/interpreter/getContent/plugins.cjs.map +1 -1
  9. package/dist/cjs/interpreter/getDictionary.cjs +5 -5
  10. package/dist/cjs/interpreter/getDictionary.cjs.map +1 -1
  11. package/dist/cjs/interpreter/getIntlayer.cjs +8 -3
  12. package/dist/cjs/interpreter/getIntlayer.cjs.map +1 -1
  13. package/dist/cjs/localization/comparePaths.cjs +75 -0
  14. package/dist/cjs/localization/comparePaths.cjs.map +1 -0
  15. package/dist/cjs/localization/getLocalizedUrl.cjs +4 -4
  16. package/dist/cjs/localization/getLocalizedUrl.cjs.map +1 -1
  17. package/dist/cjs/localization/getPathWithoutLocale.cjs +2 -2
  18. package/dist/cjs/localization/getPathWithoutLocale.cjs.map +1 -1
  19. package/dist/cjs/localization/getPrefix.cjs +2 -2
  20. package/dist/cjs/localization/getPrefix.cjs.map +1 -1
  21. package/dist/cjs/localization/index.cjs +3 -0
  22. package/dist/cjs/localization/rewriteUtils.cjs +1 -1
  23. package/dist/cjs/localization/rewriteUtils.cjs.map +1 -1
  24. package/dist/cjs/localization/validatePrefix.cjs +2 -2
  25. package/dist/cjs/localization/validatePrefix.cjs.map +1 -1
  26. package/dist/cjs/utils/localeStorage.cjs +4 -4
  27. package/dist/cjs/utils/localeStorage.cjs.map +1 -1
  28. package/dist/esm/dictionaryManipulator/index.mjs +2 -2
  29. package/dist/esm/dictionaryManipulator/mergeQualifiedDictionaries.mjs +1 -5
  30. package/dist/esm/dictionaryManipulator/mergeQualifiedDictionaries.mjs.map +1 -1
  31. package/dist/esm/dictionaryManipulator/qualifiedDictionary.mjs +48 -75
  32. package/dist/esm/dictionaryManipulator/qualifiedDictionary.mjs.map +1 -1
  33. package/dist/esm/index.mjs +3 -2
  34. package/dist/esm/interpreter/getContent/plugins.mjs +8 -8
  35. package/dist/esm/interpreter/getContent/plugins.mjs.map +1 -1
  36. package/dist/esm/interpreter/getDictionary.mjs +5 -5
  37. package/dist/esm/interpreter/getDictionary.mjs.map +1 -1
  38. package/dist/esm/interpreter/getIntlayer.mjs +8 -3
  39. package/dist/esm/interpreter/getIntlayer.mjs.map +1 -1
  40. package/dist/esm/localization/comparePaths.mjs +73 -0
  41. package/dist/esm/localization/comparePaths.mjs.map +1 -0
  42. package/dist/esm/localization/getLocalizedUrl.mjs +4 -4
  43. package/dist/esm/localization/getLocalizedUrl.mjs.map +1 -1
  44. package/dist/esm/localization/getPathWithoutLocale.mjs +2 -2
  45. package/dist/esm/localization/getPathWithoutLocale.mjs.map +1 -1
  46. package/dist/esm/localization/getPrefix.mjs +2 -2
  47. package/dist/esm/localization/getPrefix.mjs.map +1 -1
  48. package/dist/esm/localization/index.mjs +2 -1
  49. package/dist/esm/localization/rewriteUtils.mjs +1 -1
  50. package/dist/esm/localization/rewriteUtils.mjs.map +1 -1
  51. package/dist/esm/localization/validatePrefix.mjs +2 -2
  52. package/dist/esm/localization/validatePrefix.mjs.map +1 -1
  53. package/dist/esm/utils/localeStorage.mjs +4 -4
  54. package/dist/esm/utils/localeStorage.mjs.map +1 -1
  55. package/dist/types/deepTransformPlugins/getFilterMissingTranslationsContent.d.ts +1 -2
  56. package/dist/types/deepTransformPlugins/getFilterTranslationsOnlyContent.d.ts +1 -2
  57. package/dist/types/deepTransformPlugins/getFilteredLocalesContent.d.ts +1 -2
  58. package/dist/types/dictionaryManipulator/index.d.ts +2 -2
  59. package/dist/types/dictionaryManipulator/mergeQualifiedDictionaries.d.ts +1 -1
  60. package/dist/types/dictionaryManipulator/mergeQualifiedDictionaries.d.ts.map +1 -1
  61. package/dist/types/dictionaryManipulator/qualifiedDictionary.d.ts +33 -20
  62. package/dist/types/dictionaryManipulator/qualifiedDictionary.d.ts.map +1 -1
  63. package/dist/types/index.d.ts +3 -2
  64. package/dist/types/interpreter/getDictionary.d.ts +5 -5
  65. package/dist/types/interpreter/getIntlayer.d.ts +1 -1
  66. package/dist/types/localization/comparePaths.d.ts +66 -0
  67. package/dist/types/localization/comparePaths.d.ts.map +1 -0
  68. package/dist/types/localization/index.d.ts +2 -1
  69. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"getPrefix.mjs","names":[],"sources":["../../../src/localization/getPrefix.ts"],"sourcesContent":["import { internationalization, routing } from '@intlayer/config/built';\nimport {\n DEFAULT_LOCALE,\n LOCALES,\n ROUTING_MODE,\n} from '@intlayer/config/defaultValues';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { RoutingConfig } from '@intlayer/types/config';\nimport type {\n DeclaredLocales,\n LocalesValues,\n ResolvedDefaultLocale,\n ResolvedRoutingMode,\n} from '@intlayer/types/module_augmentation';\n\n/**\n * Shared routing options used across all URL localization functions.\n */\nexport type RoutingOptions = {\n locales?: LocalesValues[];\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n rewrite?: RoutingConfig['rewrite'];\n domains?: RoutingConfig['domains'];\n /**\n * The hostname of the page currently being rendered (e.g. `'intlayer.org'`).\n * When provided, `getLocalizedUrl` returns a relative URL for locales whose\n * configured domain matches `currentDomain`, and an absolute URL only when\n * the target locale lives on a different domain.\n *\n * When omitted the function tries to infer it from:\n * 1. The domain of an absolute input URL.\n * 2. `window.location.hostname` in browser environments.\n * Falls back to always generating absolute URLs when neither is available.\n */\n currentDomain?: string;\n};\n\n/**\n * Resolves routing configuration by merging provided options with configuration defaults.\n * Single source of truth for default routing config resolution across all localization functions.\n */\nexport const resolveRoutingConfig = (\n options: RoutingOptions = {}\n): Omit<RoutingOptions, 'defaultLocale' | 'mode' | 'locales'> & {\n defaultLocale: LocalesValues;\n mode: RoutingConfig['mode'];\n locales: LocalesValues[];\n} => ({\n defaultLocale: internationalization?.defaultLocale ?? DEFAULT_LOCALE,\n mode: routing?.mode ?? ROUTING_MODE,\n locales: internationalization?.locales ?? LOCALES,\n rewrite: routing?.rewrite,\n domains: routing?.domains,\n ...options,\n});\n\nexport type GetPrefixOptions = {\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n};\n\nexport type GetPrefixResult = {\n /**\n * The locale path segment appended to `/`, with a trailing slash (e.g. `'fr/'`).\n * Empty string when no prefix is needed.\n */\n prefix: string;\n /**\n * The bare locale identifier (e.g. `'fr'`), or `undefined` when no prefix is applied.\n */\n localePrefix: Locale | undefined;\n};\n\n/**\n * Narrowed return type for {@link getPrefix} that carries the locale literal through.\n *\n * Distributes over union locales — calling `getPrefix('fr')` in `prefix-no-default`\n * mode with `defaultLocale = 'en'` resolves to `{ prefix: 'fr/'; localePrefix: 'fr' }`.\n *\n * Note: domain-based routing and \"locale not in locales\" edge cases may return an\n * empty result at runtime regardless of what this type reports.\n */\nexport type GetPrefixResultNarrowed<\n L extends LocalesValues | undefined,\n Mode extends string = ResolvedRoutingMode,\n Default extends LocalesValues = ResolvedDefaultLocale,\n> = L extends string\n ? [string] extends [L] // L is wide (string / LocalesValues) → distribute over declared locales\n ? GetPrefixResultNarrowed<DeclaredLocales, Mode, Default>\n : [string] extends [Mode]\n ? GetPrefixResult // mode is wide → fall back to generic result\n : Mode extends 'prefix-all'\n ? { prefix: `${L}/`; localePrefix: L }\n : Mode extends 'prefix-no-default'\n ? L extends Default\n ? { prefix: ''; localePrefix: undefined }\n : { prefix: `${L}/`; localePrefix: L }\n : { prefix: ''; localePrefix: undefined } // no-prefix / search-params\n : { prefix: ''; localePrefix: undefined }; // locale is undefined\n\n/**\n * Determines the URL prefix for a given locale based on the routing mode configuration.\n *\n * Example:\n *\n * ```ts\n * // prefix-no-default mode with default locale\n * getPrefix('en', { defaultLocale: 'en', mode: 'prefix-no-default' })\n * // Returns { prefix: '', localePrefix: undefined }\n *\n * // prefix-no-default mode with non-default locale\n * getPrefix('fr', { defaultLocale: 'en', mode: 'prefix-no-default' })\n * // Returns { prefix: '/fr', localePrefix: 'fr' }\n *\n * // prefix-all mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'prefix-all' })\n * // Returns { prefix: '/en', localePrefix: locale }\n *\n * // search-params mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'search-params' })\n * // Returns { prefix: '', localePrefix: undefined }\n *\n * // no-prefix mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'no-prefix' })\n * // Returns { prefix: '', localePrefix: undefined }\n * ```\n *\n * @param locale - The locale to check for prefix. If not provided, uses configured default locale.\n * @param options - Configuration options\n * @param options.defaultLocale - The default locale. Defaults to configured default locale.\n * @param options.mode - URL routing mode for locale handling. Defaults to configured mode.\n * @returns An object containing pathPrefix, prefix, and localePrefix for the given locale.\n */\nexport const getPrefix = <const L extends LocalesValues | undefined>(\n locale: L,\n options: RoutingOptions = {}\n): GetPrefixResultNarrowed<L> => {\n const { defaultLocale, mode, locales, domains } =\n resolveRoutingConfig(options);\n\n if (\n (process.env['INTLAYER_ROUTING_MODE'] &&\n process.env['INTLAYER_ROUTING_MODE'] !== 'prefix-all' &&\n process.env['INTLAYER_ROUTING_MODE'] !== 'prefix-no-default') ||\n !locale ||\n !locales.includes(locale)\n ) {\n return {\n prefix: '',\n localePrefix: undefined,\n } as GetPrefixResultNarrowed<L>;\n }\n\n // If this locale is the only one assigned to its domain, no URL prefix is needed\n // (the domain itself identifies the locale). Shared domains use normal prefix logic.\n if (process.env['INTLAYER_ROUTING_DOMAINS'] !== 'false' && domains) {\n const localeDomain = domains[locale as LocalesValues];\n\n if (localeDomain) {\n const localesOnSameDomain = Object.values(domains).filter(\n (domain) => domain === localeDomain\n ).length;\n\n if (localesOnSameDomain === 1) {\n return {\n prefix: '',\n localePrefix: undefined,\n } as GetPrefixResultNarrowed<L>;\n }\n }\n }\n\n // Handle prefix-based modes (prefix-all or prefix-no-default)\n const shouldPrefix =\n mode === 'prefix-all' ||\n (mode === 'prefix-no-default' && defaultLocale !== locale);\n\n if (shouldPrefix) {\n return {\n prefix: `${locale}/`,\n localePrefix: locale as Locale,\n } as GetPrefixResultNarrowed<L>;\n }\n\n return {\n prefix: '',\n localePrefix: undefined,\n } as GetPrefixResultNarrowed<L>;\n};\n"],"mappings":";;;;;;;;AA+CA,MAAa,wBACX,UAA0B,EAAE,MAKxB;CACJ,eAAe,sBAAsB,iBAAiB;CACtD,MAAM,SAAS,QAAQ;CACvB,SAAS,sBAAsB,WAAW;CAC1C,SAAS,SAAS;CAClB,SAAS,SAAS;CAClB,GAAG;CACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+ED,MAAa,aACX,QACA,UAA0B,EAAE,KACG;CAC/B,MAAM,EAAE,eAAe,MAAM,SAAS,YACpC,qBAAqB,QAAQ;AAE/B,KACG,QAAQ,IAAI,4BACX,QAAQ,IAAI,6BAA6B,gBACzC,QAAQ,IAAI,6BAA6B,uBAC3C,CAAC,UACD,CAAC,QAAQ,SAAS,OAAO,CAEzB,QAAO;EACL,QAAQ;EACR,cAAc;EACf;AAKH,KAAI,QAAQ,IAAI,gCAAgC,WAAW,SAAS;EAClE,MAAM,eAAe,QAAQ;AAE7B,MAAI,cAKF;OAJ4B,OAAO,OAAO,QAAQ,CAAC,QAChD,WAAW,WAAW,aACxB,CAAC,WAE0B,EAC1B,QAAO;IACL,QAAQ;IACR,cAAc;IACf;;;AAUP,KAHE,SAAS,gBACR,SAAS,uBAAuB,kBAAkB,OAGnD,QAAO;EACL,QAAQ,GAAG,OAAO;EAClB,cAAc;EACf;AAGH,QAAO;EACL,QAAQ;EACR,cAAc;EACf"}
1
+ {"version":3,"file":"getPrefix.mjs","names":[],"sources":["../../../src/localization/getPrefix.ts"],"sourcesContent":["import { internationalization, routing } from '@intlayer/config/built';\nimport {\n DEFAULT_LOCALE,\n LOCALES,\n ROUTING_MODE,\n} from '@intlayer/config/defaultValues';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { RoutingConfig } from '@intlayer/types/config';\nimport type {\n DeclaredLocales,\n LocalesValues,\n ResolvedDefaultLocale,\n ResolvedRoutingMode,\n} from '@intlayer/types/module_augmentation';\n\n/**\n * Shared routing options used across all URL localization functions.\n */\nexport type RoutingOptions = {\n locales?: LocalesValues[];\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n rewrite?: RoutingConfig['rewrite'];\n domains?: RoutingConfig['domains'];\n /**\n * The hostname of the page currently being rendered (e.g. `'intlayer.org'`).\n * When provided, `getLocalizedUrl` returns a relative URL for locales whose\n * configured domain matches `currentDomain`, and an absolute URL only when\n * the target locale lives on a different domain.\n *\n * When omitted the function tries to infer it from:\n * 1. The domain of an absolute input URL.\n * 2. `window.location.hostname` in browser environments.\n * Falls back to always generating absolute URLs when neither is available.\n */\n currentDomain?: string;\n};\n\n/**\n * Resolves routing configuration by merging provided options with configuration defaults.\n * Single source of truth for default routing config resolution across all localization functions.\n */\nexport const resolveRoutingConfig = (\n options: RoutingOptions = {}\n): Omit<RoutingOptions, 'defaultLocale' | 'mode' | 'locales'> & {\n defaultLocale: LocalesValues;\n mode: RoutingConfig['mode'];\n locales: LocalesValues[];\n} => ({\n defaultLocale: internationalization?.defaultLocale ?? DEFAULT_LOCALE,\n mode: routing?.mode ?? ROUTING_MODE,\n locales: internationalization?.locales ?? LOCALES,\n rewrite: routing?.rewrite,\n domains: routing?.domains,\n ...options,\n});\n\nexport type GetPrefixOptions = {\n defaultLocale?: LocalesValues;\n mode?: RoutingConfig['mode'];\n};\n\nexport type GetPrefixResult = {\n /**\n * The locale path segment appended to `/`, with a trailing slash (e.g. `'fr/'`).\n * Empty string when no prefix is needed.\n */\n prefix: string;\n /**\n * The bare locale identifier (e.g. `'fr'`), or `undefined` when no prefix is applied.\n */\n localePrefix: Locale | undefined;\n};\n\n/**\n * Narrowed return type for {@link getPrefix} that carries the locale literal through.\n *\n * Distributes over union locales — calling `getPrefix('fr')` in `prefix-no-default`\n * mode with `defaultLocale = 'en'` resolves to `{ prefix: 'fr/'; localePrefix: 'fr' }`.\n *\n * Note: domain-based routing and \"locale not in locales\" edge cases may return an\n * empty result at runtime regardless of what this type reports.\n */\nexport type GetPrefixResultNarrowed<\n L extends LocalesValues | undefined,\n Mode extends string = ResolvedRoutingMode,\n Default extends LocalesValues = ResolvedDefaultLocale,\n> = L extends string\n ? [string] extends [L] // L is wide (string / LocalesValues) → distribute over declared locales\n ? GetPrefixResultNarrowed<DeclaredLocales, Mode, Default>\n : [string] extends [Mode]\n ? GetPrefixResult // mode is wide → fall back to generic result\n : Mode extends 'prefix-all'\n ? { prefix: `${L}/`; localePrefix: L }\n : Mode extends 'prefix-no-default'\n ? L extends Default\n ? { prefix: ''; localePrefix: undefined }\n : { prefix: `${L}/`; localePrefix: L }\n : { prefix: ''; localePrefix: undefined } // no-prefix / search-params\n : { prefix: ''; localePrefix: undefined }; // locale is undefined\n\n/**\n * Determines the URL prefix for a given locale based on the routing mode configuration.\n *\n * Example:\n *\n * ```ts\n * // prefix-no-default mode with default locale\n * getPrefix('en', { defaultLocale: 'en', mode: 'prefix-no-default' })\n * // Returns { prefix: '', localePrefix: undefined }\n *\n * // prefix-no-default mode with non-default locale\n * getPrefix('fr', { defaultLocale: 'en', mode: 'prefix-no-default' })\n * // Returns { prefix: '/fr', localePrefix: 'fr' }\n *\n * // prefix-all mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'prefix-all' })\n * // Returns { prefix: '/en', localePrefix: locale }\n *\n * // search-params mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'search-params' })\n * // Returns { prefix: '', localePrefix: undefined }\n *\n * // no-prefix mode\n * getPrefix('en', { defaultLocale: 'en', mode: 'no-prefix' })\n * // Returns { prefix: '', localePrefix: undefined }\n * ```\n *\n * @param locale - The locale to check for prefix. If not provided, uses configured default locale.\n * @param options - Configuration options\n * @param options.defaultLocale - The default locale. Defaults to configured default locale.\n * @param options.mode - URL routing mode for locale handling. Defaults to configured mode.\n * @returns An object containing pathPrefix, prefix, and localePrefix for the given locale.\n */\nexport const getPrefix = <const L extends LocalesValues | undefined>(\n locale: L,\n options: RoutingOptions = {}\n): GetPrefixResultNarrowed<L> => {\n const { defaultLocale, mode, locales, domains } =\n resolveRoutingConfig(options);\n\n if (\n (process.env.INTLAYER_ROUTING_MODE &&\n process.env.INTLAYER_ROUTING_MODE !== 'prefix-all' &&\n process.env.INTLAYER_ROUTING_MODE !== 'prefix-no-default') ||\n !locale ||\n !locales.includes(locale)\n ) {\n return {\n prefix: '',\n localePrefix: undefined,\n } as GetPrefixResultNarrowed<L>;\n }\n\n // If this locale is the only one assigned to its domain, no URL prefix is needed\n // (the domain itself identifies the locale). Shared domains use normal prefix logic.\n if (process.env.INTLAYER_ROUTING_DOMAINS !== 'false' && domains) {\n const localeDomain = domains[locale as LocalesValues];\n\n if (localeDomain) {\n const localesOnSameDomain = Object.values(domains).filter(\n (domain) => domain === localeDomain\n ).length;\n\n if (localesOnSameDomain === 1) {\n return {\n prefix: '',\n localePrefix: undefined,\n } as GetPrefixResultNarrowed<L>;\n }\n }\n }\n\n // Handle prefix-based modes (prefix-all or prefix-no-default)\n const shouldPrefix =\n mode === 'prefix-all' ||\n (mode === 'prefix-no-default' && defaultLocale !== locale);\n\n if (shouldPrefix) {\n return {\n prefix: `${locale}/`,\n localePrefix: locale as Locale,\n } as GetPrefixResultNarrowed<L>;\n }\n\n return {\n prefix: '',\n localePrefix: undefined,\n } as GetPrefixResultNarrowed<L>;\n};\n"],"mappings":";;;;;;;;AA+CA,MAAa,wBACX,UAA0B,EAAE,MAKxB;CACJ,eAAe,sBAAsB,iBAAiB;CACtD,MAAM,SAAS,QAAQ;CACvB,SAAS,sBAAsB,WAAW;CAC1C,SAAS,SAAS;CAClB,SAAS,SAAS;CAClB,GAAG;CACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+ED,MAAa,aACX,QACA,UAA0B,EAAE,KACG;CAC/B,MAAM,EAAE,eAAe,MAAM,SAAS,YACpC,qBAAqB,QAAQ;AAE/B,KACG,QAAQ,IAAI,yBACX,QAAQ,IAAI,0BAA0B,gBACtC,QAAQ,IAAI,0BAA0B,uBACxC,CAAC,UACD,CAAC,QAAQ,SAAS,OAAO,CAEzB,QAAO;EACL,QAAQ;EACR,cAAc;EACf;AAKH,KAAI,QAAQ,IAAI,6BAA6B,WAAW,SAAS;EAC/D,MAAM,eAAe,QAAQ;AAE7B,MAAI,cAKF;OAJ4B,OAAO,OAAO,QAAQ,CAAC,QAChD,WAAW,WAAW,aACxB,CAAC,WAE0B,EAC1B,QAAO;IACL,QAAQ;IACR,cAAc;IACf;;;AAUP,KAHE,SAAS,gBACR,SAAS,uBAAuB,kBAAkB,OAGnD,QAAO;EACL,QAAQ,GAAG,OAAO;EAClB,cAAc;EACf;AAGH,QAAO;EACL,QAAQ;EACR,cAAc;EACf"}
@@ -1,4 +1,5 @@
1
1
  import { getPathWithoutLocale } from "./getPathWithoutLocale.mjs";
2
+ import { comparePaths, normalizePath } from "./comparePaths.mjs";
2
3
  import { getPrefix } from "./getPrefix.mjs";
3
4
  import { getCanonicalPath, getInternalPath, getLocalizedPath, getRewritePath, getRewriteRules } from "./rewriteUtils.mjs";
4
5
  import { getLocalizedUrl } from "./getLocalizedUrl.mjs";
@@ -15,4 +16,4 @@ import { getLocaleName } from "./getLocaleName.mjs";
15
16
  import { localeFlatMap, localeMap, localeRecord } from "./localeMapper.mjs";
16
17
  import { validatePrefix } from "./validatePrefix.mjs";
17
18
 
18
- export { generateSitemap, generateSitemapUrl, getBrowserLocale, getCanonicalPath, getHTMLTextDir, getInternalPath, getLocale, getLocaleFromPath, getLocaleLang, getLocaleName, getLocalizedPath, getLocalizedUrl, getMultilingualUrls, getPathWithoutLocale, getPrefix, getRewritePath, getRewriteRules, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, validatePrefix };
19
+ export { comparePaths, generateSitemap, generateSitemapUrl, getBrowserLocale, getCanonicalPath, getHTMLTextDir, getInternalPath, getLocale, getLocaleFromPath, getLocaleLang, getLocaleName, getLocalizedPath, getLocalizedUrl, getMultilingualUrls, getPathWithoutLocale, getPrefix, getRewritePath, getRewriteRules, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, normalizePath, validatePrefix };
@@ -3,7 +3,7 @@
3
3
  * True when rewrite rules are explicitly disabled at build time
4
4
  * (INTLAYER_ROUTING_REWRITE_RULES === 'false').
5
5
  */
6
- const TREE_SHAKE_REWRITE = process.env["INTLAYER_ROUTING_REWRITE_RULES"] === "false";
6
+ const TREE_SHAKE_REWRITE = process.env.INTLAYER_ROUTING_REWRITE_RULES === "false";
7
7
  /**
8
8
  * Normalizes legacy Record format or extracts specialized rules from RewriteObject.
9
9
  */
@@ -1 +1 @@
1
- {"version":3,"file":"rewriteUtils.mjs","names":[],"sources":["../../../src/localization/rewriteUtils.ts"],"sourcesContent":["// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\n/**\n * True when rewrite rules are explicitly disabled at build time\n * (INTLAYER_ROUTING_REWRITE_RULES === 'false').\n */\nconst TREE_SHAKE_REWRITE =\n process.env['INTLAYER_ROUTING_REWRITE_RULES'] === 'false';\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type {\n RewriteObject,\n RewriteRules,\n RoutingConfig,\n} from '@intlayer/types/config';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\n\nexport type LocalizedPathResult = {\n path: string;\n isRewritten: boolean;\n};\n\n/**\n * Normalizes legacy Record format or extracts specialized rules from RewriteObject.\n */\nexport const getRewriteRules = (\n rewrite: RoutingConfig['rewrite'],\n context: keyof RewriteObject = 'url'\n): RewriteRules | undefined => {\n if (!rewrite || TREE_SHAKE_REWRITE) return undefined;\n\n if ('url' in rewrite) {\n return (rewrite as RewriteObject)[context];\n }\n\n // Normalize legacy format\n return {\n rules: Object.entries(rewrite).map(([canonical, localized]) => ({\n // Normalize canonical path\n canonical: canonical.startsWith('/')\n ? canonical.replace(/\\[([^\\]]+)\\]/g, ':$1')\n : `/${canonical.replace(/\\[([^\\]]+)\\]/g, ':$1')}`,\n\n // Normalize localized path\n localized: Object.fromEntries(\n Object.entries(localized).map(([locale, pattern]) => {\n const normalizedPattern = pattern?.startsWith('/')\n ? pattern.replace(/\\[([^\\]]+)\\]/g, ':$1')\n : `/${(pattern || '').replace(/\\[([^\\]]+)\\]/g, ':$1')}`;\n return [locale, normalizedPattern];\n })\n ),\n })),\n };\n};\n\n/**\n * Converts normalized pattern to Regex.\n * Internal syntax supports:\n * - :param -> ([^/]+) (one segment)\n * - :param* -> (.*) (zero or more segments)\n * - :param+ -> (.+) (one or more segments)\n * - :param? -> ([^/]*) (zero or one segment)\n */\nconst patternToRegex = (pattern: string) => {\n const regexString = pattern\n .replace(/\\//g, '\\\\/') // Escape slashes\n .replace(/\\\\\\/:(?:[^/\\\\*+?]+)\\*/g, '(?:\\\\/(.*))?') // /:param*\n .replace(/\\\\\\/:(?:[^/\\\\*+?]+)\\?/g, '(?:\\\\/([^\\\\/]+))?') // /:param?\n .replace(/:([^/\\\\*+?]+)\\*/g, '(.*)') // :param* (if no leading slash)\n .replace(/:([^/\\\\*+?]+)\\?/g, '([^\\\\/]*)') // :param? (if no leading slash)\n .replace(/:([^/\\\\*+?]+)\\+/g, '(.+)') // :param+\n .replace(/:([^/\\\\*+?]+)/g, '([^\\\\/]+)'); // :param\n\n return new RegExp(`^${regexString}$`);\n};\n\n/**\n * Replaces route parameters in a path with provided values.\n */\nconst fillPath = (pattern: string, params: string[]) => {\n let index = 0;\n return (\n pattern\n .replace(/:([^/\\\\*+?]+)[*+?]?/g, () => params[index++] ?? '')\n .replace(/\\/+/g, '/')\n .replace(/\\/$/, '') || '/'\n );\n};\n\n/**\n * Extract values from a URL based on a pattern.\n */\nconst extractParams = (url: string, pattern: string): string[] | null => {\n const regex = patternToRegex(pattern);\n const match = url.match(regex);\n return match ? match.slice(1) : null;\n};\n\n/**\n * Given a localized URL (e.g., \"/produits/123\"), finds the canonical internal path (e.g., \"/products/123\").\n * If locale is provided, only check for that locale. Otherwise, check for all locales.\n */\nexport const getCanonicalPath = (\n localizedPath: string,\n locale?: Locale,\n rewriteRules?: RewriteRules\n): string => {\n if (!rewriteRules || TREE_SHAKE_REWRITE) return localizedPath;\n\n for (const rule of rewriteRules.rules) {\n const { canonical, localized } = rule;\n const localesToCheck = locale ? [locale] : Object.keys(localized);\n\n for (const loc of localesToCheck) {\n const localizedPattern = localized[loc as keyof typeof localized];\n\n if (!localizedPattern) continue;\n\n const params = extractParams(localizedPath, localizedPattern);\n\n if (params) {\n return fillPath(canonical, params);\n }\n }\n }\n\n return localizedPath;\n};\n\n/**\n * Given a canonical path (e.g., \"/products/123\"), finds the localized URL pattern (e.g., \"/produits/123\").\n */\nexport const getLocalizedPath = (\n canonicalPath: string,\n locale: LocalesValues,\n rewriteRules?: RewriteRules\n): LocalizedPathResult => {\n if (!rewriteRules || TREE_SHAKE_REWRITE)\n return { path: canonicalPath, isRewritten: false };\n\n for (const rule of rewriteRules.rules) {\n const { canonical, localized } = rule;\n\n // Check if the input path matches a configured canonical pattern\n const params = extractParams(canonicalPath, canonical);\n\n if (params) {\n const targetPattern = localized[locale as keyof typeof localized];\n\n if (targetPattern) {\n return {\n path: fillPath(targetPattern, params),\n isRewritten: true,\n };\n }\n }\n }\n\n return { path: canonicalPath, isRewritten: false };\n};\n\n/**\n * Returns the internal path for a given canonical path and locale.\n * Ensures the locale prefix is present exactly once.\n */\nexport const getInternalPath = (\n canonicalPath: string,\n locale: Locale\n): string => {\n const pathWithLeadingSlash = canonicalPath.startsWith('/')\n ? canonicalPath\n : `/${canonicalPath}`;\n\n if (\n pathWithLeadingSlash.startsWith(`/${locale}/`) ||\n pathWithLeadingSlash === `/${locale}`\n ) {\n return pathWithLeadingSlash;\n }\n\n return `/${locale}${pathWithLeadingSlash === '/' ? '' : pathWithLeadingSlash}`;\n};\n\n/**\n * Given a current pathname and locale, returns the pretty localized path if a rewrite rule exists and the path is not already localized.\n */\nexport const getRewritePath = (\n pathname: string,\n locale: Locale,\n rewrite?: RoutingConfig['rewrite']\n): string | undefined => {\n if (TREE_SHAKE_REWRITE) return undefined;\n const rules = getRewriteRules(rewrite, 'url');\n if (!rules) return undefined;\n\n // Identify canonical path (relative to root, no locale prefix expected in 'url' context)\n const canonicalPath = getCanonicalPath(pathname, undefined, rules);\n\n // Get the localized path for the current locale\n const { path: localizedPath, isRewritten } = getLocalizedPath(\n canonicalPath,\n locale,\n rules\n );\n\n if (isRewritten && localizedPath !== pathname) {\n return localizedPath;\n }\n\n return undefined;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"rewriteUtils.mjs","names":[],"sources":["../../../src/localization/rewriteUtils.ts"],"sourcesContent":["// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\n/**\n * True when rewrite rules are explicitly disabled at build time\n * (INTLAYER_ROUTING_REWRITE_RULES === 'false').\n */\nconst TREE_SHAKE_REWRITE =\n process.env.INTLAYER_ROUTING_REWRITE_RULES === 'false';\n\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type {\n RewriteObject,\n RewriteRules,\n RoutingConfig,\n} from '@intlayer/types/config';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\n\nexport type LocalizedPathResult = {\n path: string;\n isRewritten: boolean;\n};\n\n/**\n * Normalizes legacy Record format or extracts specialized rules from RewriteObject.\n */\nexport const getRewriteRules = (\n rewrite: RoutingConfig['rewrite'],\n context: keyof RewriteObject = 'url'\n): RewriteRules | undefined => {\n if (!rewrite || TREE_SHAKE_REWRITE) return undefined;\n\n if ('url' in rewrite) {\n return (rewrite as RewriteObject)[context];\n }\n\n // Normalize legacy format\n return {\n rules: Object.entries(rewrite).map(([canonical, localized]) => ({\n // Normalize canonical path\n canonical: canonical.startsWith('/')\n ? canonical.replace(/\\[([^\\]]+)\\]/g, ':$1')\n : `/${canonical.replace(/\\[([^\\]]+)\\]/g, ':$1')}`,\n\n // Normalize localized path\n localized: Object.fromEntries(\n Object.entries(localized).map(([locale, pattern]) => {\n const normalizedPattern = pattern?.startsWith('/')\n ? pattern.replace(/\\[([^\\]]+)\\]/g, ':$1')\n : `/${(pattern || '').replace(/\\[([^\\]]+)\\]/g, ':$1')}`;\n return [locale, normalizedPattern];\n })\n ),\n })),\n };\n};\n\n/**\n * Converts normalized pattern to Regex.\n * Internal syntax supports:\n * - :param -> ([^/]+) (one segment)\n * - :param* -> (.*) (zero or more segments)\n * - :param+ -> (.+) (one or more segments)\n * - :param? -> ([^/]*) (zero or one segment)\n */\nconst patternToRegex = (pattern: string) => {\n const regexString = pattern\n .replace(/\\//g, '\\\\/') // Escape slashes\n .replace(/\\\\\\/:(?:[^/\\\\*+?]+)\\*/g, '(?:\\\\/(.*))?') // /:param*\n .replace(/\\\\\\/:(?:[^/\\\\*+?]+)\\?/g, '(?:\\\\/([^\\\\/]+))?') // /:param?\n .replace(/:([^/\\\\*+?]+)\\*/g, '(.*)') // :param* (if no leading slash)\n .replace(/:([^/\\\\*+?]+)\\?/g, '([^\\\\/]*)') // :param? (if no leading slash)\n .replace(/:([^/\\\\*+?]+)\\+/g, '(.+)') // :param+\n .replace(/:([^/\\\\*+?]+)/g, '([^\\\\/]+)'); // :param\n\n return new RegExp(`^${regexString}$`);\n};\n\n/**\n * Replaces route parameters in a path with provided values.\n */\nconst fillPath = (pattern: string, params: string[]) => {\n let index = 0;\n return (\n pattern\n .replace(/:([^/\\\\*+?]+)[*+?]?/g, () => params[index++] ?? '')\n .replace(/\\/+/g, '/')\n .replace(/\\/$/, '') || '/'\n );\n};\n\n/**\n * Extract values from a URL based on a pattern.\n */\nconst extractParams = (url: string, pattern: string): string[] | null => {\n const regex = patternToRegex(pattern);\n const match = url.match(regex);\n return match ? match.slice(1) : null;\n};\n\n/**\n * Given a localized URL (e.g., \"/produits/123\"), finds the canonical internal path (e.g., \"/products/123\").\n * If locale is provided, only check for that locale. Otherwise, check for all locales.\n */\nexport const getCanonicalPath = (\n localizedPath: string,\n locale?: Locale,\n rewriteRules?: RewriteRules\n): string => {\n if (!rewriteRules || TREE_SHAKE_REWRITE) return localizedPath;\n\n for (const rule of rewriteRules.rules) {\n const { canonical, localized } = rule;\n const localesToCheck = locale ? [locale] : Object.keys(localized);\n\n for (const loc of localesToCheck) {\n const localizedPattern = localized[loc as keyof typeof localized];\n\n if (!localizedPattern) continue;\n\n const params = extractParams(localizedPath, localizedPattern);\n\n if (params) {\n return fillPath(canonical, params);\n }\n }\n }\n\n return localizedPath;\n};\n\n/**\n * Given a canonical path (e.g., \"/products/123\"), finds the localized URL pattern (e.g., \"/produits/123\").\n */\nexport const getLocalizedPath = (\n canonicalPath: string,\n locale: LocalesValues,\n rewriteRules?: RewriteRules\n): LocalizedPathResult => {\n if (!rewriteRules || TREE_SHAKE_REWRITE)\n return { path: canonicalPath, isRewritten: false };\n\n for (const rule of rewriteRules.rules) {\n const { canonical, localized } = rule;\n\n // Check if the input path matches a configured canonical pattern\n const params = extractParams(canonicalPath, canonical);\n\n if (params) {\n const targetPattern = localized[locale as keyof typeof localized];\n\n if (targetPattern) {\n return {\n path: fillPath(targetPattern, params),\n isRewritten: true,\n };\n }\n }\n }\n\n return { path: canonicalPath, isRewritten: false };\n};\n\n/**\n * Returns the internal path for a given canonical path and locale.\n * Ensures the locale prefix is present exactly once.\n */\nexport const getInternalPath = (\n canonicalPath: string,\n locale: Locale\n): string => {\n const pathWithLeadingSlash = canonicalPath.startsWith('/')\n ? canonicalPath\n : `/${canonicalPath}`;\n\n if (\n pathWithLeadingSlash.startsWith(`/${locale}/`) ||\n pathWithLeadingSlash === `/${locale}`\n ) {\n return pathWithLeadingSlash;\n }\n\n return `/${locale}${pathWithLeadingSlash === '/' ? '' : pathWithLeadingSlash}`;\n};\n\n/**\n * Given a current pathname and locale, returns the pretty localized path if a rewrite rule exists and the path is not already localized.\n */\nexport const getRewritePath = (\n pathname: string,\n locale: Locale,\n rewrite?: RoutingConfig['rewrite']\n): string | undefined => {\n if (TREE_SHAKE_REWRITE) return undefined;\n const rules = getRewriteRules(rewrite, 'url');\n if (!rules) return undefined;\n\n // Identify canonical path (relative to root, no locale prefix expected in 'url' context)\n const canonicalPath = getCanonicalPath(pathname, undefined, rules);\n\n // Get the localized path for the current locale\n const { path: localizedPath, isRewritten } = getLocalizedPath(\n canonicalPath,\n locale,\n rules\n );\n\n if (isRewritten && localizedPath !== pathname) {\n return localizedPath;\n }\n\n return undefined;\n};\n"],"mappings":"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"}
@@ -4,11 +4,11 @@ import { getPrefix, resolveRoutingConfig } from "./getPrefix.mjs";
4
4
  /**
5
5
  * True when the build-time routing mode is known and is NOT 'no-prefix'.
6
6
  */
7
- const TREE_SHAKE_NO_PREFIX = process.env["INTLAYER_ROUTING_MODE"] && process.env["INTLAYER_ROUTING_MODE"] !== "no-prefix";
7
+ const TREE_SHAKE_NO_PREFIX = process.env.INTLAYER_ROUTING_MODE && process.env.INTLAYER_ROUTING_MODE !== "no-prefix";
8
8
  /**
9
9
  * True when the build-time routing mode is known and is NOT 'search-params'.
10
10
  */
11
- const TREE_SHAKE_SEARCH_PARAMS = process.env["INTLAYER_ROUTING_MODE"] && process.env["INTLAYER_ROUTING_MODE"] !== "search-params";
11
+ const TREE_SHAKE_SEARCH_PARAMS = process.env.INTLAYER_ROUTING_MODE && process.env.INTLAYER_ROUTING_MODE !== "search-params";
12
12
  /**
13
13
  * Checks whether a given locale is valid based on the configured locales.
14
14
  *
@@ -1 +1 @@
1
- {"version":3,"file":"validatePrefix.mjs","names":[],"sources":["../../../src/localization/validatePrefix.ts"],"sourcesContent":["// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\n/**\n * True when the build-time routing mode is known and is NOT 'no-prefix'.\n */\nconst TREE_SHAKE_NO_PREFIX =\n process.env['INTLAYER_ROUTING_MODE'] &&\n process.env['INTLAYER_ROUTING_MODE'] !== 'no-prefix';\n\n/**\n * True when the build-time routing mode is known and is NOT 'search-params'.\n */\nconst TREE_SHAKE_SEARCH_PARAMS =\n process.env['INTLAYER_ROUTING_MODE'] &&\n process.env['INTLAYER_ROUTING_MODE'] !== 'search-params';\n\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport {\n getPrefix,\n type RoutingOptions,\n resolveRoutingConfig,\n} from './getPrefix';\n\nexport type ValidatePrefixResult = {\n isValid: boolean;\n localePrefix: string | undefined;\n};\n\n/**\n * Checks whether a given locale is valid based on the configured locales.\n *\n * @param locale - The locale value to validate. Can be `undefined` or `null`.\n * @param options - Optional configuration to override default settings.\n * @param options.locales - Array of valid locales. Defaults to the configured internationalization locales.\n * @param options.defaultLocale - The default locale to use as fallback. Defaults to the configured default locale.\n * @param options.mode - The routing mode (`'prefix'`, `'prefix-all'`, or `'no-prefix'`). Defaults to the configured routing mode.\n * @returns An object containing the validation result and the locale prefix.\n *\n * @example\n * // Check if 'en' is a valid locale\n * const { isValid, localePrefix } = validatePrefix('en');\n *\n * @example\n * // Check with custom options\n * const { isValid, localePrefix } = validatePrefix('fr', {\n * locales: ['en', 'fr', 'es'],\n * defaultLocale: 'en',\n * mode: 'prefix-all',\n * });\n */\nexport const validatePrefix = (\n locale: LocalesValues | undefined | null,\n options?: RoutingOptions\n): ValidatePrefixResult => {\n const { defaultLocale, mode, locales } = resolveRoutingConfig(options);\n\n if (\n (!TREE_SHAKE_NO_PREFIX && mode === 'no-prefix') ||\n (!TREE_SHAKE_SEARCH_PARAMS && mode === 'search-params')\n ) {\n return { isValid: true, localePrefix: undefined };\n }\n\n const { localePrefix } = getPrefix(locale || defaultLocale, {\n mode,\n locales,\n defaultLocale,\n });\n\n if (localePrefix === locale && locale === undefined) {\n return { isValid: true, localePrefix: undefined };\n }\n\n // A segment that doesn't match a locale code pattern (e.g. 'concept', 'compiler')\n // is a content slug from a default-locale URL, not an invalid locale attempt.\n if (locale && !/^[a-z]{2,3}(-[a-zA-Z]{2,4})?$/.test(locale)) {\n return { isValid: true, localePrefix: undefined };\n }\n\n const isValid = locales.some((localeEl) => localeEl === locale);\n\n return { isValid, localePrefix };\n};\n"],"mappings":";;;;;;AAOA,MAAM,uBACJ,QAAQ,IAAI,4BACZ,QAAQ,IAAI,6BAA6B;;;;AAK3C,MAAM,2BACJ,QAAQ,IAAI,4BACZ,QAAQ,IAAI,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;AAoC3C,MAAa,kBACX,QACA,YACyB;CACzB,MAAM,EAAE,eAAe,MAAM,YAAY,qBAAqB,QAAQ;AAEtE,KACG,CAAC,wBAAwB,SAAS,eAClC,CAAC,4BAA4B,SAAS,gBAEvC,QAAO;EAAE,SAAS;EAAM,cAAc;EAAW;CAGnD,MAAM,EAAE,iBAAiB,UAAU,UAAU,eAAe;EAC1D;EACA;EACA;EACD,CAAC;AAEF,KAAI,iBAAiB,UAAU,WAAW,OACxC,QAAO;EAAE,SAAS;EAAM,cAAc;EAAW;AAKnD,KAAI,UAAU,CAAC,gCAAgC,KAAK,OAAO,CACzD,QAAO;EAAE,SAAS;EAAM,cAAc;EAAW;AAKnD,QAAO;EAAE,SAFO,QAAQ,MAAM,aAAa,aAAa,OAExC;EAAE;EAAc"}
1
+ {"version":3,"file":"validatePrefix.mjs","names":[],"sources":["../../../src/localization/validatePrefix.ts"],"sourcesContent":["// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\n/**\n * True when the build-time routing mode is known and is NOT 'no-prefix'.\n */\nconst TREE_SHAKE_NO_PREFIX =\n process.env.INTLAYER_ROUTING_MODE &&\n process.env.INTLAYER_ROUTING_MODE !== 'no-prefix';\n\n/**\n * True when the build-time routing mode is known and is NOT 'search-params'.\n */\nconst TREE_SHAKE_SEARCH_PARAMS =\n process.env.INTLAYER_ROUTING_MODE &&\n process.env.INTLAYER_ROUTING_MODE !== 'search-params';\n\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport {\n getPrefix,\n type RoutingOptions,\n resolveRoutingConfig,\n} from './getPrefix';\n\nexport type ValidatePrefixResult = {\n isValid: boolean;\n localePrefix: string | undefined;\n};\n\n/**\n * Checks whether a given locale is valid based on the configured locales.\n *\n * @param locale - The locale value to validate. Can be `undefined` or `null`.\n * @param options - Optional configuration to override default settings.\n * @param options.locales - Array of valid locales. Defaults to the configured internationalization locales.\n * @param options.defaultLocale - The default locale to use as fallback. Defaults to the configured default locale.\n * @param options.mode - The routing mode (`'prefix'`, `'prefix-all'`, or `'no-prefix'`). Defaults to the configured routing mode.\n * @returns An object containing the validation result and the locale prefix.\n *\n * @example\n * // Check if 'en' is a valid locale\n * const { isValid, localePrefix } = validatePrefix('en');\n *\n * @example\n * // Check with custom options\n * const { isValid, localePrefix } = validatePrefix('fr', {\n * locales: ['en', 'fr', 'es'],\n * defaultLocale: 'en',\n * mode: 'prefix-all',\n * });\n */\nexport const validatePrefix = (\n locale: LocalesValues | undefined | null,\n options?: RoutingOptions\n): ValidatePrefixResult => {\n const { defaultLocale, mode, locales } = resolveRoutingConfig(options);\n\n if (\n (!TREE_SHAKE_NO_PREFIX && mode === 'no-prefix') ||\n (!TREE_SHAKE_SEARCH_PARAMS && mode === 'search-params')\n ) {\n return { isValid: true, localePrefix: undefined };\n }\n\n const { localePrefix } = getPrefix(locale || defaultLocale, {\n mode,\n locales,\n defaultLocale,\n });\n\n if (localePrefix === locale && locale === undefined) {\n return { isValid: true, localePrefix: undefined };\n }\n\n // A segment that doesn't match a locale code pattern (e.g. 'concept', 'compiler')\n // is a content slug from a default-locale URL, not an invalid locale attempt.\n if (locale && !/^[a-z]{2,3}(-[a-zA-Z]{2,4})?$/.test(locale)) {\n return { isValid: true, localePrefix: undefined };\n }\n\n const isValid = locales.some((localeEl) => localeEl === locale);\n\n return { isValid, localePrefix };\n};\n"],"mappings":";;;;;;AAOA,MAAM,uBACJ,QAAQ,IAAI,yBACZ,QAAQ,IAAI,0BAA0B;;;;AAKxC,MAAM,2BACJ,QAAQ,IAAI,yBACZ,QAAQ,IAAI,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;AAoCxC,MAAa,kBACX,QACA,YACyB;CACzB,MAAM,EAAE,eAAe,MAAM,YAAY,qBAAqB,QAAQ;AAEtE,KACG,CAAC,wBAAwB,SAAS,eAClC,CAAC,4BAA4B,SAAS,gBAEvC,QAAO;EAAE,SAAS;EAAM,cAAc;EAAW;CAGnD,MAAM,EAAE,iBAAiB,UAAU,UAAU,eAAe;EAC1D;EACA;EACA;EACD,CAAC;AAEF,KAAI,iBAAiB,UAAU,WAAW,OACxC,QAAO;EAAE,SAAS;EAAM,cAAc;EAAW;AAKnD,KAAI,UAAU,CAAC,gCAAgC,KAAK,OAAO,CACzD,QAAO;EAAE,SAAS;EAAM,cAAc;EAAW;AAKnD,QAAO;EAAE,SAFO,QAAQ,MAAM,aAAa,aAAa,OAExC;EAAE;EAAc"}
@@ -6,19 +6,19 @@ import { internationalization, routing } from "@intlayer/config/built";
6
6
  /**
7
7
  * True when cookie storage is explicitly disabled at build time.
8
8
  */
9
- const TREE_SHAKE_STORAGE_COOKIES = process.env["INTLAYER_ROUTING_STORAGE_COOKIES"] === "false";
9
+ const TREE_SHAKE_STORAGE_COOKIES = process.env.INTLAYER_ROUTING_STORAGE_COOKIES === "false";
10
10
  /**
11
11
  * True when localStorage is explicitly disabled at build time.
12
12
  */
13
- const TREE_SHAKE_STORAGE_LOCAL_STORAGE = process.env["INTLAYER_ROUTING_STORAGE_LOCALSTORAGE"] === "false";
13
+ const TREE_SHAKE_STORAGE_LOCAL_STORAGE = process.env.INTLAYER_ROUTING_STORAGE_LOCALSTORAGE === "false";
14
14
  /**
15
15
  * True when sessionStorage is explicitly disabled at build time.
16
16
  */
17
- const TREE_SHAKE_STORAGE_SESSION_STORAGE = process.env["INTLAYER_ROUTING_STORAGE_SESSIONSTORAGE"] === "false";
17
+ const TREE_SHAKE_STORAGE_SESSION_STORAGE = process.env.INTLAYER_ROUTING_STORAGE_SESSIONSTORAGE === "false";
18
18
  /**
19
19
  * True when header storage is explicitly disabled at build time.
20
20
  */
21
- const TREE_SHAKE_STORAGE_HEADERS = process.env["INTLAYER_ROUTING_STORAGE_HEADERS"] === "false";
21
+ const TREE_SHAKE_STORAGE_HEADERS = process.env.INTLAYER_ROUTING_STORAGE_HEADERS === "false";
22
22
  const localeStorageOptions = {
23
23
  getCookie: (name) => document.cookie.split(";").find((c) => c.trim().startsWith(`${name}=`))?.split("=")[1],
24
24
  getLocaleStorage: (name) => localStorage.getItem(name),
@@ -1 +1 @@
1
- {"version":3,"file":"localeStorage.mjs","names":[],"sources":["../../../src/utils/localeStorage.ts"],"sourcesContent":["import { internationalization, routing } from '@intlayer/config/built';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { buildCookieString, resolveExpiresToTimestamp } from './cookieExpiry';\nimport { getCookie } from './getCookie';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\n/**\n * True when cookie storage is explicitly disabled at build time.\n */\nconst TREE_SHAKE_STORAGE_COOKIES =\n process.env['INTLAYER_ROUTING_STORAGE_COOKIES'] === 'false';\n\n/**\n * True when localStorage is explicitly disabled at build time.\n */\nconst TREE_SHAKE_STORAGE_LOCAL_STORAGE =\n process.env['INTLAYER_ROUTING_STORAGE_LOCALSTORAGE'] === 'false';\n\n/**\n * True when sessionStorage is explicitly disabled at build time.\n */\nconst TREE_SHAKE_STORAGE_SESSION_STORAGE =\n process.env['INTLAYER_ROUTING_STORAGE_SESSIONSTORAGE'] === 'false';\n\n/**\n * True when header storage is explicitly disabled at build time.\n */\nconst TREE_SHAKE_STORAGE_HEADERS =\n process.env['INTLAYER_ROUTING_STORAGE_HEADERS'] === 'false';\n\n// ============================================================================\n// Shared types\n// ============================================================================\n\nexport type CookieBuildAttributes = {\n domain?: string;\n path?: string;\n secure?: boolean;\n httpOnly?: boolean;\n sameSite?: 'strict' | 'lax' | 'none';\n /**\n * Absolute expiry as milliseconds since epoch, ready for `cookieStore.set()`.\n * Already resolved from the normalized `expires` by\n * `resolveExpiresToTimestamp`.\n */\n expires?: number | undefined;\n};\n\n// ============================================================================\n// Client-specific types and functions\n// (cookies via browser APIs, localStorage, sessionStorage — no headers)\n// ============================================================================\n\nexport type LocaleStorageClientOptions = {\n overwrite?: boolean;\n isCookieEnabled?: boolean;\n setCookieStore?: (\n name: string,\n value: string,\n cookie: CookieBuildAttributes\n ) => void;\n setCookieString?: (name: string, cookie: string) => void;\n getCookie?: (name: string) => string | undefined | null;\n setSessionStorage?: (name: string, value: string) => void;\n getSessionStorage?: (name: string) => string | undefined | null;\n setLocaleStorage?: (name: string, value: string) => void;\n getLocaleStorage?: (name: string) => string | undefined | null;\n};\n\n// cookieStore is part of the experimental Cookie Store API\ndeclare const cookieStore: any;\n\nexport const localeStorageOptions: LocaleStorageClientOptions = {\n getCookie: (name: string) =>\n document.cookie\n .split(';')\n .find((c) => c.trim().startsWith(`${name}=`))\n ?.split('=')[1],\n getLocaleStorage: (name: string) => localStorage.getItem(name),\n getSessionStorage: (name: string) => sessionStorage.getItem(name),\n isCookieEnabled: true,\n setCookieStore: (name, value, attributes) =>\n cookieStore.set({\n name,\n value,\n path: attributes.path,\n domain: attributes.domain,\n expires: attributes.expires,\n sameSite: attributes.sameSite,\n }),\n setCookieString: (_name, cookie) => {\n // biome-ignore lint/suspicious/noDocumentCookie: set cookie fallback\n document.cookie = cookie;\n },\n setSessionStorage: (name, value) => sessionStorage.setItem(name, value),\n setLocaleStorage: (name, value) => localStorage.setItem(name, value),\n};\n\n/**\n * Retrieves the locale from browser storage mechanisms\n * (cookies, localStorage, sessionStorage).\n * Does not read from headers — use `getLocaleFromStorageServer` for that.\n */\nexport const getLocaleFromStorageClient = (\n options: LocaleStorageClientOptions = localeStorageOptions\n): Locale | undefined => {\n const { locales } = internationalization;\n\n if (options?.isCookieEnabled === false) return undefined;\n\n const isValidLocale = (value: string | null | undefined): value is Locale =>\n !!value && locales.includes(value as Locale);\n\n if (!TREE_SHAKE_STORAGE_COOKIES) {\n for (let i = 0; i < (routing.storage.cookies ?? []).length; i++) {\n try {\n const value = options?.getCookie?.(routing.storage.cookies![i].name);\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_LOCAL_STORAGE) {\n for (let i = 0; i < (routing.storage.localStorage ?? []).length; i++) {\n try {\n const value = options?.getLocaleStorage?.(\n routing.storage.localStorage![i].name\n );\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_SESSION_STORAGE && routing.storage.sessionStorage) {\n for (let i = 0; i < routing.storage.sessionStorage.length; i++) {\n try {\n const value = options?.getSessionStorage?.(\n routing.storage.sessionStorage[i].name\n );\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n};\n\n/**\n * Stores the locale in browser storage mechanisms\n * (cookies, localStorage, sessionStorage).\n * Does not write to headers — use `setLocaleInStorageServer` for that.\n */\nexport const setLocaleInStorageClient = (\n locale: LocalesValues,\n options?: LocaleStorageClientOptions\n): void => {\n if (options?.isCookieEnabled === false) return;\n\n if (!TREE_SHAKE_STORAGE_COOKIES && routing.storage.cookies) {\n for (let i = 0; i < routing.storage.cookies.length; i++) {\n const { name, attributes } = routing.storage.cookies[i];\n try {\n if (options?.setCookieStore) {\n options.setCookieStore(name, locale, {\n ...attributes,\n expires: resolveExpiresToTimestamp(attributes.expires),\n });\n }\n } catch {\n try {\n if (options?.setCookieString) {\n options.setCookieString(\n name,\n buildCookieString(name, locale, attributes)\n );\n }\n } catch {}\n }\n }\n }\n\n if (\n !TREE_SHAKE_STORAGE_LOCAL_STORAGE &&\n routing.storage.localStorage &&\n options?.setLocaleStorage\n ) {\n for (let i = 0; i < routing.storage.localStorage.length; i++) {\n const { name } = routing.storage.localStorage[i];\n try {\n if (!(options?.overwrite ?? true) && options?.getLocaleStorage) {\n if (options.getLocaleStorage(name)) continue;\n }\n options.setLocaleStorage(name, locale);\n } catch {}\n }\n }\n\n if (\n !TREE_SHAKE_STORAGE_SESSION_STORAGE &&\n routing.storage.sessionStorage &&\n options?.setSessionStorage\n ) {\n for (let i = 0; i < routing.storage.sessionStorage.length; i++) {\n const { name } = routing.storage.sessionStorage[i];\n try {\n if (!(options?.overwrite ?? true) && options?.getSessionStorage) {\n if (options.getSessionStorage(name)) continue;\n }\n options.setSessionStorage(name, locale);\n } catch {}\n }\n }\n};\n\n/**\n * Client-side locale storage utility.\n * Handles cookies (browser), localStorage and sessionStorage.\n * Does not access headers.\n *\n * @example\n * ```ts\n * const storage = LocaleStorageClient(localeStorageOptions);\n * const locale = storage.getLocale();\n * storage.setLocale('fr');\n * ```\n */\nexport const LocaleStorageClient = (options: LocaleStorageClientOptions) => ({\n getLocale: () => getLocaleFromStorageClient(options),\n setLocale: (locale: LocalesValues) =>\n setLocaleInStorageClient(locale, options),\n});\n\n// ============================================================================\n// Server-specific types and functions\n// (cookies via injected getter/setter, headers — no localStorage/sessionStorage)\n// ============================================================================\n\nexport type LocaleStorageServerOptions = {\n overwrite?: boolean;\n isCookieEnabled?: boolean;\n setCookieStore?: (\n name: string,\n value: string,\n cookie: CookieBuildAttributes\n ) => void;\n setCookieString?: (name: string, cookie: string) => void;\n getCookie?: (name: string) => string | undefined | null;\n getHeader?: (name: string) => string | undefined | null;\n setHeader?: (name: string, value: string) => void;\n};\n\n/**\n * Retrieves the locale from server-side storage mechanisms (cookies, headers).\n * Does not access localStorage or sessionStorage.\n * No browser cookie fallback — the caller must provide `getCookie`.\n */\nexport const getLocaleFromStorageServer = (\n options: LocaleStorageServerOptions\n): Locale | undefined => {\n const { locales } = internationalization;\n\n if (options?.isCookieEnabled === false) return undefined;\n\n const isValidLocale = (value: string | null | undefined): value is Locale =>\n !!value && locales.includes(value as Locale);\n\n if (!TREE_SHAKE_STORAGE_COOKIES && routing.storage.cookies) {\n for (let i = 0; i < routing.storage.cookies.length; i++) {\n try {\n const value = options?.getCookie?.(routing.storage.cookies[i].name);\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_HEADERS && routing.storage.headers) {\n for (let i = 0; i < routing.storage.headers.length; i++) {\n try {\n const value = options?.getHeader?.(routing.storage.headers[i].name);\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n};\n\n/**\n * Stores the locale in server-side storage mechanisms (cookies, headers).\n * Does not write to localStorage or sessionStorage.\n */\nexport const setLocaleInStorageServer = (\n locale: LocalesValues,\n options?: LocaleStorageServerOptions\n): void => {\n if (options?.isCookieEnabled === false) return;\n\n if (!TREE_SHAKE_STORAGE_COOKIES && routing.storage.cookies) {\n for (let i = 0; i < routing.storage.cookies.length; i++) {\n const { name, attributes } = routing.storage.cookies[i];\n\n try {\n if (options?.setCookieStore) {\n options.setCookieStore(name, locale, {\n ...attributes,\n expires: resolveExpiresToTimestamp(attributes.expires),\n });\n }\n } catch {\n try {\n if (options?.setCookieString) {\n options.setCookieString(\n name,\n buildCookieString(name, locale, attributes)\n );\n }\n } catch {}\n }\n }\n }\n\n if (\n !TREE_SHAKE_STORAGE_HEADERS &&\n routing.storage.headers &&\n options?.setHeader\n ) {\n for (let i = 0; i < routing.storage.headers.length; i++) {\n try {\n options.setHeader(routing.storage.headers[i].name, locale);\n } catch {}\n }\n }\n};\n\n/**\n * Server-side locale storage utility.\n * Handles cookies (via injected getter/setter) and headers.\n * Does not access localStorage or sessionStorage.\n *\n * @example\n * ```ts\n * const storage = LocaleStorageServer({\n * getCookie: (name) => req.cookies[name],\n * setCookieStore: (name, value, attrs) => res.cookie(name, value, attrs),\n * getHeader: (name) => req.headers[name],\n * setHeader: (name, value) => res.setHeader(name, value),\n * });\n * const locale = storage.getLocale();\n * storage.setLocale('fr');\n * ```\n */\nexport const LocaleStorageServer = (options: LocaleStorageServerOptions) => ({\n getLocale: () => getLocaleFromStorageServer(options),\n setLocale: (locale: LocalesValues) =>\n setLocaleInStorageServer(locale, options),\n});\n\n// ============================================================================\n// Deprecated: combined LocaleStorage\n// Use LocaleStorageClient or LocaleStorageServer instead\n// ============================================================================\n\n/**\n * @deprecated Use {@link LocaleStorageClientOptions} or {@link LocaleStorageServerOptions} instead.\n */\nexport type LocaleStorageOptions = LocaleStorageClientOptions &\n LocaleStorageServerOptions;\n\n/**\n * Retrieves the locale from all storage mechanisms\n * (cookies, localStorage, sessionStorage, headers).\n *\n * @deprecated Use {@link getLocaleFromStorageClient} (browser) or\n * {@link getLocaleFromStorageServer} (server) instead.\n */\nexport const getLocaleFromStorage = (\n options: Pick<\n LocaleStorageOptions,\n | 'getCookie'\n | 'getSessionStorage'\n | 'getLocaleStorage'\n | 'getHeader'\n | 'isCookieEnabled'\n >\n): Locale | undefined => {\n const { locales } = internationalization;\n\n if (options?.isCookieEnabled === false) return undefined;\n\n const isValidLocale = (value: string | null | undefined): value is Locale =>\n !!value && locales.includes(value as Locale);\n\n const readCookie = (name: string): string | undefined => {\n try {\n const fromOption = options?.getCookie?.(name);\n if (fromOption !== null && fromOption !== undefined) return fromOption;\n } catch {}\n // Browser fallback kept for backward compatibility\n return getCookie(name);\n };\n\n if (!TREE_SHAKE_STORAGE_COOKIES && routing.storage.cookies) {\n for (let i = 0; i < routing.storage.cookies.length; i++) {\n const value = readCookie(routing.storage.cookies[i].name);\n if (isValidLocale(value)) return value;\n }\n }\n\n if (!TREE_SHAKE_STORAGE_LOCAL_STORAGE && routing.storage.localStorage) {\n for (let i = 0; i < routing.storage.localStorage.length; i++) {\n try {\n const value = options?.getLocaleStorage?.(\n routing.storage.localStorage[i].name\n );\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_SESSION_STORAGE && routing.storage.sessionStorage) {\n for (let i = 0; i < routing.storage.sessionStorage.length; i++) {\n try {\n const value = options?.getSessionStorage?.(\n routing.storage.sessionStorage[i].name\n );\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_HEADERS && routing.storage.headers) {\n for (let i = 0; i < routing.storage.headers.length; i++) {\n try {\n const value = options?.getHeader?.(routing.storage.headers[i].name);\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n};\n\n/**\n * Stores the locale in all configured storage mechanisms\n * (cookies, localStorage, sessionStorage, headers).\n *\n * @deprecated Use {@link setLocaleInStorageClient} (browser) or\n * {@link setLocaleInStorageServer} (server) instead.\n */\nexport const setLocaleInStorage = (\n locale: LocalesValues,\n options?: LocaleStorageOptions\n): void => {\n if (options?.isCookieEnabled === false) return;\n\n if (!TREE_SHAKE_STORAGE_COOKIES && routing.storage.cookies) {\n for (let i = 0; i < routing.storage.cookies.length; i++) {\n const { name, attributes } = routing.storage.cookies[i];\n try {\n if (options?.setCookieStore) {\n options.setCookieStore(name, locale, {\n ...attributes,\n expires: resolveExpiresToTimestamp(attributes.expires),\n });\n }\n } catch {\n try {\n if (options?.setCookieString) {\n options.setCookieString(\n name,\n buildCookieString(name, locale, attributes)\n );\n }\n } catch {}\n }\n }\n }\n\n if (\n !TREE_SHAKE_STORAGE_LOCAL_STORAGE &&\n routing.storage.localStorage &&\n options?.setLocaleStorage\n ) {\n for (let i = 0; i < routing.storage.localStorage.length; i++) {\n const { name } = routing.storage.localStorage[i];\n try {\n if (!(options?.overwrite ?? true) && options?.getLocaleStorage) {\n if (options.getLocaleStorage(name)) continue;\n }\n options.setLocaleStorage(name, locale);\n } catch {}\n }\n }\n\n if (\n !TREE_SHAKE_STORAGE_SESSION_STORAGE &&\n routing.storage.sessionStorage &&\n options?.setSessionStorage\n ) {\n for (let i = 0; i < routing.storage.sessionStorage.length; i++) {\n const { name } = routing.storage.sessionStorage[i];\n try {\n if (!(options?.overwrite ?? true) && options?.getSessionStorage) {\n if (options.getSessionStorage(name)) continue;\n }\n options.setSessionStorage(name, locale);\n } catch {}\n }\n }\n\n if (\n !TREE_SHAKE_STORAGE_HEADERS &&\n routing.storage.headers &&\n options?.setHeader\n ) {\n for (let i = 0; i < routing.storage.headers.length; i++) {\n try {\n options.setHeader(routing.storage.headers[i].name, locale);\n } catch {}\n }\n }\n};\n\n/**\n * Utility object to get and set the locale in storage based on configuration.\n *\n * @deprecated Use {@link LocaleStorageClient} (browser) or\n * {@link LocaleStorageServer} (server) instead.\n */\nexport const LocaleStorage = (options: LocaleStorageOptions) => ({\n getLocale: () => getLocaleFromStorage(options),\n setLocale: (locale: LocalesValues) => setLocaleInStorage(locale, options),\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"localeStorage.mjs","names":[],"sources":["../../../src/utils/localeStorage.ts"],"sourcesContent":["import { internationalization, routing } from '@intlayer/config/built';\nimport type { Locale } from '@intlayer/types/allLocales';\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { buildCookieString, resolveExpiresToTimestamp } from './cookieExpiry';\nimport { getCookie } from './getCookie';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\n/**\n * True when cookie storage is explicitly disabled at build time.\n */\nconst TREE_SHAKE_STORAGE_COOKIES =\n process.env.INTLAYER_ROUTING_STORAGE_COOKIES === 'false';\n\n/**\n * True when localStorage is explicitly disabled at build time.\n */\nconst TREE_SHAKE_STORAGE_LOCAL_STORAGE =\n process.env.INTLAYER_ROUTING_STORAGE_LOCALSTORAGE === 'false';\n\n/**\n * True when sessionStorage is explicitly disabled at build time.\n */\nconst TREE_SHAKE_STORAGE_SESSION_STORAGE =\n process.env.INTLAYER_ROUTING_STORAGE_SESSIONSTORAGE === 'false';\n\n/**\n * True when header storage is explicitly disabled at build time.\n */\nconst TREE_SHAKE_STORAGE_HEADERS =\n process.env.INTLAYER_ROUTING_STORAGE_HEADERS === 'false';\n\n// ============================================================================\n// Shared types\n// ============================================================================\n\nexport type CookieBuildAttributes = {\n domain?: string;\n path?: string;\n secure?: boolean;\n httpOnly?: boolean;\n sameSite?: 'strict' | 'lax' | 'none';\n /**\n * Absolute expiry as milliseconds since epoch, ready for `cookieStore.set()`.\n * Already resolved from the normalized `expires` by\n * `resolveExpiresToTimestamp`.\n */\n expires?: number | undefined;\n};\n\n// ============================================================================\n// Client-specific types and functions\n// (cookies via browser APIs, localStorage, sessionStorage — no headers)\n// ============================================================================\n\nexport type LocaleStorageClientOptions = {\n overwrite?: boolean;\n isCookieEnabled?: boolean;\n setCookieStore?: (\n name: string,\n value: string,\n cookie: CookieBuildAttributes\n ) => void;\n setCookieString?: (name: string, cookie: string) => void;\n getCookie?: (name: string) => string | undefined | null;\n setSessionStorage?: (name: string, value: string) => void;\n getSessionStorage?: (name: string) => string | undefined | null;\n setLocaleStorage?: (name: string, value: string) => void;\n getLocaleStorage?: (name: string) => string | undefined | null;\n};\n\n// cookieStore is part of the experimental Cookie Store API\ndeclare const cookieStore: any;\n\nexport const localeStorageOptions: LocaleStorageClientOptions = {\n getCookie: (name: string) =>\n document.cookie\n .split(';')\n .find((c) => c.trim().startsWith(`${name}=`))\n ?.split('=')[1],\n getLocaleStorage: (name: string) => localStorage.getItem(name),\n getSessionStorage: (name: string) => sessionStorage.getItem(name),\n isCookieEnabled: true,\n setCookieStore: (name, value, attributes) =>\n cookieStore.set({\n name,\n value,\n path: attributes.path,\n domain: attributes.domain,\n expires: attributes.expires,\n sameSite: attributes.sameSite,\n }),\n setCookieString: (_name, cookie) => {\n // biome-ignore lint/suspicious/noDocumentCookie: set cookie fallback\n document.cookie = cookie;\n },\n setSessionStorage: (name, value) => sessionStorage.setItem(name, value),\n setLocaleStorage: (name, value) => localStorage.setItem(name, value),\n};\n\n/**\n * Retrieves the locale from browser storage mechanisms\n * (cookies, localStorage, sessionStorage).\n * Does not read from headers — use `getLocaleFromStorageServer` for that.\n */\nexport const getLocaleFromStorageClient = (\n options: LocaleStorageClientOptions = localeStorageOptions\n): Locale | undefined => {\n const { locales } = internationalization;\n\n if (options?.isCookieEnabled === false) return undefined;\n\n const isValidLocale = (value: string | null | undefined): value is Locale =>\n !!value && locales.includes(value as Locale);\n\n if (!TREE_SHAKE_STORAGE_COOKIES) {\n for (let i = 0; i < (routing.storage.cookies ?? []).length; i++) {\n try {\n const value = options?.getCookie?.(routing.storage.cookies![i].name);\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_LOCAL_STORAGE) {\n for (let i = 0; i < (routing.storage.localStorage ?? []).length; i++) {\n try {\n const value = options?.getLocaleStorage?.(\n routing.storage.localStorage![i].name\n );\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_SESSION_STORAGE && routing.storage.sessionStorage) {\n for (let i = 0; i < routing.storage.sessionStorage.length; i++) {\n try {\n const value = options?.getSessionStorage?.(\n routing.storage.sessionStorage[i].name\n );\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n};\n\n/**\n * Stores the locale in browser storage mechanisms\n * (cookies, localStorage, sessionStorage).\n * Does not write to headers — use `setLocaleInStorageServer` for that.\n */\nexport const setLocaleInStorageClient = (\n locale: LocalesValues,\n options?: LocaleStorageClientOptions\n): void => {\n if (options?.isCookieEnabled === false) return;\n\n if (!TREE_SHAKE_STORAGE_COOKIES && routing.storage.cookies) {\n for (let i = 0; i < routing.storage.cookies.length; i++) {\n const { name, attributes } = routing.storage.cookies[i];\n try {\n if (options?.setCookieStore) {\n options.setCookieStore(name, locale, {\n ...attributes,\n expires: resolveExpiresToTimestamp(attributes.expires),\n });\n }\n } catch {\n try {\n if (options?.setCookieString) {\n options.setCookieString(\n name,\n buildCookieString(name, locale, attributes)\n );\n }\n } catch {}\n }\n }\n }\n\n if (\n !TREE_SHAKE_STORAGE_LOCAL_STORAGE &&\n routing.storage.localStorage &&\n options?.setLocaleStorage\n ) {\n for (let i = 0; i < routing.storage.localStorage.length; i++) {\n const { name } = routing.storage.localStorage[i];\n try {\n if (!(options?.overwrite ?? true) && options?.getLocaleStorage) {\n if (options.getLocaleStorage(name)) continue;\n }\n options.setLocaleStorage(name, locale);\n } catch {}\n }\n }\n\n if (\n !TREE_SHAKE_STORAGE_SESSION_STORAGE &&\n routing.storage.sessionStorage &&\n options?.setSessionStorage\n ) {\n for (let i = 0; i < routing.storage.sessionStorage.length; i++) {\n const { name } = routing.storage.sessionStorage[i];\n try {\n if (!(options?.overwrite ?? true) && options?.getSessionStorage) {\n if (options.getSessionStorage(name)) continue;\n }\n options.setSessionStorage(name, locale);\n } catch {}\n }\n }\n};\n\n/**\n * Client-side locale storage utility.\n * Handles cookies (browser), localStorage and sessionStorage.\n * Does not access headers.\n *\n * @example\n * ```ts\n * const storage = LocaleStorageClient(localeStorageOptions);\n * const locale = storage.getLocale();\n * storage.setLocale('fr');\n * ```\n */\nexport const LocaleStorageClient = (options: LocaleStorageClientOptions) => ({\n getLocale: () => getLocaleFromStorageClient(options),\n setLocale: (locale: LocalesValues) =>\n setLocaleInStorageClient(locale, options),\n});\n\n// ============================================================================\n// Server-specific types and functions\n// (cookies via injected getter/setter, headers — no localStorage/sessionStorage)\n// ============================================================================\n\nexport type LocaleStorageServerOptions = {\n overwrite?: boolean;\n isCookieEnabled?: boolean;\n setCookieStore?: (\n name: string,\n value: string,\n cookie: CookieBuildAttributes\n ) => void;\n setCookieString?: (name: string, cookie: string) => void;\n getCookie?: (name: string) => string | undefined | null;\n getHeader?: (name: string) => string | undefined | null;\n setHeader?: (name: string, value: string) => void;\n};\n\n/**\n * Retrieves the locale from server-side storage mechanisms (cookies, headers).\n * Does not access localStorage or sessionStorage.\n * No browser cookie fallback — the caller must provide `getCookie`.\n */\nexport const getLocaleFromStorageServer = (\n options: LocaleStorageServerOptions\n): Locale | undefined => {\n const { locales } = internationalization;\n\n if (options?.isCookieEnabled === false) return undefined;\n\n const isValidLocale = (value: string | null | undefined): value is Locale =>\n !!value && locales.includes(value as Locale);\n\n if (!TREE_SHAKE_STORAGE_COOKIES && routing.storage.cookies) {\n for (let i = 0; i < routing.storage.cookies.length; i++) {\n try {\n const value = options?.getCookie?.(routing.storage.cookies[i].name);\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_HEADERS && routing.storage.headers) {\n for (let i = 0; i < routing.storage.headers.length; i++) {\n try {\n const value = options?.getHeader?.(routing.storage.headers[i].name);\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n};\n\n/**\n * Stores the locale in server-side storage mechanisms (cookies, headers).\n * Does not write to localStorage or sessionStorage.\n */\nexport const setLocaleInStorageServer = (\n locale: LocalesValues,\n options?: LocaleStorageServerOptions\n): void => {\n if (options?.isCookieEnabled === false) return;\n\n if (!TREE_SHAKE_STORAGE_COOKIES && routing.storage.cookies) {\n for (let i = 0; i < routing.storage.cookies.length; i++) {\n const { name, attributes } = routing.storage.cookies[i];\n\n try {\n if (options?.setCookieStore) {\n options.setCookieStore(name, locale, {\n ...attributes,\n expires: resolveExpiresToTimestamp(attributes.expires),\n });\n }\n } catch {\n try {\n if (options?.setCookieString) {\n options.setCookieString(\n name,\n buildCookieString(name, locale, attributes)\n );\n }\n } catch {}\n }\n }\n }\n\n if (\n !TREE_SHAKE_STORAGE_HEADERS &&\n routing.storage.headers &&\n options?.setHeader\n ) {\n for (let i = 0; i < routing.storage.headers.length; i++) {\n try {\n options.setHeader(routing.storage.headers[i].name, locale);\n } catch {}\n }\n }\n};\n\n/**\n * Server-side locale storage utility.\n * Handles cookies (via injected getter/setter) and headers.\n * Does not access localStorage or sessionStorage.\n *\n * @example\n * ```ts\n * const storage = LocaleStorageServer({\n * getCookie: (name) => req.cookies[name],\n * setCookieStore: (name, value, attrs) => res.cookie(name, value, attrs),\n * getHeader: (name) => req.headers[name],\n * setHeader: (name, value) => res.setHeader(name, value),\n * });\n * const locale = storage.getLocale();\n * storage.setLocale('fr');\n * ```\n */\nexport const LocaleStorageServer = (options: LocaleStorageServerOptions) => ({\n getLocale: () => getLocaleFromStorageServer(options),\n setLocale: (locale: LocalesValues) =>\n setLocaleInStorageServer(locale, options),\n});\n\n// ============================================================================\n// Deprecated: combined LocaleStorage\n// Use LocaleStorageClient or LocaleStorageServer instead\n// ============================================================================\n\n/**\n * @deprecated Use {@link LocaleStorageClientOptions} or {@link LocaleStorageServerOptions} instead.\n */\nexport type LocaleStorageOptions = LocaleStorageClientOptions &\n LocaleStorageServerOptions;\n\n/**\n * Retrieves the locale from all storage mechanisms\n * (cookies, localStorage, sessionStorage, headers).\n *\n * @deprecated Use {@link getLocaleFromStorageClient} (browser) or\n * {@link getLocaleFromStorageServer} (server) instead.\n */\nexport const getLocaleFromStorage = (\n options: Pick<\n LocaleStorageOptions,\n | 'getCookie'\n | 'getSessionStorage'\n | 'getLocaleStorage'\n | 'getHeader'\n | 'isCookieEnabled'\n >\n): Locale | undefined => {\n const { locales } = internationalization;\n\n if (options?.isCookieEnabled === false) return undefined;\n\n const isValidLocale = (value: string | null | undefined): value is Locale =>\n !!value && locales.includes(value as Locale);\n\n const readCookie = (name: string): string | undefined => {\n try {\n const fromOption = options?.getCookie?.(name);\n if (fromOption !== null && fromOption !== undefined) return fromOption;\n } catch {}\n // Browser fallback kept for backward compatibility\n return getCookie(name);\n };\n\n if (!TREE_SHAKE_STORAGE_COOKIES && routing.storage.cookies) {\n for (let i = 0; i < routing.storage.cookies.length; i++) {\n const value = readCookie(routing.storage.cookies[i].name);\n if (isValidLocale(value)) return value;\n }\n }\n\n if (!TREE_SHAKE_STORAGE_LOCAL_STORAGE && routing.storage.localStorage) {\n for (let i = 0; i < routing.storage.localStorage.length; i++) {\n try {\n const value = options?.getLocaleStorage?.(\n routing.storage.localStorage[i].name\n );\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_SESSION_STORAGE && routing.storage.sessionStorage) {\n for (let i = 0; i < routing.storage.sessionStorage.length; i++) {\n try {\n const value = options?.getSessionStorage?.(\n routing.storage.sessionStorage[i].name\n );\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n\n if (!TREE_SHAKE_STORAGE_HEADERS && routing.storage.headers) {\n for (let i = 0; i < routing.storage.headers.length; i++) {\n try {\n const value = options?.getHeader?.(routing.storage.headers[i].name);\n if (isValidLocale(value)) return value;\n } catch {}\n }\n }\n};\n\n/**\n * Stores the locale in all configured storage mechanisms\n * (cookies, localStorage, sessionStorage, headers).\n *\n * @deprecated Use {@link setLocaleInStorageClient} (browser) or\n * {@link setLocaleInStorageServer} (server) instead.\n */\nexport const setLocaleInStorage = (\n locale: LocalesValues,\n options?: LocaleStorageOptions\n): void => {\n if (options?.isCookieEnabled === false) return;\n\n if (!TREE_SHAKE_STORAGE_COOKIES && routing.storage.cookies) {\n for (let i = 0; i < routing.storage.cookies.length; i++) {\n const { name, attributes } = routing.storage.cookies[i];\n try {\n if (options?.setCookieStore) {\n options.setCookieStore(name, locale, {\n ...attributes,\n expires: resolveExpiresToTimestamp(attributes.expires),\n });\n }\n } catch {\n try {\n if (options?.setCookieString) {\n options.setCookieString(\n name,\n buildCookieString(name, locale, attributes)\n );\n }\n } catch {}\n }\n }\n }\n\n if (\n !TREE_SHAKE_STORAGE_LOCAL_STORAGE &&\n routing.storage.localStorage &&\n options?.setLocaleStorage\n ) {\n for (let i = 0; i < routing.storage.localStorage.length; i++) {\n const { name } = routing.storage.localStorage[i];\n try {\n if (!(options?.overwrite ?? true) && options?.getLocaleStorage) {\n if (options.getLocaleStorage(name)) continue;\n }\n options.setLocaleStorage(name, locale);\n } catch {}\n }\n }\n\n if (\n !TREE_SHAKE_STORAGE_SESSION_STORAGE &&\n routing.storage.sessionStorage &&\n options?.setSessionStorage\n ) {\n for (let i = 0; i < routing.storage.sessionStorage.length; i++) {\n const { name } = routing.storage.sessionStorage[i];\n try {\n if (!(options?.overwrite ?? true) && options?.getSessionStorage) {\n if (options.getSessionStorage(name)) continue;\n }\n options.setSessionStorage(name, locale);\n } catch {}\n }\n }\n\n if (\n !TREE_SHAKE_STORAGE_HEADERS &&\n routing.storage.headers &&\n options?.setHeader\n ) {\n for (let i = 0; i < routing.storage.headers.length; i++) {\n try {\n options.setHeader(routing.storage.headers[i].name, locale);\n } catch {}\n }\n }\n};\n\n/**\n * Utility object to get and set the locale in storage based on configuration.\n *\n * @deprecated Use {@link LocaleStorageClient} (browser) or\n * {@link LocaleStorageServer} (server) instead.\n */\nexport const LocaleStorage = (options: LocaleStorageOptions) => ({\n getLocale: () => getLocaleFromStorage(options),\n setLocale: (locale: LocalesValues) => setLocaleInStorage(locale, options),\n});\n"],"mappings":"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"}
@@ -37,8 +37,7 @@ declare const getFilterMissingTranslationsDictionary: (dictionary: Dictionary, l
37
37
  filePath?: string;
38
38
  tags?: string[];
39
39
  item?: number;
40
- variant?: string;
41
- meta?: _$_intlayer_types0.DictionaryMeta;
40
+ variant?: string | Record<string, string | number>;
42
41
  locale?: LocalesValues;
43
42
  contentAutoTransformation?: _$_intlayer_types0.ContentAutoTransformation;
44
43
  fill?: _$_intlayer_types0.Fill;
@@ -29,8 +29,7 @@ declare const getFilterTranslationsOnlyDictionary: (dictionary: Dictionary, loca
29
29
  filePath?: string;
30
30
  tags?: string[];
31
31
  item?: number;
32
- variant?: string;
33
- meta?: _$_intlayer_types0.DictionaryMeta;
32
+ variant?: string | Record<string, string | number>;
34
33
  locale?: LocalesValues;
35
34
  contentAutoTransformation?: _$_intlayer_types0.ContentAutoTransformation;
36
35
  fill?: _$_intlayer_types0.Fill;
@@ -21,8 +21,7 @@ declare const getFilteredLocalesDictionary: (dictionary: Dictionary, locale: Loc
21
21
  filePath?: string;
22
22
  tags?: string[];
23
23
  item?: number;
24
- variant?: string;
25
- meta?: _$_intlayer_types0.DictionaryMeta;
24
+ variant?: string | Record<string, string | number>;
26
25
  locale?: LocalesValues;
27
26
  contentAutoTransformation?: _$_intlayer_types0.ContentAutoTransformation;
28
27
  fill?: _$_intlayer_types0.Fill;
@@ -8,8 +8,8 @@ import { mergeDictionaries } from "./mergeDictionaries.js";
8
8
  import { mergeQualifiedDictionaries } from "./mergeQualifiedDictionaries.js";
9
9
  import { normalizeDictionaries, normalizeDictionary } from "./normalizeDictionary.js";
10
10
  import { orderDictionaries } from "./orderDictionaries.js";
11
- import { COMPOSITE_ID_SEPARATOR, DynamicDictionaryLoader, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, getDictionaryCompositeId, getDictionaryQualifierId, getDictionaryQualifierSegments, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, parseDictionarySelector, reconstructQualifiedEntry, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync } from "./qualifiedDictionary.js";
11
+ import { COMPOSITE_ID_SEPARATOR, DynamicDictionaryLoader, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, getDictionaryCompositeId, getDictionaryQualifierId, getDictionaryQualifierSegments, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, parseDictionarySelector, reconstructQualifiedEntry, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, serializeVariant } from "./qualifiedDictionary.js";
12
12
  import { removeContentNodeByKeyPath } from "./removeContentNodeByKeyPath.js";
13
13
  import { renameContentNodeByKeyPath } from "./renameContentNodeByKeyPath.js";
14
14
  import { updateNodeChildren } from "./updateNodeChildren.js";
15
- export { COMPOSITE_ID_SEPARATOR, DynamicDictionaryLoader, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, editDictionaryByKeyPath, getContentNodeByKeyPath, getDefaultNode, getDictionaryCompositeId, getDictionaryQualifierId, getDictionaryQualifierSegments, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getEmptyNode, getNodeChildren, getNodeType, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, mergeDictionaries, mergeQualifiedDictionaries, normalizeDictionaries, normalizeDictionary, orderDictionaries, parseDictionarySelector, reconstructQualifiedEntry, removeContentNodeByKeyPath, renameContentNodeByKeyPath, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, updateNodeChildren };
15
+ export { COMPOSITE_ID_SEPARATOR, DynamicDictionaryLoader, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, editDictionaryByKeyPath, getContentNodeByKeyPath, getDefaultNode, getDictionaryCompositeId, getDictionaryQualifierId, getDictionaryQualifierSegments, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getEmptyNode, getNodeChildren, getNodeType, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, mergeDictionaries, mergeQualifiedDictionaries, normalizeDictionaries, normalizeDictionary, orderDictionaries, parseDictionarySelector, reconstructQualifiedEntry, removeContentNodeByKeyPath, renameContentNodeByKeyPath, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, serializeVariant, updateNodeChildren };
@@ -8,7 +8,7 @@ import { Dictionary, QualifiedDictionaryGroup } from "@intlayer/types/dictionary
8
8
  * `mergeDictionaries` (single merged dictionary).
9
9
  * - At least one dictionary declares a qualifier → the group's dimension set is
10
10
  * the union of every declared dimension (in canonical order
11
- * `variant → meta → item`). Dictionaries are grouped by their composite id
11
+ * `variant → item`). Dictionaries are grouped by their composite id
12
12
  * (one segment per dimension), merged within each group (locale completion /
13
13
  * priority overrides preserved), and a `QualifiedDictionaryGroup` is returned.
14
14
  * Unqualified siblings act as shared base content merged into every entry.
@@ -1 +1 @@
1
- {"version":3,"file":"mergeQualifiedDictionaries.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/mergeQualifiedDictionaries.ts"],"mappings":";;;;;AA8BA;;;;;;;;;;;;;cAAa,0BAAA,GACX,YAAA,EAAc,UAAA,OACb,UAAA,GAAa,wBAAA"}
1
+ {"version":3,"file":"mergeQualifiedDictionaries.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/mergeQualifiedDictionaries.ts"],"mappings":";;;;;AA6BA;;;;;;;;;;;;;cAAa,0BAAA,GACX,YAAA,EAAc,UAAA,OACb,UAAA,GAAa,wBAAA"}
@@ -3,19 +3,32 @@ import { LocalesValues } from "@intlayer/types/module_augmentation";
3
3
 
4
4
  //#region src/dictionaryManipulator/qualifiedDictionary.d.ts
5
5
  /**
6
- * Canonical order of qualifier dimensions. A key that declares several
7
- * dimensions always nests them in this order, with `item` innermost so it can
8
- * act as the collection (array) axis.
6
+ * Canonical order of qualifier dimensions. A key that declares both dimensions
7
+ * always nests them in this order, with `item` innermost so it can act as the
8
+ * collection (array) axis.
9
9
  */
10
- declare const QUALIFIER_ORDER: readonly ["variant", "meta", "item"];
10
+ declare const QUALIFIER_ORDER: readonly ["variant", "item"];
11
11
  /**
12
12
  * Separator joining per-dimension ids into a composite entry id. Also used as
13
13
  * the chunk path separator in dynamic mode.
14
14
  */
15
15
  declare const COMPOSITE_ID_SEPARATOR = "/";
16
+ /**
17
+ * Canonical serialization of a variant value into its identity string — the
18
+ * variant segment of a composite id and the runtime matching key.
19
+ *
20
+ * - `undefined` → `'default'` (the implicit fallback variant)
21
+ * - a string → the string itself (a named variant)
22
+ * - an object → its sorted `key=value` pairs joined by `&`
23
+ * (e.g. `{ userId: '123', id: 'abc' }` → `'id=abc&userId=123'`)
24
+ *
25
+ * Two variants resolve to the same entry iff their serializations are equal, so
26
+ * an object variant in a selector must equal the one declared on the dictionary.
27
+ */
28
+ declare const serializeVariant: (variant: string | Record<string, string | number> | undefined) => string;
16
29
  /**
17
30
  * Returns the qualifier dimensions declared on a dictionary, in canonical
18
- * order (`variant → meta → item`). Empty when the dictionary is unqualified
31
+ * order (`variant → item`). Empty when the dictionary is unqualified
19
32
  * (plain dictionary or shared base content of a qualified group).
20
33
  */
21
34
  declare const getDictionaryQualifierTypes: (dictionary: Dictionary) => DictionaryQualifierType[];
@@ -23,8 +36,7 @@ declare const getDictionaryQualifierTypes: (dictionary: Dictionary) => Dictionar
23
36
  * Returns the qualifier identifier of a dictionary for the given qualifier
24
37
  * dimension — one segment of the composite entry id.
25
38
  *
26
- * - 'variant' → the variant name
27
- * - 'meta' → the `meta.id` discriminator
39
+ * - 'variant' → the serialized variant (named string or object identity)
28
40
  * - 'item' → the item index as string
29
41
  */
30
42
  declare const getDictionaryQualifierId: (dictionary: Dictionary, qualifierType: DictionaryQualifierType) => string | undefined;
@@ -48,12 +60,13 @@ declare const isQualifiedDictionaryGroup: (value: unknown) => value is Qualified
48
60
  /**
49
61
  * Reconstructs a resolvable {@link Dictionary} from a single entry of a
50
62
  * qualified group: the content node stored under its composite id, plus the
51
- * qualifier coordinates decoded from that id (`variant`, `item`) and the
52
- * preserved `meta` object for the meta dimension.
63
+ * qualifier coordinates decoded from that id (`variant`, `item`).
53
64
  *
54
65
  * This keeps the resolver's matching/transform code unchanged: it still sees a
55
- * `{ key, content, variant?, item?, meta? }` shape, even though the stored
56
- * format no longer duplicates those fields per entry.
66
+ * `{ key, content, variant?, item? }` shape, even though the stored format no
67
+ * longer duplicates those fields per entry. The `variant` coordinate stays in
68
+ * its serialized form (e.g. `'id=abc&userId=123'`), which round-trips through
69
+ * {@link serializeVariant} during matching.
57
70
  */
58
71
  declare const reconstructQualifiedEntry: (group: QualifiedDictionaryGroup, compositeId: string) => Dictionary;
59
72
  /**
@@ -63,8 +76,8 @@ declare const reconstructQualifiedEntry: (group: QualifiedDictionaryGroup, compo
63
76
  * - Plain dictionary → returned as-is (selector ignored)
64
77
  * - `item` declared but not selected → every matching entry ordered by index
65
78
  * - `item` selected → the matching entry or null
66
- * - `variant` defaults to the `default` entry when not selected
67
- * - `meta` requires `{ id }` and every declared meta field to match
79
+ * - `variant` defaults to the `default` entry when not selected; an object
80
+ * variant resolves only when the selector provides an equal object
68
81
  *
69
82
  * Dimensions compose: e.g. a variant × item key with `{ variant: 'promo' }`
70
83
  * returns every promo item as an array; adding `{ item: 2 }` narrows to one.
@@ -119,7 +132,7 @@ type QualifiedDynamicLoaderMap = {
119
132
  };
120
133
  /**
121
134
  * Type guard discriminating a qualified dynamic loader map (collections /
122
- * variants / meta records, possibly combined) from a plain dynamic loader map.
135
+ * variants, possibly combined) from a plain dynamic loader map.
123
136
  */
124
137
  declare const isQualifiedDynamicLoaderMap: (value: unknown) => value is QualifiedDynamicLoaderMap;
125
138
  /**
@@ -127,11 +140,11 @@ declare const isQualifiedDynamicLoaderMap: (value: unknown) => value is Qualifie
127
140
  * loading only the chunk(s) the selector actually targets.
128
141
  *
129
142
  * Walks the nested loader tree one dimension at a time (canonical order
130
- * `variant → meta → item`): `variant` defaults to `default`, `meta` descends by
131
- * `id`, and `item` either narrows to the selected index or — when no item is
132
- * given — expands into every sibling chunk (the collection axis). Meta-equality
133
- * is verified on the loaded chunk. Semantics mirror
134
- * {@link resolveQualifiedDictionary} so dynamic and static modes behave alike.
143
+ * `variant → item`): `variant` defaults to `default` (or descends by the
144
+ * serialized object identity), and `item` either narrows to the selected index
145
+ * or — when no item is given — expands into every sibling chunk (the collection
146
+ * axis). Semantics mirror {@link resolveQualifiedDictionary} so dynamic and
147
+ * static modes behave alike.
135
148
  *
136
149
  * The Suspense mechanism is injected through `loadChunk` so the same logic
137
150
  * serves both the client (suspender cache) and the server (`react.use`). Every
@@ -172,5 +185,5 @@ declare const resolveQualifiedDynamicContentAsync: <Content>(params: {
172
185
  transform: (dictionary: Dictionary) => Content;
173
186
  }) => Promise<Content | Content[] | null>;
174
187
  //#endregion
175
- export { COMPOSITE_ID_SEPARATOR, DynamicDictionaryLoader, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, getDictionaryCompositeId, getDictionaryQualifierId, getDictionaryQualifierSegments, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, parseDictionarySelector, reconstructQualifiedEntry, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync };
188
+ export { COMPOSITE_ID_SEPARATOR, DynamicDictionaryLoader, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, getDictionaryCompositeId, getDictionaryQualifierId, getDictionaryQualifierSegments, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, parseDictionarySelector, reconstructQualifiedEntry, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, serializeVariant };
176
189
  //# sourceMappingURL=qualifiedDictionary.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"qualifiedDictionary.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/qualifiedDictionary.ts"],"mappings":";;;;;;AAmBA;;;cAAa,eAAA;;AAUb;;;cAAa,sBAAA;;AAOb;;;;cAAa,2BAAA,GACX,UAAA,EAAY,UAAA,KACX,uBAAA;;;;;AAmBH;;;;cAAa,wBAAA,GACX,UAAA,EAAY,UAAA,EACZ,aAAA,EAAe,uBAAA;;;;;;cAeJ,8BAAA,GACX,UAAA,EAAY,UAAA,EACZ,cAAA,EAAgB,uBAAA;;;;;cAiBL,wBAAA,GACX,UAAA,EAAY,UAAA,EACZ,cAAA,EAAgB,uBAAA;;;;;AAFlB;cAgEa,0BAAA,GACX,KAAA,cACC,KAAA,IAAS,wBAAA;;;;;;;;;AAFZ;;cAmBa,yBAAA,GACX,KAAA,EAAO,wBAAA,EACP,WAAA,aACC,UAAA;;;;;;;AAHH;;;;;;;cAwCa,0BAAA,GACX,iBAAA,EAAmB,UAAA,GAAa,wBAAA,EAChC,QAAA,GAAW,kBAAA,KACV,UAAA,GAAa,UAAA;;;AAHhB;;cAqCa,uBAAA,aAAqC,aAAA,EAChD,gBAAA,GAAmB,CAAA,GAAI,kBAAA;EACpB,MAAA,GAAS,CAAA;EAAG,QAAA,GAAW,kBAAA;AAAA;;;;;cAef,6BAAA,GACX,QAAA,GAAW,kBAAA;;;;;;;cAiBA,2BAAA;;AAnCb;;KAwCY,uBAAA,SAAgC,OAAA,CAAQ,UAAA;;;;;KAMxC,0BAAA;EAAA,CACT,OAAA,WAAkB,0BAAA,GAA6B,uBAAA;AAAA;;;;;;;;;;;;AA9BlD;KA6CY,yBAAA;EAAA,CACT,2BAAA,GAA8B,uBAAA;EAAA,CAC9B,MAAA,WAAiB,0BAAA,GAA6B,uBAAA;AAAA;AA7BjD;;;;AAAA,cAoCa,2BAAA,GACX,KAAA,cACC,KAAA,IAAS,yBAAA;AAjCZ;;;;;AAMA;;;;;;;;;AAgBA;;;;;;;;;AAtBA,cAuLa,8BAAA,YAA2C,MAAA;EACtD,SAAA,EAAW,yBAAA;EACX,GAAA;EACA,MAAA;EACA,QAAA,EAAU,kBAAA;EACV,SAAA,GAAY,QAAA,UAAkB,OAAA,EAAS,OAAA,CAAQ,UAAA,MAAgB,UAAA;EAC/D,SAAA,GAAY,UAAA,EAAY,UAAA,KAAe,OAAA;AAAA,MACrC,OAAA,GAAU,OAAA;;;;;;;;;AAPd;;;cAyCa,mCAAA,YAAsD,MAAA;EACjE,SAAA,EAAW,yBAAA;EACX,GAAA;EACA,MAAA;EACA,QAAA,EAAU,kBAAA;EACV,SAAA,GAAY,UAAA,EAAY,UAAA,KAAe,OAAA;AAAA,MACrC,OAAA,CAAQ,OAAA,GAAU,OAAA"}
1
+ {"version":3,"file":"qualifiedDictionary.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/qualifiedDictionary.ts"],"mappings":";;;;;;AAaA;;;cAAa,eAAA;;AASb;;;cAAa,sBAAA;;AAcb;;;;;AAiBA;;;;;;cAjBa,gBAAA,GACX,OAAA,WAAkB,MAAA;;;AAkCpB;;;cAlBa,2BAAA,GACX,UAAA,EAAY,UAAA,KACX,uBAAA;;;;;;;AAiCH;cAjBa,wBAAA,GACX,UAAA,EAAY,UAAA,EACZ,aAAA,EAAe,uBAAA;;;;;;cAeJ,8BAAA,GACX,UAAA,EAAY,UAAA,EACZ,cAAA,EAAgB,uBAAA;;;AAiBlB;;cAAa,wBAAA,GACX,UAAA,EAAY,UAAA,EACZ,cAAA,EAAgB,uBAAA;;;;;;cAmCL,0BAAA,GACX,KAAA,cACC,KAAA,IAAS,wBAAA;;AAFZ;;;;;;;;;AAoBA;cAAa,yBAAA,GACX,KAAA,EAAO,wBAAA,EACP,WAAA,aACC,UAAA;;;;;;;;;AAgCH;;;;;cAAa,0BAAA,GACX,iBAAA,EAAmB,UAAA,GAAa,wBAAA,EAChC,QAAA,GAAW,kBAAA,KACV,UAAA,GAAa,UAAA;;;;;cA6BH,uBAAA,aAAqC,aAAA,EAChD,gBAAA,GAAmB,CAAA,GAAI,kBAAA;EACpB,MAAA,GAAS,CAAA;EAAG,QAAA,GAAW,kBAAA;AAAA;;;;;cAef,6BAAA,GACX,QAAA,GAAW,kBAAA;AAlBb;;;;;;AAAA,cA0Ca,2BAAA;;;;KAKD,uBAAA,SAAgC,OAAA,CAAQ,UAAA;;;;;KAMxC,0BAAA;EAAA,CACT,OAAA,WAAkB,0BAAA,GAA6B,uBAAA;AAAA;;;;AArClD;;;;;AAyBA;;;;KA2BY,yBAAA;EAAA,CACT,2BAAA,GAA8B,uBAAA;EAAA,CAC9B,MAAA,WAAiB,0BAAA,GAA6B,uBAAA;AAAA;;;AAlBjD;;cAyBa,2BAAA,GACX,KAAA,cACC,KAAA,IAAS,yBAAA;;;;;;;AAXZ;;;;;;;;;;;;;;;;AASA;cA+Ga,8BAAA,YAA2C,MAAA;EACtD,SAAA,EAAW,yBAAA;EACX,GAAA;EACA,MAAA;EACA,QAAA,EAAU,kBAAA;EACV,SAAA,GAAY,QAAA,UAAkB,OAAA,EAAS,OAAA,CAAQ,UAAA,MAAgB,UAAA;EAC/D,SAAA,GAAY,UAAA,EAAY,UAAA,KAAe,OAAA;AAAA,MACrC,OAAA,GAAU,OAAA;AAPd;;;;;;;;;;;AAAA,cAyCa,mCAAA,YAAsD,MAAA;EACjE,SAAA,EAAW,yBAAA;EACX,GAAA;EACA,MAAA;EACA,QAAA,EAAU,kBAAA;EACV,SAAA,GAAY,UAAA,EAAY,UAAA,KAAe,OAAA;AAAA,MACrC,OAAA,CAAQ,OAAA,GAAU,OAAA"}
@@ -46,7 +46,7 @@ import { mergeDictionaries } from "./dictionaryManipulator/mergeDictionaries.js"
46
46
  import { mergeQualifiedDictionaries } from "./dictionaryManipulator/mergeQualifiedDictionaries.js";
47
47
  import { normalizeDictionaries, normalizeDictionary } from "./dictionaryManipulator/normalizeDictionary.js";
48
48
  import { orderDictionaries } from "./dictionaryManipulator/orderDictionaries.js";
49
- import { COMPOSITE_ID_SEPARATOR, DynamicDictionaryLoader, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, getDictionaryCompositeId, getDictionaryQualifierId, getDictionaryQualifierSegments, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, parseDictionarySelector, reconstructQualifiedEntry, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync } from "./dictionaryManipulator/qualifiedDictionary.js";
49
+ import { COMPOSITE_ID_SEPARATOR, DynamicDictionaryLoader, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, getDictionaryCompositeId, getDictionaryQualifierId, getDictionaryQualifierSegments, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, parseDictionarySelector, reconstructQualifiedEntry, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, serializeVariant } from "./dictionaryManipulator/qualifiedDictionary.js";
50
50
  import { removeContentNodeByKeyPath } from "./dictionaryManipulator/removeContentNodeByKeyPath.js";
51
51
  import { renameContentNodeByKeyPath } from "./dictionaryManipulator/renameContentNodeByKeyPath.js";
52
52
  import { updateNodeChildren } from "./dictionaryManipulator/updateNodeChildren.js";
@@ -59,6 +59,7 @@ import { number } from "./formatters/number.js";
59
59
  import { percentage } from "./formatters/percentage.js";
60
60
  import { relativeTime } from "./formatters/relativeTime.js";
61
61
  import { units } from "./formatters/units.js";
62
+ import { comparePaths, normalizePath } from "./localization/comparePaths.js";
62
63
  import { GenerateSitemapOptions, SitemapUrlEntry, generateSitemap, generateSitemapUrl } from "./localization/generateSitemap.js";
63
64
  import { getBrowserLocale } from "./localization/getBrowserLocale.js";
64
65
  import { getHTMLTextDir } from "./localization/getHTMLTextDir.js";
@@ -93,4 +94,4 @@ import { isValidElement } from "./utils/isValidReactElement.js";
93
94
  import { CookieBuildAttributes, LocaleStorage, LocaleStorageClient, LocaleStorageClientOptions, LocaleStorageOptions, LocaleStorageServer, LocaleStorageServerOptions, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, localeStorageOptions, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer } from "./utils/localeStorage.js";
94
95
  import { YamlRecord, YamlValue, parseYaml } from "./utils/parseYaml.js";
95
96
  import { stringifyYaml } from "./utils/stringifyYaml.js";
96
- export { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, BlockQuoteNode, BoldTextNode, BreakLineNode, BreakThematicNode, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, COMPOSITE_ID_SEPARATOR, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CUSTOM_COMPONENT_R, CachedIntl, CachedIntl as Intl, CodeBlockNode, CodeFencedNode, CodeInlineNode, CompileOptions, ComponentOverrides, ConditionCond, ConditionContent, ConditionContentStates, CookieBuildAttributes, CustomComponentNode, DO_NOT_PROCESS_HTML_ELEMENTS, DURATION_DELAY_TRIGGER, DateTimePreset, DeepTransformContent, DotPath, DynamicDictionaryLoader, ElementType, EnterFormat, EnumerationCond, EnumerationContent, EnumerationContentState, EscapedTextNode, FOOTNOTE_R, FOOTNOTE_REFERENCE_R, FORMFEED_R, FRONT_MATTER_R, FileCond, FileContent, FileContentConstructor, FootnoteNode, FootnoteReferenceNode, GFMTaskNode, GFM_TASK_R, Gender, GenderCond, GenderContent, GenderContentStates, GenerateSitemapOptions, GetNestingResult, GetPrefixOptions, GetPrefixResult, HEADING_ATX_COMPLIANT_R, HEADING_R, HEADING_SETEXT_R, HTMLCommentNode, HTMLContent, HTMLContentConstructor, HTMLNode, HTMLSelfClosingNode, HTMLTag, HTMLTagsType, HTMLValidationIssue, HTMLValidationResult, HTML_BLOCK_ELEMENT_R, HTML_CHAR_CODE_R, HTML_COMMENT_R, HTML_CUSTOM_ATTR_R, HTML_LEFT_TRIM_AMOUNT_R, HTML_SELF_CLOSING_ELEMENT_R, HTML_TAGS, HeadingNode, HeadingSetextNode, IInterpreterPlugin, IInterpreterPluginState, INLINE_SKIP_R, INTERPOLATION_R, ImageNode, InsertionCond, InsertionContent, InsertionContentConstructor, IsAny, ItalicTextNode, JsonValue, LINK_AUTOLINK_BARE_URL_R, LINK_AUTOLINK_R, LIST_LOOKBEHIND_R, LOOKAHEAD, LinkAngleBraceNode, LinkBareURLNode, LinkNode, ListType, LocaleStorage, LocaleStorageClient, LocaleStorageClientOptions, LocaleStorageOptions, LocaleStorageServer, LocaleStorageServerOptions, LocalizedPathResult, MarkdownContent, MarkdownContentConstructor, MarkdownContext, MarkdownOptions, MarkdownRuntime, HTMLValidationIssue as MarkdownValidationIssue, MarkdownValidationResult, MarkedTextNode, MessageFormatDialect, MessageValues, NAMED_CODES_TO_UNICODE, NP_TABLE_R, NestedCond, NestedContent, NestedContentState, NestedParser, NewlineNode, NodeProps, ORDERED, ORDERED_LIST_BULLET, ORDERED_LIST_ITEM_PREFIX, ORDERED_LIST_ITEM_PREFIX_R, ORDERED_LIST_ITEM_R, ORDERED_LIST_R, OrderedListNode, PARAGRAPH_R, ParagraphNode, ParseState, ParsedMarkdown, Parser, ParserResult, Plugins, PluralCategory, PluralCond, PluralContent, PluralContentState, PortableObject, Priority, PriorityValue, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, REFERENCE_IMAGE_OR_LINK, REFERENCE_IMAGE_R, REFERENCE_LINK_R, ReferenceImageNode, ReferenceLinkNode, ReferenceNode, RenderRuleHook, Rule, RuleOutput, RuleType, RuleTypeValue, Rules, SHORTCODE_R, SHOULD_RENDER_AS_BLOCK_R, SitemapUrlEntry, StrikethroughTextNode, TABLE_CENTER_ALIGN, TABLE_LEFT_ALIGN, TABLE_RIGHT_ALIGN, TABLE_TRIM_PIPES, TAB_R, TEXT_BOLD_R, TEXT_EMPHASIZED_R, TEXT_ESCAPED_R, TEXT_MARKED_R, TEXT_PLAIN_R, TEXT_STRIKETHROUGHED_R, TRIM_STARTING_NEWLINES, TableNode, TableSeparatorNode, TaggedMessageToken, TextNode, TranslationCond, TranslationContent, UNESCAPE_R, UNORDERED, UNORDERED_LIST_BULLET, UNORDERED_LIST_ITEM_PREFIX, UNORDERED_LIST_ITEM_PREFIX_R, UNORDERED_LIST_ITEM_R, UNORDERED_LIST_R, UnionKeys, UnorderedListNode, VOID_HTML_ELEMENTS, ValidDotPathsFor, ValueAtKey, WrappedIntl, YamlRecord, YamlValue, allowInline, anyScopeRegex, attributeValueToNodePropValue, bindIntl, blockRegex, buildMaskPlugin, captureNothing, checkIsURLAbsolute, checkMissingLocalesPlugin, compact, compile, compileWithOptions, condition as cond, conditionPlugin, createCompiler, createRenderer, currency, cx, date, deepTransformNode, editDictionaryByKeyPath, enumeration as enu, enumerationPlugin, fallbackPlugin, file, fileContent, filePlugin, filterMissingTranslationsOnlyPlugin, filterTranslationsOnlyPlugin, findMatchingCondition, gender, genderPlugin, generateListItemPrefix, generateListItemPrefixRegex, generateListItemRegex, generateListRegex, generateSitemap, generateSitemapUrl, get, getBasePlugins, getBrowserLocale, getCachedIntl, getCanonicalPath, getCondition, getContent, getContentNodeByKeyPath, getCookie, getDefaultNode, getDictionary, getDictionaryCompositeId, getDictionaryQualifierId, getDictionaryQualifierSegments, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getEditedContent, getEditedDictionary, getEmptyNode, getEnumeration, getFilterMissingTranslationsContent, getFilterMissingTranslationsDictionary, getFilterTranslationsOnlyContent, getFilterTranslationsOnlyDictionary, getFilteredLocalesContent, getFilteredLocalesDictionary, getHTML, getHTMLTextDir, getInsertionValues, getInternalPath, getIntlayer, getLocale, getLocaleFromPath, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, getLocaleLang, getLocaleName, getLocalizedContent, getLocalizedPath, getLocalizedUrl, getMarkdownMetadata, getMaskContent, getMissingLocalesContent, getMissingLocalesContentFromDictionary, getMultilingualDictionary, getMultilingualUrls, getNesting, getNodeChildren, getNodeType, getPathWithoutLocale, getPerLocaleDictionary, getPlural, getPrefix, getReplacedValuesContent, getRewritePath, getRewriteRules, getSplittedContent, getSplittedDictionaryContent, getTranslation, html, i18nextToIntlayerFormatter, icuToIntlayerFormatter, inlineRegex, insertion as insert, insertContentInDictionary, insertionPlugin, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, isSameKeyPath, isValidElement, list, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, localeStorageOptions, markdown as md, mergeDictionaries, mergeQualifiedDictionaries, nesting as nest, nestedPlugin, normalizeAttributeKey, normalizeDictionaries, normalizeDictionary, normalizeWhitespace, number, orderDictionaries, parseBlock, parseCaptureInline, parseDictionarySelector, parseInline, parseMarkdown, parseSimpleInline, parseStyleAttribute, parseTableAlign, parseTableAlignCapture, parseTableCells, parseTableRow, parseTaggedMessage, parseYaml, parserFor, percentage, plural, pluralPlugin, portableObjectToIntlayerFormatter, presets, qualifies, reconstructQualifiedEntry, relativeTime, removeContentNodeByKeyPath, renameContentNodeByKeyPath, renderFor, renderMarkdownAst, renderNothing, resolveMessage, resolveMessageNode, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, sanitizer, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer, simpleInlineRegex, slugify, some, splitInsertionTemplate, startsWith, stringifyYaml, translation as t, translationPlugin, trimEnd, trimLeadingWhitespaceOutsideFences, unescapeString, units, unquote, updateNodeChildren, validateHTML, validateMarkdown, validatePrefix, vueI18nToIntlayerFormatter };
97
+ export { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, BlockQuoteNode, BoldTextNode, BreakLineNode, BreakThematicNode, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, COMPOSITE_ID_SEPARATOR, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CUSTOM_COMPONENT_R, CachedIntl, CachedIntl as Intl, CodeBlockNode, CodeFencedNode, CodeInlineNode, CompileOptions, ComponentOverrides, ConditionCond, ConditionContent, ConditionContentStates, CookieBuildAttributes, CustomComponentNode, DO_NOT_PROCESS_HTML_ELEMENTS, DURATION_DELAY_TRIGGER, DateTimePreset, DeepTransformContent, DotPath, DynamicDictionaryLoader, ElementType, EnterFormat, EnumerationCond, EnumerationContent, EnumerationContentState, EscapedTextNode, FOOTNOTE_R, FOOTNOTE_REFERENCE_R, FORMFEED_R, FRONT_MATTER_R, FileCond, FileContent, FileContentConstructor, FootnoteNode, FootnoteReferenceNode, GFMTaskNode, GFM_TASK_R, Gender, GenderCond, GenderContent, GenderContentStates, GenerateSitemapOptions, GetNestingResult, GetPrefixOptions, GetPrefixResult, HEADING_ATX_COMPLIANT_R, HEADING_R, HEADING_SETEXT_R, HTMLCommentNode, HTMLContent, HTMLContentConstructor, HTMLNode, HTMLSelfClosingNode, HTMLTag, HTMLTagsType, HTMLValidationIssue, HTMLValidationResult, HTML_BLOCK_ELEMENT_R, HTML_CHAR_CODE_R, HTML_COMMENT_R, HTML_CUSTOM_ATTR_R, HTML_LEFT_TRIM_AMOUNT_R, HTML_SELF_CLOSING_ELEMENT_R, HTML_TAGS, HeadingNode, HeadingSetextNode, IInterpreterPlugin, IInterpreterPluginState, INLINE_SKIP_R, INTERPOLATION_R, ImageNode, InsertionCond, InsertionContent, InsertionContentConstructor, IsAny, ItalicTextNode, JsonValue, LINK_AUTOLINK_BARE_URL_R, LINK_AUTOLINK_R, LIST_LOOKBEHIND_R, LOOKAHEAD, LinkAngleBraceNode, LinkBareURLNode, LinkNode, ListType, LocaleStorage, LocaleStorageClient, LocaleStorageClientOptions, LocaleStorageOptions, LocaleStorageServer, LocaleStorageServerOptions, LocalizedPathResult, MarkdownContent, MarkdownContentConstructor, MarkdownContext, MarkdownOptions, MarkdownRuntime, HTMLValidationIssue as MarkdownValidationIssue, MarkdownValidationResult, MarkedTextNode, MessageFormatDialect, MessageValues, NAMED_CODES_TO_UNICODE, NP_TABLE_R, NestedCond, NestedContent, NestedContentState, NestedParser, NewlineNode, NodeProps, ORDERED, ORDERED_LIST_BULLET, ORDERED_LIST_ITEM_PREFIX, ORDERED_LIST_ITEM_PREFIX_R, ORDERED_LIST_ITEM_R, ORDERED_LIST_R, OrderedListNode, PARAGRAPH_R, ParagraphNode, ParseState, ParsedMarkdown, Parser, ParserResult, Plugins, PluralCategory, PluralCond, PluralContent, PluralContentState, PortableObject, Priority, PriorityValue, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, REFERENCE_IMAGE_OR_LINK, REFERENCE_IMAGE_R, REFERENCE_LINK_R, ReferenceImageNode, ReferenceLinkNode, ReferenceNode, RenderRuleHook, Rule, RuleOutput, RuleType, RuleTypeValue, Rules, SHORTCODE_R, SHOULD_RENDER_AS_BLOCK_R, SitemapUrlEntry, StrikethroughTextNode, TABLE_CENTER_ALIGN, TABLE_LEFT_ALIGN, TABLE_RIGHT_ALIGN, TABLE_TRIM_PIPES, TAB_R, TEXT_BOLD_R, TEXT_EMPHASIZED_R, TEXT_ESCAPED_R, TEXT_MARKED_R, TEXT_PLAIN_R, TEXT_STRIKETHROUGHED_R, TRIM_STARTING_NEWLINES, TableNode, TableSeparatorNode, TaggedMessageToken, TextNode, TranslationCond, TranslationContent, UNESCAPE_R, UNORDERED, UNORDERED_LIST_BULLET, UNORDERED_LIST_ITEM_PREFIX, UNORDERED_LIST_ITEM_PREFIX_R, UNORDERED_LIST_ITEM_R, UNORDERED_LIST_R, UnionKeys, UnorderedListNode, VOID_HTML_ELEMENTS, ValidDotPathsFor, ValueAtKey, WrappedIntl, YamlRecord, YamlValue, allowInline, anyScopeRegex, attributeValueToNodePropValue, bindIntl, blockRegex, buildMaskPlugin, captureNothing, checkIsURLAbsolute, checkMissingLocalesPlugin, compact, comparePaths, compile, compileWithOptions, condition as cond, conditionPlugin, createCompiler, createRenderer, currency, cx, date, deepTransformNode, editDictionaryByKeyPath, enumeration as enu, enumerationPlugin, fallbackPlugin, file, fileContent, filePlugin, filterMissingTranslationsOnlyPlugin, filterTranslationsOnlyPlugin, findMatchingCondition, gender, genderPlugin, generateListItemPrefix, generateListItemPrefixRegex, generateListItemRegex, generateListRegex, generateSitemap, generateSitemapUrl, get, getBasePlugins, getBrowserLocale, getCachedIntl, getCanonicalPath, getCondition, getContent, getContentNodeByKeyPath, getCookie, getDefaultNode, getDictionary, getDictionaryCompositeId, getDictionaryQualifierId, getDictionaryQualifierSegments, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getEditedContent, getEditedDictionary, getEmptyNode, getEnumeration, getFilterMissingTranslationsContent, getFilterMissingTranslationsDictionary, getFilterTranslationsOnlyContent, getFilterTranslationsOnlyDictionary, getFilteredLocalesContent, getFilteredLocalesDictionary, getHTML, getHTMLTextDir, getInsertionValues, getInternalPath, getIntlayer, getLocale, getLocaleFromPath, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, getLocaleLang, getLocaleName, getLocalizedContent, getLocalizedPath, getLocalizedUrl, getMarkdownMetadata, getMaskContent, getMissingLocalesContent, getMissingLocalesContentFromDictionary, getMultilingualDictionary, getMultilingualUrls, getNesting, getNodeChildren, getNodeType, getPathWithoutLocale, getPerLocaleDictionary, getPlural, getPrefix, getReplacedValuesContent, getRewritePath, getRewriteRules, getSplittedContent, getSplittedDictionaryContent, getTranslation, html, i18nextToIntlayerFormatter, icuToIntlayerFormatter, inlineRegex, insertion as insert, insertContentInDictionary, insertionPlugin, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, isSameKeyPath, isValidElement, list, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, localeStorageOptions, markdown as md, mergeDictionaries, mergeQualifiedDictionaries, nesting as nest, nestedPlugin, normalizeAttributeKey, normalizeDictionaries, normalizeDictionary, normalizePath, normalizeWhitespace, number, orderDictionaries, parseBlock, parseCaptureInline, parseDictionarySelector, parseInline, parseMarkdown, parseSimpleInline, parseStyleAttribute, parseTableAlign, parseTableAlignCapture, parseTableCells, parseTableRow, parseTaggedMessage, parseYaml, parserFor, percentage, plural, pluralPlugin, portableObjectToIntlayerFormatter, presets, qualifies, reconstructQualifiedEntry, relativeTime, removeContentNodeByKeyPath, renameContentNodeByKeyPath, renderFor, renderMarkdownAst, renderNothing, resolveMessage, resolveMessageNode, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, sanitizer, serializeVariant, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer, simpleInlineRegex, slugify, some, splitInsertionTemplate, startsWith, stringifyYaml, translation as t, translationPlugin, trimEnd, trimLeadingWhitespaceOutsideFences, unescapeString, units, unquote, updateNodeChildren, validateHTML, validateMarkdown, validatePrefix, vueI18nToIntlayerFormatter };
@@ -6,14 +6,14 @@ import { DeclaredLocales, ExtractSelectorLocale, LocalesValues } from "@intlayer
6
6
  /**
7
7
  * Transforms a dictionary in a single pass, applying each plugin as needed.
8
8
  *
9
- * Also accepts a `QualifiedDictionaryGroup` (collections, variants, meta
10
- * records) together with a selector as second argument — the group is resolved
11
- * to a single entry (or an ordered array of entries for collections without an
12
- * `item` selector) before transformation.
9
+ * Also accepts a `QualifiedDictionaryGroup` (collections, variants) together
10
+ * with a selector as second argument — the group is resolved to a single entry
11
+ * (or an ordered array of entries for collections without an `item` selector)
12
+ * before transformation.
13
13
  *
14
14
  * @param dictionary The dictionary (or qualified dictionary group) to transform.
15
15
  * @param localeOrSelector The locale, or a selector object (`{ item }`,
16
- * `{ variant }`, `{ id, ...meta }`, optionally with `locale`).
16
+ * `{ variant }`, optionally with `locale`).
17
17
  * @param plugins An array of NodeTransformer that define how to transform recognized nodes.
18
18
  * If omitted, we’ll use a default set of plugins.
19
19
  */
@@ -10,7 +10,7 @@ import { DeclaredLocales, DictionaryKeys, DictionaryRegistryResult, ExtractSelec
10
10
  * The second argument is either a locale (`'fr'`) or a selector object:
11
11
  * - `{ item: 2 }` — collection item (omit `item` to get every item as array)
12
12
  * - `{ variant: 'black-friday' }` — named variant (omit for the `default` one)
13
- * - `{ id: 'prod_abc', ...metaFields }` — meta record
13
+ * - `{ variant: { id: 'prod_abc', userId: '123' } }` — structured variant
14
14
  * - `locale` can be combined with any selector: `{ item: 2, locale: 'fr' }`
15
15
  */
16
16
  declare const getIntlayer: <const T extends DictionaryKeys, const A extends LocalesValues | DictionarySelector = DeclaredLocales>(key: T, localeOrSelector?: A, plugins?: Plugins[]) => DeepTransformContent<DictionaryRegistryResult<T, A>, IInterpreterPluginState, ExtractSelectorLocale<A>>;