UNPKG

@intlayer/core

Version:

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

320 lines (318 loc) 10.7 kB
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs'); const require_interpreter_getContent_deepTransform = require('../interpreter/getContent/deepTransform.cjs'); const require_transpiler_enumeration_enumeration = require('../transpiler/enumeration/enumeration.cjs'); const require_transpiler_gender_gender = require('../transpiler/gender/gender.cjs'); const require_transpiler_insertion_insertion = require('../transpiler/insertion/insertion.cjs'); let _intlayer_types = require("@intlayer/types"); //#region src/messageFormat/i18next.ts const parseI18Next = (text) => { let index = 0; const parseNodes = () => { const nodes = []; let currentText = ""; while (index < text.length) { const char = text[index]; if (char === "{" && text[index + 1] === "{") { if (currentText) { nodes.push(currentText); currentText = ""; } index += 2; nodes.push(parseStandardArgument()); } else if (char === "{") { if (currentText) { nodes.push(currentText); currentText = ""; } index++; nodes.push(parseICUArgument()); } else if (char === "}") break; else { currentText += char; index++; } } if (currentText) nodes.push(currentText); return nodes; }; const parseStandardArgument = () => { let name = ""; while (index < text.length) { if (text[index] === "}" && text[index + 1] === "}") { index += 2; return { type: "argument", name: name.trim() }; } name += text[index]; index++; } throw new Error("Unclosed i18next variable"); }; const parseICUArgument = () => { let name = ""; while (index < text.length && /[^,}]/.test(text[index])) { name += text[index]; index++; } name = name.trim(); if (index >= text.length) throw new Error("Unclosed argument"); if (text[index] === "}") { index++; return { type: "argument", name }; } if (text[index] === ",") { index++; let type = ""; while (index < text.length && /[^,}]/.test(text[index])) { type += text[index]; index++; } type = type.trim(); if (index >= text.length) throw new Error("Unclosed argument"); if (text[index] === "}") { index++; return { type: "argument", name, format: { type } }; } if (text[index] === ",") { index++; if (type === "plural" || type === "select") { const options = {}; while (index < text.length && text[index] !== "}") { while (index < text.length && /\s/.test(text[index])) index++; let key = ""; while (index < text.length && /[^{\s]/.test(text[index])) { key += text[index]; index++; } while (index < text.length && /\s/.test(text[index])) index++; if (text[index] !== "{") throw new Error("Expected { after option key"); index++; const value = parseNodes(); if (text[index] !== "}") throw new Error("Expected } after option value"); index++; options[key] = value; while (index < text.length && /\s/.test(text[index])) index++; } index++; if (type === "plural") return { type: "plural", name, options }; else if (type === "select") return { type: "select", name, options }; } else { let style = ""; while (index < text.length && text[index] !== "}") { style += text[index]; index++; } if (index >= text.length) throw new Error("Unclosed argument"); style = style.trim(); index++; return { type: "argument", name, format: { type, style } }; } } } throw new Error("Malformed argument"); }; return parseNodes(); }; const i18nextNodesToIntlayer = (nodes) => { if (nodes.length === 0) return ""; if (nodes.length === 1 && typeof nodes[0] === "string") return nodes[0]; if (nodes.every((node) => typeof node === "string" || node.type === "argument")) { let str = ""; for (const node of nodes) if (typeof node === "string") str += node; else if (typeof node !== "string" && node.type === "argument") if (node.format) str += `{${node.name}, ${node.format.type}${node.format.style ? `, ${node.format.style}` : ""}}`; else str += `{{${node.name}}}`; return require_transpiler_insertion_insertion.insert(str); } if (nodes.length === 1) { const node = nodes[0]; if (typeof node === "string") return node; if (node.type === "argument") { if (node.format) return require_transpiler_insertion_insertion.insert(`{${node.name}, ${node.format.type}${node.format.style ? `, ${node.format.style}` : ""}}`); return require_transpiler_insertion_insertion.insert(`{{${node.name}}}`); } if (node.type === "plural") { const options = {}; for (const [key, val] of Object.entries(node.options)) { let newKey = key; if (key.startsWith("=")) newKey = key.substring(1); else if (key === "one") newKey = "1"; else if (key === "two") newKey = "2"; else if (key === "few") newKey = "<=3"; else if (key === "many") newKey = ">=4"; else if (key === "other") newKey = "fallback"; options[newKey] = i18nextNodesToIntlayer(val.map((v) => { if (typeof v === "string") return v.replace(/#/g, `{{${node.name}}}`); return v; })); } options.__intlayer_icu_var = node.name; return require_transpiler_enumeration_enumeration.enu(options); } if (node.type === "select") { const options = {}; for (const [key, val] of Object.entries(node.options)) options[key] = i18nextNodesToIntlayer(val); const optionKeys = Object.keys(options); if ((options.male || options.female) && optionKeys.every((k) => [ "male", "female", "other", "fallback" ].includes(k))) return require_transpiler_gender_gender.gender({ fallback: options.other, male: options.male, female: options.female }); options.__intlayer_icu_var = node.name; return require_transpiler_enumeration_enumeration.enu(options); } } return nodes.map((node) => i18nextNodesToIntlayer([node])); }; const i18nextToIntlayerPlugin = { canHandle: (node) => typeof node === "string" && (node.includes("{") || node.includes("}")), transform: (node) => { try { return i18nextNodesToIntlayer(parseI18Next(node)); } catch { return node; } } }; const intlayerToI18nextPlugin = { canHandle: (node) => typeof node === "string" || node && typeof node === "object" && (node.nodeType === _intlayer_types.NodeType.Insertion || node.nodeType === _intlayer_types.NodeType.Enumeration || node.nodeType === _intlayer_types.NodeType.Gender || node.nodeType === "composite") || Array.isArray(node), transform: (node, props, next) => { if (typeof node === "string") return node; if (node.nodeType === _intlayer_types.NodeType.Insertion) { if (node.insertion.match(/\{[^}]*,[^}]*\}/)) return node.insertion; return node.insertion; } if (node.nodeType === _intlayer_types.NodeType.Enumeration) { const options = node.enumeration; const transformedOptions = {}; for (const [key, val] of Object.entries(options)) { if (key === "__intlayer_icu_var") continue; const childVal = next(val, props); transformedOptions[key] = typeof childVal === "string" ? childVal : JSON.stringify(childVal); } let varName = options.__intlayer_icu_var || "count"; if (!options.__intlayer_icu_var) { const fallbackVal = transformedOptions.fallback || transformedOptions.other || Object.values(transformedOptions)[0]; const match = fallbackVal.match(/\{\{([a-zA-Z0-9_]+)\}\}/) || fallbackVal.match(/\{([a-zA-Z0-9_]+)\}(?!,)/); if (match) varName = match[1]; } const keys = Object.keys(transformedOptions); const pluralKeys = [ "1", "2", "<=3", ">=4", "fallback", "other", "zero", "one", "two", "few", "many" ]; const isPlural = keys.every((k) => pluralKeys.includes(k) || /^[<>=]?\d+(\.\d+)?$/.test(k)); const parts = []; if (isPlural) { for (const [key, val] of Object.entries(transformedOptions)) { let icuKey = key; if (key === "fallback") icuKey = "other"; else if (key === "<=3") icuKey = "few"; else if (key === ">=4") icuKey = "many"; else if (/^\d+$/.test(key)) icuKey = `=${key}`; let strVal = val; strVal = strVal.replace(/\{\{([^}]+)\}\}/g, "{$1}"); strVal = strVal.replace(new RegExp(`\\{${varName}\\}`, "g"), "#"); parts.push(`${icuKey} {${strVal}}`); } return `{${varName}, plural, ${parts.join(" ")}}`; } else { const entries = Object.entries(transformedOptions).sort(([keyA], [keyB]) => { if (keyA === "fallback" || keyA === "other") return 1; if (keyB === "fallback" || keyB === "other") return -1; return 0; }); for (const [key, val] of entries) { let icuKey = key; if (key === "fallback") icuKey = "other"; let strVal = val; strVal = strVal.replace(/\{\{([^}]+)\}\}/g, "{$1}"); parts.push(`${icuKey} {${strVal}}`); } return `{${varName}, select, ${parts.join(" ")}}`; } } if (node.nodeType === _intlayer_types.NodeType.Gender) { const options = node.gender; const varName = "gender"; const parts = []; const entries = Object.entries(options).sort(([keyA], [keyB]) => { if (keyA === "fallback") return 1; if (keyB === "fallback") return -1; return 0; }); for (const [key, val] of entries) { let icuKey = key; if (key === "fallback") icuKey = "other"; const childVal = next(val, props); let strVal = typeof childVal === "string" ? childVal : JSON.stringify(childVal); strVal = strVal.replace(/\{\{([^}]+)\}\}/g, "{$1}"); parts.push(`${icuKey} {${strVal}}`); } return `{${varName}, select, ${parts.join(" ")}}`; } if (Array.isArray(node) || node.nodeType === "composite" && Array.isArray(node.composite)) return (Array.isArray(node) ? node : node.composite).map((item) => next(item, props)).join(""); return next(node, props); } }; const intlayerToI18nextFormatter = (message) => { return require_interpreter_getContent_deepTransform.deepTransformNode(message, { dictionaryKey: "i18next", keyPath: [], plugins: [{ id: "i18next", ...intlayerToI18nextPlugin }] }); }; const i18nextToIntlayerFormatter = (message) => { return require_interpreter_getContent_deepTransform.deepTransformNode(message, { dictionaryKey: "i18next", keyPath: [], plugins: [{ id: "i18next", ...i18nextToIntlayerPlugin }] }); }; //#endregion exports.i18nextToIntlayerFormatter = i18nextToIntlayerFormatter; exports.intlayerToI18nextFormatter = intlayerToI18nextFormatter; //# sourceMappingURL=i18next.cjs.map