UNPKG

@intlayer/core

Version:

Includes core Intlayer functions like translation, dictionary, and utility functions shared across multiple packages.

1 lines 13 kB
{"version":3,"file":"po.cjs","names":["NodeTypes","html","insert","gender","enu","plural","deepTransformNode"],"sources":["../../../src/messageFormat/po.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';\nimport type { JsonValue } from './ICU';\n\nexport type PortableObject = {\n msgid: string;\n msgctxt?: string;\n msgid_plural?: string;\n msgstr: string[];\n};\n\n/**\n * Extracts the string value from a transformed AST node or generic object.\n */\nconst extractStringValue = (val: any): string => {\n if (typeof val === 'string') return val;\n if (val && typeof val === 'object' && 'msgstr' in val) {\n return val.msgstr[0] || '';\n }\n return JSON.stringify(val);\n};\n\nconst intlayerToPoPlugin = {\n canHandle: (node: any) => {\n if (typeof node === 'string') return true;\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 // Handle structural string arrays (composite phrases)\n if (Array.isArray(node)) {\n if (node.length === 0) return false;\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.PLURAL ||\n item.nodeType === NodeTypes.GENDER ||\n item.nodeType === 'composite')\n ) {\n hasNode = true;\n } else {\n hasPlainObjectOrArray = true;\n }\n }\n\n if (hasPlainObjectOrArray) return false;\n if (!hasNode) return false;\n return true;\n }\n\n return false;\n },\n transform: (node: any, props: any, next: any): PortableObject => {\n // 1. Strings\n if (typeof node === 'string') {\n const poVal = node.replace(/\\{\\{([^}]+)\\}\\}/g, '%($1)s');\n return { msgid: poVal, msgstr: [poVal] };\n }\n\n // 2. Insertions & Variables\n if (node.nodeType === NodeTypes.INSERTION) {\n return next(node[NodeTypes.INSERTION], props);\n }\n\n // 3. HTML\n if (node.nodeType === NodeTypes.HTML) {\n const val = node[NodeTypes.HTML];\n return { msgid: val, msgstr: [val] };\n }\n\n // 4. Plurals & Enumerations\n if (\n node.nodeType === NodeTypes.PLURAL ||\n node.nodeType === NodeTypes.ENUMERATION\n ) {\n const isPlural = node.nodeType === NodeTypes.PLURAL;\n const options = isPlural\n ? node[NodeTypes.PLURAL]\n : node[NodeTypes.ENUMERATION];\n\n const rawMsgid = isPlural\n ? options.one || options.other || options.fallback\n : options.fallback || options['0'];\n\n const msgid = extractStringValue(next(rawMsgid, props));\n const msgid_plural = isPlural\n ? extractStringValue(\n next(options.other || options.fallback || rawMsgid, props)\n )\n : extractStringValue(next(options.fallback || rawMsgid, props));\n\n const msgstr: string[] = [];\n\n if (isPlural) {\n // Standard CLDR/Gettext mapping fallback\n if ('zero' in options)\n msgstr.push(extractStringValue(next(options.zero, props)));\n msgstr.push(\n extractStringValue(next(options.one || options.fallback, props))\n );\n if ('two' in options)\n msgstr.push(extractStringValue(next(options.two, props)));\n if ('few' in options)\n msgstr.push(extractStringValue(next(options.few, props)));\n if ('many' in options)\n msgstr.push(extractStringValue(next(options.many, props)));\n\n // Ensure 'other' is always the last fallback if others are missing\n const otherVal = extractStringValue(\n next(options.other || options.fallback, props)\n );\n if (!msgstr.includes(otherVal)) msgstr.push(otherVal);\n } else {\n // Enums don't have standard PO mapping, pack linearly\n msgstr[0] = extractStringValue(\n next(options.fallback || options['0'], props)\n );\n msgstr[1] = msgstr[0];\n }\n\n return {\n msgctxt: isPlural ? undefined : 'enumeration',\n msgid,\n msgid_plural,\n msgstr,\n };\n }\n\n // 5. Gender (mapped to PO via msgctxt)\n if (node.nodeType === NodeTypes.GENDER) {\n const options = node[NodeTypes.GENDER];\n const fallback = extractStringValue(next(options.fallback, props));\n return {\n msgctxt: 'gender',\n msgid: fallback,\n msgstr: [\n extractStringValue(next(options.male || options.fallback, props)),\n extractStringValue(next(options.female || options.fallback, props)),\n fallback,\n ],\n };\n }\n\n // 6. Arrays / Composites\n if (\n Array.isArray(node) ||\n (node.nodeType === 'composite' && Array.isArray(node.composite))\n ) {\n const arr = Array.isArray(node) ? node : node.composite;\n const combined = arr\n .map((item: any) => extractStringValue(next(item, props)))\n .join('');\n return { msgid: combined, msgstr: [combined] };\n }\n\n return node;\n },\n};\n\nconst poToIntlayerPlugin = {\n canHandle: (node: any) =>\n node && typeof node === 'object' && 'msgid' in node && 'msgstr' in node,\n\n transform: (node: PortableObject) => {\n const msgstr = node.msgstr || [];\n const isPlural = Boolean(node.msgid_plural) || msgstr.length > 1;\n\n const processString = (str: string) => {\n if (!str) return '';\n // Convert Python/C-style gettext variables %(name)s or %(name)d -> {{name}}\n const parsed = str.replace(/%\\(([a-zA-Z0-9_-]+)\\)[sdf]/g, '{{$1}}');\n\n if (/<[a-zA-Z0-9-]+[^>]*>/.test(parsed)) return html(parsed);\n if (parsed.includes('{{')) return insert(parsed);\n return parsed;\n };\n\n // Fast-path: Single string translation\n if (!isPlural) {\n return processString(msgstr[0] || node.msgid || '');\n }\n\n // Handle Plural/Enum/Gender matrix\n const options: Record<string, any> = {};\n\n if (node.msgctxt === 'gender') {\n return gender({\n male: processString(msgstr[0] || node.msgid),\n female: processString(msgstr[1] || msgstr[0]),\n fallback: processString(msgstr[2] || msgstr[msgstr.length - 1]),\n });\n }\n\n if (node.msgctxt === 'enumeration') {\n return enu({\n '0': processString(msgstr[0]),\n fallback: processString(msgstr[msgstr.length - 1]),\n });\n }\n\n // Plural Form Mapping based on array length (Gettext Plural-Forms approximation)\n if (msgstr.length === 2) {\n options.one = processString(msgstr[0]);\n options.other = processString(msgstr[1]);\n } else if (msgstr.length === 3) {\n // E.g., Polish/Russian: one, few, many/other\n options.one = processString(msgstr[0]);\n options.few = processString(msgstr[1]);\n options.other = processString(msgstr[2]);\n } else if (msgstr.length === 6) {\n // E.g., Arabic: zero, one, two, few, many, other\n options.zero = processString(msgstr[0]);\n options.one = processString(msgstr[1]);\n options.two = processString(msgstr[2]);\n options.few = processString(msgstr[3]);\n options.many = processString(msgstr[4]);\n options.other = processString(msgstr[5]);\n } else {\n // Generic arbitrary length mapping\n options.one = processString(msgstr[0]);\n options.other = processString(msgstr[msgstr.length - 1]);\n for (let i = 1; i < msgstr.length - 1; i++) {\n options[`${i + 1}`] = processString(msgstr[i]);\n }\n }\n\n return plural(options as any);\n },\n};\n\nexport const intlayerToPortableObjectFormatter = (\n dictionary: Dictionary['content']\n): JsonValue => {\n return deepTransformNode(dictionary, {\n dictionaryKey: 'po',\n keyPath: [],\n plugins: [{ id: 'po', ...intlayerToPoPlugin }],\n });\n};\n\nexport const portableObjectToIntlayerFormatter = (\n message: JsonValue\n): Dictionary['content'] => {\n return deepTransformNode(message, {\n dictionaryKey: 'po',\n keyPath: [],\n plugins: [{ id: 'po', ...poToIntlayerPlugin }],\n });\n};\n"],"mappings":"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"}