@intlayer/core 9.0.2 → 9.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/dist/cjs/dictionaryManipulator/editDictionaryByKeyPath.cjs +5 -5
  2. package/dist/cjs/dictionaryManipulator/editDictionaryByKeyPath.cjs.map +1 -1
  3. package/dist/cjs/dictionaryManipulator/getContentNodeByKeyPath.cjs +1 -1
  4. package/dist/cjs/dictionaryManipulator/getContentNodeByKeyPath.cjs.map +1 -1
  5. package/dist/cjs/dictionaryManipulator/getDefaultNode.cjs +15 -0
  6. package/dist/cjs/dictionaryManipulator/getDefaultNode.cjs.map +1 -1
  7. package/dist/cjs/dictionaryManipulator/getEmptyNode.cjs +1 -1
  8. package/dist/cjs/dictionaryManipulator/getEmptyNode.cjs.map +1 -1
  9. package/dist/cjs/dictionaryManipulator/getNodeChildren.cjs +1 -1
  10. package/dist/cjs/dictionaryManipulator/getNodeChildren.cjs.map +1 -1
  11. package/dist/cjs/dictionaryManipulator/getNodeType.cjs +30 -22
  12. package/dist/cjs/dictionaryManipulator/getNodeType.cjs.map +1 -1
  13. package/dist/cjs/dictionaryManipulator/removeContentNodeByKeyPath.cjs +1 -1
  14. package/dist/cjs/dictionaryManipulator/removeContentNodeByKeyPath.cjs.map +1 -1
  15. package/dist/cjs/dictionaryManipulator/renameContentNodeByKeyPath.cjs +1 -1
  16. package/dist/cjs/dictionaryManipulator/renameContentNodeByKeyPath.cjs.map +1 -1
  17. package/dist/cjs/dictionaryManipulator/updateNodeChildren.cjs +1 -1
  18. package/dist/cjs/dictionaryManipulator/updateNodeChildren.cjs.map +1 -1
  19. package/dist/cjs/index.cjs +7 -0
  20. package/dist/cjs/interpreter/getContent/getContent.cjs +2 -1
  21. package/dist/cjs/interpreter/getContent/getContent.cjs.map +1 -1
  22. package/dist/cjs/interpreter/getContent/index.cjs +1 -0
  23. package/dist/cjs/interpreter/getContent/plugins.cjs +28 -0
  24. package/dist/cjs/interpreter/getContent/plugins.cjs.map +1 -1
  25. package/dist/cjs/interpreter/getSelect.cjs +36 -0
  26. package/dist/cjs/interpreter/getSelect.cjs.map +1 -0
  27. package/dist/cjs/interpreter/index.cjs +5 -0
  28. package/dist/cjs/messageFormat/ICU.cjs +23 -6
  29. package/dist/cjs/messageFormat/ICU.cjs.map +1 -1
  30. package/dist/cjs/messageFormat/i18next.cjs +24 -6
  31. package/dist/cjs/messageFormat/i18next.cjs.map +1 -1
  32. package/dist/cjs/messageFormat/resolveMessage.cjs +8 -0
  33. package/dist/cjs/messageFormat/resolveMessage.cjs.map +1 -1
  34. package/dist/cjs/messageFormat/vue-i18n.cjs +11 -2
  35. package/dist/cjs/messageFormat/vue-i18n.cjs.map +1 -1
  36. package/dist/cjs/transpiler/index.cjs +2 -0
  37. package/dist/cjs/transpiler/select/index.cjs +4 -0
  38. package/dist/cjs/transpiler/select/select.cjs +42 -0
  39. package/dist/cjs/transpiler/select/select.cjs.map +1 -0
  40. package/dist/esm/dictionaryManipulator/editDictionaryByKeyPath.mjs +5 -5
  41. package/dist/esm/dictionaryManipulator/editDictionaryByKeyPath.mjs.map +1 -1
  42. package/dist/esm/dictionaryManipulator/getContentNodeByKeyPath.mjs +1 -1
  43. package/dist/esm/dictionaryManipulator/getContentNodeByKeyPath.mjs.map +1 -1
  44. package/dist/esm/dictionaryManipulator/getDefaultNode.mjs +15 -0
  45. package/dist/esm/dictionaryManipulator/getDefaultNode.mjs.map +1 -1
  46. package/dist/esm/dictionaryManipulator/getEmptyNode.mjs +1 -1
  47. package/dist/esm/dictionaryManipulator/getEmptyNode.mjs.map +1 -1
  48. package/dist/esm/dictionaryManipulator/getNodeChildren.mjs +1 -1
  49. package/dist/esm/dictionaryManipulator/getNodeChildren.mjs.map +1 -1
  50. package/dist/esm/dictionaryManipulator/getNodeType.mjs +30 -22
  51. package/dist/esm/dictionaryManipulator/getNodeType.mjs.map +1 -1
  52. package/dist/esm/dictionaryManipulator/removeContentNodeByKeyPath.mjs +1 -1
  53. package/dist/esm/dictionaryManipulator/removeContentNodeByKeyPath.mjs.map +1 -1
  54. package/dist/esm/dictionaryManipulator/renameContentNodeByKeyPath.mjs +1 -1
  55. package/dist/esm/dictionaryManipulator/renameContentNodeByKeyPath.mjs.map +1 -1
  56. package/dist/esm/dictionaryManipulator/updateNodeChildren.mjs +1 -1
  57. package/dist/esm/dictionaryManipulator/updateNodeChildren.mjs.map +1 -1
  58. package/dist/esm/index.mjs +5 -2
  59. package/dist/esm/interpreter/getContent/getContent.mjs +3 -2
  60. package/dist/esm/interpreter/getContent/getContent.mjs.map +1 -1
  61. package/dist/esm/interpreter/getContent/index.mjs +2 -2
  62. package/dist/esm/interpreter/getContent/plugins.mjs +28 -1
  63. package/dist/esm/interpreter/getContent/plugins.mjs.map +1 -1
  64. package/dist/esm/interpreter/getSelect.mjs +34 -0
  65. package/dist/esm/interpreter/getSelect.mjs.map +1 -0
  66. package/dist/esm/interpreter/index.mjs +4 -2
  67. package/dist/esm/messageFormat/ICU.mjs +23 -6
  68. package/dist/esm/messageFormat/ICU.mjs.map +1 -1
  69. package/dist/esm/messageFormat/i18next.mjs +24 -6
  70. package/dist/esm/messageFormat/i18next.mjs.map +1 -1
  71. package/dist/esm/messageFormat/resolveMessage.mjs +8 -0
  72. package/dist/esm/messageFormat/resolveMessage.mjs.map +1 -1
  73. package/dist/esm/messageFormat/vue-i18n.mjs +11 -2
  74. package/dist/esm/messageFormat/vue-i18n.mjs.map +1 -1
  75. package/dist/esm/transpiler/index.mjs +2 -1
  76. package/dist/esm/transpiler/select/index.mjs +3 -0
  77. package/dist/esm/transpiler/select/select.mjs +41 -0
  78. package/dist/esm/transpiler/select/select.mjs.map +1 -0
  79. package/dist/types/dictionaryManipulator/getNodeType.d.ts.map +1 -1
  80. package/dist/types/index.d.ts +5 -2
  81. package/dist/types/interpreter/getContent/getContent.d.ts.map +1 -1
  82. package/dist/types/interpreter/getContent/index.d.ts +2 -2
  83. package/dist/types/interpreter/getContent/plugins.d.ts +22 -1
  84. package/dist/types/interpreter/getContent/plugins.d.ts.map +1 -1
  85. package/dist/types/interpreter/getSelect.d.ts +31 -0
  86. package/dist/types/interpreter/getSelect.d.ts.map +1 -0
  87. package/dist/types/interpreter/index.d.ts +4 -2
  88. package/dist/types/messageFormat/ICU.d.ts.map +1 -1
  89. package/dist/types/messageFormat/i18next.d.ts.map +1 -1
  90. package/dist/types/messageFormat/resolveMessage.d.ts.map +1 -1
  91. package/dist/types/messageFormat/vue-i18n.d.ts.map +1 -1
  92. package/dist/types/transpiler/index.d.ts +3 -1
  93. package/dist/types/transpiler/select/index.d.ts +2 -0
  94. package/dist/types/transpiler/select/select.d.ts +62 -0
  95. package/dist/types/transpiler/select/select.d.ts.map +1 -0
  96. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"plugins.cjs","names":["NodeTypes","getTranslation","getEnumeration","isInterpolableWrapperNode","transformInterpolableNode","getInsertion","getPlural","getCondition","getGender","getNesting"],"sources":["../../../../src/interpreter/getContent/plugins.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types/allLocales';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type {\n DeclaredLocales,\n DictionaryKeys,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type { NodeType } from '@intlayer/types/nodeType';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type {\n ConditionContent,\n EnumerationContent,\n FileContent,\n Gender,\n GenderContent,\n InsertionContent,\n NestedContent,\n PluralContent,\n PluralContentState,\n TranslationContent,\n} from '../../transpiler';\nimport { getCondition } from '../getCondition';\nimport { getEnumeration } from '../getEnumeration';\nimport { getGender } from '../getGender';\nimport { getInsertion } from '../getInsertion';\nimport { type GetNestingResult, getNesting } from '../getNesting';\nimport { getPlural } from '../getPlural';\nimport { getTranslation } from '../getTranslation';\nimport {\n isInterpolableWrapperNode,\n transformInterpolableNode,\n} from '../interpolableNode';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\n/** ---------------------------------------------\n * PLUGIN DEFINITION\n * --------------------------------------------- */\n\n/**\n * A plugin/transformer that can optionally transform a node during a single DFS pass.\n * - `canHandle` decides if the node is transformable by this plugin.\n * - `transform` returns the transformed node (and does not recurse further).\n *\n * > `transformFn` is a function that can be used to deeply transform inside the plugin.\n */\nexport type Plugins = {\n id: string;\n canHandle: (node: any) => boolean;\n transform: (\n node: any,\n props: NodeProps,\n transformFn: (node: any, props: NodeProps) => any\n ) => any;\n};\n\n/** ---------------------------------------------\n * FALLBACK PLUGIN\n *\n * Used to fallback a tree-shaken plugin\n * --------------------------------------------- */\n\nexport const fallbackPlugin: Plugins = {\n id: 'fallback-plugin',\n canHandle: () => false,\n transform: (node) => node,\n};\n\n/** ---------------------------------------------\n * TRANSLATION PLUGIN\n * --------------------------------------------- */\n\nexport type UnionKeys<T> = T extends unknown ? keyof T : never;\nexport type ValueAtKey<T, K> = T extends unknown\n ? K extends keyof T\n ? T[K]\n : never\n : never;\n\nexport type TranslationCond<T, S, L extends LocalesValues> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.TRANSLATION]: infer U;\n}\n ? U extends Record<PropertyKey, unknown>\n ? U[keyof U] extends Record<PropertyKey, unknown>\n ? {\n [K in UnionKeys<U[keyof U]>]: L extends keyof U\n ? K extends keyof U[L]\n ? U[L][K]\n : ValueAtKey<U[keyof U], K>\n : ValueAtKey<U[keyof U], K>;\n } extends infer Content\n ? DeepTransformContent<Content, S>\n : never\n : (L extends keyof U ? U[L] : U[keyof U]) extends infer Content\n ? DeepTransformContent<Content, S>\n : never\n : never\n : never;\n\n/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */\nexport const translationPlugin = (\n locale: LocalesValues,\n fallback?: LocalesValues\n): Plugins =>\n process.env.INTLAYER_NODE_TYPE_TRANSLATION === 'false'\n ? fallbackPlugin\n : {\n id: 'translation-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.TRANSLATION,\n transform: (node: TranslationContent, props, deepTransformNode) => {\n const original = node[NodeTypes.TRANSLATION] ?? {};\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const childProps = {\n ...props,\n children: original[key as keyof typeof original],\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.TRANSLATION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(\n original[key as keyof typeof original],\n childProps\n );\n }\n\n return getTranslation(result, locale, fallback);\n },\n };\n\n/** ---------------------------------------------\n * ENUMERATION PLUGIN\n * --------------------------------------------- */\n\nexport type EnumerationCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.ENUMERATION]: object;\n}\n ? (\n quantity: number\n ) => DeepTransformContent<\n T[typeof NodeTypes.ENUMERATION][keyof T[typeof NodeTypes.ENUMERATION]],\n S\n >\n : never;\n\n/** Enumeration plugin. Replaces node with a function that takes quantity => string. */\nexport const enumerationPlugin: Plugins =\n process.env.INTLAYER_NODE_TYPE_ENUMERATION === 'false'\n ? fallbackPlugin\n : {\n id: 'enumeration-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.ENUMERATION,\n transform: (node: EnumerationContent, props, deepTransformNode) => {\n const original = node[NodeTypes.ENUMERATION];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as unknown as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.ENUMERATION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (arg: number | { count: number }) => {\n const quantity = typeof arg === 'number' ? arg : arg.count;\n const subResult = getEnumeration(result, quantity);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * PLURAL PLUGIN\n * --------------------------------------------- */\n\nexport type PluralCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.PLURAL]: object;\n}\n ? (\n arg: number | { count: number; [key: string]: unknown }\n ) => DeepTransformContent<\n T[typeof NodeTypes.PLURAL][keyof T[typeof NodeTypes.PLURAL]],\n S\n >\n : never;\n\ntype SubResultFunction = (values: Record<string, string | number>) => string;\n\n/**\n * Plural plugin. Replaces node with a function that takes a count (or\n * `{ count, ...values }`) => string, picking the matching CLDR plural form\n * for the active locale and interpolating `{{count}}` (and other values).\n */\nexport const pluralPlugin = (locale?: LocalesValues): Plugins =>\n process.env.INTLAYER_NODE_TYPE_PLURAL === 'false'\n ? fallbackPlugin\n : {\n id: 'plural-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.PLURAL,\n transform: (node: PluralContent, props, deepTransformNode) => {\n const original = node[NodeTypes.PLURAL];\n const result: Record<string, any> = {};\n\n /** String plugin for plural. Replaces string node with a component that renders the insertion. */\n const pluralStringPlugin: Plugins = {\n id: 'plural-string-plugin',\n canHandle: (node) =>\n typeof node === 'string' || isInterpolableWrapperNode(node),\n transform: (node, subProps, deepTransformNode) => {\n // `html()`/`markdown()` nodes carry their `{{count}}` placeholders\n // inside a raw string. Interpolate into that string, then re-run\n // the transform so the html/markdown renderer applies afterwards.\n if (isInterpolableWrapperNode(node)) {\n return (values: { [k: string]: string | number }) =>\n transformInterpolableNode(\n node,\n values,\n subProps,\n props.plugins,\n deepTransformNode\n );\n }\n\n const transformedResult = deepTransformNode(node, {\n ...subProps,\n children: node,\n plugins: [\n ...(props.plugins ?? ([] as Plugins[])).filter(\n (plugin) => plugin.id !== 'intlayer-node-plugin'\n ),\n ],\n });\n\n return (values: { [k: string]: string | number }) => {\n const children = getInsertion(transformedResult, values);\n\n return deepTransformNode(children, {\n ...subProps,\n plugins: props.plugins,\n children,\n });\n };\n },\n };\n\n for (const key in original) {\n const child = original[key as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.PLURAL, key } as KeyPath,\n ],\n plugins: [pluralStringPlugin, ...(props.plugins ?? [])],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n const effectiveLocale = String(locale ?? props.locale ?? 'en');\n\n return (arg: number | { count: number; [key: string]: unknown }) => {\n const count = typeof arg === 'number' ? arg : arg.count;\n const values =\n typeof arg === 'number'\n ? { count: arg }\n : (arg as { count: number; [key: string]: unknown });\n\n const subResult: string | SubResultFunction = getPlural(\n result as PluralContent['plural'] as PluralContentState<string>,\n count,\n effectiveLocale\n );\n\n if (typeof subResult === 'function') {\n return (subResult as SubResultFunction)(values);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * CONDITION PLUGIN\n * --------------------------------------------- */\n\nexport type ConditionCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.CONDITION]: object;\n}\n ? (\n value: boolean | { value: boolean }\n ) => DeepTransformContent<\n T[typeof NodeTypes.CONDITION][keyof T[typeof NodeTypes.CONDITION]],\n S\n >\n : never;\n\n/** Condition plugin. Replaces node with a function that takes boolean => string. */\nexport const conditionPlugin: Plugins =\n process.env.INTLAYER_NODE_TYPE_CONDITION === 'false'\n ? fallbackPlugin\n : {\n id: 'condition-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.CONDITION,\n transform: (node: ConditionContent, props, deepTransformNode) => {\n const original = node[NodeTypes.CONDITION];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.CONDITION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (arg: boolean | { value: boolean }) => {\n const value = typeof arg === 'boolean' ? arg : arg.value;\n const subResult = getCondition(result as any, value);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * INSERTION PLUGIN\n * --------------------------------------------- */\n\nexport type InsertionCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.INSERTION]: infer I;\n fields: readonly string[];\n}\n ? (\n values: {\n [K in T['fields'][number]]: string | number;\n }\n ) => I extends string\n ? DeepTransformContent<string, S>\n : DeepTransformContent<I, S>\n : never;\n\n/** Insertion plugin. Replaces node with a function that takes quantity => string. */\nexport const insertionPlugin: Plugins =\n process.env.INTLAYER_NODE_TYPE_INSERTION === 'false'\n ? fallbackPlugin\n : {\n id: 'insertion-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.INSERTION,\n transform: (node: InsertionContent, props, deepTransformNode) => {\n const newKeyPath: KeyPath[] = [\n ...props.keyPath,\n {\n type: NodeTypes.INSERTION,\n },\n ];\n\n const children = node[NodeTypes.INSERTION];\n\n /** Insertion string plugin. Replaces string node with a component that render the insertion. */\n const insertionStringPlugin: Plugins = {\n id: 'insertion-string-plugin',\n canHandle: (node) =>\n typeof node === 'string' || isInterpolableWrapperNode(node),\n transform: (node, subProps, deepTransformNode) => {\n // `html()`/`markdown()` nodes carry their `{{ … }}` placeholders\n // inside a raw string. Interpolate into that string, then re-run\n // the transform so the html/markdown renderer applies afterwards.\n if (isInterpolableWrapperNode(node)) {\n return (\n values: {\n [K in InsertionContent['fields'][number]]: string | number;\n }\n ) =>\n transformInterpolableNode(\n node,\n values,\n subProps,\n props.plugins,\n deepTransformNode\n );\n }\n\n const transformedResult = deepTransformNode(node, {\n ...subProps,\n children: node,\n plugins: [\n ...(props.plugins ?? ([] as Plugins[])).filter(\n (plugin) => plugin.id !== 'intlayer-node-plugin'\n ),\n ],\n });\n\n return (\n values: {\n [K in InsertionContent['fields'][number]]: string | number;\n }\n ) => {\n const children = getInsertion(transformedResult, values);\n\n return deepTransformNode(children, {\n ...subProps,\n plugins: props.plugins,\n children,\n });\n };\n },\n };\n\n return deepTransformNode(children, {\n ...props,\n children,\n keyPath: newKeyPath,\n plugins: [insertionStringPlugin, ...(props.plugins ?? [])],\n });\n },\n };\n\n/** ---------------------------------------------\n * GENDER PLUGIN\n * --------------------------------------------- */\n\nexport type GenderCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.GENDER]: object;\n}\n ? (\n value: Gender\n ) => DeepTransformContent<\n T[typeof NodeTypes.GENDER][keyof T[typeof NodeTypes.GENDER]],\n S\n >\n : never;\n\n/** Gender plugin. Replaces node with a function that takes gender => string. */\nexport const genderPlugin: Plugins =\n process.env.INTLAYER_NODE_TYPE_GENDER === 'false'\n ? fallbackPlugin\n : {\n id: 'gender-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.GENDER,\n transform: (node: GenderContent, props, deepTransformNode) => {\n const original = node[NodeTypes.GENDER];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.GENDER, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (value: Gender) => getGender(result as any, value);\n },\n };\n\n/** ---------------------------------------------\n * NESTED PLUGIN\n * --------------------------------------------- */\n\nexport type NestedCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.NESTED]: infer U;\n}\n ? U extends {\n dictionaryKey: infer K extends DictionaryKeys;\n path?: infer P;\n }\n ? GetNestingResult<K, P, S>\n : never\n : never;\n\n/** Nested plugin. Replaces node with the result of `getNesting`. */\nexport const nestedPlugin = (locale?: LocalesValues): Plugins =>\n process.env.INTLAYER_NODE_TYPE_NESTED === 'false'\n ? fallbackPlugin\n : {\n id: 'nested-plugin',\n canHandle: (node) =>\n typeof node === 'object' &&\n (node?.nodeType === NodeTypes.NESTED || node?.nodeType === 'n'),\n transform: (node: NestedContent, props) =>\n getNesting(\n node[NodeTypes.NESTED].dictionaryKey,\n node[NodeTypes.NESTED].path,\n {\n ...props,\n locale: (locale ?? props.locale) as Locale,\n }\n ),\n };\n\n/** ---------------------------------------------\n * FILE PLUGIN\n * --------------------------------------------- */\n\nexport type FileCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.FILE]: string;\n content?: string;\n}\n ? DeepTransformContent<string, S>\n : never;\n\n/** File plugin. Replaces node with the result of `getNesting`. */\nexport const filePlugin: Plugins =\n process.env.INTLAYER_NODE_TYPE_FILE === 'false'\n ? fallbackPlugin\n : {\n id: 'file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.FILE,\n transform: (node: FileContent, props, deepTransform) =>\n deepTransform(node.content, {\n ...props,\n children: node.content,\n }),\n };\n\n/**\n * PLUGIN RESULT\n */\n\n/**\n * Interface that defines the properties of a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface NodeProps {\n dictionaryKey: string;\n keyPath: KeyPath[];\n plugins?: Plugins[];\n locale?: Locale;\n dictionaryPath?: string;\n children?: any;\n /**\n * Forces eager traversal of plain objects in `deepTransformNode`. By default\n * traversal is lazy (property getters), so callers that discard the returned\n * value never trigger plugins on nested nodes. Set this when running plugins\n * for their side effects only (e.g. missing-locale detection).\n */\n eager?: boolean;\n}\n\n/**\n * Interface that defines the plugins that can be used to transform a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface IInterpreterPlugin<T, S, L extends LocalesValues> {\n translation: TranslationCond<T, S, L>;\n enumeration: EnumerationCond<T, S, L>;\n plural: PluralCond<T, S, L>;\n condition: ConditionCond<T, S, L>;\n insertion: InsertionCond<T, S, L>;\n gender: GenderCond<T, S, L>;\n nested: NestedCond<T, S, L>;\n file: FileCond<T, S, L>;\n}\n\n/**\n * Allow to avoid overwriting import from `intlayer` package when `IInterpreterPlugin<T>` interface is augmented in another package, such as `react-intlayer`.\n */\nexport type IInterpreterPluginState = {\n translation: true;\n enumeration: true;\n plural: true;\n condition: true;\n insertion: true;\n gender: true;\n nested: true;\n file: true;\n};\n\n/**\n * Utility type to check if a plugin can be applied to a node.\n */\ntype CheckApplyPlugin<\n T,\n K extends keyof IInterpreterPlugin<T, S, L>,\n S,\n L extends LocalesValues = DeclaredLocales,\n> = K extends keyof S // Test if the key is a key of S.\n ? // Test if the key of S is true. Then the plugin can be applied.\n S[K] extends true\n ? // Test if the key of S exist\n IInterpreterPlugin<T, S, L>[K] extends never\n ? never\n : // Test if the plugin condition is true (if it's not, the plugin is skipped for this node)\n IInterpreterPlugin<T, S, L>[K]\n : never\n : never;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\ntype Traverse<T, S, L extends LocalesValues = DeclaredLocales> =\n T extends ReadonlyArray<infer U> // Turn any read-only array into a plain mutable array\n ? Array<DeepTransformContent<U, S, L>>\n : T extends object\n ? { [K in keyof T]: DeepTransformContent<T[K], S, L> }\n : T;\n\nexport type IsAny<T> = 0 extends 1 & T ? true : false;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\nexport type DeepTransformContent<\n T,\n S = IInterpreterPluginState,\n L extends LocalesValues = DeclaredLocales,\n> =\n IsAny<T> extends true\n ? T\n : CheckApplyPlugin<T, keyof IInterpreterPlugin<T, S, L>, S, L> extends never // Check if there is a plugin for T:\n ? // No plugin was found, so try to transform T recursively:\n Traverse<T, S, L>\n : // A plugin was found – use the plugin's transformation.\n CheckApplyPlugin<T, keyof IInterpreterPlugin<T, S, L>, S, L>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAgEA,MAAa,iBAA0B;CACrC,IAAI;CACJ,iBAAiB;CACjB,YAAY,SAAS;AACvB;;AAmCA,MAAa,qBACX,QACA,aAEA,QAAQ,IAAI,mCAAmC,UAC3C,iBACA;CACE,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaA,yBAAU;CAC3D,YAAY,MAA0B,OAAO,sBAAsB;EACjE,MAAM,WAAW,KAAKA,yBAAU,gBAAgB,CAAC;EACjD,MAAM,SAA8B,CAAC;EAErC,KAAK,MAAM,OAAO,UAAU;GAC1B,MAAM,aAAa;IACjB,GAAG;IACH,UAAU,SAAS;IACnB,SAAS,CACP,GAAG,MAAM,SACT;KAAE,MAAMA,yBAAU;KAAa;IAAI,CACrC;GACF;GACA,OAAO,OAAO,kBACZ,SAAS,MACT,UACF;EACF;EAEA,OAAOC,kDAAe,QAAQ,QAAQ,QAAQ;CAChD;AACF;;AAmBN,MAAa,oBACX,QAAQ,IAAI,mCAAmC,UAC3C,iBACA;CACE,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaD,yBAAU;CAC3D,YAAY,MAA0B,OAAO,sBAAsB;EACjE,MAAM,WAAW,KAAKA,yBAAU;EAChC,MAAM,SAA8B,CAAC;EAErC,KAAK,MAAM,OAAO,UAAU;GAC1B,MAAM,QAAQ,SAAS;GASvB,OAAO,OAAO,kBAAkB,OAAO;IAPrC,GAAG;IACH,UAAU;IACV,SAAS,CACP,GAAG,MAAM,SACT;KAAE,MAAMA,yBAAU;KAAa;IAAI,CACrC;GAE8C,CAAC;EACnD;EAEA,QAAQ,QAAoC;GAC1C,MAAM,WAAW,OAAO,QAAQ,WAAW,MAAM,IAAI;GACrD,MAAM,YAAYE,kDAAe,QAAQ,QAAQ;GAEjD,IAAI,OAAO,cAAc,cAAc,OAAO,QAAQ,UACpD,OAAO,UAAU,GAAG;GAGtB,OAAO;EACT;CACF;AACF;;;;;;AAyBN,MAAa,gBAAgB,WAC3B,QAAQ,IAAI,8BAA8B,UACtC,iBACA;CACE,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaF,yBAAU;CAC3D,YAAY,MAAqB,OAAO,sBAAsB;EAC5D,MAAM,WAAW,KAAKA,yBAAU;EAChC,MAAM,SAA8B,CAAC;;EAGrC,MAAM,qBAA8B;GAClC,IAAI;GACJ,YAAY,SACV,OAAO,SAAS,YAAYG,+DAA0B,IAAI;GAC5D,YAAY,MAAM,UAAU,sBAAsB;IAIhD,IAAIA,+DAA0B,IAAI,GAChC,QAAQ,WACNC,+DACE,MACA,QACA,UACA,MAAM,SACN,iBACF;IAGJ,MAAM,oBAAoB,kBAAkB,MAAM;KAChD,GAAG;KACH,UAAU;KACV,SAAS,CACP,IAAI,MAAM,WAAY,CAAC,EAAe,CAAE,QACrC,WAAW,OAAO,OAAO,sBAC5B,CACF;IACF,CAAC;IAED,QAAQ,WAA6C;KACnD,MAAM,WAAWC,8CAAa,mBAAmB,MAAM;KAEvD,OAAO,kBAAkB,UAAU;MACjC,GAAG;MACH,SAAS,MAAM;MACf;KACF,CAAC;IACH;GACF;EACF;EAEA,KAAK,MAAM,OAAO,UAAU;GAC1B,MAAM,QAAQ,SAAS;GAUvB,OAAO,OAAO,kBAAkB,OAAO;IARrC,GAAG;IACH,UAAU;IACV,SAAS,CACP,GAAG,MAAM,SACT;KAAE,MAAML,yBAAU;KAAQ;IAAI,CAChC;IACA,SAAS,CAAC,oBAAoB,GAAI,MAAM,WAAW,CAAC,CAAE;GAER,CAAC;EACnD;EAEA,MAAM,kBAAkB,OAAO,UAAU,MAAM,UAAU,IAAI;EAE7D,QAAQ,QAA4D;GAClE,MAAM,QAAQ,OAAO,QAAQ,WAAW,MAAM,IAAI;GAClD,MAAM,SACJ,OAAO,QAAQ,WACX,EAAE,OAAO,IAAI,IACZ;GAEP,MAAM,YAAwCM,wCAC5C,QACA,OACA,eACF;GAEA,IAAI,OAAO,cAAc,YACvB,OAAQ,UAAgC,MAAM;GAGhD,OAAO;EACT;CACF;AACF;;AAmBN,MAAa,kBACX,QAAQ,IAAI,iCAAiC,UACzC,iBACA;CACE,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaN,yBAAU;CAC3D,YAAY,MAAwB,OAAO,sBAAsB;EAC/D,MAAM,WAAW,KAAKA,yBAAU;EAChC,MAAM,SAA8B,CAAC;EAErC,KAAK,MAAM,OAAO,UAAU;GAC1B,MAAM,QAAQ,SAAS;GASvB,OAAO,OAAO,kBAAkB,OAAO;IAPrC,GAAG;IACH,UAAU;IACV,SAAS,CACP,GAAG,MAAM,SACT;KAAE,MAAMA,yBAAU;KAAW;IAAI,CACnC;GAE8C,CAAC;EACnD;EAEA,QAAQ,QAAsC;GAC5C,MAAM,QAAQ,OAAO,QAAQ,YAAY,MAAM,IAAI;GACnD,MAAM,YAAYO,8CAAa,QAAe,KAAK;GAEnD,IAAI,OAAO,cAAc,cAAc,OAAO,QAAQ,UACpD,OAAO,UAAU,GAAG;GAGtB,OAAO;EACT;CACF;AACF;;AAqBN,MAAa,kBACX,QAAQ,IAAI,iCAAiC,UACzC,iBACA;CACE,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaP,yBAAU;CAC3D,YAAY,MAAwB,OAAO,sBAAsB;EAC/D,MAAM,aAAwB,CAC5B,GAAG,MAAM,SACT,EACE,MAAMA,yBAAU,UAClB,CACF;EAEA,MAAM,WAAW,KAAKA,yBAAU;;EAGhC,MAAM,wBAAiC;GACrC,IAAI;GACJ,YAAY,SACV,OAAO,SAAS,YAAYG,+DAA0B,IAAI;GAC5D,YAAY,MAAM,UAAU,sBAAsB;IAIhD,IAAIA,+DAA0B,IAAI,GAChC,QACE,WAIAC,+DACE,MACA,QACA,UACA,MAAM,SACN,iBACF;IAGJ,MAAM,oBAAoB,kBAAkB,MAAM;KAChD,GAAG;KACH,UAAU;KACV,SAAS,CACP,IAAI,MAAM,WAAY,CAAC,EAAe,CAAE,QACrC,WAAW,OAAO,OAAO,sBAC5B,CACF;IACF,CAAC;IAED,QACE,WAGG;KACH,MAAM,WAAWC,8CAAa,mBAAmB,MAAM;KAEvD,OAAO,kBAAkB,UAAU;MACjC,GAAG;MACH,SAAS,MAAM;MACf;KACF,CAAC;IACH;GACF;EACF;EAEA,OAAO,kBAAkB,UAAU;GACjC,GAAG;GACH;GACA,SAAS;GACT,SAAS,CAAC,uBAAuB,GAAI,MAAM,WAAW,CAAC,CAAE;EAC3D,CAAC;CACH;AACF;;AAmBN,MAAa,eACX,QAAQ,IAAI,8BAA8B,UACtC,iBACA;CACE,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaL,yBAAU;CAC3D,YAAY,MAAqB,OAAO,sBAAsB;EAC5D,MAAM,WAAW,KAAKA,yBAAU;EAChC,MAAM,SAA8B,CAAC;EAErC,KAAK,MAAM,OAAO,UAAU;GAC1B,MAAM,QAAQ,SAAS;GASvB,OAAO,OAAO,kBAAkB,OAAO;IAPrC,GAAG;IACH,UAAU;IACV,SAAS,CACP,GAAG,MAAM,SACT;KAAE,MAAMA,yBAAU;KAAQ;IAAI,CAChC;GAE8C,CAAC;EACnD;EAEA,QAAQ,UAAkBQ,wCAAU,QAAe,KAAK;CAC1D;AACF;;AAmBN,MAAa,gBAAgB,WAC3B,QAAQ,IAAI,8BAA8B,UACtC,iBACA;CACE,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,aACf,MAAM,aAAaR,yBAAU,UAAU,MAAM,aAAa;CAC7D,YAAY,MAAqB,UAC/BS,0CACE,KAAKT,yBAAU,OAAO,CAAC,eACvB,KAAKA,yBAAU,OAAO,CAAC,MACvB;EACE,GAAG;EACH,QAAS,UAAU,MAAM;CAC3B,CACF;AACJ;;AAeN,MAAa,aACX,QAAQ,IAAI,4BAA4B,UACpC,iBACA;CACE,IAAI;CACJ,YAAY,SACV,OAAO,SAAS,YAAY,MAAM,aAAaA,yBAAU;CAC3D,YAAY,MAAmB,OAAO,kBACpC,cAAc,KAAK,SAAS;EAC1B,GAAG;EACH,UAAU,KAAK;CACjB,CAAC;AACL"}
1
+ {"version":3,"file":"plugins.cjs","names":["NodeTypes","getTranslation","getEnumeration","isInterpolableWrapperNode","transformInterpolableNode","getInsertion","getPlural","getCondition","getGender","getSelect","getNesting"],"sources":["../../../../src/interpreter/getContent/plugins.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types/allLocales';\nimport type { KeyPath } from '@intlayer/types/keyPath';\nimport type {\n DeclaredLocales,\n DictionaryKeys,\n LocalesValues,\n} from '@intlayer/types/module_augmentation';\nimport type { NodeType } from '@intlayer/types/nodeType';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport type {\n ConditionContent,\n EnumerationContent,\n FileContent,\n Gender,\n GenderContent,\n InsertionContent,\n NestedContent,\n PluralContent,\n PluralContentState,\n SelectContent,\n TranslationContent,\n} from '../../transpiler';\nimport { getCondition } from '../getCondition';\nimport { getEnumeration } from '../getEnumeration';\nimport { getGender } from '../getGender';\nimport { getInsertion } from '../getInsertion';\nimport { type GetNestingResult, getNesting } from '../getNesting';\nimport { getPlural } from '../getPlural';\nimport { getSelect } from '../getSelect';\nimport { getTranslation } from '../getTranslation';\nimport {\n isInterpolableWrapperNode,\n transformInterpolableNode,\n} from '../interpolableNode';\n\n// ── Tree-shake constants ──────────────────────────────────────────────────────\n// When these env vars are injected at build time, bundlers eliminate the\n// branches guarded by these constants.\n\n/** ---------------------------------------------\n * PLUGIN DEFINITION\n * --------------------------------------------- */\n\n/**\n * A plugin/transformer that can optionally transform a node during a single DFS pass.\n * - `canHandle` decides if the node is transformable by this plugin.\n * - `transform` returns the transformed node (and does not recurse further).\n *\n * > `transformFn` is a function that can be used to deeply transform inside the plugin.\n */\nexport type Plugins = {\n id: string;\n canHandle: (node: any) => boolean;\n transform: (\n node: any,\n props: NodeProps,\n transformFn: (node: any, props: NodeProps) => any\n ) => any;\n};\n\n/** ---------------------------------------------\n * FALLBACK PLUGIN\n *\n * Used to fallback a tree-shaken plugin\n * --------------------------------------------- */\n\nexport const fallbackPlugin: Plugins = {\n id: 'fallback-plugin',\n canHandle: () => false,\n transform: (node) => node,\n};\n\n/** ---------------------------------------------\n * TRANSLATION PLUGIN\n * --------------------------------------------- */\n\nexport type UnionKeys<T> = T extends unknown ? keyof T : never;\nexport type ValueAtKey<T, K> = T extends unknown\n ? K extends keyof T\n ? T[K]\n : never\n : never;\n\nexport type TranslationCond<T, S, L extends LocalesValues> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.TRANSLATION]: infer U;\n}\n ? U extends Record<PropertyKey, unknown>\n ? U[keyof U] extends Record<PropertyKey, unknown>\n ? {\n [K in UnionKeys<U[keyof U]>]: L extends keyof U\n ? K extends keyof U[L]\n ? U[L][K]\n : ValueAtKey<U[keyof U], K>\n : ValueAtKey<U[keyof U], K>;\n } extends infer Content\n ? DeepTransformContent<Content, S>\n : never\n : (L extends keyof U ? U[L] : U[keyof U]) extends infer Content\n ? DeepTransformContent<Content, S>\n : never\n : never\n : never;\n\n/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */\nexport const translationPlugin = (\n locale: LocalesValues,\n fallback?: LocalesValues\n): Plugins =>\n process.env.INTLAYER_NODE_TYPE_TRANSLATION === 'false'\n ? fallbackPlugin\n : {\n id: 'translation-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.TRANSLATION,\n transform: (node: TranslationContent, props, deepTransformNode) => {\n const original = node[NodeTypes.TRANSLATION] ?? {};\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const childProps = {\n ...props,\n children: original[key as keyof typeof original],\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.TRANSLATION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(\n original[key as keyof typeof original],\n childProps\n );\n }\n\n return getTranslation(result, locale, fallback);\n },\n };\n\n/** ---------------------------------------------\n * ENUMERATION PLUGIN\n * --------------------------------------------- */\n\nexport type EnumerationCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.ENUMERATION]: object;\n}\n ? (\n quantity: number\n ) => DeepTransformContent<\n T[typeof NodeTypes.ENUMERATION][keyof T[typeof NodeTypes.ENUMERATION]],\n S\n >\n : never;\n\n/** Enumeration plugin. Replaces node with a function that takes quantity => string. */\nexport const enumerationPlugin: Plugins =\n process.env.INTLAYER_NODE_TYPE_ENUMERATION === 'false'\n ? fallbackPlugin\n : {\n id: 'enumeration-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.ENUMERATION,\n transform: (node: EnumerationContent, props, deepTransformNode) => {\n const original = node[NodeTypes.ENUMERATION];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as unknown as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.ENUMERATION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (arg: number | { count: number }) => {\n const quantity = typeof arg === 'number' ? arg : arg.count;\n const subResult = getEnumeration(result, quantity);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * PLURAL PLUGIN\n * --------------------------------------------- */\n\nexport type PluralCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.PLURAL]: object;\n}\n ? (\n arg: number | { count: number; [key: string]: unknown }\n ) => DeepTransformContent<\n T[typeof NodeTypes.PLURAL][keyof T[typeof NodeTypes.PLURAL]],\n S\n >\n : never;\n\ntype SubResultFunction = (values: Record<string, string | number>) => string;\n\n/**\n * Plural plugin. Replaces node with a function that takes a count (or\n * `{ count, ...values }`) => string, picking the matching CLDR plural form\n * for the active locale and interpolating `{{count}}` (and other values).\n */\nexport const pluralPlugin = (locale?: LocalesValues): Plugins =>\n process.env.INTLAYER_NODE_TYPE_PLURAL === 'false'\n ? fallbackPlugin\n : {\n id: 'plural-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.PLURAL,\n transform: (node: PluralContent, props, deepTransformNode) => {\n const original = node[NodeTypes.PLURAL];\n const result: Record<string, any> = {};\n\n /** String plugin for plural. Replaces string node with a component that renders the insertion. */\n const pluralStringPlugin: Plugins = {\n id: 'plural-string-plugin',\n canHandle: (node) =>\n typeof node === 'string' || isInterpolableWrapperNode(node),\n transform: (node, subProps, deepTransformNode) => {\n // `html()`/`markdown()` nodes carry their `{{count}}` placeholders\n // inside a raw string. Interpolate into that string, then re-run\n // the transform so the html/markdown renderer applies afterwards.\n if (isInterpolableWrapperNode(node)) {\n return (values: { [k: string]: string | number }) =>\n transformInterpolableNode(\n node,\n values,\n subProps,\n props.plugins,\n deepTransformNode\n );\n }\n\n const transformedResult = deepTransformNode(node, {\n ...subProps,\n children: node,\n plugins: [\n ...(props.plugins ?? ([] as Plugins[])).filter(\n (plugin) => plugin.id !== 'intlayer-node-plugin'\n ),\n ],\n });\n\n return (values: { [k: string]: string | number }) => {\n const children = getInsertion(transformedResult, values);\n\n return deepTransformNode(children, {\n ...subProps,\n plugins: props.plugins,\n children,\n });\n };\n },\n };\n\n for (const key in original) {\n const child = original[key as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.PLURAL, key } as KeyPath,\n ],\n plugins: [pluralStringPlugin, ...(props.plugins ?? [])],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n const effectiveLocale = String(locale ?? props.locale ?? 'en');\n\n return (arg: number | { count: number; [key: string]: unknown }) => {\n const count = typeof arg === 'number' ? arg : arg.count;\n const values =\n typeof arg === 'number'\n ? { count: arg }\n : (arg as { count: number; [key: string]: unknown });\n\n const subResult: string | SubResultFunction = getPlural(\n result as PluralContent['plural'] as PluralContentState<string>,\n count,\n effectiveLocale\n );\n\n if (typeof subResult === 'function') {\n return (subResult as SubResultFunction)(values);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * CONDITION PLUGIN\n * --------------------------------------------- */\n\nexport type ConditionCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.CONDITION]: object;\n}\n ? (\n value: boolean | { value: boolean }\n ) => DeepTransformContent<\n T[typeof NodeTypes.CONDITION][keyof T[typeof NodeTypes.CONDITION]],\n S\n >\n : never;\n\n/** Condition plugin. Replaces node with a function that takes boolean => string. */\nexport const conditionPlugin: Plugins =\n process.env.INTLAYER_NODE_TYPE_CONDITION === 'false'\n ? fallbackPlugin\n : {\n id: 'condition-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.CONDITION,\n transform: (node: ConditionContent, props, deepTransformNode) => {\n const original = node[NodeTypes.CONDITION];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.CONDITION, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (arg: boolean | { value: boolean }) => {\n const value = typeof arg === 'boolean' ? arg : arg.value;\n const subResult = getCondition(result as any, value);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * INSERTION PLUGIN\n * --------------------------------------------- */\n\nexport type InsertionCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.INSERTION]: infer I;\n fields: readonly string[];\n}\n ? (\n values: {\n [K in T['fields'][number]]: string | number;\n }\n ) => I extends string\n ? DeepTransformContent<string, S>\n : DeepTransformContent<I, S>\n : never;\n\n/** Insertion plugin. Replaces node with a function that takes quantity => string. */\nexport const insertionPlugin: Plugins =\n process.env.INTLAYER_NODE_TYPE_INSERTION === 'false'\n ? fallbackPlugin\n : {\n id: 'insertion-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.INSERTION,\n transform: (node: InsertionContent, props, deepTransformNode) => {\n const newKeyPath: KeyPath[] = [\n ...props.keyPath,\n {\n type: NodeTypes.INSERTION,\n },\n ];\n\n const children = node[NodeTypes.INSERTION];\n\n /** Insertion string plugin. Replaces string node with a component that render the insertion. */\n const insertionStringPlugin: Plugins = {\n id: 'insertion-string-plugin',\n canHandle: (node) =>\n typeof node === 'string' || isInterpolableWrapperNode(node),\n transform: (node, subProps, deepTransformNode) => {\n // `html()`/`markdown()` nodes carry their `{{ … }}` placeholders\n // inside a raw string. Interpolate into that string, then re-run\n // the transform so the html/markdown renderer applies afterwards.\n if (isInterpolableWrapperNode(node)) {\n return (\n values: {\n [K in InsertionContent['fields'][number]]: string | number;\n }\n ) =>\n transformInterpolableNode(\n node,\n values,\n subProps,\n props.plugins,\n deepTransformNode\n );\n }\n\n const transformedResult = deepTransformNode(node, {\n ...subProps,\n children: node,\n plugins: [\n ...(props.plugins ?? ([] as Plugins[])).filter(\n (plugin) => plugin.id !== 'intlayer-node-plugin'\n ),\n ],\n });\n\n return (\n values: {\n [K in InsertionContent['fields'][number]]: string | number;\n }\n ) => {\n const children = getInsertion(transformedResult, values);\n\n return deepTransformNode(children, {\n ...subProps,\n plugins: props.plugins,\n children,\n });\n };\n },\n };\n\n return deepTransformNode(children, {\n ...props,\n children,\n keyPath: newKeyPath,\n plugins: [insertionStringPlugin, ...(props.plugins ?? [])],\n });\n },\n };\n\n/** ---------------------------------------------\n * GENDER PLUGIN\n * --------------------------------------------- */\n\nexport type GenderCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.GENDER]: object;\n}\n ? (\n value: Gender\n ) => DeepTransformContent<\n T[typeof NodeTypes.GENDER][keyof T[typeof NodeTypes.GENDER]],\n S\n >\n : never;\n\n/** Gender plugin. Replaces node with a function that takes gender => string. */\nexport const genderPlugin: Plugins =\n process.env.INTLAYER_NODE_TYPE_GENDER === 'false'\n ? fallbackPlugin\n : {\n id: 'gender-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.GENDER,\n transform: (node: GenderContent, props, deepTransformNode) => {\n const original = node[NodeTypes.GENDER];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.GENDER, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (value: Gender) => getGender(result as any, value);\n },\n };\n\n/** ---------------------------------------------\n * SELECT PLUGIN\n * --------------------------------------------- */\n\n/**\n * Accepted selector for a select node.\n *\n * When the node declares a `fallback` case, any string is accepted (the\n * fallback covers the unmatched values) while the declared cases still\n * autocomplete. Without a `fallback`, only the declared cases are accepted.\n */\nexport type SelectSelector<States> = 'fallback' extends keyof States\n ? Exclude<keyof States & string, 'fallback'> | (string & {})\n : keyof States & string;\n\nexport type SelectCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.SELECT]: object;\n}\n ? (\n value:\n | SelectSelector<T[typeof NodeTypes.SELECT]>\n | { value: SelectSelector<T[typeof NodeTypes.SELECT]> }\n ) => DeepTransformContent<\n T[typeof NodeTypes.SELECT][keyof T[typeof NodeTypes.SELECT]],\n S\n >\n : never;\n\n/** Select plugin. Replaces node with a function that takes a string => content. */\nexport const selectPlugin: Plugins =\n process.env.INTLAYER_NODE_TYPE_SELECT === 'false'\n ? fallbackPlugin\n : {\n id: 'select-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.SELECT,\n transform: (node: SelectContent, props, deepTransformNode) => {\n const original = node[NodeTypes.SELECT];\n const result: Record<string, any> = {};\n\n for (const key in original) {\n const child = original[key as keyof typeof original];\n const childProps = {\n ...props,\n children: child,\n keyPath: [\n ...props.keyPath,\n { type: NodeTypes.SELECT, key } as KeyPath,\n ],\n };\n result[key] = deepTransformNode(child, childProps);\n }\n\n return (arg: string | { value: string }) => {\n const value = typeof arg === 'string' ? arg : arg?.value;\n const subResult = getSelect(result, value);\n\n if (typeof subResult === 'function' && typeof arg === 'object') {\n return subResult(arg);\n }\n\n return subResult;\n };\n },\n };\n\n/** ---------------------------------------------\n * NESTED PLUGIN\n * --------------------------------------------- */\n\nexport type NestedCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.NESTED]: infer U;\n}\n ? U extends {\n dictionaryKey: infer K extends DictionaryKeys;\n path?: infer P;\n }\n ? GetNestingResult<K, P, S>\n : never\n : never;\n\n/** Nested plugin. Replaces node with the result of `getNesting`. */\nexport const nestedPlugin = (locale?: LocalesValues): Plugins =>\n process.env.INTLAYER_NODE_TYPE_NESTED === 'false'\n ? fallbackPlugin\n : {\n id: 'nested-plugin',\n canHandle: (node) =>\n typeof node === 'object' &&\n (node?.nodeType === NodeTypes.NESTED || node?.nodeType === 'n'),\n transform: (node: NestedContent, props) =>\n getNesting(\n node[NodeTypes.NESTED].dictionaryKey,\n node[NodeTypes.NESTED].path,\n {\n ...props,\n locale: (locale ?? props.locale) as Locale,\n }\n ),\n };\n\n/** ---------------------------------------------\n * FILE PLUGIN\n * --------------------------------------------- */\n\nexport type FileCond<T, S, _L> = T extends {\n nodeType: NodeType | string;\n [NodeTypes.FILE]: string;\n content?: string;\n}\n ? DeepTransformContent<string, S>\n : never;\n\n/** File plugin. Replaces node with the result of `getNesting`. */\nexport const filePlugin: Plugins =\n process.env.INTLAYER_NODE_TYPE_FILE === 'false'\n ? fallbackPlugin\n : {\n id: 'file-plugin',\n canHandle: (node) =>\n typeof node === 'object' && node?.nodeType === NodeTypes.FILE,\n transform: (node: FileContent, props, deepTransform) =>\n deepTransform(node.content, {\n ...props,\n children: node.content,\n }),\n };\n\n/**\n * PLUGIN RESULT\n */\n\n/**\n * Interface that defines the properties of a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface NodeProps {\n dictionaryKey: string;\n keyPath: KeyPath[];\n plugins?: Plugins[];\n locale?: Locale;\n dictionaryPath?: string;\n children?: any;\n /**\n * Forces eager traversal of plain objects in `deepTransformNode`. By default\n * traversal is lazy (property getters), so callers that discard the returned\n * value never trigger plugins on nested nodes. Set this when running plugins\n * for their side effects only (e.g. missing-locale detection).\n */\n eager?: boolean;\n}\n\n/**\n * Interface that defines the plugins that can be used to transform a node.\n * This interface can be augmented in other packages, such as `react-intlayer`.\n */\nexport interface IInterpreterPlugin<T, S, L extends LocalesValues> {\n translation: TranslationCond<T, S, L>;\n enumeration: EnumerationCond<T, S, L>;\n plural: PluralCond<T, S, L>;\n condition: ConditionCond<T, S, L>;\n insertion: InsertionCond<T, S, L>;\n gender: GenderCond<T, S, L>;\n select: SelectCond<T, S, L>;\n nested: NestedCond<T, S, L>;\n file: FileCond<T, S, L>;\n}\n\n/**\n * Allow to avoid overwriting import from `intlayer` package when `IInterpreterPlugin<T>` interface is augmented in another package, such as `react-intlayer`.\n */\nexport type IInterpreterPluginState = {\n translation: true;\n enumeration: true;\n plural: true;\n condition: true;\n insertion: true;\n gender: true;\n select: true;\n nested: true;\n file: true;\n};\n\n/**\n * Utility type to check if a plugin can be applied to a node.\n */\ntype CheckApplyPlugin<\n T,\n K extends keyof IInterpreterPlugin<T, S, L>,\n S,\n L extends LocalesValues = DeclaredLocales,\n> = K extends keyof S // Test if the key is a key of S.\n ? // Test if the key of S is true. Then the plugin can be applied.\n S[K] extends true\n ? // Test if the key of S exist\n IInterpreterPlugin<T, S, L>[K] extends never\n ? never\n : // Test if the plugin condition is true (if it's not, the plugin is skipped for this node)\n IInterpreterPlugin<T, S, L>[K]\n : never\n : never;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\ntype Traverse<T, S, L extends LocalesValues = DeclaredLocales> =\n T extends ReadonlyArray<infer U> // Turn any read-only array into a plain mutable array\n ? Array<DeepTransformContent<U, S, L>>\n : T extends object\n ? { [K in keyof T]: DeepTransformContent<T[K], S, L> }\n : T;\n\nexport type IsAny<T> = 0 extends 1 & T ? true : false;\n\n/**\n * Traverse recursively through an object or array, applying each plugin as needed.\n */\nexport type DeepTransformContent<\n T,\n S = IInterpreterPluginState,\n L extends LocalesValues = DeclaredLocales,\n> =\n IsAny<T> extends true\n ? T\n : CheckApplyPlugin<T, keyof IInterpreterPlugin<T, S, L>, S, L> extends never // Check if there is a plugin for T:\n ? // No plugin was found, so try to transform T recursively:\n Traverse<T, S, L>\n : // A plugin was found – use the plugin's transformation.\n CheckApplyPlugin<T, keyof IInterpreterPlugin<T, S, L>, S, L>;\n"],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ //#region src/interpreter/getSelect.ts
4
+ /**
5
+ * Picks content from a select map based on an arbitrary string value.
6
+ *
7
+ * Resolution order:
8
+ * 1. Exact match on the provided value.
9
+ * 2. The `fallback` key.
10
+ * 3. The `other` key — kept for content imported from an ICU `select` message,
11
+ * where the catch-all case is named `other`.
12
+ * 4. The last declared key, so a select node never resolves to `undefined`.
13
+ *
14
+ * @param selectContent - A map of string cases to content.
15
+ * @param value - The value to match against the declared cases.
16
+ * @returns The matching content.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const content = getSelect({
21
+ * draft: 'This post is a draft',
22
+ * published: 'This post is live',
23
+ * fallback: 'Unknown status',
24
+ * }, 'published');
25
+ * // 'This post is live'
26
+ * ```
27
+ */
28
+ const getSelect = (selectContent, value) => {
29
+ const caseList = Object.keys(selectContent);
30
+ const lastCase = caseList[caseList.length - 1];
31
+ return selectContent[value] ?? selectContent.fallback ?? selectContent.other ?? selectContent[lastCase];
32
+ };
33
+
34
+ //#endregion
35
+ exports.getSelect = getSelect;
36
+ //# sourceMappingURL=getSelect.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getSelect.cjs","names":[],"sources":["../../../src/interpreter/getSelect.ts"],"sourcesContent":["import type { SelectContentStates } from '../transpiler';\n\n/**\n * Picks content from a select map based on an arbitrary string value.\n *\n * Resolution order:\n * 1. Exact match on the provided value.\n * 2. The `fallback` key.\n * 3. The `other` key — kept for content imported from an ICU `select` message,\n * where the catch-all case is named `other`.\n * 4. The last declared key, so a select node never resolves to `undefined`.\n *\n * @param selectContent - A map of string cases to content.\n * @param value - The value to match against the declared cases.\n * @returns The matching content.\n *\n * @example\n * ```ts\n * const content = getSelect({\n * draft: 'This post is a draft',\n * published: 'This post is live',\n * fallback: 'Unknown status',\n * }, 'published');\n * // 'This post is live'\n * ```\n */\nexport const getSelect = <const Content>(\n selectContent: SelectContentStates<Content>,\n value?: string\n): Content => {\n const caseList = Object.keys(selectContent);\n const lastCase = caseList[caseList.length - 1] as keyof typeof selectContent;\n\n return (selectContent[value as keyof typeof selectContent] ??\n selectContent.fallback ??\n selectContent.other ??\n selectContent[lastCase]) as Content;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAa,aACX,eACA,UACY;CACZ,MAAM,WAAW,OAAO,KAAK,aAAa;CAC1C,MAAM,WAAW,SAAS,SAAS,SAAS;CAE5C,OAAQ,cAAc,UACpB,cAAc,YACd,cAAc,SACd,cAAc;AAClB"}
@@ -2,11 +2,13 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_interpreter_getCondition = require('./getCondition.cjs');
3
3
  const require_interpreter_getContent_deepTransform = require('./getContent/deepTransform.cjs');
4
4
  const require_interpreter_getEnumeration = require('./getEnumeration.cjs');
5
+ const require_interpreter_getGender = require('./getGender.cjs');
5
6
  const require_interpreter_getInsertion = require('./getInsertion.cjs');
6
7
  const require_interpreter_getDictionary = require('./getDictionary.cjs');
7
8
  const require_interpreter_getIntlayer = require('./getIntlayer.cjs');
8
9
  const require_interpreter_getNesting = require('./getNesting.cjs');
9
10
  const require_interpreter_getPlural = require('./getPlural.cjs');
11
+ const require_interpreter_getSelect = require('./getSelect.cjs');
10
12
  const require_interpreter_getTranslation = require('./getTranslation.cjs');
11
13
  const require_interpreter_interpolableNode = require('./interpolableNode.cjs');
12
14
  const require_interpreter_getContent_plugins = require('./getContent/plugins.cjs');
@@ -26,18 +28,21 @@ exports.getCondition = require_interpreter_getCondition.getCondition;
26
28
  exports.getContent = require_interpreter_getContent_getContent.getContent;
27
29
  exports.getDictionary = require_interpreter_getDictionary.getDictionary;
28
30
  exports.getEnumeration = require_interpreter_getEnumeration.getEnumeration;
31
+ exports.getGender = require_interpreter_getGender.getGender;
29
32
  exports.getHTML = require_interpreter_getHTML.getHTML;
30
33
  exports.getInsertion = require_interpreter_getInsertion.getInsertion;
31
34
  exports.getInterpolableContent = require_interpreter_interpolableNode.getInterpolableContent;
32
35
  exports.getIntlayer = require_interpreter_getIntlayer.getIntlayer;
33
36
  exports.getNesting = require_interpreter_getNesting.getNesting;
34
37
  exports.getPlural = require_interpreter_getPlural.getPlural;
38
+ exports.getSelect = require_interpreter_getSelect.getSelect;
35
39
  exports.getTranslation = require_interpreter_getTranslation.getTranslation;
36
40
  exports.insertionPlugin = require_interpreter_getContent_plugins.insertionPlugin;
37
41
  exports.isInterpolableWrapperNode = require_interpreter_interpolableNode.isInterpolableWrapperNode;
38
42
  exports.nestedPlugin = require_interpreter_getContent_plugins.nestedPlugin;
39
43
  exports.pluralPlugin = require_interpreter_getContent_plugins.pluralPlugin;
40
44
  exports.rebuildInterpolableContent = require_interpreter_interpolableNode.rebuildInterpolableContent;
45
+ exports.selectPlugin = require_interpreter_getContent_plugins.selectPlugin;
41
46
  exports.splitInsertionTemplate = require_interpreter_splitAndJoinInsertion.splitInsertionTemplate;
42
47
  exports.transformInterpolableNode = require_interpreter_interpolableNode.transformInterpolableNode;
43
48
  exports.translationPlugin = require_interpreter_getContent_plugins.translationPlugin;
@@ -6,6 +6,7 @@ const require_transpiler_gender_gender = require('../transpiler/gender/gender.cj
6
6
  const require_transpiler_html_html = require('../transpiler/html/html.cjs');
7
7
  const require_transpiler_insertion_insertion = require('../transpiler/insertion/insertion.cjs');
8
8
  const require_transpiler_plural_plural = require('../transpiler/plural/plural.cjs');
9
+ const require_transpiler_select_select = require('../transpiler/select/select.cjs');
9
10
  let _intlayer_types_nodeType = require("@intlayer/types/nodeType");
10
11
  _intlayer_types_nodeType = require_runtime.__toESM(_intlayer_types_nodeType);
11
12
 
@@ -200,7 +201,7 @@ const icuNodesToIntlayer = (nodes) => {
200
201
  }
201
202
  if (node.type === "select") {
202
203
  const options = {};
203
- for (const [key, val] of Object.entries(node.options)) options[key] = icuNodesToIntlayer(val);
204
+ for (const [key, val] of Object.entries(node.options)) options[key === "other" ? "fallback" : key] = icuNodesToIntlayer(val);
204
205
  const optionKeys = Object.keys(options);
205
206
  if ((options.male || options.female) && optionKeys.every((k) => [
206
207
  "male",
@@ -208,12 +209,11 @@ const icuNodesToIntlayer = (nodes) => {
208
209
  "other",
209
210
  "fallback"
210
211
  ].includes(k))) return require_transpiler_gender_gender.gender({
211
- fallback: options.other,
212
+ fallback: options.fallback,
212
213
  male: options.male,
213
214
  female: options.female
214
215
  });
215
- options.__intlayer_icu_var = node.name;
216
- return require_transpiler_enumeration_enumeration.enu(options);
216
+ return require_transpiler_select_select.select(options, node.name);
217
217
  }
218
218
  if (node.type === "selectordinal") {
219
219
  const options = {};
@@ -246,12 +246,12 @@ const icuToIntlayerPlugin = {
246
246
  const intlayerToIcuPlugin = {
247
247
  canHandle: (node) => {
248
248
  if (typeof node === "string" && (node.includes("{") || node.includes("}"))) return true;
249
- if (node && typeof node === "object" && (node.nodeType === _intlayer_types_nodeType.INSERTION || node.nodeType === _intlayer_types_nodeType.HTML || node.nodeType === _intlayer_types_nodeType.ENUMERATION || node.nodeType === _intlayer_types_nodeType.PLURAL || node.nodeType === _intlayer_types_nodeType.GENDER || node.nodeType === "composite")) return true;
249
+ if (node && typeof node === "object" && (node.nodeType === _intlayer_types_nodeType.INSERTION || node.nodeType === _intlayer_types_nodeType.HTML || node.nodeType === _intlayer_types_nodeType.ENUMERATION || node.nodeType === _intlayer_types_nodeType.PLURAL || node.nodeType === _intlayer_types_nodeType.GENDER || node.nodeType === _intlayer_types_nodeType.SELECT || node.nodeType === "composite")) return true;
250
250
  if (Array.isArray(node)) {
251
251
  if (node.length === 0) return false;
252
252
  let hasNode = false;
253
253
  let hasPlainObjectOrArray = false;
254
- for (const item of node) if (typeof item === "string") {} else if (item && typeof item === "object" && (item.nodeType === _intlayer_types_nodeType.INSERTION || item.nodeType === _intlayer_types_nodeType.HTML || item.nodeType === _intlayer_types_nodeType.ENUMERATION || item.nodeType === _intlayer_types_nodeType.GENDER || item.nodeType === "composite")) hasNode = true;
254
+ for (const item of node) if (typeof item === "string") {} else if (item && typeof item === "object" && (item.nodeType === _intlayer_types_nodeType.INSERTION || item.nodeType === _intlayer_types_nodeType.HTML || item.nodeType === _intlayer_types_nodeType.ENUMERATION || item.nodeType === _intlayer_types_nodeType.GENDER || item.nodeType === _intlayer_types_nodeType.SELECT || item.nodeType === "composite")) hasNode = true;
255
255
  else hasPlainObjectOrArray = true;
256
256
  if (hasPlainObjectOrArray) return false;
257
257
  if (!hasNode) return false;
@@ -375,6 +375,23 @@ const intlayerToIcuPlugin = {
375
375
  }
376
376
  return `{${varName}, select, ${parts.join(" ")}}`;
377
377
  }
378
+ if (node.nodeType === _intlayer_types_nodeType.SELECT) {
379
+ const options = node[_intlayer_types_nodeType.SELECT];
380
+ const varName = node.variable || "value";
381
+ const parts = [];
382
+ const entries = Object.entries(options).sort(([keyA], [keyB]) => {
383
+ if (keyA === "fallback") return 1;
384
+ if (keyB === "fallback") return -1;
385
+ return 0;
386
+ });
387
+ for (const [key, val] of entries) {
388
+ const icuKey = key === "fallback" ? "other" : key;
389
+ const childVal = next(val, props);
390
+ const strVal = typeof childVal === "string" ? childVal : JSON.stringify(childVal);
391
+ parts.push(`${icuKey} {${strVal}}`);
392
+ }
393
+ return `{${varName}, select, ${parts.join(" ")}}`;
394
+ }
378
395
  if (Array.isArray(node) || node.nodeType === "composite" && Array.isArray(node.composite)) return (Array.isArray(node) ? node : node.composite).map((item) => next(item, props)).join("");
379
396
  return next(node, props);
380
397
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ICU.cjs","names":["html","insert","enu","plural","gender","NodeTypes","deepTransformNode"],"sources":["../../../src/messageFormat/ICU.ts"],"sourcesContent":["import type { Dictionary } from '@intlayer/types/dictionary';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport { deepTransformNode } from '../interpreter';\nimport { enu, gender, html, insert, plural } from '../transpiler';\n\n/**\n * ICU MessageFormat Converter\n *\n * This module converts between ICU MessageFormat and Intlayer's internal format.\n *\n * IMPORTANT: Two different formats are used:\n *\n * 1. ICU MessageFormat (external format):\n * - Simple variables: {name}\n * - Formatted variables: {amount, number, currency}\n * - Plural: {count, plural, =0 {none} other {# items}}\n * - Select: {gender, select, male {He} female {She} other {They}}\n *\n * 2. Intlayer Internal Format:\n * - Simple variables: {{name}} (double braces for clarity and to distinguish from literal text)\n * - Formatted variables: {amount, number, currency} (keeps ICU format)\n * - Plural: enu({ 0: 'none', fallback: '{{count}} items' })\n * - Select/Gender: gender({ male: 'He', female: 'She', fallback: 'They' })\n *\n * Conversion flow:\n * - ICU → Intlayer: {name} → {{name}}\n * - Intlayer → ICU: {{name}} → {name}\n *\n * The double braces in Intlayer format serve to:\n * - Distinguish variables from literal text containing braces\n * - Work with getInsertion() runtime function which expects {{var}} patterns\n * - Provide clear visual distinction in content dictionaries\n */\n\n// Types for our AST\ntype ICUNode =\n | string\n | {\n type: 'argument';\n name: string;\n format?: { type: string; style?: string };\n }\n | { type: 'plural'; name: string; options: Record<string, ICUNode[]> }\n | { type: 'select'; name: string; options: Record<string, ICUNode[]> }\n | {\n type: 'selectordinal';\n name: string;\n options: Record<string, ICUNode[]>;\n };\n\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue };\n\nconst parseICU = (text: string): ICUNode[] => {\n let index = 0;\n\n const parseNodes = (): ICUNode[] => {\n const nodes: ICUNode[] = [];\n let currentText = '';\n\n while (index < text.length) {\n const char = text[index];\n\n if (char === '{') {\n if (currentText) {\n nodes.push(currentText);\n currentText = '';\n }\n index++; // skip {\n nodes.push(parseArgument());\n } else if (char === '}') {\n // End of current block\n break;\n } else if (char === \"'\") {\n // Escaping\n if (index + 1 < text.length && text[index + 1] === \"'\") {\n currentText += \"'\";\n index += 2;\n } else {\n // Find next quote\n const nextQuote = text.indexOf(\"'\", index + 1);\n if (nextQuote !== -1) {\n // Determine if this is escaping syntax characters\n // For simplicity, we'll treat content between single quotes as literal\n // provided it contains syntax chars.\n // Standard ICU: ' quoted string '\n // If it is just an apostrophe, it should be doubled.\n // But simplified: take content between quotes literally.\n currentText += text.substring(index + 1, nextQuote);\n index = nextQuote + 1;\n } else {\n currentText += \"'\";\n index++;\n }\n }\n } else {\n currentText += char;\n index++;\n }\n }\n\n if (currentText) {\n nodes.push(currentText);\n }\n return nodes;\n };\n\n const parseArgument = (): ICUNode => {\n // We are past '{'\n // Parse name\n let name = '';\n while (index < text.length && /[^,}]/.test(text[index])) {\n name += text[index];\n index++;\n }\n name = name.trim();\n\n if (index >= text.length) throw new Error('Unclosed argument');\n\n if (text[index] === '}') {\n index++;\n return { type: 'argument', name };\n }\n\n // Must be comma\n if (text[index] === ',') {\n index++;\n // Parse type\n let type = '';\n while (index < text.length && /[^,}]/.test(text[index])) {\n type += text[index];\n index++;\n }\n type = type.trim();\n\n if (index >= text.length) throw new Error('Unclosed argument');\n\n if (text[index] === '}') {\n index++;\n return { type: 'argument', name, format: { type } };\n }\n\n if (text[index] === ',') {\n index++;\n\n // If plural, select or selectordinal, parse options\n if (\n type === 'plural' ||\n type === 'select' ||\n type === 'selectordinal'\n ) {\n // Parse options\n const options: Record<string, ICUNode[]> = {};\n\n while (index < text.length && text[index] !== '}') {\n // skip whitespace\n while (index < text.length && /\\s/.test(text[index])) index++;\n\n // parse key\n let key = '';\n while (index < text.length && /[^{\\s]/.test(text[index])) {\n key += text[index];\n index++;\n }\n\n while (index < text.length && /\\s/.test(text[index])) index++;\n\n if (text[index] !== '{')\n throw new Error('Expected { after option key');\n index++; // skip {\n\n const value = parseNodes();\n\n if (text[index] !== '}')\n throw new Error('Expected } after option value');\n index++; // skip }\n\n options[key] = value;\n\n while (index < text.length && /\\s/.test(text[index])) index++;\n }\n\n index++; // skip closing argument }\n\n if (type === 'plural') {\n return { type: 'plural', name, options };\n } else if (type === 'select') {\n return { type: 'select', name, options };\n } else if (type === 'selectordinal') {\n return { type: 'selectordinal', name, options };\n }\n } else {\n // Parse style for number/date/time\n let style = '';\n while (index < text.length && text[index] !== '}') {\n style += text[index];\n index++;\n }\n if (index >= text.length) throw new Error('Unclosed argument');\n\n style = style.trim();\n index++; // skip }\n\n return { type: 'argument', name, format: { type, style } };\n }\n }\n }\n\n throw new Error('Malformed argument');\n };\n\n return parseNodes();\n};\n\nconst icuNodesToIntlayer = (nodes: ICUNode[]): any => {\n if (nodes.length === 0) return '';\n if (nodes.length === 1 && typeof nodes[0] === 'string') {\n const node = nodes[0];\n if (/<[a-zA-Z0-9-]+[^>]*>/.test(node)) {\n return html(node);\n }\n return node;\n }\n\n // Check if we can flatten to a single string (insert)\n const canFlatten = nodes.every(\n (node) => typeof node === 'string' || node.type === 'argument'\n );\n if (canFlatten) {\n let str = '';\n for (const node of nodes) {\n if (typeof node === 'string') {\n str += node;\n } else if (typeof node !== 'string' && node.type === 'argument') {\n if (node.format) {\n // Formatted variables keep ICU format: {var, type, style}\n str += `{${node.name}, ${node.format.type}${\n node.format.style ? `, ${node.format.style}` : ''\n }}`;\n } else {\n // Simple variables use Intlayer format: {{var}}\n str += `{{${node.name}}}`;\n }\n }\n }\n if (/<[a-zA-Z0-9-]+[^>]*>/.test(str)) {\n return html(str);\n }\n return insert(str);\n }\n\n // Mix of string and complex types.\n // If we have just one complex type and it covers everything?\n if (nodes.length === 1) {\n const node = nodes[0];\n\n if (typeof node === 'string') {\n if (/<[a-zA-Z0-9-]+[^>]*>/.test(node)) {\n return html(node);\n }\n return node;\n }\n if (node.type === 'argument') {\n if (node.format) {\n return insert(\n `{${node.name}, ${node.format.type}${\n node.format.style ? `, ${node.format.style}` : ''\n }}`\n );\n }\n return insert(`{{${node.name}}}`);\n }\n if (node.type === 'plural') {\n const options: Record<string, any> = {};\n let hasExactMatch = false;\n\n for (const key of Object.keys(node.options)) {\n if (key.startsWith('=')) {\n hasExactMatch = true;\n break;\n }\n }\n\n if (hasExactMatch) {\n for (const [key, val] of Object.entries(node.options)) {\n // Map ICU keys to Intlayer keys\n let newKey = key;\n if (key.startsWith('=')) {\n newKey = key.substring(1); // =0 -> 0\n } else if (key === 'one') {\n newKey = '1';\n } else if (key === 'two') {\n newKey = '2';\n } else if (key === 'few') {\n newKey = '<=3';\n } else if (key === 'many') {\n newKey = '>=4';\n } else if (key === 'other') {\n newKey = 'fallback';\n }\n // Handle # in plural value\n // For plural, we need to pass the variable name down or replace #\n // Intlayer uses {{n}} (or whatever var name) for simple variables\n // We should replace # with {{n}} in the string parts of val\n const replacedVal = val.map((v) => {\n if (typeof v === 'string') {\n return v.replace(/#/g, `{{${node.name}}}`);\n }\n return v;\n });\n\n options[newKey] = icuNodesToIntlayer(replacedVal);\n }\n\n // Preserve variable name\n options.__intlayer_icu_var = node.name;\n\n return enu(options);\n } else {\n for (const [key, val] of Object.entries(node.options)) {\n // Handle # in plural value\n const replacedVal = val.map((v) => {\n if (typeof v === 'string') {\n return v.replace(/#/g, `{{${node.name}}}`);\n }\n return v;\n });\n\n options[key] = icuNodesToIntlayer(replacedVal);\n }\n\n return plural(options as any);\n }\n }\n if (node.type === 'select') {\n const options: Record<string, any> = {};\n\n for (const [key, val] of Object.entries(node.options)) {\n options[key] = icuNodesToIntlayer(val);\n }\n\n // Check if it looks like gender\n const optionKeys = Object.keys(options);\n // It is gender if it has 'male' OR 'female' AND only contains gender keys (male, female, other)\n const isGender =\n (options.male || options.female) &&\n optionKeys.every((k) =>\n ['male', 'female', 'other', 'fallback'].includes(k)\n );\n\n if (isGender) {\n return gender({\n fallback: options.other,\n male: options.male,\n female: options.female,\n });\n }\n\n // Preserve variable name\n options.__intlayer_icu_var = node.name;\n\n return enu(options);\n }\n\n if (node.type === 'selectordinal') {\n // Ordinal plural ({n, selectordinal, one {#st} two {#nd} other {#th}}).\n // Stored as an enumeration with the ordinal marker: exact matches keep\n // numeric keys, CLDR ordinal categories keep their names, and the\n // runtime selects via `Intl.PluralRules(locale, { type: 'ordinal' })`.\n const options: Record<string, any> = {};\n\n for (const [key, val] of Object.entries(node.options)) {\n const newKey = key.startsWith('=')\n ? key.substring(1)\n : key === 'other'\n ? 'fallback'\n : key;\n\n const replacedVal = val.map((value) => {\n if (typeof value === 'string') {\n return value.replace(/#/g, `{{${node.name}}}`);\n }\n return value;\n });\n\n options[newKey] = icuNodesToIntlayer(replacedVal);\n }\n\n options.__intlayer_icu_var = node.name;\n options.__intlayer_icu_ordinal = true;\n\n return enu(options);\n }\n }\n\n // If multiple nodes, return array\n return nodes.map((node) => icuNodesToIntlayer([node]));\n};\n\nconst icuToIntlayerPlugin = {\n canHandle: (node: any) =>\n typeof node === 'string' &&\n (node.includes('{') ||\n node.includes('}') ||\n /<[a-zA-Z0-9-]+[^>]*>/.test(node)),\n transform: (node: any) => {\n try {\n const ast = parseICU(node);\n return icuNodesToIntlayer(ast);\n } catch {\n // If parsing fails, return original string\n return node;\n }\n },\n};\n\nconst intlayerToIcuPlugin = {\n canHandle: (node: any) => {\n if (\n typeof node === 'string' &&\n (node.includes('{') || node.includes('}'))\n ) {\n return true;\n }\n\n if (\n node &&\n typeof node === 'object' &&\n (node.nodeType === NodeTypes.INSERTION ||\n node.nodeType === NodeTypes.HTML ||\n node.nodeType === NodeTypes.ENUMERATION ||\n node.nodeType === NodeTypes.PLURAL ||\n node.nodeType === NodeTypes.GENDER ||\n node.nodeType === 'composite')\n ) {\n return true;\n }\n\n if (Array.isArray(node)) {\n if (node.length === 0) return false;\n\n let hasNode = false;\n let hasPlainObjectOrArray = false;\n\n for (const item of node) {\n if (typeof item === 'string') {\n } else if (\n item &&\n typeof item === 'object' &&\n (item.nodeType === NodeTypes.INSERTION ||\n item.nodeType === NodeTypes.HTML ||\n item.nodeType === NodeTypes.ENUMERATION ||\n item.nodeType === NodeTypes.GENDER ||\n item.nodeType === 'composite')\n ) {\n hasNode = true;\n } else {\n hasPlainObjectOrArray = true;\n }\n }\n\n // If it contains plain objects or nested arrays, it's a structural array\n if (hasPlainObjectOrArray) return false;\n // If it contains ONLY strings, it's a structural array, not a composite string\n if (!hasNode) return false;\n\n return true;\n }\n\n return false;\n },\n transform: (node: any, props: any, next: any) => {\n // Convert Intlayer's double-brace format {{var}} to ICU's single-brace format {var}\n if (typeof node === 'string') {\n return node.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n }\n\n if (node.nodeType === NodeTypes.INSERTION) {\n return node[NodeTypes.INSERTION].replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n }\n\n if (node.nodeType === NodeTypes.HTML) {\n return node[NodeTypes.HTML];\n }\n\n if (node.nodeType === NodeTypes.PLURAL) {\n const options = node[NodeTypes.PLURAL];\n\n const transformedOptions: Record<string, string> = {};\n for (const [key, val] of Object.entries(options)) {\n const childVal = next(val, props);\n transformedOptions[key] =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n }\n\n let varName = 'count';\n\n const fallbackVal =\n transformedOptions.other || Object.values(transformedOptions)[0];\n\n if (fallbackVal) {\n const match = fallbackVal.match(/\\{([a-zA-Z0-9_]+)\\}(?!,)/);\n if (match) {\n varName = match[1];\n }\n }\n\n const parts = [];\n\n for (const [key, val] of Object.entries(transformedOptions)) {\n let strVal = val;\n strVal = strVal.replace(new RegExp(`\\\\{${varName}\\\\}`, 'g'), '#');\n parts.push(`${key} {${strVal}}`);\n }\n return `{${varName}, plural, ${parts.join(' ')}}`;\n }\n\n if (node.nodeType === NodeTypes.ENUMERATION) {\n const options = node[NodeTypes.ENUMERATION];\n\n const transformedOptions: Record<string, string> = {};\n for (const [key, val] of Object.entries(options)) {\n if (key === '__intlayer_icu_var' || key === '__intlayer_icu_ordinal')\n continue;\n const childVal = next(val, props);\n transformedOptions[key] =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n }\n\n let varName = options.__intlayer_icu_var || 'n';\n\n if (!options.__intlayer_icu_var) {\n const fallbackVal =\n transformedOptions.fallback ||\n transformedOptions.other ||\n Object.values(transformedOptions)[0];\n const match = fallbackVal.match(/\\{([a-zA-Z0-9_]+)\\}(?!,)/);\n if (match) {\n varName = match[1];\n }\n }\n\n // Ordinal enumerations round-trip back to `selectordinal`\n if (options.__intlayer_icu_ordinal === true) {\n const ordinalParts = [];\n\n for (const [key, val] of Object.entries(transformedOptions)) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n else if (/^\\d+$/.test(key)) icuKey = `=${key}`;\n\n let strVal = val;\n strVal = strVal.replace(new RegExp(`\\\\{${varName}\\\\}`, 'g'), '#');\n ordinalParts.push(`${icuKey} {${strVal}}`);\n }\n\n return `{${varName}, selectordinal, ${ordinalParts.join(' ')}}`;\n }\n\n const keys = Object.keys(transformedOptions);\n const pluralKeys = [\n '1',\n '2',\n '<=3',\n '>=4',\n 'fallback',\n 'other',\n 'zero',\n 'one',\n 'two',\n 'few',\n 'many',\n ];\n\n const isPlural = keys.every(\n (k) => pluralKeys.includes(k) || /^[<>=]?\\d+(\\.\\d+)?$/.test(k)\n );\n\n const parts = [];\n\n if (isPlural) {\n for (const [key, val] of Object.entries(transformedOptions)) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n else if (key === '<=3') icuKey = 'few';\n else if (key === '>=4') icuKey = 'many';\n else if (/^\\d+$/.test(key)) icuKey = `=${key}`;\n else if (['zero', 'few', 'many'].includes(key)) icuKey = key;\n else icuKey = 'other';\n\n let strVal = val;\n strVal = strVal.replace(new RegExp(`\\\\{${varName}\\\\}`, 'g'), '#');\n parts.push(`${icuKey} {${strVal}}`);\n }\n return `{${varName}, plural, ${parts.join(' ')}}`;\n } else {\n const entries = Object.entries(transformedOptions).sort(\n ([keyA], [keyB]) => {\n if (keyA === 'fallback' || keyA === 'other') return 1;\n if (keyB === 'fallback' || keyB === 'other') return -1;\n return 0;\n }\n );\n\n for (const [key, val] of entries) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n parts.push(`${icuKey} {${val}}`);\n }\n return `{${varName}, select, ${parts.join(' ')}}`;\n }\n }\n\n if (node.nodeType === NodeTypes.GENDER) {\n const options = node[NodeTypes.GENDER];\n const varName = 'gender';\n const parts = [];\n\n const entries = Object.entries(options).sort(([keyA], [keyB]) => {\n if (keyA === 'fallback') return 1;\n if (keyB === 'fallback') return -1;\n return 0;\n });\n\n for (const [key, val] of entries) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n\n const childVal = next(val, props);\n const strVal =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n\n parts.push(`${icuKey} {${strVal}}`);\n }\n return `{${varName}, select, ${parts.join(' ')}}`;\n }\n\n if (\n Array.isArray(node) ||\n (node.nodeType === 'composite' && Array.isArray(node.composite))\n ) {\n // handle array/composite strings that passed canHandle\n const arr = Array.isArray(node) ? node : node.composite;\n const items = arr.map((item: any) => next(item, props));\n return items.join('');\n }\n\n return next(node, props);\n },\n};\n\nexport const intlayerToICUFormatter = (\n message: Dictionary['content']\n): JsonValue => {\n return deepTransformNode(message, {\n dictionaryKey: 'icu',\n keyPath: [],\n plugins: [{ id: 'icu', ...intlayerToIcuPlugin }],\n });\n};\n\nexport const icuToIntlayerFormatter = (\n message: Dictionary['content']\n): JsonValue => {\n return deepTransformNode(message, {\n dictionaryKey: 'icu',\n keyPath: [],\n plugins: [{ id: 'icu', ...icuToIntlayerPlugin }],\n });\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"ICU.cjs","names":["html","insert","enu","plural","gender","select","NodeTypes","deepTransformNode"],"sources":["../../../src/messageFormat/ICU.ts"],"sourcesContent":["import type { Dictionary } from '@intlayer/types/dictionary';\nimport * as NodeTypes from '@intlayer/types/nodeType';\nimport { deepTransformNode } from '../interpreter';\nimport { enu, gender, html, insert, plural, select } from '../transpiler';\n\n/**\n * ICU MessageFormat Converter\n *\n * This module converts between ICU MessageFormat and Intlayer's internal format.\n *\n * IMPORTANT: Two different formats are used:\n *\n * 1. ICU MessageFormat (external format):\n * - Simple variables: {name}\n * - Formatted variables: {amount, number, currency}\n * - Plural: {count, plural, =0 {none} other {# items}}\n * - Select: {gender, select, male {He} female {She} other {They}}\n *\n * 2. Intlayer Internal Format:\n * - Simple variables: {{name}} (double braces for clarity and to distinguish from literal text)\n * - Formatted variables: {amount, number, currency} (keeps ICU format)\n * - Plural: enu({ 0: 'none', fallback: '{{count}} items' })\n * - Select/Gender: gender({ male: 'He', female: 'She', fallback: 'They' })\n *\n * Conversion flow:\n * - ICU → Intlayer: {name} → {{name}}\n * - Intlayer → ICU: {{name}} → {name}\n *\n * The double braces in Intlayer format serve to:\n * - Distinguish variables from literal text containing braces\n * - Work with getInsertion() runtime function which expects {{var}} patterns\n * - Provide clear visual distinction in content dictionaries\n */\n\n// Types for our AST\ntype ICUNode =\n | string\n | {\n type: 'argument';\n name: string;\n format?: { type: string; style?: string };\n }\n | { type: 'plural'; name: string; options: Record<string, ICUNode[]> }\n | { type: 'select'; name: string; options: Record<string, ICUNode[]> }\n | {\n type: 'selectordinal';\n name: string;\n options: Record<string, ICUNode[]>;\n };\n\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue };\n\nconst parseICU = (text: string): ICUNode[] => {\n let index = 0;\n\n const parseNodes = (): ICUNode[] => {\n const nodes: ICUNode[] = [];\n let currentText = '';\n\n while (index < text.length) {\n const char = text[index];\n\n if (char === '{') {\n if (currentText) {\n nodes.push(currentText);\n currentText = '';\n }\n index++; // skip {\n nodes.push(parseArgument());\n } else if (char === '}') {\n // End of current block\n break;\n } else if (char === \"'\") {\n // Escaping\n if (index + 1 < text.length && text[index + 1] === \"'\") {\n currentText += \"'\";\n index += 2;\n } else {\n // Find next quote\n const nextQuote = text.indexOf(\"'\", index + 1);\n if (nextQuote !== -1) {\n // Determine if this is escaping syntax characters\n // For simplicity, we'll treat content between single quotes as literal\n // provided it contains syntax chars.\n // Standard ICU: ' quoted string '\n // If it is just an apostrophe, it should be doubled.\n // But simplified: take content between quotes literally.\n currentText += text.substring(index + 1, nextQuote);\n index = nextQuote + 1;\n } else {\n currentText += \"'\";\n index++;\n }\n }\n } else {\n currentText += char;\n index++;\n }\n }\n\n if (currentText) {\n nodes.push(currentText);\n }\n return nodes;\n };\n\n const parseArgument = (): ICUNode => {\n // We are past '{'\n // Parse name\n let name = '';\n while (index < text.length && /[^,}]/.test(text[index])) {\n name += text[index];\n index++;\n }\n name = name.trim();\n\n if (index >= text.length) throw new Error('Unclosed argument');\n\n if (text[index] === '}') {\n index++;\n return { type: 'argument', name };\n }\n\n // Must be comma\n if (text[index] === ',') {\n index++;\n // Parse type\n let type = '';\n while (index < text.length && /[^,}]/.test(text[index])) {\n type += text[index];\n index++;\n }\n type = type.trim();\n\n if (index >= text.length) throw new Error('Unclosed argument');\n\n if (text[index] === '}') {\n index++;\n return { type: 'argument', name, format: { type } };\n }\n\n if (text[index] === ',') {\n index++;\n\n // If plural, select or selectordinal, parse options\n if (\n type === 'plural' ||\n type === 'select' ||\n type === 'selectordinal'\n ) {\n // Parse options\n const options: Record<string, ICUNode[]> = {};\n\n while (index < text.length && text[index] !== '}') {\n // skip whitespace\n while (index < text.length && /\\s/.test(text[index])) index++;\n\n // parse key\n let key = '';\n while (index < text.length && /[^{\\s]/.test(text[index])) {\n key += text[index];\n index++;\n }\n\n while (index < text.length && /\\s/.test(text[index])) index++;\n\n if (text[index] !== '{')\n throw new Error('Expected { after option key');\n index++; // skip {\n\n const value = parseNodes();\n\n if (text[index] !== '}')\n throw new Error('Expected } after option value');\n index++; // skip }\n\n options[key] = value;\n\n while (index < text.length && /\\s/.test(text[index])) index++;\n }\n\n index++; // skip closing argument }\n\n if (type === 'plural') {\n return { type: 'plural', name, options };\n } else if (type === 'select') {\n return { type: 'select', name, options };\n } else if (type === 'selectordinal') {\n return { type: 'selectordinal', name, options };\n }\n } else {\n // Parse style for number/date/time\n let style = '';\n while (index < text.length && text[index] !== '}') {\n style += text[index];\n index++;\n }\n if (index >= text.length) throw new Error('Unclosed argument');\n\n style = style.trim();\n index++; // skip }\n\n return { type: 'argument', name, format: { type, style } };\n }\n }\n }\n\n throw new Error('Malformed argument');\n };\n\n return parseNodes();\n};\n\nconst icuNodesToIntlayer = (nodes: ICUNode[]): any => {\n if (nodes.length === 0) return '';\n if (nodes.length === 1 && typeof nodes[0] === 'string') {\n const node = nodes[0];\n if (/<[a-zA-Z0-9-]+[^>]*>/.test(node)) {\n return html(node);\n }\n return node;\n }\n\n // Check if we can flatten to a single string (insert)\n const canFlatten = nodes.every(\n (node) => typeof node === 'string' || node.type === 'argument'\n );\n if (canFlatten) {\n let str = '';\n for (const node of nodes) {\n if (typeof node === 'string') {\n str += node;\n } else if (typeof node !== 'string' && node.type === 'argument') {\n if (node.format) {\n // Formatted variables keep ICU format: {var, type, style}\n str += `{${node.name}, ${node.format.type}${\n node.format.style ? `, ${node.format.style}` : ''\n }}`;\n } else {\n // Simple variables use Intlayer format: {{var}}\n str += `{{${node.name}}}`;\n }\n }\n }\n if (/<[a-zA-Z0-9-]+[^>]*>/.test(str)) {\n return html(str);\n }\n return insert(str);\n }\n\n // Mix of string and complex types.\n // If we have just one complex type and it covers everything?\n if (nodes.length === 1) {\n const node = nodes[0];\n\n if (typeof node === 'string') {\n if (/<[a-zA-Z0-9-]+[^>]*>/.test(node)) {\n return html(node);\n }\n return node;\n }\n if (node.type === 'argument') {\n if (node.format) {\n return insert(\n `{${node.name}, ${node.format.type}${\n node.format.style ? `, ${node.format.style}` : ''\n }}`\n );\n }\n return insert(`{{${node.name}}}`);\n }\n if (node.type === 'plural') {\n const options: Record<string, any> = {};\n let hasExactMatch = false;\n\n for (const key of Object.keys(node.options)) {\n if (key.startsWith('=')) {\n hasExactMatch = true;\n break;\n }\n }\n\n if (hasExactMatch) {\n for (const [key, val] of Object.entries(node.options)) {\n // Map ICU keys to Intlayer keys\n let newKey = key;\n if (key.startsWith('=')) {\n newKey = key.substring(1); // =0 -> 0\n } else if (key === 'one') {\n newKey = '1';\n } else if (key === 'two') {\n newKey = '2';\n } else if (key === 'few') {\n newKey = '<=3';\n } else if (key === 'many') {\n newKey = '>=4';\n } else if (key === 'other') {\n newKey = 'fallback';\n }\n // Handle # in plural value\n // For plural, we need to pass the variable name down or replace #\n // Intlayer uses {{n}} (or whatever var name) for simple variables\n // We should replace # with {{n}} in the string parts of val\n const replacedVal = val.map((v) => {\n if (typeof v === 'string') {\n return v.replace(/#/g, `{{${node.name}}}`);\n }\n return v;\n });\n\n options[newKey] = icuNodesToIntlayer(replacedVal);\n }\n\n // Preserve variable name\n options.__intlayer_icu_var = node.name;\n\n return enu(options);\n } else {\n for (const [key, val] of Object.entries(node.options)) {\n // Handle # in plural value\n const replacedVal = val.map((v) => {\n if (typeof v === 'string') {\n return v.replace(/#/g, `{{${node.name}}}`);\n }\n return v;\n });\n\n options[key] = icuNodesToIntlayer(replacedVal);\n }\n\n return plural(options as any);\n }\n }\n if (node.type === 'select') {\n const options: Record<string, any> = {};\n\n for (const [key, val] of Object.entries(node.options)) {\n // ICU names its catch-all case `other`; intlayer names it `fallback`.\n options[key === 'other' ? 'fallback' : key] = icuNodesToIntlayer(val);\n }\n\n // Check if it looks like gender\n const optionKeys = Object.keys(options);\n // It is gender if it has 'male' OR 'female' AND only contains gender keys (male, female, other)\n const isGender =\n (options.male || options.female) &&\n optionKeys.every((k) =>\n ['male', 'female', 'other', 'fallback'].includes(k)\n );\n\n if (isGender) {\n return gender({\n fallback: options.fallback,\n male: options.male,\n female: options.female,\n });\n }\n\n // Any other discriminant (status, plan, platform…) maps to a `select`\n // node, which resolves on arbitrary string values at runtime.\n return select(options, node.name);\n }\n\n if (node.type === 'selectordinal') {\n // Ordinal plural ({n, selectordinal, one {#st} two {#nd} other {#th}}).\n // Stored as an enumeration with the ordinal marker: exact matches keep\n // numeric keys, CLDR ordinal categories keep their names, and the\n // runtime selects via `Intl.PluralRules(locale, { type: 'ordinal' })`.\n const options: Record<string, any> = {};\n\n for (const [key, val] of Object.entries(node.options)) {\n const newKey = key.startsWith('=')\n ? key.substring(1)\n : key === 'other'\n ? 'fallback'\n : key;\n\n const replacedVal = val.map((value) => {\n if (typeof value === 'string') {\n return value.replace(/#/g, `{{${node.name}}}`);\n }\n return value;\n });\n\n options[newKey] = icuNodesToIntlayer(replacedVal);\n }\n\n options.__intlayer_icu_var = node.name;\n options.__intlayer_icu_ordinal = true;\n\n return enu(options);\n }\n }\n\n // If multiple nodes, return array\n return nodes.map((node) => icuNodesToIntlayer([node]));\n};\n\nconst icuToIntlayerPlugin = {\n canHandle: (node: any) =>\n typeof node === 'string' &&\n (node.includes('{') ||\n node.includes('}') ||\n /<[a-zA-Z0-9-]+[^>]*>/.test(node)),\n transform: (node: any) => {\n try {\n const ast = parseICU(node);\n return icuNodesToIntlayer(ast);\n } catch {\n // If parsing fails, return original string\n return node;\n }\n },\n};\n\nconst intlayerToIcuPlugin = {\n canHandle: (node: any) => {\n if (\n typeof node === 'string' &&\n (node.includes('{') || node.includes('}'))\n ) {\n return true;\n }\n\n if (\n node &&\n typeof node === 'object' &&\n (node.nodeType === NodeTypes.INSERTION ||\n node.nodeType === NodeTypes.HTML ||\n node.nodeType === NodeTypes.ENUMERATION ||\n node.nodeType === NodeTypes.PLURAL ||\n node.nodeType === NodeTypes.GENDER ||\n node.nodeType === NodeTypes.SELECT ||\n node.nodeType === 'composite')\n ) {\n return true;\n }\n\n if (Array.isArray(node)) {\n if (node.length === 0) return false;\n\n let hasNode = false;\n let hasPlainObjectOrArray = false;\n\n for (const item of node) {\n if (typeof item === 'string') {\n } else if (\n item &&\n typeof item === 'object' &&\n (item.nodeType === NodeTypes.INSERTION ||\n item.nodeType === NodeTypes.HTML ||\n item.nodeType === NodeTypes.ENUMERATION ||\n item.nodeType === NodeTypes.GENDER ||\n item.nodeType === NodeTypes.SELECT ||\n item.nodeType === 'composite')\n ) {\n hasNode = true;\n } else {\n hasPlainObjectOrArray = true;\n }\n }\n\n // If it contains plain objects or nested arrays, it's a structural array\n if (hasPlainObjectOrArray) return false;\n // If it contains ONLY strings, it's a structural array, not a composite string\n if (!hasNode) return false;\n\n return true;\n }\n\n return false;\n },\n transform: (node: any, props: any, next: any) => {\n // Convert Intlayer's double-brace format {{var}} to ICU's single-brace format {var}\n if (typeof node === 'string') {\n return node.replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n }\n\n if (node.nodeType === NodeTypes.INSERTION) {\n return node[NodeTypes.INSERTION].replace(/\\{\\{([^}]+)\\}\\}/g, '{$1}');\n }\n\n if (node.nodeType === NodeTypes.HTML) {\n return node[NodeTypes.HTML];\n }\n\n if (node.nodeType === NodeTypes.PLURAL) {\n const options = node[NodeTypes.PLURAL];\n\n const transformedOptions: Record<string, string> = {};\n for (const [key, val] of Object.entries(options)) {\n const childVal = next(val, props);\n transformedOptions[key] =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n }\n\n let varName = 'count';\n\n const fallbackVal =\n transformedOptions.other || Object.values(transformedOptions)[0];\n\n if (fallbackVal) {\n const match = fallbackVal.match(/\\{([a-zA-Z0-9_]+)\\}(?!,)/);\n if (match) {\n varName = match[1];\n }\n }\n\n const parts = [];\n\n for (const [key, val] of Object.entries(transformedOptions)) {\n let strVal = val;\n strVal = strVal.replace(new RegExp(`\\\\{${varName}\\\\}`, 'g'), '#');\n parts.push(`${key} {${strVal}}`);\n }\n return `{${varName}, plural, ${parts.join(' ')}}`;\n }\n\n if (node.nodeType === NodeTypes.ENUMERATION) {\n const options = node[NodeTypes.ENUMERATION];\n\n const transformedOptions: Record<string, string> = {};\n for (const [key, val] of Object.entries(options)) {\n if (key === '__intlayer_icu_var' || key === '__intlayer_icu_ordinal')\n continue;\n const childVal = next(val, props);\n transformedOptions[key] =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n }\n\n let varName = options.__intlayer_icu_var || 'n';\n\n if (!options.__intlayer_icu_var) {\n const fallbackVal =\n transformedOptions.fallback ||\n transformedOptions.other ||\n Object.values(transformedOptions)[0];\n const match = fallbackVal.match(/\\{([a-zA-Z0-9_]+)\\}(?!,)/);\n if (match) {\n varName = match[1];\n }\n }\n\n // Ordinal enumerations round-trip back to `selectordinal`\n if (options.__intlayer_icu_ordinal === true) {\n const ordinalParts = [];\n\n for (const [key, val] of Object.entries(transformedOptions)) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n else if (/^\\d+$/.test(key)) icuKey = `=${key}`;\n\n let strVal = val;\n strVal = strVal.replace(new RegExp(`\\\\{${varName}\\\\}`, 'g'), '#');\n ordinalParts.push(`${icuKey} {${strVal}}`);\n }\n\n return `{${varName}, selectordinal, ${ordinalParts.join(' ')}}`;\n }\n\n const keys = Object.keys(transformedOptions);\n const pluralKeys = [\n '1',\n '2',\n '<=3',\n '>=4',\n 'fallback',\n 'other',\n 'zero',\n 'one',\n 'two',\n 'few',\n 'many',\n ];\n\n const isPlural = keys.every(\n (k) => pluralKeys.includes(k) || /^[<>=]?\\d+(\\.\\d+)?$/.test(k)\n );\n\n const parts = [];\n\n if (isPlural) {\n for (const [key, val] of Object.entries(transformedOptions)) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n else if (key === '<=3') icuKey = 'few';\n else if (key === '>=4') icuKey = 'many';\n else if (/^\\d+$/.test(key)) icuKey = `=${key}`;\n else if (['zero', 'few', 'many'].includes(key)) icuKey = key;\n else icuKey = 'other';\n\n let strVal = val;\n strVal = strVal.replace(new RegExp(`\\\\{${varName}\\\\}`, 'g'), '#');\n parts.push(`${icuKey} {${strVal}}`);\n }\n return `{${varName}, plural, ${parts.join(' ')}}`;\n } else {\n const entries = Object.entries(transformedOptions).sort(\n ([keyA], [keyB]) => {\n if (keyA === 'fallback' || keyA === 'other') return 1;\n if (keyB === 'fallback' || keyB === 'other') return -1;\n return 0;\n }\n );\n\n for (const [key, val] of entries) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n parts.push(`${icuKey} {${val}}`);\n }\n return `{${varName}, select, ${parts.join(' ')}}`;\n }\n }\n\n if (node.nodeType === NodeTypes.GENDER) {\n const options = node[NodeTypes.GENDER];\n const varName = 'gender';\n const parts = [];\n\n const entries = Object.entries(options).sort(([keyA], [keyB]) => {\n if (keyA === 'fallback') return 1;\n if (keyB === 'fallback') return -1;\n return 0;\n });\n\n for (const [key, val] of entries) {\n let icuKey = key;\n if (key === 'fallback') icuKey = 'other';\n\n const childVal = next(val, props);\n const strVal =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n\n parts.push(`${icuKey} {${strVal}}`);\n }\n return `{${varName}, select, ${parts.join(' ')}}`;\n }\n\n if (node.nodeType === NodeTypes.SELECT) {\n const options = node[NodeTypes.SELECT];\n const varName = node.variable || 'value';\n const parts = [];\n\n // ICU requires the `other` case to come last.\n const entries = Object.entries(options).sort(([keyA], [keyB]) => {\n if (keyA === 'fallback') return 1;\n if (keyB === 'fallback') return -1;\n return 0;\n });\n\n for (const [key, val] of entries) {\n const icuKey = key === 'fallback' ? 'other' : key;\n\n const childVal = next(val, props);\n const strVal =\n typeof childVal === 'string' ? childVal : JSON.stringify(childVal);\n\n parts.push(`${icuKey} {${strVal}}`);\n }\n return `{${varName}, select, ${parts.join(' ')}}`;\n }\n\n if (\n Array.isArray(node) ||\n (node.nodeType === 'composite' && Array.isArray(node.composite))\n ) {\n // handle array/composite strings that passed canHandle\n const arr = Array.isArray(node) ? node : node.composite;\n const items = arr.map((item: any) => next(item, props));\n return items.join('');\n }\n\n return next(node, props);\n },\n};\n\nexport const intlayerToICUFormatter = (\n message: Dictionary['content']\n): JsonValue => {\n return deepTransformNode(message, {\n dictionaryKey: 'icu',\n keyPath: [],\n plugins: [{ id: 'icu', ...intlayerToIcuPlugin }],\n });\n};\n\nexport const icuToIntlayerFormatter = (\n message: Dictionary['content']\n): JsonValue => {\n return deepTransformNode(message, {\n dictionaryKey: 'icu',\n keyPath: [],\n plugins: [{ id: 'icu', ...icuToIntlayerPlugin }],\n });\n};\n"],"mappings":"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"}
@@ -6,6 +6,7 @@ const require_transpiler_gender_gender = require('../transpiler/gender/gender.cj
6
6
  const require_transpiler_html_html = require('../transpiler/html/html.cjs');
7
7
  const require_transpiler_insertion_insertion = require('../transpiler/insertion/insertion.cjs');
8
8
  const require_transpiler_plural_plural = require('../transpiler/plural/plural.cjs');
9
+ const require_transpiler_select_select = require('../transpiler/select/select.cjs');
9
10
  let _intlayer_types_nodeType = require("@intlayer/types/nodeType");
10
11
  _intlayer_types_nodeType = require_runtime.__toESM(_intlayer_types_nodeType);
11
12
 
@@ -204,7 +205,7 @@ const i18nextNodesToIntlayer = (nodes) => {
204
205
  }
205
206
  if (node.type === "select") {
206
207
  const options = {};
207
- for (const [key, val] of Object.entries(node.options)) options[key] = i18nextNodesToIntlayer(val);
208
+ for (const [key, val] of Object.entries(node.options)) options[key === "other" ? "fallback" : key] = i18nextNodesToIntlayer(val);
208
209
  const optionKeys = Object.keys(options);
209
210
  if ((options.male || options.female) && optionKeys.every((k) => [
210
211
  "male",
@@ -212,12 +213,11 @@ const i18nextNodesToIntlayer = (nodes) => {
212
213
  "other",
213
214
  "fallback"
214
215
  ].includes(k))) return require_transpiler_gender_gender.gender({
215
- fallback: options.other,
216
+ fallback: options.fallback,
216
217
  male: options.male,
217
218
  female: options.female
218
219
  });
219
- options.__intlayer_icu_var = node.name;
220
- return require_transpiler_enumeration_enumeration.enu(options);
220
+ return require_transpiler_select_select.select(options, node.name);
221
221
  }
222
222
  }
223
223
  return nodes.map((node) => i18nextNodesToIntlayer([node]));
@@ -236,12 +236,12 @@ const i18nextToIntlayerPlugin = {
236
236
  const intlayerToI18nextPlugin = {
237
237
  canHandle: (node) => {
238
238
  if (typeof node === "string") return true;
239
- if (node && typeof node === "object" && (node.nodeType === _intlayer_types_nodeType.INSERTION || node.nodeType === _intlayer_types_nodeType.HTML || node.nodeType === _intlayer_types_nodeType.ENUMERATION || node.nodeType === _intlayer_types_nodeType.PLURAL || node.nodeType === _intlayer_types_nodeType.GENDER || node.nodeType === "composite")) return true;
239
+ if (node && typeof node === "object" && (node.nodeType === _intlayer_types_nodeType.INSERTION || node.nodeType === _intlayer_types_nodeType.HTML || node.nodeType === _intlayer_types_nodeType.ENUMERATION || node.nodeType === _intlayer_types_nodeType.PLURAL || node.nodeType === _intlayer_types_nodeType.GENDER || node.nodeType === _intlayer_types_nodeType.SELECT || node.nodeType === "composite")) return true;
240
240
  if (Array.isArray(node)) {
241
241
  if (node.length === 0) return false;
242
242
  let hasNode = false;
243
243
  let hasPlainObjectOrArray = false;
244
- for (const item of node) if (typeof item === "string") {} else if (item && typeof item === "object" && (item.nodeType === _intlayer_types_nodeType.INSERTION || item.nodeType === _intlayer_types_nodeType.HTML || item.nodeType === _intlayer_types_nodeType.ENUMERATION || item.nodeType === _intlayer_types_nodeType.GENDER || item.nodeType === "composite")) hasNode = true;
244
+ for (const item of node) if (typeof item === "string") {} else if (item && typeof item === "object" && (item.nodeType === _intlayer_types_nodeType.INSERTION || item.nodeType === _intlayer_types_nodeType.HTML || item.nodeType === _intlayer_types_nodeType.ENUMERATION || item.nodeType === _intlayer_types_nodeType.GENDER || item.nodeType === _intlayer_types_nodeType.SELECT || item.nodeType === "composite")) hasNode = true;
245
245
  else hasPlainObjectOrArray = true;
246
246
  if (hasPlainObjectOrArray) return false;
247
247
  if (!hasNode) return false;
@@ -357,6 +357,24 @@ const intlayerToI18nextPlugin = {
357
357
  }
358
358
  return `{${varName}, select, ${parts.join(" ")}}`;
359
359
  }
360
+ if (node.nodeType === _intlayer_types_nodeType.SELECT) {
361
+ const options = node[_intlayer_types_nodeType.SELECT];
362
+ const varName = node.variable || "value";
363
+ const parts = [];
364
+ const entries = Object.entries(options).sort(([keyA], [keyB]) => {
365
+ if (keyA === "fallback") return 1;
366
+ if (keyB === "fallback") return -1;
367
+ return 0;
368
+ });
369
+ for (const [key, val] of entries) {
370
+ const icuKey = key === "fallback" ? "other" : key;
371
+ const childVal = next(val, props);
372
+ let strVal = typeof childVal === "string" ? childVal : JSON.stringify(childVal);
373
+ strVal = strVal.replace(/\{\{([^}]+)\}\}/g, "{$1}");
374
+ parts.push(`${icuKey} {${strVal}}`);
375
+ }
376
+ return `{${varName}, select, ${parts.join(" ")}}`;
377
+ }
360
378
  if (Array.isArray(node) || node.nodeType === "composite" && Array.isArray(node.composite)) return (Array.isArray(node) ? node : node.composite).map((item) => next(item, props)).join("");
361
379
  return next(node, props);
362
380
  }