@intlayer/core 9.7.1 → 9.7.3

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 (55) hide show
  1. package/dist/cjs/deepTransformPlugins/getFilteredLocalesContent.cjs.map +1 -1
  2. package/dist/cjs/dictionaryManipulator/getContentNodeByKeyPath.cjs +8 -2
  3. package/dist/cjs/dictionaryManipulator/getContentNodeByKeyPath.cjs.map +1 -1
  4. package/dist/cjs/dictionaryManipulator/getDefaultNode.cjs.map +1 -1
  5. package/dist/cjs/dictionaryManipulator/getEmptyNode.cjs.map +1 -1
  6. package/dist/cjs/dictionaryManipulator/getNodeChildren.cjs.map +1 -1
  7. package/dist/cjs/dictionaryManipulator/getNodeType.cjs.map +1 -1
  8. package/dist/cjs/dictionaryManipulator/removeContentNodeByKeyPath.cjs.map +1 -1
  9. package/dist/cjs/dictionaryManipulator/renameContentNodeByKeyPath.cjs.map +1 -1
  10. package/dist/cjs/dictionaryManipulator/updateNodeChildren.cjs.map +1 -1
  11. package/dist/cjs/interpreter/getContent/plugins.cjs +2 -2
  12. package/dist/cjs/interpreter/getContent/plugins.cjs.map +1 -1
  13. package/dist/cjs/markdown/compiler.cjs.map +1 -1
  14. package/dist/cjs/messageFormat/resolveMessage.cjs +1 -1
  15. package/dist/cjs/messageFormat/resolveMessage.cjs.map +1 -1
  16. package/dist/cjs/transpiler/nesting/nesting.cjs.map +1 -1
  17. package/dist/cjs/transpiler/translation/translation.cjs.map +1 -1
  18. package/dist/cjs/utils/intl.cjs.map +1 -1
  19. package/dist/cjs/utils/localeStorage.cjs.map +1 -1
  20. package/dist/esm/deepTransformPlugins/getFilteredLocalesContent.mjs.map +1 -1
  21. package/dist/esm/dictionaryManipulator/getContentNodeByKeyPath.mjs +8 -2
  22. package/dist/esm/dictionaryManipulator/getContentNodeByKeyPath.mjs.map +1 -1
  23. package/dist/esm/dictionaryManipulator/getDefaultNode.mjs.map +1 -1
  24. package/dist/esm/dictionaryManipulator/getEmptyNode.mjs.map +1 -1
  25. package/dist/esm/dictionaryManipulator/getNodeChildren.mjs.map +1 -1
  26. package/dist/esm/dictionaryManipulator/getNodeType.mjs.map +1 -1
  27. package/dist/esm/dictionaryManipulator/removeContentNodeByKeyPath.mjs.map +1 -1
  28. package/dist/esm/dictionaryManipulator/renameContentNodeByKeyPath.mjs.map +1 -1
  29. package/dist/esm/dictionaryManipulator/updateNodeChildren.mjs.map +1 -1
  30. package/dist/esm/interpreter/getContent/plugins.mjs +2 -2
  31. package/dist/esm/interpreter/getContent/plugins.mjs.map +1 -1
  32. package/dist/esm/markdown/compiler.mjs.map +1 -1
  33. package/dist/esm/messageFormat/resolveMessage.mjs +1 -1
  34. package/dist/esm/messageFormat/resolveMessage.mjs.map +1 -1
  35. package/dist/esm/transpiler/nesting/nesting.mjs.map +1 -1
  36. package/dist/esm/transpiler/translation/translation.mjs.map +1 -1
  37. package/dist/esm/utils/intl.mjs.map +1 -1
  38. package/dist/esm/utils/localeStorage.mjs.map +1 -1
  39. package/dist/types/deepTransformPlugins/getFilteredLocalesContent.d.ts.map +1 -1
  40. package/dist/types/dictionaryManipulator/getContentNodeByKeyPath.d.ts +6 -0
  41. package/dist/types/dictionaryManipulator/getContentNodeByKeyPath.d.ts.map +1 -1
  42. package/dist/types/dictionaryManipulator/getDefaultNode.d.ts.map +1 -1
  43. package/dist/types/dictionaryManipulator/getEmptyNode.d.ts.map +1 -1
  44. package/dist/types/dictionaryManipulator/getNodeChildren.d.ts.map +1 -1
  45. package/dist/types/dictionaryManipulator/getNodeType.d.ts.map +1 -1
  46. package/dist/types/dictionaryManipulator/removeContentNodeByKeyPath.d.ts.map +1 -1
  47. package/dist/types/dictionaryManipulator/renameContentNodeByKeyPath.d.ts.map +1 -1
  48. package/dist/types/dictionaryManipulator/updateNodeChildren.d.ts.map +1 -1
  49. package/dist/types/index.d.ts +2 -2
  50. package/dist/types/interpreter/getContent/plugins.d.ts.map +1 -1
  51. package/dist/types/transpiler/nesting/nesting.d.ts.map +1 -1
  52. package/dist/types/transpiler/translation/translation.d.ts.map +1 -1
  53. package/dist/types/utils/intl.d.ts +25 -0
  54. package/dist/types/utils/intl.d.ts.map +1 -1
  55. package/package.json +72 -72
@@ -1 +1 @@
1
- {"version":3,"file":"resolveMessage.mjs","names":[],"sources":["../../../src/messageFormat/resolveMessage.ts"],"sourcesContent":["import type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport { getCachedIntl } from '../formatters';\nimport { getEnumeration } from '../interpreter/getEnumeration';\nimport { getPlural } from '../interpreter/getPlural';\nimport { getSelect } from '../interpreter/getSelect';\nimport type { PluralContentState } from '../transpiler/plural/plural';\nimport { icuToIntlayerFormatter } from './ICU';\nimport { i18nextToIntlayerFormatter } from './i18next';\nimport { vueI18nToIntlayerFormatter } from './vue-i18n';\n\n/**\n * Runtime counterpart of the `messageFormat` converters.\n *\n * The converters (`icuToIntlayerFormatter`, `i18nextToIntlayerFormatter`,\n * `vueI18nToIntlayerFormatter`) turn library-specific message syntax into\n * intlayer nodes (`insert`, `plural`, `enu`, `gender`, `html`). This module\n * resolves those nodes — or raw message strings — into a final string using\n * the provided interpolation values and locale.\n *\n * It is the mutualized resolution engine used by the compat adapter packages\n * (`@intlayer/i18next`, `@intlayer/next-intl`, `@intlayer/vue-i18n`, …).\n */\n\n/** Message syntax dialect of the source i18n library. */\nexport type MessageFormatDialect = 'icu' | 'i18next' | 'vue-i18n';\n\n/** Interpolation values passed alongside a translation lookup. */\nexport type MessageValues = Record<string, unknown>;\n\n/** Internal enumeration metadata keys injected by the converters. */\nconst ENUMERATION_METADATA_KEYS = [\n '__intlayer_icu_var',\n '__intlayer_icu_ordinal',\n '__intlayer_vue_i18n_var',\n] as const;\n\n/**\n * Resolves a possibly-dotted path (`user.name`) inside the values object.\n */\nconst resolveValuePath = (values: MessageValues, path: string): unknown => {\n if (path in values) return values[path];\n\n let current: unknown = values;\n for (const part of path.split('.')) {\n if (\n current === null ||\n current === undefined ||\n typeof current !== 'object'\n ) {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n return current;\n};\n\n/** Formats an ICU-style formatted argument (`{value, number, percent}`). */\nconst formatArgument = (\n value: unknown,\n type: string,\n style: string | undefined,\n locale: LocalesValues\n): string => {\n try {\n if (type === 'number') {\n const numberValue = Number(value);\n if (style === 'percent') {\n return getCachedIntl('NumberFormat', locale, {\n style: 'percent',\n }).format(numberValue);\n }\n if (style === 'integer') {\n return getCachedIntl('NumberFormat', locale, {\n maximumFractionDigits: 0,\n }).format(numberValue);\n }\n return getCachedIntl('NumberFormat', locale).format(numberValue);\n }\n\n if (type === 'date' || type === 'time') {\n const dateValue =\n value instanceof Date ? value : new Date(value as string | number);\n const dateTimeStyle = (\n ['short', 'medium', 'long', 'full'].includes(style ?? '')\n ? style\n : type === 'date'\n ? 'medium'\n : 'short'\n ) as 'short' | 'medium' | 'long' | 'full';\n\n return getCachedIntl(\n 'DateTimeFormat',\n locale,\n type === 'date'\n ? { dateStyle: dateTimeStyle }\n : { timeStyle: dateTimeStyle }\n ).format(dateValue);\n }\n } catch {\n // Fall through to the raw string representation below\n }\n\n return String(value);\n};\n\n/**\n * Interpolates a message template with values.\n *\n * Handles, in order:\n * 1. Intlayer insertions `{{name}}` (whitespace-tolerant, dotted paths),\n * optionally formatted the i18next way (`{{price, number}}`)\n * 2. ICU formatted arguments `{value, number}` / `{ts, date, long}`\n * 3. Bare single-brace arguments `{name}` (ICU / vue-i18n simple args)\n */\nexport const interpolateMessage = (\n template: string,\n values: MessageValues = {},\n locale: LocalesValues = 'en' as LocalesValues\n): string =>\n template\n .replace(\n /\\{\\{\\s*([^{},]+?)\\s*(?:,\\s*(\\w+)\\s*(?:,\\s*([^{}]+?)\\s*)?)?\\}\\}/g,\n (match, path: string, type: string | undefined, style?: string) => {\n const value = resolveValuePath(values, path);\n if (value === undefined) return match;\n return type\n ? formatArgument(value, type, style, locale)\n : String(value);\n }\n )\n .replace(\n /\\{\\s*([\\w.]+)\\s*,\\s*(\\w+)\\s*(?:,\\s*([^}]+?)\\s*)?\\}/g,\n (match, path: string, type: string, style: string | undefined) => {\n const value = resolveValuePath(values, path);\n if (value === undefined) return match;\n return formatArgument(value, type, style, locale);\n }\n )\n .replace(/\\{\\s*([\\w.]+)\\s*\\}/g, (match, path: string) => {\n const value = resolveValuePath(values, path);\n return value === undefined ? match : String(value);\n });\n\n/** Reads the selector value of an enumeration/plural node from the values. */\nconst getSelectorValue = (\n values: MessageValues,\n variableName: string\n): unknown => values[variableName] ?? values.count ?? values.n;\n\n/**\n * Resolves an intlayer message node tree (as produced by the\n * `*ToIntlayerFormatter` converters, or already present in a built\n * dictionary) into its final value using interpolation values and locale.\n *\n * Function nodes (produced by the interpreter plugins for `insertion`,\n * `enumeration` and `plural` content) are invoked with the values.\n */\nexport const resolveMessageNode = (\n node: unknown,\n values: MessageValues = {},\n locale: LocalesValues = 'en' as LocalesValues\n): unknown => {\n if (node === null || node === undefined) return node;\n\n if (typeof node === 'string') {\n return interpolateMessage(node, values, locale);\n }\n\n if (typeof node === 'number' || typeof node === 'boolean') {\n return String(node);\n }\n\n // Interpreter-transformed nodes (insertion/enumeration/plural plugins)\n // are exposed as callables taking the interpolation values.\n if (typeof node === 'function') {\n try {\n return resolveMessageNode(\n (node as (arg: MessageValues) => unknown)(values),\n values,\n locale\n );\n } catch {\n return undefined;\n }\n }\n\n if (Array.isArray(node)) {\n return node\n .map((item) => String(resolveMessageNode(item, values, locale) ?? ''))\n .join('');\n }\n\n const typedNode = node as Record<string, unknown> & { nodeType?: string };\n\n if (typedNode.nodeType === NodeTypes.INSERTION) {\n return resolveMessageNode(typedNode[NodeTypes.INSERTION], values, locale);\n }\n\n if (typedNode.nodeType === NodeTypes.HTML) {\n // Tags are kept intact — rich rendering is handled by the caller\n return resolveMessageNode(typedNode[NodeTypes.HTML], values, locale);\n }\n\n if (typedNode.nodeType === NodeTypes.PLURAL) {\n const pluralState = typedNode[\n NodeTypes.PLURAL\n ] as PluralContentState<unknown>;\n const count = Number(getSelectorValue(values, 'count') ?? 1);\n const selected = getPlural(\n pluralState as PluralContentState<string>,\n count,\n locale\n );\n return resolveMessageNode(selected, values, locale);\n }\n\n if (typedNode.nodeType === NodeTypes.ENUMERATION) {\n const enumerationState = typedNode[NodeTypes.ENUMERATION] as Record<\n string,\n unknown\n >;\n\n const variableName = (ENUMERATION_METADATA_KEYS.map(\n (metadataKey) => enumerationState[metadataKey]\n ).find((name) => typeof name === 'string') ?? 'count') as string;\n\n const isOrdinal = enumerationState.__intlayer_icu_ordinal === true;\n\n const options: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(enumerationState)) {\n if (!(ENUMERATION_METADATA_KEYS as readonly string[]).includes(key)) {\n options[key] = value;\n }\n }\n\n const selector = getSelectorValue(values, variableName);\n\n let selected: unknown;\n if (isOrdinal && !Number.isNaN(Number(selector))) {\n // ICU `selectordinal` — exact numeric match first, then the CLDR\n // ordinal category, then the fallback\n const ordinalCount = Number(selector);\n const ordinalCategory = getCachedIntl('PluralRules', locale, {\n type: 'ordinal',\n }).select(ordinalCount);\n selected =\n options[String(ordinalCount)] ??\n options[ordinalCategory] ??\n options.fallback ??\n options.other;\n } else if (\n typeof selector === 'number' ||\n !Number.isNaN(Number(selector))\n ) {\n selected = getEnumeration(options, Number(selector));\n } else {\n // String selector — ICU `select` converted to an enumeration\n selected = options[String(selector)] ?? options.fallback ?? options.other;\n }\n\n return resolveMessageNode(selected, values, locale);\n }\n\n if (typedNode.nodeType === NodeTypes.SELECT) {\n const selectState = typedNode[NodeTypes.SELECT] as Record<string, unknown>;\n\n // The node records the ICU variable it was imported from; fall back to\n // `value` for nodes authored directly with `select()`.\n const variableName =\n typeof typedNode.variable === 'string' ? typedNode.variable : 'value';\n\n const selector = getSelectorValue(values, variableName);\n const selected = getSelect(selectState, String(selector ?? ''));\n\n return resolveMessageNode(selected, values, locale);\n }\n\n if (typedNode.nodeType === NodeTypes.GENDER) {\n const genderState = typedNode[NodeTypes.GENDER] as Record<string, unknown>;\n const genderValue = String(values.gender ?? '');\n const selected =\n genderState[genderValue] ?? genderState.fallback ?? genderState.other;\n return resolveMessageNode(selected, values, locale);\n }\n\n return node;\n};\n\n/**\n * {@link resolveMessageNode} coerced to a string.\n *\n * This is the whole runtime a compat adapter needs for content that reached\n * the bundle through a built dictionary: the build already converted every\n * dialect construct into intlayer nodes, and the interpreter turned those into\n * callables, so no message parser is involved. Plain strings still get\n * `{{name}}` / `{name}` / `{value, number}` interpolation.\n */\nexport const resolveMessageNodeToString = (\n node: unknown,\n values: MessageValues = {},\n locale: LocalesValues = 'en' as LocalesValues\n): string => {\n const resolved = resolveMessageNode(node, values, locale);\n\n return typeof resolved === 'string' ? resolved : String(resolved ?? '');\n};\n\n/** Converts a raw message string of one dialect into an intlayer node tree. */\nexport type MessageFormatter = (message: string) => unknown;\n\n/**\n * Resolves a raw message — string, or an intlayer node tree — into a final\n * string using interpolation values and locale.\n */\nexport type MessageResolver = (\n message: unknown,\n values?: MessageValues,\n locale?: LocalesValues\n) => string;\n\n/**\n * Binds {@link resolveMessageNode} to one dialect converter.\n *\n * The compat adapters each speak a single dialect, and referencing the\n * converter directly — rather than picking it from a record keyed by dialect —\n * is what lets a bundler drop the two parsers the adapter never uses.\n *\n * @example\n * ```ts\n * const resolveIcuMessage = createMessageResolver(icuToIntlayerFormatter);\n * resolveIcuMessage('Hello {name}', { name: 'John' }, 'en'); // 'Hello John'\n * ```\n */\nexport const createMessageResolver =\n (formatter: MessageFormatter): MessageResolver =>\n (message, values = {}, locale = 'en' as LocalesValues) =>\n resolveMessageNodeToString(\n typeof message === 'string' ? formatter(message) : message,\n values,\n locale\n );\n\nconst DIALECT_FORMATTERS: Record<MessageFormatDialect, MessageFormatter> = {\n icu: icuToIntlayerFormatter,\n i18next: i18nextToIntlayerFormatter,\n 'vue-i18n': vueI18nToIntlayerFormatter,\n};\n\n/**\n * Resolves a raw message — string in a library dialect, or an intlayer node\n * tree — into a final string using interpolation values and locale.\n *\n * Selecting the dialect at runtime keeps every converter reachable; a package\n * that only ever needs one should bind it with {@link createMessageResolver}.\n *\n * @example\n * ```ts\n * resolveMessage('Hello {name}', { name: 'John' }, 'en', 'icu');\n * // 'Hello John'\n *\n * resolveMessage(\n * '{count, plural, one {# item} other {# items}}',\n * { count: 3 },\n * 'en',\n * 'icu'\n * );\n * // '3 items'\n * ```\n */\nexport const resolveMessage = (\n message: unknown,\n values: MessageValues = {},\n locale: LocalesValues = 'en' as LocalesValues,\n dialect: MessageFormatDialect = 'icu'\n): string =>\n createMessageResolver(DIALECT_FORMATTERS[dialect])(message, values, locale);\n\n/** A parsed token of a tagged message: plain text or a tag with children. */\nexport type TaggedMessageToken =\n | string\n | { tag: string; children: TaggedMessageToken[] };\n\n/**\n * Tokenizes a message containing XML-like tags (`'Visit <link>the docs</link>'`,\n * `'hello <1>{{name}}</1>'`, `'line<br/>break'`) into a token tree.\n *\n * Used by rich-text renderers (`t.rich`, `<Trans components>`,\n * `<i18n-t>` slots) to map tags to framework elements.\n */\nexport const parseTaggedMessage = (message: string): TaggedMessageToken[] => {\n const tokens: TaggedMessageToken[] = [];\n const tagRegex = /<([\\w-]+)\\s*\\/>|<([\\w-]+)[^>]*>([\\s\\S]*?)<\\/\\2>/g;\n let lastIndex = 0;\n let match = tagRegex.exec(message);\n\n while (match !== null) {\n if (match.index > lastIndex) {\n tokens.push(message.slice(lastIndex, match.index));\n }\n\n const [, selfClosingTag, tag, inner] = match;\n\n if (selfClosingTag) {\n tokens.push({ tag: selfClosingTag, children: [] });\n } else if (tag) {\n tokens.push({ tag, children: parseTaggedMessage(inner ?? '') });\n }\n\n lastIndex = match.index + match[0].length;\n match = tagRegex.exec(message);\n }\n\n if (lastIndex < message.length) {\n tokens.push(message.slice(lastIndex));\n }\n\n return tokens;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"resolveMessage.mjs","names":[],"sources":["../../../src/messageFormat/resolveMessage.ts"],"sourcesContent":["import type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport { getCachedIntl } from '../formatters';\nimport { getEnumeration } from '../interpreter/getEnumeration';\nimport { getPlural } from '../interpreter/getPlural';\nimport { getSelect } from '../interpreter/getSelect';\nimport type { PluralContentState } from '../transpiler/plural/plural';\nimport { i18nextToIntlayerFormatter } from './i18next';\nimport { icuToIntlayerFormatter } from './ICU';\nimport { vueI18nToIntlayerFormatter } from './vue-i18n';\n\n/**\n * Runtime counterpart of the `messageFormat` converters.\n *\n * The converters (`icuToIntlayerFormatter`, `i18nextToIntlayerFormatter`,\n * `vueI18nToIntlayerFormatter`) turn library-specific message syntax into\n * intlayer nodes (`insert`, `plural`, `enu`, `gender`, `html`). This module\n * resolves those nodes — or raw message strings — into a final string using\n * the provided interpolation values and locale.\n *\n * It is the mutualized resolution engine used by the compat adapter packages\n * (`@intlayer/i18next`, `@intlayer/next-intl`, `@intlayer/vue-i18n`, …).\n */\n\n/** Message syntax dialect of the source i18n library. */\nexport type MessageFormatDialect = 'icu' | 'i18next' | 'vue-i18n';\n\n/** Interpolation values passed alongside a translation lookup. */\nexport type MessageValues = Record<string, unknown>;\n\n/** Internal enumeration metadata keys injected by the converters. */\nconst ENUMERATION_METADATA_KEYS = [\n '__intlayer_icu_var',\n '__intlayer_icu_ordinal',\n '__intlayer_vue_i18n_var',\n] as const;\n\n/**\n * Resolves a possibly-dotted path (`user.name`) inside the values object.\n */\nconst resolveValuePath = (values: MessageValues, path: string): unknown => {\n if (path in values) return values[path];\n\n let current: unknown = values;\n for (const part of path.split('.')) {\n if (\n current === null ||\n current === undefined ||\n typeof current !== 'object'\n ) {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n return current;\n};\n\n/** Formats an ICU-style formatted argument (`{value, number, percent}`). */\nconst formatArgument = (\n value: unknown,\n type: string,\n style: string | undefined,\n locale: LocalesValues\n): string => {\n try {\n if (type === 'number') {\n const numberValue = Number(value);\n if (style === 'percent') {\n return getCachedIntl('NumberFormat', locale, {\n style: 'percent',\n }).format(numberValue);\n }\n if (style === 'integer') {\n return getCachedIntl('NumberFormat', locale, {\n maximumFractionDigits: 0,\n }).format(numberValue);\n }\n return getCachedIntl('NumberFormat', locale).format(numberValue);\n }\n\n if (type === 'date' || type === 'time') {\n const dateValue =\n value instanceof Date ? value : new Date(value as string | number);\n const dateTimeStyle = (\n ['short', 'medium', 'long', 'full'].includes(style ?? '')\n ? style\n : type === 'date'\n ? 'medium'\n : 'short'\n ) as 'short' | 'medium' | 'long' | 'full';\n\n return getCachedIntl(\n 'DateTimeFormat',\n locale,\n type === 'date'\n ? { dateStyle: dateTimeStyle }\n : { timeStyle: dateTimeStyle }\n ).format(dateValue);\n }\n } catch {\n // Fall through to the raw string representation below\n }\n\n return String(value);\n};\n\n/**\n * Interpolates a message template with values.\n *\n * Handles, in order:\n * 1. Intlayer insertions `{{name}}` (whitespace-tolerant, dotted paths),\n * optionally formatted the i18next way (`{{price, number}}`)\n * 2. ICU formatted arguments `{value, number}` / `{ts, date, long}`\n * 3. Bare single-brace arguments `{name}` (ICU / vue-i18n simple args)\n */\nexport const interpolateMessage = (\n template: string,\n values: MessageValues = {},\n locale: LocalesValues = 'en' as LocalesValues\n): string =>\n template\n .replace(\n /\\{\\{\\s*([^{},]+?)\\s*(?:,\\s*(\\w+)\\s*(?:,\\s*([^{}]+?)\\s*)?)?\\}\\}/g,\n (match, path: string, type: string | undefined, style?: string) => {\n const value = resolveValuePath(values, path);\n if (value === undefined) return match;\n return type\n ? formatArgument(value, type, style, locale)\n : String(value);\n }\n )\n .replace(\n /\\{\\s*([\\w.]+)\\s*,\\s*(\\w+)\\s*(?:,\\s*([^}]+?)\\s*)?\\}/g,\n (match, path: string, type: string, style: string | undefined) => {\n const value = resolveValuePath(values, path);\n if (value === undefined) return match;\n return formatArgument(value, type, style, locale);\n }\n )\n .replace(/\\{\\s*([\\w.]+)\\s*\\}/g, (match, path: string) => {\n const value = resolveValuePath(values, path);\n return value === undefined ? match : String(value);\n });\n\n/** Reads the selector value of an enumeration/plural node from the values. */\nconst getSelectorValue = (\n values: MessageValues,\n variableName: string\n): unknown => values[variableName] ?? values.count ?? values.n;\n\n/**\n * Resolves an intlayer message node tree (as produced by the\n * `*ToIntlayerFormatter` converters, or already present in a built\n * dictionary) into its final value using interpolation values and locale.\n *\n * Function nodes (produced by the interpreter plugins for `insertion`,\n * `enumeration` and `plural` content) are invoked with the values.\n */\nexport const resolveMessageNode = (\n node: unknown,\n values: MessageValues = {},\n locale: LocalesValues = 'en' as LocalesValues\n): unknown => {\n if (node === null || node === undefined) return node;\n\n if (typeof node === 'string') {\n return interpolateMessage(node, values, locale);\n }\n\n if (typeof node === 'number' || typeof node === 'boolean') {\n return String(node);\n }\n\n // Interpreter-transformed nodes (insertion/enumeration/plural plugins)\n // are exposed as callables taking the interpolation values.\n if (typeof node === 'function') {\n try {\n return resolveMessageNode(\n (node as (arg: MessageValues) => unknown)(values),\n values,\n locale\n );\n } catch {\n return undefined;\n }\n }\n\n if (Array.isArray(node)) {\n return node\n .map((item) => String(resolveMessageNode(item, values, locale) ?? ''))\n .join('');\n }\n\n const typedNode = node as Record<string, unknown> & { nodeType?: string };\n\n if (typedNode.nodeType === NodeTypes.INSERTION) {\n return resolveMessageNode(typedNode[NodeTypes.INSERTION], values, locale);\n }\n\n if (typedNode.nodeType === NodeTypes.HTML) {\n // Tags are kept intact — rich rendering is handled by the caller\n return resolveMessageNode(typedNode[NodeTypes.HTML], values, locale);\n }\n\n if (typedNode.nodeType === NodeTypes.PLURAL) {\n const pluralState = typedNode[\n NodeTypes.PLURAL\n ] as PluralContentState<unknown>;\n const count = Number(getSelectorValue(values, 'count') ?? 1);\n const selected = getPlural(\n pluralState as PluralContentState<string>,\n count,\n locale\n );\n return resolveMessageNode(selected, values, locale);\n }\n\n if (typedNode.nodeType === NodeTypes.ENUMERATION) {\n const enumerationState = typedNode[NodeTypes.ENUMERATION] as Record<\n string,\n unknown\n >;\n\n const variableName = (ENUMERATION_METADATA_KEYS.map(\n (metadataKey) => enumerationState[metadataKey]\n ).find((name) => typeof name === 'string') ?? 'count') as string;\n\n const isOrdinal = enumerationState.__intlayer_icu_ordinal === true;\n\n const options: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(enumerationState)) {\n if (!(ENUMERATION_METADATA_KEYS as readonly string[]).includes(key)) {\n options[key] = value;\n }\n }\n\n const selector = getSelectorValue(values, variableName);\n\n let selected: unknown;\n if (isOrdinal && !Number.isNaN(Number(selector))) {\n // ICU `selectordinal` — exact numeric match first, then the CLDR\n // ordinal category, then the fallback\n const ordinalCount = Number(selector);\n const ordinalCategory = getCachedIntl('PluralRules', locale, {\n type: 'ordinal',\n }).select(ordinalCount);\n selected =\n options[String(ordinalCount)] ??\n options[ordinalCategory] ??\n options.fallback ??\n options.other;\n } else if (\n typeof selector === 'number' ||\n !Number.isNaN(Number(selector))\n ) {\n selected = getEnumeration(options, Number(selector));\n } else {\n // String selector — ICU `select` converted to an enumeration\n selected = options[String(selector)] ?? options.fallback ?? options.other;\n }\n\n return resolveMessageNode(selected, values, locale);\n }\n\n if (typedNode.nodeType === NodeTypes.SELECT) {\n const selectState = typedNode[NodeTypes.SELECT] as Record<string, unknown>;\n\n // The node records the ICU variable it was imported from; fall back to\n // `value` for nodes authored directly with `select()`.\n const variableName =\n typeof typedNode.variable === 'string' ? typedNode.variable : 'value';\n\n const selector = getSelectorValue(values, variableName);\n const selected = getSelect(selectState, String(selector ?? ''));\n\n return resolveMessageNode(selected, values, locale);\n }\n\n if (typedNode.nodeType === NodeTypes.GENDER) {\n const genderState = typedNode[NodeTypes.GENDER] as Record<string, unknown>;\n const genderValue = String(values.gender ?? '');\n const selected =\n genderState[genderValue] ?? genderState.fallback ?? genderState.other;\n return resolveMessageNode(selected, values, locale);\n }\n\n return node;\n};\n\n/**\n * {@link resolveMessageNode} coerced to a string.\n *\n * This is the whole runtime a compat adapter needs for content that reached\n * the bundle through a built dictionary: the build already converted every\n * dialect construct into intlayer nodes, and the interpreter turned those into\n * callables, so no message parser is involved. Plain strings still get\n * `{{name}}` / `{name}` / `{value, number}` interpolation.\n */\nexport const resolveMessageNodeToString = (\n node: unknown,\n values: MessageValues = {},\n locale: LocalesValues = 'en' as LocalesValues\n): string => {\n const resolved = resolveMessageNode(node, values, locale);\n\n return typeof resolved === 'string' ? resolved : String(resolved ?? '');\n};\n\n/** Converts a raw message string of one dialect into an intlayer node tree. */\nexport type MessageFormatter = (message: string) => unknown;\n\n/**\n * Resolves a raw message — string, or an intlayer node tree — into a final\n * string using interpolation values and locale.\n */\nexport type MessageResolver = (\n message: unknown,\n values?: MessageValues,\n locale?: LocalesValues\n) => string;\n\n/**\n * Binds {@link resolveMessageNode} to one dialect converter.\n *\n * The compat adapters each speak a single dialect, and referencing the\n * converter directly — rather than picking it from a record keyed by dialect —\n * is what lets a bundler drop the two parsers the adapter never uses.\n *\n * @example\n * ```ts\n * const resolveIcuMessage = createMessageResolver(icuToIntlayerFormatter);\n * resolveIcuMessage('Hello {name}', { name: 'John' }, 'en'); // 'Hello John'\n * ```\n */\nexport const createMessageResolver =\n (formatter: MessageFormatter): MessageResolver =>\n (message, values = {}, locale = 'en' as LocalesValues) =>\n resolveMessageNodeToString(\n typeof message === 'string' ? formatter(message) : message,\n values,\n locale\n );\n\nconst DIALECT_FORMATTERS: Record<MessageFormatDialect, MessageFormatter> = {\n icu: icuToIntlayerFormatter,\n i18next: i18nextToIntlayerFormatter,\n 'vue-i18n': vueI18nToIntlayerFormatter,\n};\n\n/**\n * Resolves a raw message — string in a library dialect, or an intlayer node\n * tree — into a final string using interpolation values and locale.\n *\n * Selecting the dialect at runtime keeps every converter reachable; a package\n * that only ever needs one should bind it with {@link createMessageResolver}.\n *\n * @example\n * ```ts\n * resolveMessage('Hello {name}', { name: 'John' }, 'en', 'icu');\n * // 'Hello John'\n *\n * resolveMessage(\n * '{count, plural, one {# item} other {# items}}',\n * { count: 3 },\n * 'en',\n * 'icu'\n * );\n * // '3 items'\n * ```\n */\nexport const resolveMessage = (\n message: unknown,\n values: MessageValues = {},\n locale: LocalesValues = 'en' as LocalesValues,\n dialect: MessageFormatDialect = 'icu'\n): string =>\n createMessageResolver(DIALECT_FORMATTERS[dialect])(message, values, locale);\n\n/** A parsed token of a tagged message: plain text or a tag with children. */\nexport type TaggedMessageToken =\n | string\n | { tag: string; children: TaggedMessageToken[] };\n\n/**\n * Tokenizes a message containing XML-like tags (`'Visit <link>the docs</link>'`,\n * `'hello <1>{{name}}</1>'`, `'line<br/>break'`) into a token tree.\n *\n * Used by rich-text renderers (`t.rich`, `<Trans components>`,\n * `<i18n-t>` slots) to map tags to framework elements.\n */\nexport const parseTaggedMessage = (message: string): TaggedMessageToken[] => {\n const tokens: TaggedMessageToken[] = [];\n const tagRegex = /<([\\w-]+)\\s*\\/>|<([\\w-]+)[^>]*>([\\s\\S]*?)<\\/\\2>/g;\n let lastIndex = 0;\n let match = tagRegex.exec(message);\n\n while (match !== null) {\n if (match.index > lastIndex) {\n tokens.push(message.slice(lastIndex, match.index));\n }\n\n const [, selfClosingTag, tag, inner] = match;\n\n if (selfClosingTag) {\n tokens.push({ tag: selfClosingTag, children: [] });\n } else if (tag) {\n tokens.push({ tag, children: parseTaggedMessage(inner ?? '') });\n }\n\n lastIndex = match.index + match[0].length;\n match = tagRegex.exec(message);\n }\n\n if (lastIndex < message.length) {\n tokens.push(message.slice(lastIndex));\n }\n\n return tokens;\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"nesting.mjs","names":[],"sources":["../../../../src/transpiler/nesting/nesting.ts"],"sourcesContent":["import type {\n DictionaryKeys,\n DictionaryRegistryContent,\n} from '@intlayer/types/module_augmentation';\nimport type { TypedNodeModel } from '@intlayer/types/nodeType';\nimport { formatNodeType, NESTED } from '@intlayer/types/nodeType';\n\nimport type { DeepTransformContent } from '../../interpreter';\n\n/**\n * Recursively builds dot-notation strings for all valid paths in T.\n * Example:\n * type X = { a: { b: { c: string }}, d: number };\n * DotPath<X> = \"a\" | \"a.b\" | \"a.b.c\" | \"d\"\n */\nexport type DotPath<T> = T extends object\n ? {\n [K in keyof T & (string | number)]: T[K] extends object\n ? // Either just K, or K + '.' + deeper path\n `${K}` | `${K}.${DotPath<T[K]>}`\n : `${K}`;\n }[keyof T & (string | number)]\n : never;\n\ntype DeepReplace<T, From, To> = T extends From\n ? To\n : T extends object\n ? { [K in keyof T]: DeepReplace<T[K], From, To> }\n : T;\n\n/** Build all valid dot-notation strings for a dictionary entry. */\nexport type ValidDotPathsFor<K extends DictionaryKeys> = DotPath<\n DeepReplace<\n DeepTransformContent<DictionaryRegistryContent<K>>,\n // Replace ReactElement type with string\n {\n type: any;\n props: any;\n key: any;\n },\n string\n >\n>;\n\nexport type NestedContentState<K extends DictionaryKeys> = {\n dictionaryKey: K;\n\n /**\n * Path must match existing keys in DictionaryRegistryContent<K>.\n * Can be either:\n * - \"dot.dot.dot\" format\n */\n path?: ValidDotPathsFor<K>;\n};\n\nexport type NestedContent<K extends DictionaryKeys = never> = TypedNodeModel<\n typeof NESTED,\n NestedContentState<K>\n>;\n\n/**\n * Function intended to be used to build intlayer dictionaries.\n *\n * Allow to extract the content of another dictionary and nest it in the current dictionary.\n *\n * Usage:\n *\n * ```ts\n * nest(\"dictionaryKey\");\n * nest(\"dictionaryKey\", \"path.to.content\");\n * ```\n *\n * The order of the keys will define the priority of the content.\n *\n */\nconst nesting = <K extends DictionaryKeys>(\n dictionaryKey: K,\n path?: ValidDotPathsFor<K>\n): NestedContent<K> =>\n formatNodeType(NESTED, {\n dictionaryKey,\n path,\n });\n\nexport { nesting as nest };\n"],"mappings":";;;;;;;;;;;;;;;;;;AA2EA,MAAM,WACJ,eACA,SAEA,eAAe,QAAQ;CACrB;CACA;AACF,CAAC"}
1
+ {"version":3,"file":"nesting.mjs","names":[],"sources":["../../../../src/transpiler/nesting/nesting.ts"],"sourcesContent":["import type {\n DictionaryKeys,\n DictionaryRegistryContent,\n} from '@intlayer/types/module_augmentation';\nimport type { TypedNodeModel } from '@intlayer/types/nodeType';\nimport { formatNodeType, NESTED } from '@intlayer/types/nodeType';\nimport type { DeepTransformContent } from '../../interpreter';\n\n/**\n * Recursively builds dot-notation strings for all valid paths in T.\n * Example:\n * type X = { a: { b: { c: string }}, d: number };\n * DotPath<X> = \"a\" | \"a.b\" | \"a.b.c\" | \"d\"\n */\nexport type DotPath<T> = T extends object\n ? {\n [K in keyof T & (string | number)]: T[K] extends object\n ? // Either just K, or K + '.' + deeper path\n `${K}` | `${K}.${DotPath<T[K]>}`\n : `${K}`;\n }[keyof T & (string | number)]\n : never;\n\ntype DeepReplace<T, From, To> = T extends From\n ? To\n : T extends object\n ? { [K in keyof T]: DeepReplace<T[K], From, To> }\n : T;\n\n/** Build all valid dot-notation strings for a dictionary entry. */\nexport type ValidDotPathsFor<K extends DictionaryKeys> = DotPath<\n DeepReplace<\n DeepTransformContent<DictionaryRegistryContent<K>>,\n // Replace ReactElement type with string\n {\n type: any;\n props: any;\n key: any;\n },\n string\n >\n>;\n\nexport type NestedContentState<K extends DictionaryKeys> = {\n dictionaryKey: K;\n\n /**\n * Path must match existing keys in DictionaryRegistryContent<K>.\n * Can be either:\n * - \"dot.dot.dot\" format\n */\n path?: ValidDotPathsFor<K>;\n};\n\nexport type NestedContent<K extends DictionaryKeys = never> = TypedNodeModel<\n typeof NESTED,\n NestedContentState<K>\n>;\n\n/**\n * Function intended to be used to build intlayer dictionaries.\n *\n * Allow to extract the content of another dictionary and nest it in the current dictionary.\n *\n * Usage:\n *\n * ```ts\n * nest(\"dictionaryKey\");\n * nest(\"dictionaryKey\", \"path.to.content\");\n * ```\n *\n * The order of the keys will define the priority of the content.\n *\n */\nconst nesting = <K extends DictionaryKeys>(\n dictionaryKey: K,\n path?: ValidDotPathsFor<K>\n): NestedContent<K> =>\n formatNodeType(NESTED, {\n dictionaryKey,\n path,\n });\n\nexport { nesting as nest };\n"],"mappings":";;;;;;;;;;;;;;;;;;AA0EA,MAAM,WACJ,eACA,SAEA,eAAe,QAAQ;CACrB;CACA;AACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"translation.mjs","names":[],"sources":["../../../../src/transpiler/translation/translation.ts"],"sourcesContent":["import type { StrictModeLocaleMap } from '@intlayer/types/module_augmentation';\nimport type { TypedNodeModel } from '@intlayer/types/nodeType';\nimport { formatNodeType, TRANSLATION } from '@intlayer/types/nodeType';\n\nexport type TranslationContent<\n Content = unknown,\n RecordContent extends\n StrictModeLocaleMap<Content> = StrictModeLocaleMap<Content>,\n> = TypedNodeModel<typeof TRANSLATION, RecordContent>;\n\n/**\n *\n * Function intended to be used to build intlayer dictionaries.\n *\n * Get the content of a translation based on the locale.\n *\n * Usage:\n *\n * ```ts\n * translation<string>({\n * \"en\": \"Hello\",\n * \"fr\": \"Bonjour\",\n * // ... any other available locale\n * })\n * ```\n *\n * Using TypeScript:\n * - this function require each locale to be defined if defined in the project configuration.\n * - If a locale is missing, it will make each existing locale optional and raise an error if the locale is not found.\n */\nconst translation = <\n Content = unknown,\n ContentRecord extends\n StrictModeLocaleMap<Content> = StrictModeLocaleMap<Content>,\n>(\n content: ContentRecord\n): TranslationContent<Content, ContentRecord> =>\n formatNodeType(TRANSLATION, content) satisfies TranslationContent<\n Content,\n ContentRecord\n >;\n\nexport { translation as t };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA8BA,MAAM,eAKJ,YAEA,eAAe,aAAa,OAAO"}
1
+ {"version":3,"file":"translation.mjs","names":[],"sources":["../../../../src/transpiler/translation/translation.ts"],"sourcesContent":["import type { StrictModeLocaleMap } from '@intlayer/types/module_augmentation';\nimport type { TypedNodeModel } from '@intlayer/types/nodeType';\nimport { formatNodeType, TRANSLATION } from '@intlayer/types/nodeType';\n\nexport type TranslationContent<\n Content = unknown,\n RecordContent extends StrictModeLocaleMap<Content> =\n StrictModeLocaleMap<Content>,\n> = TypedNodeModel<typeof TRANSLATION, RecordContent>;\n\n/**\n *\n * Function intended to be used to build intlayer dictionaries.\n *\n * Get the content of a translation based on the locale.\n *\n * Usage:\n *\n * ```ts\n * translation<string>({\n * \"en\": \"Hello\",\n * \"fr\": \"Bonjour\",\n * // ... any other available locale\n * })\n * ```\n *\n * Using TypeScript:\n * - this function require each locale to be defined if defined in the project configuration.\n * - If a locale is missing, it will make each existing locale optional and raise an error if the locale is not found.\n */\nconst translation = <\n Content = unknown,\n ContentRecord extends StrictModeLocaleMap<Content> =\n StrictModeLocaleMap<Content>,\n>(\n content: ContentRecord\n): TranslationContent<Content, ContentRecord> =>\n formatNodeType(TRANSLATION, content) satisfies TranslationContent<\n Content,\n ContentRecord\n >;\n\nexport { translation as t };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA8BA,MAAM,eAKJ,YAEA,eAAe,aAAa,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"intl.mjs","names":[],"sources":["../../../src/utils/intl.ts"],"sourcesContent":["/**\n * Cached Intl helper – drop‑in replacement for the global `Intl` object.\n * ‑‑‑\n * • Uses a `Proxy` to lazily wrap every *constructor* hanging off `Intl` (NumberFormat, DateTimeFormat, …).\n * • Each wrapped constructor keeps an in‑memory cache keyed by `[locales, options]` so that identical requests\n * reuse the same heavy instance instead of reparsing CLDR data every time.\n * • A polyfill warning for `Intl.DisplayNames` is emitted only once and only in dev.\n * • The public API is fully type‑safe and mirrors the native `Intl` surface exactly –\n * you can treat `CachedIntl` just like the built‑in `Intl`.\n *\n * Usage @example:\n * ---------------\n * ```ts\n * import { CachedIntl } from \"./cached-intl\";\n *\n * const nf = CachedIntl.NumberFormat(\"en-US\", { style: \"currency\", currency: \"USD\" });\n * console.log(nf.format(1234));\n *\n * const dn = CachedIntl.DisplayNames([\"fr\"], { type: \"language\" });\n * console.log(dn.of(\"en\")); * → \"anglais\"\n *\n * You can also spin up an isolated instance with its own caches (handy in test suites):\n * const TestIntl = createCachedIntl();\n * ```\n */\n\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { resolveInterpreterLocale } from '../interpreter/resolveInterpreterLocale';\n\nconst MAX_CACHE_SIZE = 50;\nconst cache = new Map<any, Map<string, any>>();\n\n/**\n * Minimal `Intl.ListFormat` surface, declared locally so consumers do not need\n * the `ES2021.Intl` lib in their tsconfig.\n */\ntype ListFormatInstance = {\n format(list: Iterable<string>): string;\n formatToParts(\n list: Iterable<string>\n ): { type: 'element' | 'literal'; value: string }[];\n};\n\n/**\n * Minimal `Intl.Segmenter` surface, declared locally so consumers do not need\n * the `ES2022.Intl` lib in their tsconfig.\n */\ntype SegmenterInstance = {\n segment(input: string): Iterable<{ segment: string; index: number }>;\n};\n\n/**\n * Instance type produced by each `Intl` constructor this module can build.\n */\ntype IntlInstanceByName = {\n Collator: Intl.Collator;\n DateTimeFormat: Intl.DateTimeFormat;\n DisplayNames: Intl.DisplayNames;\n ListFormat: ListFormatInstance;\n Locale: Intl.Locale;\n NumberFormat: Intl.NumberFormat;\n PluralRules: Intl.PluralRules;\n RelativeTimeFormat: Intl.RelativeTimeFormat;\n Segmenter: SegmenterInstance;\n};\n\n/**\n * Names of the `Intl` constructors this module knows how to instantiate.\n */\nexport type IntlConstructorName = keyof IntlInstanceByName;\n\nconst alreadyWarnedConstructors = new Set<string>();\n\n/**\n * Warns once per missing `Intl` constructor, in development only.\n */\nconst warnMissingIntlConstructor = (constructorName: string): void => {\n if (process.env.NODE_ENV === 'production') return;\n if (alreadyWarnedConstructors.has(constructorName)) return;\n\n alreadyWarnedConstructors.add(constructorName);\n\n console.warn(\n `[intlayer] \\`Intl.${constructorName}\\` is not available in this JavaScript engine. ` +\n `A degraded fallback is used instead. ` +\n `On React Native, load a polyfill (e.g. \\`@formatjs/intl-${constructorName.toLowerCase()}/polyfill\\`) before rendering your app.`\n );\n};\n\n/**\n * Minimal stand-ins used when the engine ships without the matching `Intl`\n * constructor. Hermes — the default React Native engine — omits\n * `DisplayNames`, `ListFormat` and `Segmenter` in release builds unless the\n * app opts into the full ICU build or loads a polyfill. Without these shims,\n * `new Intl.DisplayNames(...)` throws\n * `TypeError: undefined cannot be used as a constructor` and takes the whole\n * app down at render time.\n *\n * Each shim mirrors only the surface Intlayer relies on, and returns the\n * un-localized input so rendering degrades rather than crashing.\n */\nconst intlConstructorFallbacks: Partial<\n Record<IntlConstructorName, new (locale?: any, options?: any) => any>\n> = {\n DisplayNames: class DisplayNamesFallback {\n /** Returns the requested code unchanged, since no CLDR data is available. */\n public of(code: string): string {\n return code;\n }\n },\n ListFormat: class ListFormatFallback {\n /** Joins the list with a comma, the most neutral separator available. */\n public format(list: Iterable<string>): string {\n return Array.from(list).join(', ');\n }\n\n /** Mirrors `Intl.ListFormat.prototype.formatToParts` shape. */\n public formatToParts(\n list: Iterable<string>\n ): { type: 'element' | 'literal'; value: string }[] {\n return Array.from(list).flatMap((value, index) =>\n index === 0\n ? [{ type: 'element' as const, value }]\n : [\n { type: 'literal' as const, value: ', ' },\n { type: 'element' as const, value },\n ]\n );\n }\n },\n Segmenter: class SegmenterFallback {\n /** Segments by code point, the closest approximation without ICU data. */\n public segment(input: string): { segment: string; index: number }[] {\n let index = 0;\n\n return Array.from(input).map((segment) => {\n const segmentStart = index;\n index += segment.length;\n\n return { segment, index: segmentStart };\n });\n }\n },\n};\n\n/**\n * Resolves an `Intl` constructor by name at call time, falling back to a\n * degraded shim when the engine does not provide it.\n *\n * Resolution is deliberately lazy: React Native apps install their polyfills\n * at startup, which may run after this module is first imported.\n */\nconst resolveIntlConstructor = (\n constructorName: IntlConstructorName\n): (new (locale?: any, options?: any) => any) | undefined => {\n const nativeConstructor = (\n Intl as unknown as Record<string, new (...args: any[]) => any>\n )[constructorName];\n\n if (typeof nativeConstructor === 'function') return nativeConstructor;\n\n warnMissingIntlConstructor(constructorName);\n\n return intlConstructorFallbacks[constructorName];\n};\n\ntype IntlConstructors = {\n [K in keyof typeof Intl as (typeof Intl)[K] extends new (\n ...args: any\n ) => any\n ? K\n : never]: (typeof Intl)[K];\n};\n\ntype ReplaceLocaleWithLocalesValues<T> = T extends new (\n locales: any,\n options?: infer Options\n) => infer Instance\n ? {\n new (locales?: LocalesValues, options?: Options): Instance;\n new (options?: Options & { locale?: LocalesValues }): Instance;\n (locales?: LocalesValues, options?: Options): Instance;\n (options?: Options & { locale?: LocalesValues }): Instance;\n }\n : T extends new (\n locales: any\n ) => infer Instance\n ? {\n new (locales?: LocalesValues): Instance;\n new (options?: { locale?: LocalesValues }): Instance;\n (locales?: LocalesValues): Instance;\n (options?: { locale?: LocalesValues }): Instance;\n }\n : T;\n\nexport type WrappedIntl = {\n [K in keyof typeof Intl]: K extends keyof IntlConstructors\n ? ReplaceLocaleWithLocalesValues<(typeof Intl)[K]>\n : (typeof Intl)[K];\n};\n\n/**\n * Generic caching instantiator for Intl constructors.\n *\n * Prefer passing the constructor *name* (e.g. `'DisplayNames'`) rather than the\n * constructor itself: the name is resolved lazily against the global `Intl`, so\n * late-installed polyfills are picked up and missing constructors degrade to a\n * fallback instead of throwing.\n */\nexport function getCachedIntl<Name extends IntlConstructorName>(\n constructorName: Name,\n locale?: LocalesValues | string,\n options?: any\n): IntlInstanceByName[Name];\nexport function getCachedIntl<T extends new (...args: any[]) => any>(\n Ctor: T,\n locale?: LocalesValues | string,\n options?: any\n): InstanceType<T>;\nexport function getCachedIntl(\n intlConstructor: IntlConstructorName | (new (...args: any[]) => any),\n locale?: LocalesValues | string,\n options?: any\n): any {\n // No locale given: request locale → browser storage → default locale\n const resLoc = resolveInterpreterLocale(locale as LocalesValues | undefined);\n\n const optKey = options ? JSON.stringify(options) : '';\n const key = `${resLoc}|${optKey}`;\n\n // Cache per name when available, so two constructors that are both missing\n // from the engine do not collide on a single `undefined` cache bucket.\n const cacheKey = intlConstructor;\n\n let ctorCache = cache.get(cacheKey);\n\n if (!ctorCache) {\n ctorCache = new Map();\n cache.set(cacheKey, ctorCache);\n }\n\n let instance = ctorCache.get(key);\n\n if (!instance) {\n const ResolvedConstructor =\n typeof intlConstructor === 'string'\n ? resolveIntlConstructor(intlConstructor)\n : intlConstructor;\n\n if (typeof ResolvedConstructor !== 'function') {\n throw new Error(\n `[intlayer] \\`Intl.${String(intlConstructor)}\\` is not available in this JavaScript engine and has no fallback. ` +\n `Load the matching polyfill before formatting.`\n );\n }\n\n if (ctorCache.size > MAX_CACHE_SIZE) ctorCache.clear();\n instance = new ResolvedConstructor(resLoc, options);\n ctorCache.set(key, instance);\n }\n return instance;\n}\n\n/**\n * Optional: Keep bindIntl if your library exports it publicly.\n * It now uses the much smaller getCachedIntl under the hood.\n */\nexport const bindIntl = (boundLocale?: LocalesValues): WrappedIntl => {\n const bindWrap = (constructorName: IntlConstructorName) =>\n // function is used as a constructor, do not change in arrow function\n function intlConstructor(locales?: any, options?: any) {\n const isOptsFirst =\n locales !== null &&\n typeof locales === 'object' &&\n !Array.isArray(locales);\n const resOpts = isOptsFirst ? locales : options;\n const resLoc = isOptsFirst\n ? (resOpts as any).locale || boundLocale\n : locales || boundLocale;\n\n return getCachedIntl(constructorName, resLoc, resOpts);\n };\n\n return {\n ...Intl,\n Collator: bindWrap('Collator'),\n DateTimeFormat: bindWrap('DateTimeFormat'),\n DisplayNames: bindWrap('DisplayNames'),\n ListFormat: bindWrap('ListFormat'),\n NumberFormat: bindWrap('NumberFormat'),\n PluralRules: bindWrap('PluralRules'),\n RelativeTimeFormat: bindWrap('RelativeTimeFormat'),\n Locale: bindWrap('Locale'),\n Segmenter: bindWrap('Segmenter'),\n } as unknown as WrappedIntl;\n};\n\n// Add this to the bottom of utils/intl.ts ONLY if required for public API compatibility.\nexport const CachedIntl = {\n // function is used as a constructor, do not change in arrow function\n Collator: function Collator(locales?: any, options?: any) {\n return getCachedIntl('Collator', locales, options);\n },\n DateTimeFormat: function DateTimeFormat(locales?: any, options?: any) {\n return getCachedIntl('DateTimeFormat', locales, options);\n },\n DisplayNames: function DisplayNames(locales?: any, options?: any) {\n return getCachedIntl('DisplayNames', locales, options);\n },\n ListFormat: function ListFormat(locales?: any, options?: any) {\n return getCachedIntl('ListFormat', locales, options);\n },\n NumberFormat: function NumberFormat(locales?: any, options?: any) {\n return getCachedIntl('NumberFormat', locales, options);\n },\n PluralRules: function PluralRules(locales?: any, options?: any) {\n return getCachedIntl('PluralRules', locales, options);\n },\n RelativeTimeFormat: function RelativeTimeFormat(\n locales?: any,\n options?: any\n ) {\n return getCachedIntl('RelativeTimeFormat', locales, options);\n },\n Segmenter: function Segmenter(locales?: any, options?: any) {\n return getCachedIntl('Segmenter', locales, options);\n },\n} as any; // Cast to 'any' internally to avoid TS readonly errors\n\nexport { CachedIntl as Intl };\n"],"mappings":"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"}
1
+ {"version":3,"file":"intl.mjs","names":[],"sources":["../../../src/utils/intl.ts"],"sourcesContent":["/**\n * Cached Intl helper – drop‑in replacement for the global `Intl` object.\n * ‑‑‑\n * • Uses a `Proxy` to lazily wrap every *constructor* hanging off `Intl` (NumberFormat, DateTimeFormat, …).\n * • Each wrapped constructor keeps an in‑memory cache keyed by `[locales, options]` so that identical requests\n * reuse the same heavy instance instead of reparsing CLDR data every time.\n * • A polyfill warning for `Intl.DisplayNames` is emitted only once and only in dev.\n * • The public API is fully type‑safe and mirrors the native `Intl` surface exactly –\n * you can treat `CachedIntl` just like the built‑in `Intl`.\n *\n * Usage @example:\n * ---------------\n * ```ts\n * import { CachedIntl } from \"./cached-intl\";\n *\n * const nf = CachedIntl.NumberFormat(\"en-US\", { style: \"currency\", currency: \"USD\" });\n * console.log(nf.format(1234));\n *\n * const dn = CachedIntl.DisplayNames([\"fr\"], { type: \"language\" });\n * console.log(dn.of(\"en\")); * → \"anglais\"\n *\n * You can also spin up an isolated instance with its own caches (handy in test suites):\n * const TestIntl = createCachedIntl();\n * ```\n */\n\nimport type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { resolveInterpreterLocale } from '../interpreter/resolveInterpreterLocale';\n\nconst MAX_CACHE_SIZE = 50;\nconst cache = new Map<any, Map<string, any>>();\n\n/**\n * Minimal `Intl.ListFormat` surface, declared locally so consumers do not need\n * the `ES2021.Intl` lib in their tsconfig.\n */\ntype ListFormatInstance = {\n format(list: Iterable<string>): string;\n formatToParts(\n list: Iterable<string>\n ): { type: 'element' | 'literal'; value: string }[];\n};\n\n/**\n * Minimal `Intl.Segmenter` surface, declared locally so consumers do not need\n * the `ES2022.Intl` lib in their tsconfig.\n */\ntype SegmenterInstance = {\n segment(input: string): Iterable<{ segment: string; index: number }>;\n};\n\n/**\n * Instance type produced by each `Intl` constructor this module can build.\n */\ntype IntlInstanceByName = {\n Collator: Intl.Collator;\n DateTimeFormat: Intl.DateTimeFormat;\n DisplayNames: Intl.DisplayNames;\n ListFormat: ListFormatInstance;\n Locale: Intl.Locale;\n NumberFormat: Intl.NumberFormat;\n PluralRules: Intl.PluralRules;\n RelativeTimeFormat: Intl.RelativeTimeFormat;\n Segmenter: SegmenterInstance;\n};\n\n/**\n * Names of the `Intl` constructors this module knows how to instantiate.\n */\nexport type IntlConstructorName = keyof IntlInstanceByName;\n\nconst alreadyWarnedConstructors = new Set<string>();\n\n/**\n * Warns once per missing `Intl` constructor, in development only.\n */\nconst warnMissingIntlConstructor = (constructorName: string): void => {\n if (process.env.NODE_ENV === 'production') return;\n if (alreadyWarnedConstructors.has(constructorName)) return;\n\n alreadyWarnedConstructors.add(constructorName);\n\n console.warn(\n `[intlayer] \\`Intl.${constructorName}\\` is not available in this JavaScript engine. ` +\n `A degraded fallback is used instead. ` +\n `On React Native, load a polyfill (e.g. \\`@formatjs/intl-${constructorName.toLowerCase()}/polyfill\\`) before rendering your app.`\n );\n};\n\n/**\n * Minimal stand-ins used when the engine ships without the matching `Intl`\n * constructor. Hermes — the default React Native engine — omits\n * `DisplayNames`, `ListFormat` and `Segmenter` in release builds unless the\n * app opts into the full ICU build or loads a polyfill. Without these shims,\n * `new Intl.DisplayNames(...)` throws\n * `TypeError: undefined cannot be used as a constructor` and takes the whole\n * app down at render time.\n *\n * Each shim mirrors only the surface Intlayer relies on, and returns the\n * un-localized input so rendering degrades rather than crashing.\n */\nconst intlConstructorFallbacks: Partial<\n Record<IntlConstructorName, new (locale?: any, options?: any) => any>\n> = {\n DisplayNames: class DisplayNamesFallback {\n /** Returns the requested code unchanged, since no CLDR data is available. */\n public of(code: string): string {\n return code;\n }\n },\n ListFormat: class ListFormatFallback {\n /** Joins the list with a comma, the most neutral separator available. */\n public format(list: Iterable<string>): string {\n return Array.from(list).join(', ');\n }\n\n /** Mirrors `Intl.ListFormat.prototype.formatToParts` shape. */\n public formatToParts(\n list: Iterable<string>\n ): { type: 'element' | 'literal'; value: string }[] {\n return Array.from(list).flatMap((value, index) =>\n index === 0\n ? [{ type: 'element' as const, value }]\n : [\n { type: 'literal' as const, value: ', ' },\n { type: 'element' as const, value },\n ]\n );\n }\n },\n Segmenter: class SegmenterFallback {\n /** Segments by code point, the closest approximation without ICU data. */\n public segment(input: string): { segment: string; index: number }[] {\n let index = 0;\n\n return Array.from(input).map((segment) => {\n const segmentStart = index;\n index += segment.length;\n\n return { segment, index: segmentStart };\n });\n }\n },\n};\n\n/**\n * Resolves an `Intl` constructor by name at call time, falling back to a\n * degraded shim when the engine does not provide it.\n *\n * Resolution is deliberately lazy: React Native apps install their polyfills\n * at startup, which may run after this module is first imported.\n */\nconst resolveIntlConstructor = (\n constructorName: IntlConstructorName\n): (new (locale?: any, options?: any) => any) | undefined => {\n const nativeConstructor = (\n Intl as unknown as Record<string, new (...args: any[]) => any>\n )[constructorName];\n\n if (typeof nativeConstructor === 'function') return nativeConstructor;\n\n warnMissingIntlConstructor(constructorName);\n\n return intlConstructorFallbacks[constructorName];\n};\n\ntype IntlConstructors = {\n [\n K in keyof typeof Intl as (typeof Intl)[K] extends new (...args: any) => any\n ? K\n : never\n ]: (typeof Intl)[K];\n};\n\ntype ReplaceLocaleWithLocalesValues<T> = T extends new (\n locales: any,\n options?: infer Options\n) => infer Instance\n ? {\n new (locales?: LocalesValues, options?: Options): Instance;\n new (options?: Options & { locale?: LocalesValues }): Instance;\n (locales?: LocalesValues, options?: Options): Instance;\n (options?: Options & { locale?: LocalesValues }): Instance;\n }\n : T extends new (locales: any) => infer Instance\n ? {\n new (locales?: LocalesValues): Instance;\n new (options?: { locale?: LocalesValues }): Instance;\n (locales?: LocalesValues): Instance;\n (options?: { locale?: LocalesValues }): Instance;\n }\n : T;\n\nexport type WrappedIntl = {\n [K in keyof typeof Intl]: K extends keyof IntlConstructors\n ? ReplaceLocaleWithLocalesValues<(typeof Intl)[K]>\n : (typeof Intl)[K];\n};\n\n/**\n * Generic caching instantiator for Intl constructors.\n *\n * Prefer passing the constructor *name* (e.g. `'DisplayNames'`) rather than the\n * constructor itself: the name is resolved lazily against the global `Intl`, so\n * late-installed polyfills are picked up and missing constructors degrade to a\n * fallback instead of throwing.\n */\nexport function getCachedIntl<Name extends IntlConstructorName>(\n constructorName: Name,\n locale?: LocalesValues | string,\n options?: any\n): IntlInstanceByName[Name];\nexport function getCachedIntl<T extends new (...args: any[]) => any>(\n Ctor: T,\n locale?: LocalesValues | string,\n options?: any\n): InstanceType<T>;\nexport function getCachedIntl(\n intlConstructor: IntlConstructorName | (new (...args: any[]) => any),\n locale?: LocalesValues | string,\n options?: any\n): any {\n // No locale given: request locale → browser storage → default locale\n const resLoc = resolveInterpreterLocale(locale as LocalesValues | undefined);\n\n const optKey = options ? JSON.stringify(options) : '';\n const key = `${resLoc}|${optKey}`;\n\n // Cache per name when available, so two constructors that are both missing\n // from the engine do not collide on a single `undefined` cache bucket.\n const cacheKey = intlConstructor;\n\n let ctorCache = cache.get(cacheKey);\n\n if (!ctorCache) {\n ctorCache = new Map();\n cache.set(cacheKey, ctorCache);\n }\n\n let instance = ctorCache.get(key);\n\n if (!instance) {\n const ResolvedConstructor =\n typeof intlConstructor === 'string'\n ? resolveIntlConstructor(intlConstructor)\n : intlConstructor;\n\n if (typeof ResolvedConstructor !== 'function') {\n throw new Error(\n `[intlayer] \\`Intl.${String(intlConstructor)}\\` is not available in this JavaScript engine and has no fallback. ` +\n `Load the matching polyfill before formatting.`\n );\n }\n\n if (ctorCache.size > MAX_CACHE_SIZE) ctorCache.clear();\n instance = new ResolvedConstructor(resLoc, options);\n ctorCache.set(key, instance);\n }\n return instance;\n}\n\n/**\n * Optional: Keep bindIntl if your library exports it publicly.\n * It now uses the much smaller getCachedIntl under the hood.\n */\nexport const bindIntl = (boundLocale?: LocalesValues): WrappedIntl => {\n const bindWrap = (constructorName: IntlConstructorName) =>\n // function is used as a constructor, do not change in arrow function\n function intlConstructor(locales?: any, options?: any) {\n const isOptsFirst =\n locales !== null &&\n typeof locales === 'object' &&\n !Array.isArray(locales);\n const resOpts = isOptsFirst ? locales : options;\n const resLoc = isOptsFirst\n ? (resOpts as any).locale || boundLocale\n : locales || boundLocale;\n\n return getCachedIntl(constructorName, resLoc, resOpts);\n };\n\n return {\n ...Intl,\n Collator: bindWrap('Collator'),\n DateTimeFormat: bindWrap('DateTimeFormat'),\n DisplayNames: bindWrap('DisplayNames'),\n ListFormat: bindWrap('ListFormat'),\n NumberFormat: bindWrap('NumberFormat'),\n PluralRules: bindWrap('PluralRules'),\n RelativeTimeFormat: bindWrap('RelativeTimeFormat'),\n Locale: bindWrap('Locale'),\n Segmenter: bindWrap('Segmenter'),\n } as unknown as WrappedIntl;\n};\n\n// Add this to the bottom of utils/intl.ts ONLY if required for public API compatibility.\nexport const CachedIntl = {\n // function is used as a constructor, do not change in arrow function\n Collator: function Collator(locales?: any, options?: any) {\n return getCachedIntl('Collator', locales, options);\n },\n DateTimeFormat: function DateTimeFormat(locales?: any, options?: any) {\n return getCachedIntl('DateTimeFormat', locales, options);\n },\n DisplayNames: function DisplayNames(locales?: any, options?: any) {\n return getCachedIntl('DisplayNames', locales, options);\n },\n ListFormat: function ListFormat(locales?: any, options?: any) {\n return getCachedIntl('ListFormat', locales, options);\n },\n NumberFormat: function NumberFormat(locales?: any, options?: any) {\n return getCachedIntl('NumberFormat', locales, options);\n },\n PluralRules: function PluralRules(locales?: any, options?: any) {\n return getCachedIntl('PluralRules', locales, options);\n },\n RelativeTimeFormat: function RelativeTimeFormat(\n locales?: any,\n options?: any\n ) {\n return getCachedIntl('RelativeTimeFormat', locales, options);\n },\n Segmenter: function Segmenter(locales?: any, options?: any) {\n return getCachedIntl('Segmenter', locales, options);\n },\n} as any; // Cast to 'any' internally to avoid TS readonly errors\n\nexport { CachedIntl as Intl };\n"],"mappings":"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"}
@@ -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\nlet isStoredLocaleCached = false;\nlet storedLocale: Locale | undefined;\n\n/**\n * Returns the locale persisted in the browser storage, read with the default\n * options.\n *\n * The read is cached until the next `setLocaleInStorageClient`, so callers can\n * use it on every render without reading the cookie each time. On the server\n * nothing is cached: module state is shared by every request.\n */\nexport const getCachedLocaleFromStorageClient = (): Locale | undefined => {\n if (typeof window === 'undefined') {\n return getLocaleFromStorageClient(localeStorageOptions);\n }\n\n if (!isStoredLocaleCached) {\n storedLocale = getLocaleFromStorageClient(localeStorageOptions);\n isStoredLocaleCached = true;\n }\n\n return storedLocale;\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 // The next cached read must see this write\n isStoredLocaleCached = false;\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 // oxlint-disable-next-line unicorn/no-document-cookie -- 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\nlet isStoredLocaleCached = false;\nlet storedLocale: Locale | undefined;\n\n/**\n * Returns the locale persisted in the browser storage, read with the default\n * options.\n *\n * The read is cached until the next `setLocaleInStorageClient`, so callers can\n * use it on every render without reading the cookie each time. On the server\n * nothing is cached: module state is shared by every request.\n */\nexport const getCachedLocaleFromStorageClient = (): Locale | undefined => {\n if (typeof window === 'undefined') {\n return getLocaleFromStorageClient(localeStorageOptions);\n }\n\n if (!isStoredLocaleCached) {\n storedLocale = getLocaleFromStorageClient(localeStorageOptions);\n isStoredLocaleCached = true;\n }\n\n return storedLocale;\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 // The next cached read must see this write\n isStoredLocaleCached = false;\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 +1 @@
1
- {"version":3,"file":"getFilteredLocalesContent.d.ts","names":[],"sources":["../../../src/deepTransformPlugins/getFilteredLocalesContent.ts"],"mappings":";;;;qBAuCa,4BAAyB,MAC9B,aAAW,SACR,gBAAgB,iBAAe,WAC7B;qBAwBA,+BAA4B,YAC3B,YAAU,QACd,gBAAgB"}
1
+ {"version":3,"file":"getFilteredLocalesContent.d.ts","names":[],"sources":["../../../src/deepTransformPlugins/getFilteredLocalesContent.ts"],"mappings":";;;;qBAsCa,4BAAyB,MAC9B,aAAW,SACR,gBAAgB,iBAAe,WAC7B;qBAwBA,+BAA4B,YAC3B,YAAU,QACd,gBAAgB"}
@@ -1,5 +1,11 @@
1
1
  import { ContentNode } from "@intlayer/types/dictionary";
2
2
  import { LocalesValues } from "@intlayer/types/module_augmentation";
3
3
  import { KeyPath } from "@intlayer/types/keyPath";
4
+ /**
5
+ * Resolves the node at `keyPath` and returns a deep copy of it.
6
+ *
7
+ * The walk is read-only, so only the resolved node is copied: copying the
8
+ * whole dictionary up front made every lookup cost the full dictionary size.
9
+ */
4
10
  export declare const getContentNodeByKeyPath: (dictionaryContent: ContentNode, keyPath: KeyPath[], fallbackLocale?: LocalesValues) => ContentNode;
5
11
  //# sourceMappingURL=getContentNodeByKeyPath.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"getContentNodeByKeyPath.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/getContentNodeByKeyPath.ts"],"mappings":";;;qBAKa,0BAAuB,mBACf,aAAW,SACrB,WAAS,iBACD,kBAChB"}
1
+ {"version":3,"file":"getContentNodeByKeyPath.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/getContentNodeByKeyPath.ts"],"mappings":";;;;;;;;;qBAWa,0BAAuB,mBACf,aAAW,SACrB,WAAS,iBACD,kBAChB"}
@@ -1 +1 @@
1
- {"version":3,"file":"getDefaultNode.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/getDefaultNode.ts"],"mappings":";;;qBAMa,iBAAc,UACf,UAAQ,SACT,iBAAe,UACd,gBACT"}
1
+ {"version":3,"file":"getDefaultNode.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/getDefaultNode.ts"],"mappings":";;;qBAKa,iBAAc,UACf,UAAQ,SACT,iBAAe,UACd,gBACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"getEmptyNode.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/getEmptyNode.ts"],"mappings":";qBAIa,eAAY,SAAa,gBAAc"}
1
+ {"version":3,"file":"getEmptyNode.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/getEmptyNode.ts"],"mappings":";qBAGa,eAAY,SAAa,gBAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"getNodeChildren.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/getNodeChildren.ts"],"mappings":";qBAIa,kBAAe,SAAa,gBAAc"}
1
+ {"version":3,"file":"getNodeChildren.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/getNodeChildren.ts"],"mappings":";qBAGa,kBAAe,SAAa,gBAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"getNodeType.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/getNodeType.ts"],"mappings":";;qBAsDa,cAAW,SAAa,gBAAc"}
1
+ {"version":3,"file":"getNodeType.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/getNodeType.ts"],"mappings":";;qBAqDa,cAAW,SAAa,gBAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"removeContentNodeByKeyPath.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/removeContentNodeByKeyPath.ts"],"mappings":";;qBAKa,6BAA0B,mBAClB,aAAW,SACrB,cACR"}
1
+ {"version":3,"file":"removeContentNodeByKeyPath.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/removeContentNodeByKeyPath.ts"],"mappings":";;qBAIa,6BAA0B,mBAClB,aAAW,SACrB,cACR"}
@@ -1 +1 @@
1
- {"version":3,"file":"renameContentNodeByKeyPath.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/renameContentNodeByKeyPath.ts"],"mappings":";;qBAKa,6BAA0B,mBAClB,aAAW,QACtB,gBAAc,SACb,cACR"}
1
+ {"version":3,"file":"renameContentNodeByKeyPath.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/renameContentNodeByKeyPath.ts"],"mappings":";;qBAIa,6BAA0B,mBAClB,aAAW,QACtB,gBAAc,SACb,cACR"}
@@ -1 +1 @@
1
- {"version":3,"file":"updateNodeChildren.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/updateNodeChildren.ts"],"mappings":";qBAIa,qBACX,UAAU,aACV,UAAU,aAAW,SAEZ,GAAC,aACG,MACZ"}
1
+ {"version":3,"file":"updateNodeChildren.d.ts","names":[],"sources":["../../../src/dictionaryManipulator/updateNodeChildren.ts"],"mappings":";qBAGa,qBACX,UAAU,aACV,UAAU,aAAW,SAEZ,GAAC,aACG,MACZ"}
@@ -39,9 +39,9 @@ import { InterpolableNode, getInterpolableContent, isInterpolableWrapperNode, re
39
39
  import { AmbientLocaleResolver, AsyncAmbientLocaleResolver, registerAmbientLocaleResolver, registerAsyncAmbientLocaleResolver, resolveInterpreterLocale, resolveInterpreterLocaleAsync } from "./interpreter/resolveInterpreterLocale.js";
40
40
  import { splitInsertionTemplate } from "./interpreter/splitAndJoinInsertion.js";
41
41
  import "./dictionaryManipulator/index.js";
42
+ import { getFilteredLocalesContent, getFilteredLocalesDictionary } from "./deepTransformPlugins/getFilteredLocalesContent.js";
42
43
  import { filterMissingTranslationsOnlyPlugin, getFilterMissingTranslationsContent, getFilterMissingTranslationsDictionary } from "./deepTransformPlugins/getFilterMissingTranslationsContent.js";
43
44
  import { filterTranslationsOnlyPlugin, getFilterTranslationsOnlyContent, getFilterTranslationsOnlyDictionary } from "./deepTransformPlugins/getFilterTranslationsOnlyContent.js";
44
- import { getFilteredLocalesContent, getFilteredLocalesDictionary } from "./deepTransformPlugins/getFilteredLocalesContent.js";
45
45
  import { getLocalizedContent, getPerLocaleDictionary } from "./deepTransformPlugins/getLocalizedContent.js";
46
46
  import { buildMaskPlugin, getMaskContent } from "./deepTransformPlugins/getMaskContent.js";
47
47
  import { checkMissingLocalesPlugin, getMissingLocalesContent, getMissingLocalesContentFromDictionary } from "./deepTransformPlugins/getMissingLocalesContent.js";
@@ -68,10 +68,10 @@ import { removeContentNodeByKeyPath } from "./dictionaryManipulator/removeConten
68
68
  import { renameContentNodeByKeyPath } from "./dictionaryManipulator/renameContentNodeByKeyPath.js";
69
69
  import { updateNodeChildren } from "./dictionaryManipulator/updateNodeChildren.js";
70
70
  import "./interpreter/index.js";
71
+ import { CachedIntl, IntlConstructorName, WrappedIntl, bindIntl, getCachedIntl } from "./utils/intl.js";
71
72
  import { compact } from "./formatters/compact.js";
72
73
  import { currency } from "./formatters/currency.js";
73
74
  import { DateTimePreset, date, presets } from "./formatters/date.js";
74
- import { CachedIntl, IntlConstructorName, WrappedIntl, bindIntl, getCachedIntl } from "./utils/intl.js";
75
75
  import { ListFormatOptions, list } from "./formatters/list.js";
76
76
  import { number } from "./formatters/number.js";
77
77
  import { percentage } from "./formatters/percentage.js";
@@ -1 +1 @@
1
- {"version":3,"file":"plugins.d.ts","names":[],"sources":["../../../../src/interpreter/getContent/plugins.ts"],"mappings":"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"}
1
+ {"version":3,"file":"plugins.d.ts","names":[],"sources":["../../../../src/interpreter/getContent/plugins.ts"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"nesting.d.ts","names":[],"sources":["../../../../src/transpiler/nesting/nesting.ts"],"mappings":";;;;;;;;;;YAeY,QAAQ,KAAK,sBAElB,WAAW,wBAAwB,EAAE;MAE/B,SAAS,KAAK,QAAQ,EAAE,WACxB,aACD;KAGP,YAAY,GAAG,MAAM,MAAM,UAAU,OACtC,KACA,sBACK,WAAW,IAAI,YAAY,EAAE,IAAI,MAAM,SAC1C;;YAGM,iBAAiB,UAAU,kBAAkB,QACvD,YACE,qBAAqB,0BAA0B;EAG7C;EACA;EACA;;YAMM,mBAAmB,UAAU;EACvC,eAAe;;;;;;EAOf,OAAO,iBAAiB;;YAGd,cAAc,UAAU,0BAA0B,sBACrD,QACP,mBAAmB;;;;;;;;;;;;;;;;cAkBf,UAAW,UAAU,gBAAc,eACxB,GAAC,OACT,iBAAiB,OACvB,cAAc"}
1
+ {"version":3,"file":"nesting.d.ts","names":[],"sources":["../../../../src/transpiler/nesting/nesting.ts"],"mappings":";;;;;;;;;;YAcY,QAAQ,KAAK,sBAElB,WAAW,wBAAwB,EAAE;MAE/B,SAAS,KAAK,QAAQ,EAAE,WACxB,aACD;KAGP,YAAY,GAAG,MAAM,MAAM,UAAU,OACtC,KACA,sBACK,WAAW,IAAI,YAAY,EAAE,IAAI,MAAM,SAC1C;;YAGM,iBAAiB,UAAU,kBAAkB,QACvD,YACE,qBAAqB,0BAA0B;EAG7C;EACA;EACA;;YAMM,mBAAmB,UAAU;EACvC,eAAe;;;;;;EAOf,OAAO,iBAAiB;;YAGd,cAAc,UAAU,0BAA0B,sBACrD,QACP,mBAAmB;;;;;;;;;;;;;;;;cAkBf,UAAW,UAAU,gBAAc,eACxB,GAAC,OACT,iBAAiB,OACvB,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"translation.d.ts","names":[],"sources":["../../../../src/transpiler/translation/translation.ts"],"mappings":";;YAIY,mBACV,mBACA,sBACE,oBAAoB,WAAW,oBAAoB,YACnD,sBAAsB,aAAa;;;;;;;;;;;;;;;;;;;;;cAsBjC,cACJ,mBACA,sBACE,oBAAoB,WAAW,oBAAoB,UAAQ,SAEpD,kBACR,mBAAmB,SAAS"}
1
+ {"version":3,"file":"translation.d.ts","names":[],"sources":["../../../../src/transpiler/translation/translation.ts"],"mappings":";;YAIY,mBACV,mBACA,sBAAsB,oBAAoB,WACxC,oBAAoB,YACpB,sBAAsB,aAAa;;;;;;;;;;;;;;;;;;;;;cAsBjC,cACJ,mBACA,sBAAsB,oBAAoB,WACxC,oBAAoB,UAAQ,SAErB,kBACR,mBAAmB,SAAS"}
@@ -1,3 +1,28 @@
1
+ /**
2
+ * Cached Intl helper – drop‑in replacement for the global `Intl` object.
3
+ * ‑‑‑
4
+ * • Uses a `Proxy` to lazily wrap every *constructor* hanging off `Intl` (NumberFormat, DateTimeFormat, …).
5
+ * • Each wrapped constructor keeps an in‑memory cache keyed by `[locales, options]` so that identical requests
6
+ * reuse the same heavy instance instead of reparsing CLDR data every time.
7
+ * • A polyfill warning for `Intl.DisplayNames` is emitted only once and only in dev.
8
+ * • The public API is fully type‑safe and mirrors the native `Intl` surface exactly –
9
+ * you can treat `CachedIntl` just like the built‑in `Intl`.
10
+ *
11
+ * Usage @example:
12
+ * ---------------
13
+ * ```ts
14
+ * import { CachedIntl } from "./cached-intl";
15
+ *
16
+ * const nf = CachedIntl.NumberFormat("en-US", { style: "currency", currency: "USD" });
17
+ * console.log(nf.format(1234));
18
+ *
19
+ * const dn = CachedIntl.DisplayNames(["fr"], { type: "language" });
20
+ * console.log(dn.of("en")); * → "anglais"
21
+ *
22
+ * You can also spin up an isolated instance with its own caches (handy in test suites):
23
+ * const TestIntl = createCachedIntl();
24
+ * ```
25
+ */
1
26
  import { LocalesValues } from "@intlayer/types/module_augmentation";
2
27
  /**
3
28
  * Minimal `Intl.ListFormat` surface, declared locally so consumers do not need
@@ -1 +1 @@
1
- {"version":3,"file":"intl.d.ts","names":[],"sources":["../../../src/utils/intl.ts"],"mappings":";;;;;KAoCK;EACH,OAAO,MAAM;EACb,cACE,MAAM;IACH;IAA6B;;;;;;;KAO/B;EACH,QAAQ,gBAAgB;IAAW;IAAiB;;;;;;KAMjD;EACH,UAAU,KAAK;EACf,gBAAgB,KAAK;EACrB,cAAc,KAAK;EACnB,YAAY;EACZ,QAAQ,KAAK;EACb,cAAc,KAAK;EACnB,aAAa,KAAK;EAClB,oBAAoB,KAAK;EACzB,WAAW;;;;;YAMD,4BAA4B;KAiGnC,sBACF,kBAAkB,gBAAgB,MAAM,oBACpC,qBAED,oBACgB,MAAM;KAGvB,+BAA+B,KAAK,gBACvC,cACA,gBAAgB,kBACP;OAEA,UAAU,eAAe,UAAU,UAAU;OAC7C,UAAU;IAAY,SAAS;MAAkB;GACrD,UAAU,eAAe,UAAU,UAAU;GAC7C,UAAU;IAAY,SAAS;MAAkB;IAEpD,gBACI,uBACS;OAEJ,UAAU,gBAAgB;OAC1B;IAAY,SAAS;MAAkB;GAC3C,UAAU,gBAAgB;GAC1B;IAAY,SAAS;MAAkB;IAE1C;YAEM,iBACT,kBAAkB,OAAO,gBAAgB,mBACtC,uCAAuC,MAAM,cACrC,MAAM;;;;;;;;;wBAWJ,cAAc,aAAa,qBACzC,iBAAiB,MACjB,SAAS,wBACT,gBACC,mBAAmB;wBACN,cAAc,kBAAkB,qBAC9C,MAAM,GACN,SAAS,wBACT,gBACC,aAAa;;;;;qBAiDH,WAAQ,cAAkB,kBAAgB;qBA+B1C"}
1
+ {"version":3,"file":"intl.d.ts","names":[],"sources":["../../../src/utils/intl.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAoCK;EACH,OAAO,MAAM;EACb,cACE,MAAM;IACH;IAA6B;;;;;;;KAO/B;EACH,QAAQ,gBAAgB;IAAW;IAAiB;;;;;;KAMjD;EACH,UAAU,KAAK;EACf,gBAAgB,KAAK;EACrB,cAAc,KAAK;EACnB,YAAY;EACZ,QAAQ,KAAK;EACb,cAAc,KAAK;EACnB,aAAa,KAAK;EAClB,oBAAoB,KAAK;EACzB,WAAW;;;;;YAMD,4BAA4B;KAiGnC,sBAED,kBAAkB,gBAAgB,MAAM,oBAAmB,qBACvD,oBAEK,MAAM;KAGd,+BAA+B,KAAK,gBACvC,cACA,gBAAgB,kBACP;OAEA,UAAU,eAAe,UAAU,UAAU;OAC7C,UAAU;IAAY,SAAS;MAAkB;GACrD,UAAU,eAAe,UAAU,UAAU;GAC7C,UAAU;IAAY,SAAS;MAAkB;IAEpD,gBAAe,uBAAuB;OAE7B,UAAU,gBAAgB;OAC1B;IAAY,SAAS;MAAkB;GAC3C,UAAU,gBAAgB;GAC1B;IAAY,SAAS;MAAkB;IAE1C;YAEM,iBACT,kBAAkB,OAAO,gBAAgB,mBACtC,uCAAuC,MAAM,cACrC,MAAM;;;;;;;;;wBAWJ,cAAc,aAAa,qBACzC,iBAAiB,MACjB,SAAS,wBACT,gBACC,mBAAmB;wBACN,cAAc,kBAAkB,qBAC9C,MAAM,GACN,SAAS,wBACT,gBACC,aAAa;;;;;qBAiDH,WAAQ,cAAkB,kBAAgB;qBA+B1C"}