@intlayer/core 9.5.1 → 9.5.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.
package/README.md CHANGED
@@ -328,4 +328,4 @@ Contribute on [GitHub](https://github.com/aymericzip/intlayer), [GitLab](https:/
328
328
 
329
329
  If you like Intlayer, give us a ⭐ on GitHub. It helps others discover the project! [See why GitHub Stars matter](https://github.com/aymericzip/intlayer/blob/main/CONTRIBUTING.md#why-github-stars-matter-).
330
330
 
331
- [![Star History Chart](https://api.star-history.com/svg?repos=aymericzip/intlayer&type=Date)](https://api.star-history.com/#aymericzip/intlayer&Date)
331
+ [![Star History Chart](https://api.star-history.com/svg?repos=aymericzip/intlayer&type=Date)](https://star-history.com/#aymericzip/intlayer&Date)
@@ -215,6 +215,7 @@ exports.compileWithOptions = require_markdown_compiler.compileWithOptions;
215
215
  exports.cond = require_transpiler_condition_condition.cond;
216
216
  exports.conditionPlugin = require_interpreter_getContent_plugins.conditionPlugin;
217
217
  exports.createCompiler = require_markdown_compiler.createCompiler;
218
+ exports.createMessageResolver = require_messageFormat_resolveMessage.createMessageResolver;
218
219
  exports.createRenderer = require_markdown_renderer.createRenderer;
219
220
  exports.currency = require_formatters_currency.currency;
220
221
  exports.cx = require_markdown_utils.cx;
@@ -390,6 +391,7 @@ exports.resolveEffectiveVariantId = require_dictionaryManipulator_qualifiedDicti
390
391
  exports.resolveLocalizedPath = require_localization_rewriteUtils.resolveLocalizedPath;
391
392
  exports.resolveMessage = require_messageFormat_resolveMessage.resolveMessage;
392
393
  exports.resolveMessageNode = require_messageFormat_resolveMessage.resolveMessageNode;
394
+ exports.resolveMessageNodeToString = require_messageFormat_resolveMessage.resolveMessageNodeToString;
393
395
  exports.resolvePlainDynamicLoader = require_dictionaryManipulator_plainDynamicLoader.resolvePlainDynamicLoader;
394
396
  exports.resolveProviderVariant = require_dictionaryManipulator_qualifiedDictionary.resolveProviderVariant;
395
397
  exports.resolveProxyMode = require_localization_proxyMode.resolveProxyMode;
@@ -6,6 +6,7 @@ const require_messageFormat_po = require('./po.cjs');
6
6
  const require_messageFormat_vue_i18n = require('./vue-i18n.cjs');
7
7
  const require_messageFormat_resolveMessage = require('./resolveMessage.cjs');
8
8
 
9
+ exports.createMessageResolver = require_messageFormat_resolveMessage.createMessageResolver;
9
10
  exports.i18nextToIntlayerFormatter = require_messageFormat_i18next.i18nextToIntlayerFormatter;
10
11
  exports.icuToIntlayerFormatter = require_messageFormat_ICU.icuToIntlayerFormatter;
11
12
  exports.interpolateMessage = require_messageFormat_resolveMessage.interpolateMessage;
@@ -18,4 +19,5 @@ exports.parseTaggedMessage = require_messageFormat_resolveMessage.parseTaggedMes
18
19
  exports.portableObjectToIntlayerFormatter = require_messageFormat_po.portableObjectToIntlayerFormatter;
19
20
  exports.resolveMessage = require_messageFormat_resolveMessage.resolveMessage;
20
21
  exports.resolveMessageNode = require_messageFormat_resolveMessage.resolveMessageNode;
22
+ exports.resolveMessageNodeToString = require_messageFormat_resolveMessage.resolveMessageNodeToString;
21
23
  exports.vueI18nToIntlayerFormatter = require_messageFormat_vue_i18n.vueI18nToIntlayerFormatter;
@@ -55,13 +55,15 @@ const formatArgument = (value, type, style, locale) => {
55
55
  * Interpolates a message template with values.
56
56
  *
57
57
  * Handles, in order:
58
- * 1. Intlayer insertions `{{name}}` (whitespace-tolerant, dotted paths)
58
+ * 1. Intlayer insertions `{{name}}` (whitespace-tolerant, dotted paths),
59
+ * optionally formatted the i18next way (`{{price, number}}`)
59
60
  * 2. ICU formatted arguments `{value, number}` / `{ts, date, long}`
60
61
  * 3. Bare single-brace arguments `{name}` (ICU / vue-i18n simple args)
61
62
  */
62
- const interpolateMessage = (template, values = {}, locale = "en") => template.replace(/\{\{\s*([^{}]+?)\s*\}\}/g, (match, path) => {
63
+ const interpolateMessage = (template, values = {}, locale = "en") => template.replace(/\{\{\s*([^{},]+?)\s*(?:,\s*(\w+)\s*(?:,\s*([^{}]+?)\s*)?)?\}\}/g, (match, path, type, style) => {
63
64
  const value = resolveValuePath(values, path);
64
- return value === void 0 ? match : String(value);
65
+ if (value === void 0) return match;
66
+ return type ? formatArgument(value, type, style, locale) : String(value);
65
67
  }).replace(/\{\s*([\w.]+)\s*,\s*(\w+)\s*(?:,\s*([^}]+?)\s*)?\}/g, (match, path, type, style) => {
66
68
  const value = resolveValuePath(values, path);
67
69
  if (value === void 0) return match;
@@ -129,15 +131,45 @@ const resolveMessageNode = (node, values = {}, locale = "en") => {
129
131
  }
130
132
  return node;
131
133
  };
134
+ /**
135
+ * {@link resolveMessageNode} coerced to a string.
136
+ *
137
+ * This is the whole runtime a compat adapter needs for content that reached
138
+ * the bundle through a built dictionary: the build already converted every
139
+ * dialect construct into intlayer nodes, and the interpreter turned those into
140
+ * callables, so no message parser is involved. Plain strings still get
141
+ * `{{name}}` / `{name}` / `{value, number}` interpolation.
142
+ */
143
+ const resolveMessageNodeToString = (node, values = {}, locale = "en") => {
144
+ const resolved = resolveMessageNode(node, values, locale);
145
+ return typeof resolved === "string" ? resolved : String(resolved ?? "");
146
+ };
147
+ /**
148
+ * Binds {@link resolveMessageNode} to one dialect converter.
149
+ *
150
+ * The compat adapters each speak a single dialect, and referencing the
151
+ * converter directly — rather than picking it from a record keyed by dialect —
152
+ * is what lets a bundler drop the two parsers the adapter never uses.
153
+ *
154
+ * @example
155
+ * ```ts
156
+ * const resolveIcuMessage = createMessageResolver(icuToIntlayerFormatter);
157
+ * resolveIcuMessage('Hello {name}', { name: 'John' }, 'en'); // 'Hello John'
158
+ * ```
159
+ */
160
+ const createMessageResolver = (formatter) => (message, values = {}, locale = "en") => resolveMessageNodeToString(typeof message === "string" ? formatter(message) : message, values, locale);
132
161
  const DIALECT_FORMATTERS = {
133
- icu: (message) => require_messageFormat_ICU.icuToIntlayerFormatter(message),
134
- i18next: (message) => require_messageFormat_i18next.i18nextToIntlayerFormatter(message),
135
- "vue-i18n": (message) => require_messageFormat_vue_i18n.vueI18nToIntlayerFormatter(message)
162
+ icu: require_messageFormat_ICU.icuToIntlayerFormatter,
163
+ i18next: require_messageFormat_i18next.i18nextToIntlayerFormatter,
164
+ "vue-i18n": require_messageFormat_vue_i18n.vueI18nToIntlayerFormatter
136
165
  };
137
166
  /**
138
167
  * Resolves a raw message — string in a library dialect, or an intlayer node
139
168
  * tree — into a final string using interpolation values and locale.
140
169
  *
170
+ * Selecting the dialect at runtime keeps every converter reachable; a package
171
+ * that only ever needs one should bind it with {@link createMessageResolver}.
172
+ *
141
173
  * @example
142
174
  * ```ts
143
175
  * resolveMessage('Hello {name}', { name: 'John' }, 'en', 'icu');
@@ -152,11 +184,7 @@ const DIALECT_FORMATTERS = {
152
184
  * // '3 items'
153
185
  * ```
154
186
  */
155
- const resolveMessage = (message, values = {}, locale = "en", dialect = "icu") => {
156
- const node = typeof message === "string" ? DIALECT_FORMATTERS[dialect](message) : message;
157
- const resolved = resolveMessageNode(node, values, locale);
158
- return typeof resolved === "string" ? resolved : String(resolved ?? "");
159
- };
187
+ const resolveMessage = (message, values = {}, locale = "en", dialect = "icu") => createMessageResolver(DIALECT_FORMATTERS[dialect])(message, values, locale);
160
188
  /**
161
189
  * Tokenizes a message containing XML-like tags (`'Visit <link>the docs</link>'`,
162
190
  * `'hello <1>{{name}}</1>'`, `'line<br/>break'`) into a token tree.
@@ -188,8 +216,10 @@ const parseTaggedMessage = (message) => {
188
216
  };
189
217
 
190
218
  //#endregion
219
+ exports.createMessageResolver = createMessageResolver;
191
220
  exports.interpolateMessage = interpolateMessage;
192
221
  exports.parseTaggedMessage = parseTaggedMessage;
193
222
  exports.resolveMessage = resolveMessage;
194
223
  exports.resolveMessageNode = resolveMessageNode;
224
+ exports.resolveMessageNodeToString = resolveMessageNodeToString;
195
225
  //# sourceMappingURL=resolveMessage.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolveMessage.cjs","names":["getCachedIntl","NodeTypes","getPlural","getEnumeration","getSelect","icuToIntlayerFormatter","i18nextToIntlayerFormatter","vueI18nToIntlayerFormatter"],"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 * 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(/\\{\\{\\s*([^{}]+?)\\s*\\}\\}/g, (match, path: string) => {\n const value = resolveValuePath(values, path);\n return value === undefined ? match : String(value);\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\nconst DIALECT_FORMATTERS: Record<\n MessageFormatDialect,\n (message: string) => unknown\n> = {\n icu: (message) => icuToIntlayerFormatter(message),\n i18next: (message) => i18nextToIntlayerFormatter(message),\n 'vue-i18n': (message) => vueI18nToIntlayerFormatter(message),\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 * @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 const node =\n typeof message === 'string'\n ? DIALECT_FORMATTERS[dialect](message)\n : message;\n\n const resolved = resolveMessageNode(node, values, locale);\n\n return typeof resolved === 'string' ? resolved : String(resolved ?? '');\n};\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 {\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.cjs","names":["getCachedIntl","NodeTypes","getPlural","getEnumeration","getSelect","icuToIntlayerFormatter","i18nextToIntlayerFormatter","vueI18nToIntlayerFormatter"],"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 {\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":";;;;;;;;;;;;;;AA+BA,MAAM,4BAA4B;CAChC;CACA;CACA;AACF;;;;AAKA,MAAM,oBAAoB,QAAuB,SAA0B;CACzE,IAAI,QAAQ,QAAQ,OAAO,OAAO;CAElC,IAAI,UAAmB;CACvB,KAAK,MAAM,QAAQ,KAAK,MAAM,GAAG,GAAG;EAClC,IACE,YAAY,QACZ,YAAY,UACZ,OAAO,YAAY,UAEnB;EAEF,UAAW,QAAoC;CACjD;CACA,OAAO;AACT;;AAGA,MAAM,kBACJ,OACA,MACA,OACA,WACW;CACX,IAAI;EACF,IAAI,SAAS,UAAU;GACrB,MAAM,cAAc,OAAO,KAAK;GAChC,IAAI,UAAU,WACZ,OAAOA,iCAAc,gBAAgB,QAAQ,EAC3C,OAAO,UACT,CAAC,CAAC,CAAC,OAAO,WAAW;GAEvB,IAAI,UAAU,WACZ,OAAOA,iCAAc,gBAAgB,QAAQ,EAC3C,uBAAuB,EACzB,CAAC,CAAC,CAAC,OAAO,WAAW;GAEvB,OAAOA,iCAAc,gBAAgB,MAAM,CAAC,CAAC,OAAO,WAAW;EACjE;EAEA,IAAI,SAAS,UAAU,SAAS,QAAQ;GACtC,MAAM,YACJ,iBAAiB,OAAO,QAAQ,IAAI,KAAK,KAAwB;GACnE,MAAM,gBACJ;IAAC;IAAS;IAAU;IAAQ;GAAM,CAAC,CAAC,SAAS,SAAS,EAAE,IACpD,QACA,SAAS,SACP,WACA;GAGR,OAAOA,iCACL,kBACA,QACA,SAAS,SACL,EAAE,WAAW,cAAc,IAC3B,EAAE,WAAW,cAAc,CACjC,CAAC,CAAC,OAAO,SAAS;EACpB;CACF,QAAQ,CAER;CAEA,OAAO,OAAO,KAAK;AACrB;;;;;;;;;;AAWA,MAAa,sBACX,UACA,SAAwB,CAAC,GACzB,SAAwB,SAExB,SACG,QACC,oEACC,OAAO,MAAc,MAA0B,UAAmB;CACjE,MAAM,QAAQ,iBAAiB,QAAQ,IAAI;CAC3C,IAAI,UAAU,QAAW,OAAO;CAChC,OAAO,OACH,eAAe,OAAO,MAAM,OAAO,MAAM,IACzC,OAAO,KAAK;AAClB,CACF,CAAC,CACA,QACC,wDACC,OAAO,MAAc,MAAc,UAA8B;CAChE,MAAM,QAAQ,iBAAiB,QAAQ,IAAI;CAC3C,IAAI,UAAU,QAAW,OAAO;CAChC,OAAO,eAAe,OAAO,MAAM,OAAO,MAAM;AAClD,CACF,CAAC,CACA,QAAQ,wBAAwB,OAAO,SAAiB;CACvD,MAAM,QAAQ,iBAAiB,QAAQ,IAAI;CAC3C,OAAO,UAAU,SAAY,QAAQ,OAAO,KAAK;AACnD,CAAC;;AAGL,MAAM,oBACJ,QACA,iBACY,OAAO,iBAAiB,OAAO,SAAS,OAAO;;;;;;;;;AAU7D,MAAa,sBACX,MACA,SAAwB,CAAC,GACzB,SAAwB,SACZ;CACZ,IAAI,SAAS,QAAQ,SAAS,QAAW,OAAO;CAEhD,IAAI,OAAO,SAAS,UAClB,OAAO,mBAAmB,MAAM,QAAQ,MAAM;CAGhD,IAAI,OAAO,SAAS,YAAY,OAAO,SAAS,WAC9C,OAAO,OAAO,IAAI;CAKpB,IAAI,OAAO,SAAS,YAClB,IAAI;EACF,OAAO,mBACJ,KAAyC,MAAM,GAChD,QACA,MACF;CACF,QAAQ;EACN;CACF;CAGF,IAAI,MAAM,QAAQ,IAAI,GACpB,OAAO,KACJ,KAAK,SAAS,OAAO,mBAAmB,MAAM,QAAQ,MAAM,KAAK,EAAE,CAAC,CAAC,CACrE,KAAK,EAAE;CAGZ,MAAM,YAAY;CAElB,IAAI,UAAU,aAAaC,yBAAU,WACnC,OAAO,mBAAmB,UAAUA,yBAAU,YAAY,QAAQ,MAAM;CAG1E,IAAI,UAAU,aAAaA,yBAAU,MAEnC,OAAO,mBAAmB,UAAUA,yBAAU,OAAO,QAAQ,MAAM;CAGrE,IAAI,UAAU,aAAaA,yBAAU,QAAQ;EAC3C,MAAM,cAAc,UAClBA,yBAAU;EAEZ,MAAM,QAAQ,OAAO,iBAAiB,QAAQ,OAAO,KAAK,CAAC;EAC3D,MAAM,WAAWC,wCACf,aACA,OACA,MACF;EACA,OAAO,mBAAmB,UAAU,QAAQ,MAAM;CACpD;CAEA,IAAI,UAAU,aAAaD,yBAAU,aAAa;EAChD,MAAM,mBAAmB,UAAUA,yBAAU;EAK7C,MAAM,eAAgB,0BAA0B,KAC7C,gBAAgB,iBAAiB,YACpC,CAAC,CAAC,MAAM,SAAS,OAAO,SAAS,QAAQ,KAAK;EAE9C,MAAM,YAAY,iBAAiB,2BAA2B;EAE9D,MAAM,UAAmC,CAAC;EAC1C,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,gBAAgB,GACxD,IAAI,CAAE,0BAAgD,SAAS,GAAG,GAChE,QAAQ,OAAO;EAInB,MAAM,WAAW,iBAAiB,QAAQ,YAAY;EAEtD,IAAI;EACJ,IAAI,aAAa,CAAC,OAAO,MAAM,OAAO,QAAQ,CAAC,GAAG;GAGhD,MAAM,eAAe,OAAO,QAAQ;GACpC,MAAM,kBAAkBD,iCAAc,eAAe,QAAQ,EAC3D,MAAM,UACR,CAAC,CAAC,CAAC,OAAO,YAAY;GACtB,WACE,QAAQ,OAAO,YAAY,MAC3B,QAAQ,oBACR,QAAQ,YACR,QAAQ;EACZ,OAAO,IACL,OAAO,aAAa,YACpB,CAAC,OAAO,MAAM,OAAO,QAAQ,CAAC,GAE9B,WAAWG,kDAAe,SAAS,OAAO,QAAQ,CAAC;OAGnD,WAAW,QAAQ,OAAO,QAAQ,MAAM,QAAQ,YAAY,QAAQ;EAGtE,OAAO,mBAAmB,UAAU,QAAQ,MAAM;CACpD;CAEA,IAAI,UAAU,aAAaF,yBAAU,QAAQ;EAC3C,MAAM,cAAc,UAAUA,yBAAU;EAIxC,MAAM,eACJ,OAAO,UAAU,aAAa,WAAW,UAAU,WAAW;EAEhE,MAAM,WAAW,iBAAiB,QAAQ,YAAY;EACtD,MAAM,WAAWG,wCAAU,aAAa,OAAO,YAAY,EAAE,CAAC;EAE9D,OAAO,mBAAmB,UAAU,QAAQ,MAAM;CACpD;CAEA,IAAI,UAAU,aAAaH,yBAAU,QAAQ;EAC3C,MAAM,cAAc,UAAUA,yBAAU;EAExC,MAAM,WACJ,YAFkB,OAAO,OAAO,UAAU,EAEpB,MAAM,YAAY,YAAY,YAAY;EAClE,OAAO,mBAAmB,UAAU,QAAQ,MAAM;CACpD;CAEA,OAAO;AACT;;;;;;;;;;AAWA,MAAa,8BACX,MACA,SAAwB,CAAC,GACzB,SAAwB,SACb;CACX,MAAM,WAAW,mBAAmB,MAAM,QAAQ,MAAM;CAExD,OAAO,OAAO,aAAa,WAAW,WAAW,OAAO,YAAY,EAAE;AACxE;;;;;;;;;;;;;;AA4BA,MAAa,yBACV,eACA,SAAS,SAAS,CAAC,GAAG,SAAS,SAC9B,2BACE,OAAO,YAAY,WAAW,UAAU,OAAO,IAAI,SACnD,QACA,MACF;AAEJ,MAAM,qBAAqE;CACzE,KAAKI;CACL,SAASC;CACT,YAAYC;AACd;;;;;;;;;;;;;;;;;;;;;;AAuBA,MAAa,kBACX,SACA,SAAwB,CAAC,GACzB,SAAwB,MACxB,UAAgC,UAEhC,sBAAsB,mBAAmB,QAAQ,CAAC,CAAC,SAAS,QAAQ,MAAM;;;;;;;;AAc5E,MAAa,sBAAsB,YAA0C;CAC3E,MAAM,SAA+B,CAAC;CACtC,MAAM,WAAW;CACjB,IAAI,YAAY;CAChB,IAAI,QAAQ,SAAS,KAAK,OAAO;CAEjC,OAAO,UAAU,MAAM;EACrB,IAAI,MAAM,QAAQ,WAChB,OAAO,KAAK,QAAQ,MAAM,WAAW,MAAM,KAAK,CAAC;EAGnD,MAAM,GAAG,gBAAgB,KAAK,SAAS;EAEvC,IAAI,gBACF,OAAO,KAAK;GAAE,KAAK;GAAgB,UAAU,CAAC;EAAE,CAAC;OAEjD,OAAO,KAAK;GAAE;GAAK,UAAU,mBAAmB,KAAK;EAAE,CAAC;EAG1D,YAAY,MAAM,QAAQ,MAAM,EAAE,CAAC;EACnC,QAAQ,SAAS,KAAK,OAAO;CAC/B;CAEA,IAAI,YAAY,QAAQ,QACtB,OAAO,KAAK,QAAQ,MAAM,SAAS,CAAC;CAGtC,OAAO;AACT"}
@@ -109,8 +109,8 @@ import { i18nextToIntlayerFormatter, intlayerToI18nextFormatter } from "./messag
109
109
  import { navigatePath } from "./messageFormat/navigatePath.mjs";
110
110
  import { intlayerToPortableObjectFormatter, portableObjectToIntlayerFormatter } from "./messageFormat/po.mjs";
111
111
  import { intlayerToVueI18nFormatter, vueI18nToIntlayerFormatter } from "./messageFormat/vue-i18n.mjs";
112
- import { interpolateMessage, parseTaggedMessage, resolveMessage, resolveMessageNode } from "./messageFormat/resolveMessage.mjs";
112
+ import { createMessageResolver, interpolateMessage, parseTaggedMessage, resolveMessage, resolveMessageNode, resolveMessageNodeToString } from "./messageFormat/resolveMessage.mjs";
113
113
  import { isSameKeyPath } from "./utils/isSameKeyPath.mjs";
114
114
  import { stringifyYaml } from "./utils/stringifyYaml.mjs";
115
115
 
116
- export { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, COMPOSITE_ID_SEPARATOR, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CachedIntl, CachedIntl as Intl, DEFAULT_VARIANT_ID, DO_NOT_PROCESS_HTML_ELEMENTS, FENCE_DELIMITER_R, FOOTNOTE_R, FOOTNOTE_REFERENCE_R, FORMFEED_R, FRONT_MATTER_R, GFM_TASK_R, HEADING_ATX_COMPLIANT_R, HEADING_R, HEADING_SETEXT_R, HTML_CHAR_CODE_R, HTML_COMMENT_R, HTML_CUSTOM_ATTR_R, HTML_LEFT_TRIM_AMOUNT_R, HTML_TAGS, INLINE_SKIP_R, INTERPOLATION_R, LINK_AUTOLINK_BARE_URL_R, LINK_AUTOLINK_R, LOOKAHEAD, LocaleStorage, LocaleStorageClient, LocaleStorageServer, NAMED_CODES_TO_UNICODE, NP_TABLE_R, ORDERED, ORDERED_LIST_BULLET, ORDERED_LIST_ITEM_PREFIX, ORDERED_LIST_ITEM_PREFIX_R, ORDERED_LIST_ITEM_R, ORDERED_LIST_R, PARAGRAPH_R, PRELOADED_DYNAMIC_KEY, Priority, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, REFERENCE_IMAGE_OR_LINK, REFERENCE_IMAGE_R, REFERENCE_LINK_R, RuleScope, RuleType, SCOPE_BLOCK, SCOPE_BOTH, SCOPE_INLINE, SHORTCODE_R, SHOULD_RENDER_AS_BLOCK_R, TABLE_CENTER_ALIGN, TABLE_LEFT_ALIGN, TABLE_RIGHT_ALIGN, TABLE_TRIM_PIPES, TAB_R, TEXT_BOLD_R, TEXT_EMPHASIZED_R, TEXT_ESCAPED_R, TEXT_MARKED_R, TEXT_STRIKETHROUGHED_R, TRIM_STARTING_NEWLINES, UNESCAPE_R, UNORDERED, UNORDERED_LIST_BULLET, UNORDERED_LIST_ITEM_PREFIX, UNORDERED_LIST_ITEM_PREFIX_R, UNORDERED_LIST_ITEM_R, UNORDERED_LIST_R, VOID_HTML_ELEMENTS, allowInline, anyScopeRegex, attributeValueToNodePropValue, bindIntl, blockRegex, buildMaskPlugin, captureNothing, checkIsURLAbsolute, checkMissingLocalesPlugin, compact, comparePaths, compile, compileWithOptions, condition as cond, conditionPlugin, createCompiler, createRenderer, currency, cx, date, deepTransformNode, editDictionaryByKeyPath, enumeration as enu, enumerationPlugin, fallbackPlugin, filePlugin, filterMissingTranslationsOnlyPlugin, filterTranslationsOnlyPlugin, findMatchingCondition, findPlainDynamicLoader, formatProxyEnabledMessage, gender, genderPlugin, generateListItemPrefix, generateListItemPrefixRegex, generateListItemRegex, generateListRegex, generateSitemap, generateSitemapUrl, get, getBasePlugins, getBrowserLocale, getCachedIntl, getCanonicalPath, getCondition, getContent, getContentNodeByKeyPath, getCookie, getDefaultNode, getDictionary, getDictionaryAsync, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getDictionaryTransformCacheKey, getDomainHostname, getDomainOrigin, getEditedContent, getEditedDictionary, getEmptyNode, getEnumeration, getFilterMissingTranslationsContent, getFilterMissingTranslationsDictionary, getFilterTranslationsOnlyContent, getFilterTranslationsOnlyDictionary, getFilteredLocalesContent, getFilteredLocalesDictionary, getGender, getHTML, getHTMLTextDir, getInsertion, getInsertionValues, getInternalPath, getInterpolableContent, getIntlayer, getIntlayerAsync, getLocale, getLocaleFromDomain, getLocaleFromPath, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, getLocaleLang, getLocaleName, getLocalizedContent, getLocalizedPath, getLocalizedUrl, getMarkdownMetadata, getMaskContent, getMissingLocalesContent, getMissingLocalesContentFromDictionary, getMultilingualDictionary, getMultilingualUrls, getNestedDictionaryGraph, getNestedDictionaryKeys, getNestedDictionaryReferences, getNesting, getNodeChildren, getNodeType, getPathWithoutLocale, getPerLocaleDictionary, getPluginsCacheKey, getPlural, getPrefix, getPreloadLocale, getPreloadedDictionary, getReplacedValuesContent, getRewritePath, getRewriteRules, getRuleSet, getSelect, getSplittedContent, getSplittedDictionaryContent, getTranslation, getVariantIds, html, i18nextToIntlayerFormatter, icuToIntlayerFormatter, inlineRegex, insertion as insert, insertContentInDictionary, insertionPlugin, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, isDeclaredLocale, isInterpolableWrapperNode, isLocaleExclusiveOnDomain, isProxyStorageLocaleEnabled, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, isSameKeyPath, isValidElement, list, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, localeStorageOptions, markdown as md, mergeDictionaries, mergeQualifiedDictionaries, navigatePath, nesting as nest, nestedPlugin, normalizeAttributeKey, normalizeDictionaries, normalizeDictionary, normalizePath, normalizeWhitespace, number, orderDictionaries, parseBlock, parseCaptureInline, parseDictionarySelector, parseInline, parseMarkdown, parseSimpleInline, parseStyleAttribute, parseTableAlign, parseTableAlignCapture, parseTableCells, parseTableRow, parseTaggedMessage, parseYaml, parserFor, percentage, plural, pluralPlugin, portableObjectToIntlayerFormatter, presets, qualifies, readTransformCache, rebuildInterpolableContent, reconstructQualifiedEntry, relativeTime, removeContentNodeByKeyPath, renameContentNodeByKeyPath, renderFor, renderMarkdownAst, renderNothing, resolveBrowserLocale, resolveDictionaryArgument, resolveEffectiveVariantId, resolveLocalizedPath, resolveMessage, resolveMessageNode, resolvePlainDynamicLoader, resolveProviderVariant, resolveProxyMode, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, sanitizer, select, selectPlugin, serializeVariant, serializeVariantChain, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer, simpleInlineRegex, slugify, some, splitInsertionTemplate, startsWith, stringifyYaml, translation as t, transformInterpolableNode, translationPlugin, trimEnd, trimLeadingWhitespaceOutsideFences, unescapeString, units, unquote, updateNodeChildren, validateHTML, validateMarkdown, validatePrefix, vueI18nToIntlayerFormatter, writeTransformCache };
116
+ export { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, COMPOSITE_ID_SEPARATOR, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CachedIntl, CachedIntl as Intl, DEFAULT_VARIANT_ID, DO_NOT_PROCESS_HTML_ELEMENTS, FENCE_DELIMITER_R, FOOTNOTE_R, FOOTNOTE_REFERENCE_R, FORMFEED_R, FRONT_MATTER_R, GFM_TASK_R, HEADING_ATX_COMPLIANT_R, HEADING_R, HEADING_SETEXT_R, HTML_CHAR_CODE_R, HTML_COMMENT_R, HTML_CUSTOM_ATTR_R, HTML_LEFT_TRIM_AMOUNT_R, HTML_TAGS, INLINE_SKIP_R, INTERPOLATION_R, LINK_AUTOLINK_BARE_URL_R, LINK_AUTOLINK_R, LOOKAHEAD, LocaleStorage, LocaleStorageClient, LocaleStorageServer, NAMED_CODES_TO_UNICODE, NP_TABLE_R, ORDERED, ORDERED_LIST_BULLET, ORDERED_LIST_ITEM_PREFIX, ORDERED_LIST_ITEM_PREFIX_R, ORDERED_LIST_ITEM_R, ORDERED_LIST_R, PARAGRAPH_R, PRELOADED_DYNAMIC_KEY, Priority, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, REFERENCE_IMAGE_OR_LINK, REFERENCE_IMAGE_R, REFERENCE_LINK_R, RuleScope, RuleType, SCOPE_BLOCK, SCOPE_BOTH, SCOPE_INLINE, SHORTCODE_R, SHOULD_RENDER_AS_BLOCK_R, TABLE_CENTER_ALIGN, TABLE_LEFT_ALIGN, TABLE_RIGHT_ALIGN, TABLE_TRIM_PIPES, TAB_R, TEXT_BOLD_R, TEXT_EMPHASIZED_R, TEXT_ESCAPED_R, TEXT_MARKED_R, TEXT_STRIKETHROUGHED_R, TRIM_STARTING_NEWLINES, UNESCAPE_R, UNORDERED, UNORDERED_LIST_BULLET, UNORDERED_LIST_ITEM_PREFIX, UNORDERED_LIST_ITEM_PREFIX_R, UNORDERED_LIST_ITEM_R, UNORDERED_LIST_R, VOID_HTML_ELEMENTS, allowInline, anyScopeRegex, attributeValueToNodePropValue, bindIntl, blockRegex, buildMaskPlugin, captureNothing, checkIsURLAbsolute, checkMissingLocalesPlugin, compact, comparePaths, compile, compileWithOptions, condition as cond, conditionPlugin, createCompiler, createMessageResolver, createRenderer, currency, cx, date, deepTransformNode, editDictionaryByKeyPath, enumeration as enu, enumerationPlugin, fallbackPlugin, filePlugin, filterMissingTranslationsOnlyPlugin, filterTranslationsOnlyPlugin, findMatchingCondition, findPlainDynamicLoader, formatProxyEnabledMessage, gender, genderPlugin, generateListItemPrefix, generateListItemPrefixRegex, generateListItemRegex, generateListRegex, generateSitemap, generateSitemapUrl, get, getBasePlugins, getBrowserLocale, getCachedIntl, getCanonicalPath, getCondition, getContent, getContentNodeByKeyPath, getCookie, getDefaultNode, getDictionary, getDictionaryAsync, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getDictionaryTransformCacheKey, getDomainHostname, getDomainOrigin, getEditedContent, getEditedDictionary, getEmptyNode, getEnumeration, getFilterMissingTranslationsContent, getFilterMissingTranslationsDictionary, getFilterTranslationsOnlyContent, getFilterTranslationsOnlyDictionary, getFilteredLocalesContent, getFilteredLocalesDictionary, getGender, getHTML, getHTMLTextDir, getInsertion, getInsertionValues, getInternalPath, getInterpolableContent, getIntlayer, getIntlayerAsync, getLocale, getLocaleFromDomain, getLocaleFromPath, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, getLocaleLang, getLocaleName, getLocalizedContent, getLocalizedPath, getLocalizedUrl, getMarkdownMetadata, getMaskContent, getMissingLocalesContent, getMissingLocalesContentFromDictionary, getMultilingualDictionary, getMultilingualUrls, getNestedDictionaryGraph, getNestedDictionaryKeys, getNestedDictionaryReferences, getNesting, getNodeChildren, getNodeType, getPathWithoutLocale, getPerLocaleDictionary, getPluginsCacheKey, getPlural, getPrefix, getPreloadLocale, getPreloadedDictionary, getReplacedValuesContent, getRewritePath, getRewriteRules, getRuleSet, getSelect, getSplittedContent, getSplittedDictionaryContent, getTranslation, getVariantIds, html, i18nextToIntlayerFormatter, icuToIntlayerFormatter, inlineRegex, insertion as insert, insertContentInDictionary, insertionPlugin, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, isDeclaredLocale, isInterpolableWrapperNode, isLocaleExclusiveOnDomain, isProxyStorageLocaleEnabled, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, isSameKeyPath, isValidElement, list, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, localeStorageOptions, markdown as md, mergeDictionaries, mergeQualifiedDictionaries, navigatePath, nesting as nest, nestedPlugin, normalizeAttributeKey, normalizeDictionaries, normalizeDictionary, normalizePath, normalizeWhitespace, number, orderDictionaries, parseBlock, parseCaptureInline, parseDictionarySelector, parseInline, parseMarkdown, parseSimpleInline, parseStyleAttribute, parseTableAlign, parseTableAlignCapture, parseTableCells, parseTableRow, parseTaggedMessage, parseYaml, parserFor, percentage, plural, pluralPlugin, portableObjectToIntlayerFormatter, presets, qualifies, readTransformCache, rebuildInterpolableContent, reconstructQualifiedEntry, relativeTime, removeContentNodeByKeyPath, renameContentNodeByKeyPath, renderFor, renderMarkdownAst, renderNothing, resolveBrowserLocale, resolveDictionaryArgument, resolveEffectiveVariantId, resolveLocalizedPath, resolveMessage, resolveMessageNode, resolveMessageNodeToString, resolvePlainDynamicLoader, resolveProviderVariant, resolveProxyMode, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, sanitizer, select, selectPlugin, serializeVariant, serializeVariantChain, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer, simpleInlineRegex, slugify, some, splitInsertionTemplate, startsWith, stringifyYaml, translation as t, transformInterpolableNode, translationPlugin, trimEnd, trimLeadingWhitespaceOutsideFences, unescapeString, units, unquote, updateNodeChildren, validateHTML, validateMarkdown, validatePrefix, vueI18nToIntlayerFormatter, writeTransformCache };
@@ -3,6 +3,6 @@ import { i18nextToIntlayerFormatter, intlayerToI18nextFormatter } from "./i18nex
3
3
  import { navigatePath } from "./navigatePath.mjs";
4
4
  import { intlayerToPortableObjectFormatter, portableObjectToIntlayerFormatter } from "./po.mjs";
5
5
  import { intlayerToVueI18nFormatter, vueI18nToIntlayerFormatter } from "./vue-i18n.mjs";
6
- import { interpolateMessage, parseTaggedMessage, resolveMessage, resolveMessageNode } from "./resolveMessage.mjs";
6
+ import { createMessageResolver, interpolateMessage, parseTaggedMessage, resolveMessage, resolveMessageNode, resolveMessageNodeToString } from "./resolveMessage.mjs";
7
7
 
8
- export { i18nextToIntlayerFormatter, icuToIntlayerFormatter, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, navigatePath, parseTaggedMessage, portableObjectToIntlayerFormatter, resolveMessage, resolveMessageNode, vueI18nToIntlayerFormatter };
8
+ export { createMessageResolver, i18nextToIntlayerFormatter, icuToIntlayerFormatter, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, navigatePath, parseTaggedMessage, portableObjectToIntlayerFormatter, resolveMessage, resolveMessageNode, resolveMessageNodeToString, vueI18nToIntlayerFormatter };
@@ -52,13 +52,15 @@ const formatArgument = (value, type, style, locale) => {
52
52
  * Interpolates a message template with values.
53
53
  *
54
54
  * Handles, in order:
55
- * 1. Intlayer insertions `{{name}}` (whitespace-tolerant, dotted paths)
55
+ * 1. Intlayer insertions `{{name}}` (whitespace-tolerant, dotted paths),
56
+ * optionally formatted the i18next way (`{{price, number}}`)
56
57
  * 2. ICU formatted arguments `{value, number}` / `{ts, date, long}`
57
58
  * 3. Bare single-brace arguments `{name}` (ICU / vue-i18n simple args)
58
59
  */
59
- const interpolateMessage = (template, values = {}, locale = "en") => template.replace(/\{\{\s*([^{}]+?)\s*\}\}/g, (match, path) => {
60
+ const interpolateMessage = (template, values = {}, locale = "en") => template.replace(/\{\{\s*([^{},]+?)\s*(?:,\s*(\w+)\s*(?:,\s*([^{}]+?)\s*)?)?\}\}/g, (match, path, type, style) => {
60
61
  const value = resolveValuePath(values, path);
61
- return value === void 0 ? match : String(value);
62
+ if (value === void 0) return match;
63
+ return type ? formatArgument(value, type, style, locale) : String(value);
62
64
  }).replace(/\{\s*([\w.]+)\s*,\s*(\w+)\s*(?:,\s*([^}]+?)\s*)?\}/g, (match, path, type, style) => {
63
65
  const value = resolveValuePath(values, path);
64
66
  if (value === void 0) return match;
@@ -126,15 +128,45 @@ const resolveMessageNode = (node, values = {}, locale = "en") => {
126
128
  }
127
129
  return node;
128
130
  };
131
+ /**
132
+ * {@link resolveMessageNode} coerced to a string.
133
+ *
134
+ * This is the whole runtime a compat adapter needs for content that reached
135
+ * the bundle through a built dictionary: the build already converted every
136
+ * dialect construct into intlayer nodes, and the interpreter turned those into
137
+ * callables, so no message parser is involved. Plain strings still get
138
+ * `{{name}}` / `{name}` / `{value, number}` interpolation.
139
+ */
140
+ const resolveMessageNodeToString = (node, values = {}, locale = "en") => {
141
+ const resolved = resolveMessageNode(node, values, locale);
142
+ return typeof resolved === "string" ? resolved : String(resolved ?? "");
143
+ };
144
+ /**
145
+ * Binds {@link resolveMessageNode} to one dialect converter.
146
+ *
147
+ * The compat adapters each speak a single dialect, and referencing the
148
+ * converter directly — rather than picking it from a record keyed by dialect —
149
+ * is what lets a bundler drop the two parsers the adapter never uses.
150
+ *
151
+ * @example
152
+ * ```ts
153
+ * const resolveIcuMessage = createMessageResolver(icuToIntlayerFormatter);
154
+ * resolveIcuMessage('Hello {name}', { name: 'John' }, 'en'); // 'Hello John'
155
+ * ```
156
+ */
157
+ const createMessageResolver = (formatter) => (message, values = {}, locale = "en") => resolveMessageNodeToString(typeof message === "string" ? formatter(message) : message, values, locale);
129
158
  const DIALECT_FORMATTERS = {
130
- icu: (message) => icuToIntlayerFormatter(message),
131
- i18next: (message) => i18nextToIntlayerFormatter(message),
132
- "vue-i18n": (message) => vueI18nToIntlayerFormatter(message)
159
+ icu: icuToIntlayerFormatter,
160
+ i18next: i18nextToIntlayerFormatter,
161
+ "vue-i18n": vueI18nToIntlayerFormatter
133
162
  };
134
163
  /**
135
164
  * Resolves a raw message — string in a library dialect, or an intlayer node
136
165
  * tree — into a final string using interpolation values and locale.
137
166
  *
167
+ * Selecting the dialect at runtime keeps every converter reachable; a package
168
+ * that only ever needs one should bind it with {@link createMessageResolver}.
169
+ *
138
170
  * @example
139
171
  * ```ts
140
172
  * resolveMessage('Hello {name}', { name: 'John' }, 'en', 'icu');
@@ -149,11 +181,7 @@ const DIALECT_FORMATTERS = {
149
181
  * // '3 items'
150
182
  * ```
151
183
  */
152
- const resolveMessage = (message, values = {}, locale = "en", dialect = "icu") => {
153
- const node = typeof message === "string" ? DIALECT_FORMATTERS[dialect](message) : message;
154
- const resolved = resolveMessageNode(node, values, locale);
155
- return typeof resolved === "string" ? resolved : String(resolved ?? "");
156
- };
184
+ const resolveMessage = (message, values = {}, locale = "en", dialect = "icu") => createMessageResolver(DIALECT_FORMATTERS[dialect])(message, values, locale);
157
185
  /**
158
186
  * Tokenizes a message containing XML-like tags (`'Visit <link>the docs</link>'`,
159
187
  * `'hello <1>{{name}}</1>'`, `'line<br/>break'`) into a token tree.
@@ -185,5 +213,5 @@ const parseTaggedMessage = (message) => {
185
213
  };
186
214
 
187
215
  //#endregion
188
- export { interpolateMessage, parseTaggedMessage, resolveMessage, resolveMessageNode };
216
+ export { createMessageResolver, interpolateMessage, parseTaggedMessage, resolveMessage, resolveMessageNode, resolveMessageNodeToString };
189
217
  //# sourceMappingURL=resolveMessage.mjs.map
@@ -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 * 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(/\\{\\{\\s*([^{}]+?)\\s*\\}\\}/g, (match, path: string) => {\n const value = resolveValuePath(values, path);\n return value === undefined ? match : String(value);\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\nconst DIALECT_FORMATTERS: Record<\n MessageFormatDialect,\n (message: string) => unknown\n> = {\n icu: (message) => icuToIntlayerFormatter(message),\n i18next: (message) => i18nextToIntlayerFormatter(message),\n 'vue-i18n': (message) => vueI18nToIntlayerFormatter(message),\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 * @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 const node =\n typeof message === 'string'\n ? DIALECT_FORMATTERS[dialect](message)\n : message;\n\n const resolved = resolveMessageNode(node, values, locale);\n\n return typeof resolved === 'string' ? resolved : String(resolved ?? '');\n};\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 {\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 { 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 {\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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"}
@@ -112,7 +112,7 @@ import { JsonValue, icuToIntlayerFormatter, intlayerToICUFormatter } from "./mes
112
112
  import { i18nextToIntlayerFormatter, intlayerToI18nextFormatter } from "./messageFormat/i18next.js";
113
113
  import { navigatePath } from "./messageFormat/navigatePath.js";
114
114
  import { PortableObject, intlayerToPortableObjectFormatter, portableObjectToIntlayerFormatter } from "./messageFormat/po.js";
115
- import { MessageFormatDialect, MessageValues, TaggedMessageToken, interpolateMessage, parseTaggedMessage, resolveMessage, resolveMessageNode } from "./messageFormat/resolveMessage.js";
115
+ import { MessageFormatDialect, MessageFormatter, MessageResolver, MessageValues, TaggedMessageToken, createMessageResolver, interpolateMessage, parseTaggedMessage, resolveMessage, resolveMessageNode, resolveMessageNodeToString } from "./messageFormat/resolveMessage.js";
116
116
  import { intlayerToVueI18nFormatter, vueI18nToIntlayerFormatter } from "./messageFormat/vue-i18n.js";
117
117
  import "./messageFormat/index.js";
118
118
  import { checkIsURLAbsolute } from "./utils/checkIsURLAbsolute.js";
@@ -123,4 +123,4 @@ import { CookieBuildAttributes, LocaleStorage, LocaleStorageClient, LocaleStorag
123
123
  import { YamlRecord, YamlValue, parseYaml } from "./utils/parseYaml.js";
124
124
  import { stringifyYaml } from "./utils/stringifyYaml.js";
125
125
  import "./utils/index.js";
126
- export { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, type BlockQuoteNode, BlockSyntaxProbe, type BoldTextNode, type BreakLineNode, type BreakThematicNode, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, COMPOSITE_ID_SEPARATOR, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CachedIntl, CachedIntl as Intl, type CodeBlockNode, type CodeFencedNode, type CodeInlineNode, type CompileOptions, type ComponentOverrides, ConditionCond, ConditionContent, ConditionContentStates, CookieBuildAttributes, type CustomComponentNode, DEFAULT_VARIANT_ID, DO_NOT_PROCESS_HTML_ELEMENTS, DateTimePreset, DeepTransformContent, DotPath, DynamicDictionaryLoader, type ElementType, EnterFormat, EnumerationCond, EnumerationContent, EnumerationContentState, type EscapedTextNode, FENCE_DELIMITER_R, FOOTNOTE_R, FOOTNOTE_REFERENCE_R, FORMFEED_R, FRONT_MATTER_R, FileCond, type FileContent, type FileContentConstructor, type FootnoteNode, type FootnoteReferenceNode, type GFMTaskNode, GFM_TASK_R, Gender, GenderCond, GenderContent, GenderContentStates, type GenerateSitemapOptions, GetNestingResult, type GetPrefixOptions, type GetPrefixResult, HEADING_ATX_COMPLIANT_R, HEADING_R, HEADING_SETEXT_R, type HTMLCommentNode, HTMLContent, HTMLContentConstructor, type HTMLNode, type HTMLSelfClosingNode, type HTMLTag, HTMLTagsType, HTMLValidationIssue, HTMLValidationResult, HTML_CHAR_CODE_R, HTML_COMMENT_R, HTML_CUSTOM_ATTR_R, HTML_LEFT_TRIM_AMOUNT_R, HTML_TAGS, type HeadingNode, type HeadingSetextNode, IInterpreterPlugin, IInterpreterPluginState, INLINE_SKIP_R, INTERPOLATION_R, type ImageNode, InsertionCond, InsertionContent, InsertionContentConstructor, InterpolableNode, IntlConstructorName, IsAny, type ItalicTextNode, JsonValue, LINK_AUTOLINK_BARE_URL_R, LINK_AUTOLINK_R, LOOKAHEAD, type LinkAngleBraceNode, type LinkBareURLNode, type LinkNode, ListFormatOptions, ListType, type LocaleDomainMap, LocaleStorage, LocaleStorageClient, LocaleStorageClientOptions, LocaleStorageOptions, LocaleStorageServer, LocaleStorageServerOptions, type LocalizedPathResult, MarkdownContent, MarkdownContentConstructor, type MarkdownContext, type MarkdownOptions, MarkdownReferences, type MarkdownRuntime, type HTMLValidationIssue as MarkdownValidationIssue, MarkdownValidationResult, type MarkedTextNode, MessageFormatDialect, MessageValues, NAMED_CODES_TO_UNICODE, NP_TABLE_R, NestedCond, NestedContent, NestedContentState, NestedFieldReferences, type NestedParser, type NewlineNode, NodeProps, ORDERED, ORDERED_LIST_BULLET, ORDERED_LIST_ITEM_PREFIX, ORDERED_LIST_ITEM_PREFIX_R, ORDERED_LIST_ITEM_R, ORDERED_LIST_R, type OrderedListNode, PARAGRAPH_R, PRELOADED_DYNAMIC_KEY, type ParagraphNode, type ParseState, ParsedMarkdown, type Parser, type ParserResult, PlainDynamicLoaderMap, Plugins, PluralCategory, PluralCond, PluralContent, PluralContentState, PortableObject, PreloadableDynamicLoaderMap, PreloadedDynamicEntry, Priority, PriorityValue, type ProxyMode, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, REFERENCE_IMAGE_OR_LINK, REFERENCE_IMAGE_R, REFERENCE_LINK_R, type ReferenceImageNode, type ReferenceLinkNode, type ReferenceNode, type RenderRuleHook, ResolvedDynamicLoader, type Rule, type RuleOutput, RuleScope, RuleScopeValue, RuleType, RuleTypeValue, type Rules, SCOPE_BLOCK, SCOPE_BOTH, SCOPE_INLINE, SHORTCODE_R, SHOULD_RENDER_AS_BLOCK_R, SelectCond, SelectContent, SelectContentStates, SelectSelector, type SitemapUrlEntry, type StrikethroughTextNode, TABLE_CENTER_ALIGN, TABLE_LEFT_ALIGN, TABLE_RIGHT_ALIGN, TABLE_TRIM_PIPES, TAB_R, TEXT_BOLD_R, TEXT_EMPHASIZED_R, TEXT_ESCAPED_R, TEXT_MARKED_R, TEXT_STRIKETHROUGHED_R, TRIM_STARTING_NEWLINES, type TableNode, type TableSeparatorNode, TaggedMessageToken, type TextNode, TranslationCond, TranslationContent, UNESCAPE_R, UNORDERED, UNORDERED_LIST_BULLET, UNORDERED_LIST_ITEM_PREFIX, UNORDERED_LIST_ITEM_PREFIX_R, UNORDERED_LIST_ITEM_R, UNORDERED_LIST_R, UnionKeys, type UnorderedListNode, VOID_HTML_ELEMENTS, ValidDotPathsFor, ValueAtKey, WrappedIntl, YamlRecord, YamlValue, allowInline, anyScopeRegex, attributeValueToNodePropValue, bindIntl, blockRegex, buildMaskPlugin, captureNothing, checkIsURLAbsolute, checkMissingLocalesPlugin, compact, comparePaths, compile, compileWithOptions, condition as cond, conditionPlugin, createCompiler, createRenderer, currency, cx, date, deepTransformNode, editDictionaryByKeyPath, enumeration as enu, enumerationPlugin, fallbackPlugin, type file, type fileContent, filePlugin, filterMissingTranslationsOnlyPlugin, filterTranslationsOnlyPlugin, findMatchingCondition, findPlainDynamicLoader, formatProxyEnabledMessage, gender, genderPlugin, generateListItemPrefix, generateListItemPrefixRegex, generateListItemRegex, generateListRegex, generateSitemap, generateSitemapUrl, get, getBasePlugins, getBrowserLocale, getCachedIntl, getCanonicalPath, getCondition, getContent, getContentNodeByKeyPath, getCookie, getDefaultNode, getDictionary, getDictionaryAsync, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getDictionaryTransformCacheKey, getDomainHostname, getDomainOrigin, getEditedContent, getEditedDictionary, getEmptyNode, getEnumeration, getFilterMissingTranslationsContent, getFilterMissingTranslationsDictionary, getFilterTranslationsOnlyContent, getFilterTranslationsOnlyDictionary, getFilteredLocalesContent, getFilteredLocalesDictionary, getGender, getHTML, getHTMLTextDir, getInsertion, getInsertionValues, getInternalPath, getInterpolableContent, getIntlayer, getIntlayerAsync, getLocale, getLocaleFromDomain, getLocaleFromPath, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, getLocaleLang, getLocaleName, getLocalizedContent, getLocalizedPath, getLocalizedUrl, getMarkdownMetadata, getMaskContent, getMissingLocalesContent, getMissingLocalesContentFromDictionary, getMultilingualDictionary, getMultilingualUrls, getNestedDictionaryGraph, getNestedDictionaryKeys, getNestedDictionaryReferences, getNesting, getNodeChildren, getNodeType, getPathWithoutLocale, getPerLocaleDictionary, getPluginsCacheKey, getPlural, getPrefix, getPreloadLocale, getPreloadedDictionary, getReplacedValuesContent, getRewritePath, getRewriteRules, getRuleSet, getSelect, getSplittedContent, getSplittedDictionaryContent, getTranslation, getVariantIds, html, i18nextToIntlayerFormatter, icuToIntlayerFormatter, inlineRegex, insertion as insert, insertContentInDictionary, insertionPlugin, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, isDeclaredLocale, isInterpolableWrapperNode, isLocaleExclusiveOnDomain, isProxyStorageLocaleEnabled, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, isSameKeyPath, isValidElement, list, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, localeStorageOptions, markdown as md, mergeDictionaries, mergeQualifiedDictionaries, navigatePath, nesting as nest, nestedPlugin, normalizeAttributeKey, normalizeDictionaries, normalizeDictionary, normalizePath, normalizeWhitespace, number, orderDictionaries, parseBlock, parseCaptureInline, parseDictionarySelector, parseInline, parseMarkdown, parseSimpleInline, parseStyleAttribute, parseTableAlign, parseTableAlignCapture, parseTableCells, parseTableRow, parseTaggedMessage, parseYaml, parserFor, percentage, plural, pluralPlugin, portableObjectToIntlayerFormatter, presets, qualifies, readTransformCache, rebuildInterpolableContent, reconstructQualifiedEntry, relativeTime, removeContentNodeByKeyPath, renameContentNodeByKeyPath, renderFor, renderMarkdownAst, renderNothing, resolveBrowserLocale, resolveDictionaryArgument, resolveEffectiveVariantId, resolveLocalizedPath, resolveMessage, resolveMessageNode, resolvePlainDynamicLoader, resolveProviderVariant, resolveProxyMode, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, sanitizer, select, selectPlugin, serializeVariant, serializeVariantChain, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer, simpleInlineRegex, slugify, some, splitInsertionTemplate, startsWith, stringifyYaml, translation as t, transformInterpolableNode, translationPlugin, trimEnd, trimLeadingWhitespaceOutsideFences, unescapeString, units, unquote, updateNodeChildren, validateHTML, validateMarkdown, validatePrefix, vueI18nToIntlayerFormatter, writeTransformCache };
126
+ export { ATTRIBUTES_TO_SANITIZE, ATTRIBUTE_TO_NODE_PROP_MAP, ATTR_EXTRACTOR_R, BLOCKQUOTE_ALERT_R, BLOCKQUOTE_R, BLOCKQUOTE_TRIM_LEFT_MULTILINE_R, BLOCK_END_R, BREAK_LINE_R, BREAK_THEMATIC_R, type BlockQuoteNode, BlockSyntaxProbe, type BoldTextNode, type BreakLineNode, type BreakThematicNode, CAPTURE_LETTER_AFTER_HYPHEN, CODE_BLOCK_FENCED_R, CODE_BLOCK_R, CODE_INLINE_R, COMPOSITE_ID_SEPARATOR, CONSECUTIVE_NEWLINE_R, CR_NEWLINE_R, CachedIntl, CachedIntl as Intl, type CodeBlockNode, type CodeFencedNode, type CodeInlineNode, type CompileOptions, type ComponentOverrides, ConditionCond, ConditionContent, ConditionContentStates, CookieBuildAttributes, type CustomComponentNode, DEFAULT_VARIANT_ID, DO_NOT_PROCESS_HTML_ELEMENTS, DateTimePreset, DeepTransformContent, DotPath, DynamicDictionaryLoader, type ElementType, EnterFormat, EnumerationCond, EnumerationContent, EnumerationContentState, type EscapedTextNode, FENCE_DELIMITER_R, FOOTNOTE_R, FOOTNOTE_REFERENCE_R, FORMFEED_R, FRONT_MATTER_R, FileCond, type FileContent, type FileContentConstructor, type FootnoteNode, type FootnoteReferenceNode, type GFMTaskNode, GFM_TASK_R, Gender, GenderCond, GenderContent, GenderContentStates, type GenerateSitemapOptions, GetNestingResult, type GetPrefixOptions, type GetPrefixResult, HEADING_ATX_COMPLIANT_R, HEADING_R, HEADING_SETEXT_R, type HTMLCommentNode, HTMLContent, HTMLContentConstructor, type HTMLNode, type HTMLSelfClosingNode, type HTMLTag, HTMLTagsType, HTMLValidationIssue, HTMLValidationResult, HTML_CHAR_CODE_R, HTML_COMMENT_R, HTML_CUSTOM_ATTR_R, HTML_LEFT_TRIM_AMOUNT_R, HTML_TAGS, type HeadingNode, type HeadingSetextNode, IInterpreterPlugin, IInterpreterPluginState, INLINE_SKIP_R, INTERPOLATION_R, type ImageNode, InsertionCond, InsertionContent, InsertionContentConstructor, InterpolableNode, IntlConstructorName, IsAny, type ItalicTextNode, JsonValue, LINK_AUTOLINK_BARE_URL_R, LINK_AUTOLINK_R, LOOKAHEAD, type LinkAngleBraceNode, type LinkBareURLNode, type LinkNode, ListFormatOptions, ListType, type LocaleDomainMap, LocaleStorage, LocaleStorageClient, LocaleStorageClientOptions, LocaleStorageOptions, LocaleStorageServer, LocaleStorageServerOptions, type LocalizedPathResult, MarkdownContent, MarkdownContentConstructor, type MarkdownContext, type MarkdownOptions, MarkdownReferences, type MarkdownRuntime, type HTMLValidationIssue as MarkdownValidationIssue, MarkdownValidationResult, type MarkedTextNode, MessageFormatDialect, MessageFormatter, MessageResolver, MessageValues, NAMED_CODES_TO_UNICODE, NP_TABLE_R, NestedCond, NestedContent, NestedContentState, NestedFieldReferences, type NestedParser, type NewlineNode, NodeProps, ORDERED, ORDERED_LIST_BULLET, ORDERED_LIST_ITEM_PREFIX, ORDERED_LIST_ITEM_PREFIX_R, ORDERED_LIST_ITEM_R, ORDERED_LIST_R, type OrderedListNode, PARAGRAPH_R, PRELOADED_DYNAMIC_KEY, type ParagraphNode, type ParseState, ParsedMarkdown, type Parser, type ParserResult, PlainDynamicLoaderMap, Plugins, PluralCategory, PluralCond, PluralContent, PluralContentState, PortableObject, PreloadableDynamicLoaderMap, PreloadedDynamicEntry, Priority, PriorityValue, type ProxyMode, QUALIFIER_DYNAMIC_TYPES_KEY, QUALIFIER_ORDER, QualifiedDynamicLoaderMap, QualifiedDynamicLoaderTree, REFERENCE_IMAGE_OR_LINK, REFERENCE_IMAGE_R, REFERENCE_LINK_R, type ReferenceImageNode, type ReferenceLinkNode, type ReferenceNode, type RenderRuleHook, ResolvedDynamicLoader, type Rule, type RuleOutput, RuleScope, RuleScopeValue, RuleType, RuleTypeValue, type Rules, SCOPE_BLOCK, SCOPE_BOTH, SCOPE_INLINE, SHORTCODE_R, SHOULD_RENDER_AS_BLOCK_R, SelectCond, SelectContent, SelectContentStates, SelectSelector, type SitemapUrlEntry, type StrikethroughTextNode, TABLE_CENTER_ALIGN, TABLE_LEFT_ALIGN, TABLE_RIGHT_ALIGN, TABLE_TRIM_PIPES, TAB_R, TEXT_BOLD_R, TEXT_EMPHASIZED_R, TEXT_ESCAPED_R, TEXT_MARKED_R, TEXT_STRIKETHROUGHED_R, TRIM_STARTING_NEWLINES, type TableNode, type TableSeparatorNode, TaggedMessageToken, type TextNode, TranslationCond, TranslationContent, UNESCAPE_R, UNORDERED, UNORDERED_LIST_BULLET, UNORDERED_LIST_ITEM_PREFIX, UNORDERED_LIST_ITEM_PREFIX_R, UNORDERED_LIST_ITEM_R, UNORDERED_LIST_R, UnionKeys, type UnorderedListNode, VOID_HTML_ELEMENTS, ValidDotPathsFor, ValueAtKey, WrappedIntl, YamlRecord, YamlValue, allowInline, anyScopeRegex, attributeValueToNodePropValue, bindIntl, blockRegex, buildMaskPlugin, captureNothing, checkIsURLAbsolute, checkMissingLocalesPlugin, compact, comparePaths, compile, compileWithOptions, condition as cond, conditionPlugin, createCompiler, createMessageResolver, createRenderer, currency, cx, date, deepTransformNode, editDictionaryByKeyPath, enumeration as enu, enumerationPlugin, fallbackPlugin, type file, type fileContent, filePlugin, filterMissingTranslationsOnlyPlugin, filterTranslationsOnlyPlugin, findMatchingCondition, findPlainDynamicLoader, formatProxyEnabledMessage, gender, genderPlugin, generateListItemPrefix, generateListItemPrefixRegex, generateListItemRegex, generateListRegex, generateSitemap, generateSitemapUrl, get, getBasePlugins, getBrowserLocale, getCachedIntl, getCanonicalPath, getCondition, getContent, getContentNodeByKeyPath, getCookie, getDefaultNode, getDictionary, getDictionaryAsync, getDictionaryCompositeIds, getDictionaryQualifierIds, getDictionaryQualifierTypes, getDictionarySelectorCacheKey, getDictionaryTransformCacheKey, getDomainHostname, getDomainOrigin, getEditedContent, getEditedDictionary, getEmptyNode, getEnumeration, getFilterMissingTranslationsContent, getFilterMissingTranslationsDictionary, getFilterTranslationsOnlyContent, getFilterTranslationsOnlyDictionary, getFilteredLocalesContent, getFilteredLocalesDictionary, getGender, getHTML, getHTMLTextDir, getInsertion, getInsertionValues, getInternalPath, getInterpolableContent, getIntlayer, getIntlayerAsync, getLocale, getLocaleFromDomain, getLocaleFromPath, getLocaleFromStorage, getLocaleFromStorageClient, getLocaleFromStorageServer, getLocaleLang, getLocaleName, getLocalizedContent, getLocalizedPath, getLocalizedUrl, getMarkdownMetadata, getMaskContent, getMissingLocalesContent, getMissingLocalesContentFromDictionary, getMultilingualDictionary, getMultilingualUrls, getNestedDictionaryGraph, getNestedDictionaryKeys, getNestedDictionaryReferences, getNesting, getNodeChildren, getNodeType, getPathWithoutLocale, getPerLocaleDictionary, getPluginsCacheKey, getPlural, getPrefix, getPreloadLocale, getPreloadedDictionary, getReplacedValuesContent, getRewritePath, getRewriteRules, getRuleSet, getSelect, getSplittedContent, getSplittedDictionaryContent, getTranslation, getVariantIds, html, i18nextToIntlayerFormatter, icuToIntlayerFormatter, inlineRegex, insertion as insert, insertContentInDictionary, insertionPlugin, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, isDeclaredLocale, isInterpolableWrapperNode, isLocaleExclusiveOnDomain, isProxyStorageLocaleEnabled, isQualifiedDictionaryGroup, isQualifiedDynamicLoaderMap, isSameKeyPath, isValidElement, list, localeDetector, localeFlatMap, localeMap, localeRecord, localeResolver, localeStorageOptions, markdown as md, mergeDictionaries, mergeQualifiedDictionaries, navigatePath, nesting as nest, nestedPlugin, normalizeAttributeKey, normalizeDictionaries, normalizeDictionary, normalizePath, normalizeWhitespace, number, orderDictionaries, parseBlock, parseCaptureInline, parseDictionarySelector, parseInline, parseMarkdown, parseSimpleInline, parseStyleAttribute, parseTableAlign, parseTableAlignCapture, parseTableCells, parseTableRow, parseTaggedMessage, parseYaml, parserFor, percentage, plural, pluralPlugin, portableObjectToIntlayerFormatter, presets, qualifies, readTransformCache, rebuildInterpolableContent, reconstructQualifiedEntry, relativeTime, removeContentNodeByKeyPath, renameContentNodeByKeyPath, renderFor, renderMarkdownAst, renderNothing, resolveBrowserLocale, resolveDictionaryArgument, resolveEffectiveVariantId, resolveLocalizedPath, resolveMessage, resolveMessageNode, resolveMessageNodeToString, resolvePlainDynamicLoader, resolveProviderVariant, resolveProxyMode, resolveQualifiedDictionary, resolveQualifiedDynamicContent, resolveQualifiedDynamicContentAsync, sanitizer, select, selectPlugin, serializeVariant, serializeVariantChain, setLocaleInStorage, setLocaleInStorageClient, setLocaleInStorageServer, simpleInlineRegex, slugify, some, splitInsertionTemplate, startsWith, stringifyYaml, translation as t, transformInterpolableNode, translationPlugin, trimEnd, trimLeadingWhitespaceOutsideFences, unescapeString, units, unquote, updateNodeChildren, validateHTML, validateMarkdown, validatePrefix, vueI18nToIntlayerFormatter, writeTransformCache };
@@ -2,6 +2,6 @@ import { JsonValue, icuToIntlayerFormatter, intlayerToICUFormatter } from "./ICU
2
2
  import { i18nextToIntlayerFormatter, intlayerToI18nextFormatter } from "./i18next.js";
3
3
  import { navigatePath } from "./navigatePath.js";
4
4
  import { PortableObject, intlayerToPortableObjectFormatter, portableObjectToIntlayerFormatter } from "./po.js";
5
- import { MessageFormatDialect, MessageValues, TaggedMessageToken, interpolateMessage, parseTaggedMessage, resolveMessage, resolveMessageNode } from "./resolveMessage.js";
5
+ import { MessageFormatDialect, MessageFormatter, MessageResolver, MessageValues, TaggedMessageToken, createMessageResolver, interpolateMessage, parseTaggedMessage, resolveMessage, resolveMessageNode, resolveMessageNodeToString } from "./resolveMessage.js";
6
6
  import { intlayerToVueI18nFormatter, vueI18nToIntlayerFormatter } from "./vue-i18n.js";
7
- export { JsonValue, MessageFormatDialect, MessageValues, PortableObject, TaggedMessageToken, i18nextToIntlayerFormatter, icuToIntlayerFormatter, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, navigatePath, parseTaggedMessage, portableObjectToIntlayerFormatter, resolveMessage, resolveMessageNode, vueI18nToIntlayerFormatter };
7
+ export { JsonValue, MessageFormatDialect, MessageFormatter, MessageResolver, MessageValues, PortableObject, TaggedMessageToken, createMessageResolver, i18nextToIntlayerFormatter, icuToIntlayerFormatter, interpolateMessage, intlayerToI18nextFormatter, intlayerToICUFormatter, intlayerToPortableObjectFormatter, intlayerToVueI18nFormatter, navigatePath, parseTaggedMessage, portableObjectToIntlayerFormatter, resolveMessage, resolveMessageNode, resolveMessageNodeToString, vueI18nToIntlayerFormatter };
@@ -20,7 +20,8 @@ export type MessageValues = Record<string, unknown>;
20
20
  * Interpolates a message template with values.
21
21
  *
22
22
  * Handles, in order:
23
- * 1. Intlayer insertions `{{name}}` (whitespace-tolerant, dotted paths)
23
+ * 1. Intlayer insertions `{{name}}` (whitespace-tolerant, dotted paths),
24
+ * optionally formatted the i18next way (`{{price, number}}`)
24
25
  * 2. ICU formatted arguments `{value, number}` / `{ts, date, long}`
25
26
  * 3. Bare single-brace arguments `{name}` (ICU / vue-i18n simple args)
26
27
  */
@@ -34,10 +35,44 @@ export declare const interpolateMessage: (template: string, values?: MessageValu
34
35
  * `enumeration` and `plural` content) are invoked with the values.
35
36
  */
36
37
  export declare const resolveMessageNode: (node: unknown, values?: MessageValues, locale?: LocalesValues) => unknown;
38
+ /**
39
+ * {@link resolveMessageNode} coerced to a string.
40
+ *
41
+ * This is the whole runtime a compat adapter needs for content that reached
42
+ * the bundle through a built dictionary: the build already converted every
43
+ * dialect construct into intlayer nodes, and the interpreter turned those into
44
+ * callables, so no message parser is involved. Plain strings still get
45
+ * `{{name}}` / `{name}` / `{value, number}` interpolation.
46
+ */
47
+ export declare const resolveMessageNodeToString: (node: unknown, values?: MessageValues, locale?: LocalesValues) => string;
48
+ /** Converts a raw message string of one dialect into an intlayer node tree. */
49
+ export type MessageFormatter = (message: string) => unknown;
50
+ /**
51
+ * Resolves a raw message — string, or an intlayer node tree — into a final
52
+ * string using interpolation values and locale.
53
+ */
54
+ export type MessageResolver = (message: unknown, values?: MessageValues, locale?: LocalesValues) => string;
55
+ /**
56
+ * Binds {@link resolveMessageNode} to one dialect converter.
57
+ *
58
+ * The compat adapters each speak a single dialect, and referencing the
59
+ * converter directly — rather than picking it from a record keyed by dialect —
60
+ * is what lets a bundler drop the two parsers the adapter never uses.
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * const resolveIcuMessage = createMessageResolver(icuToIntlayerFormatter);
65
+ * resolveIcuMessage('Hello {name}', { name: 'John' }, 'en'); // 'Hello John'
66
+ * ```
67
+ */
68
+ export declare const createMessageResolver: (formatter: MessageFormatter) => MessageResolver;
37
69
  /**
38
70
  * Resolves a raw message — string in a library dialect, or an intlayer node
39
71
  * tree — into a final string using interpolation values and locale.
40
72
  *
73
+ * Selecting the dialect at runtime keeps every converter reachable; a package
74
+ * that only ever needs one should bind it with {@link createMessageResolver}.
75
+ *
41
76
  * @example
42
77
  * ```ts
43
78
  * resolveMessage('Hello {name}', { name: 'John' }, 'en', 'icu');
@@ -1 +1 @@
1
- {"version":3,"file":"resolveMessage.d.ts","names":[],"sources":["../../../src/messageFormat/resolveMessage.ts"],"mappings":";;;;;;;;;;;;;;;YAyBY;;YAGA,gBAAgB;;;;;;;;;qBAsFf,qBAAkB,kBACb,SACR,eAAa,SACb;;;;;;;;;qBAkCG,qBAAkB,eAChB,SACL,eAAa,SACb;;;;;;;;;;;;;;;;;;;qBA2JG,iBAAc,kBACT,SACR,eAAa,SACb,eAAa,UACZ;;YAaC;EAEN;EAAa,UAAU;;;;;;;;;qBAShB,qBAAkB,oBAAsB"}
1
+ {"version":3,"file":"resolveMessage.d.ts","names":[],"sources":["../../../src/messageFormat/resolveMessage.ts"],"mappings":";;;;;;;;;;;;;;;YAyBY;;YAGA,gBAAgB;;;;;;;;;;qBAuFf,qBAAkB,kBACb,SACR,eAAa,SACb;;;;;;;;;qBAwCG,qBAAkB,eAChB,SACL,eAAa,SACb;;;;;;;;;;qBAyIG,6BAA0B,eACxB,SACL,eAAa,SACb;;YAQE,oBAAoB;;;;;YAMpB,mBACV,kBACA,SAAS,eACT,SAAS;;;;;;;;;;;;;;qBAgBE,wBAAqB,WACpB,qBAAmB;;;;;;;;;;;;;;;;;;;;;;qBAmCpB,iBAAc,kBACT,SACR,eAAa,SACb,eAAa,UACZ;;YAKC;EAEN;EAAa,UAAU;;;;;;;;;qBAShB,qBAAkB,oBAAsB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intlayer/core",
3
- "version": "9.5.1",
3
+ "version": "9.5.3",
4
4
  "private": false,
5
5
  "description": "Includes core Intlayer functions like translation, dictionary, and utility functions shared across multiple packages.",
6
6
  "keywords": [
@@ -172,15 +172,15 @@
172
172
  "typecheck": "tsc --noEmit --project tsconfig.types.json"
173
173
  },
174
174
  "dependencies": {
175
- "@intlayer/api": "9.5.1",
176
- "@intlayer/config": "9.5.1",
177
- "@intlayer/dictionaries-entry": "9.5.1",
178
- "@intlayer/types": "9.5.1",
179
- "@intlayer/unmerged-dictionaries-entry": "9.5.1",
175
+ "@intlayer/api": "9.5.3",
176
+ "@intlayer/config": "9.5.3",
177
+ "@intlayer/dictionaries-entry": "9.5.3",
178
+ "@intlayer/types": "9.5.3",
179
+ "@intlayer/unmerged-dictionaries-entry": "9.5.3",
180
180
  "defu": "6.1.7"
181
181
  },
182
182
  "devDependencies": {
183
- "@types/node": "26.5.0",
183
+ "@types/node": "^22",
184
184
  "@utils/ts-config": "1.0.4",
185
185
  "@utils/ts-config-types": "1.0.4",
186
186
  "@utils/tsdown-config": "1.0.4",