UNPKG

@awesome-fe/translate

Version:
331 lines 13.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.markdown = void 0; var unified = require("unified"); var custom_parser_plugin_1 = require("./remark-plugins/custom-parser-plugin"); var custom_compiler_plugin_1 = require("./remark-plugins/custom-compiler-plugin"); var mast_to_hast_handlers_1 = require("./remark-plugins/mast-to-hast-handlers"); var hast_to_mast_handlers_1 = require("./remark-plugins/hast-to-mast-handlers"); var remarkParse = require("remark-parse"); var remarkStringify = require("remark-stringify"); var rehypeParse = require("rehype-parse"); var rehypeStringify = require("rehype-stringify"); var remarkRehype = require("remark-rehype"); var rehypeRemark = require("rehype-remark"); var frontmatter = require("remark-frontmatter"); var stringWidth = require("string-width"); var common_1 = require("../common"); var js_yaml_1 = require("js-yaml"); var lodash_1 = require("lodash"); var markdown; (function (markdown_1) { function isLiteral(node) { return [ 'html', 'code', 'yaml', 'text', 'inlineCode', ].includes(node.type); } markdown_1.isLiteral = isLiteral; function isParent(node) { return [ 'root', 'paragraph', 'heading', 'blockquote', 'list', 'listItem', 'table', 'tableRow', 'tableCell', 'emphasis', 'strong', 'delete', 'footnote', ].includes(node.type); } markdown_1.isParent = isParent; function isTranslatableUnit(node) { return node.type === 'paragraph' || node.type === 'heading'; } markdown_1.isTranslatableUnit = isTranslatableUnit; function isLinkReference(node) { return node.type === 'linkReference'; } markdown_1.isLinkReference = isLinkReference; function isLink(node) { return node.type === 'link'; } markdown_1.isLink = isLink; function isTableRow(node) { return node.type === 'tableRow'; } markdown_1.isTableRow = isTableRow; function isTableCell(node) { return node.type === 'tableCell'; } markdown_1.isTableCell = isTableCell; function isTable(node) { return node.type === 'table'; } markdown_1.isTable = isTable; function isTableFamily(node) { return isTable(node) || isTableRow(node) || isTableCell(node); } markdown_1.isTableFamily = isTableFamily; function isYaml(node) { return node.type === 'yaml'; } markdown_1.isYaml = isYaml; function isListItem(node) { return node.type === 'listItem'; } markdown_1.isListItem = isListItem; function parse(markdown) { return unified().use(remarkParse) .use(frontmatter) .use(custom_parser_plugin_1.customParser) .parse(markdown); } markdown_1.parse = parse; function stringify(tree) { var _a; tree.children = (_a = tree.children) !== null && _a !== void 0 ? _a : []; return unified().use(remarkStringify, stringifyOptions) .use(frontmatter) .use(custom_compiler_plugin_1.customCompiler) .stringify(tree) .replace(/ /g, '&nbsp;') .replace(/[ \t]+$/g, '') // 无法完美处理 list-item-visitor 出现两个空行或者少一个空行的问题,因此只好在这里做后期替换 .replace(/\n\n\n+/g, '\n\n') .trim(); } markdown_1.stringify = stringify; function toHtml(textOrAst) { var text; if (typeof textOrAst === 'string') { text = textOrAst; } else { text = stringify(textOrAst).replace(/^<p>([\s\S]*?)<\/p>$/gi, '$1'); } return unified().use(remarkParse) .use(frontmatter) .use(custom_parser_plugin_1.customParser) .use(remarkRehype, { handlers: mast_to_hast_handlers_1.mastToHastHandlers }) .use(rehypeStringify, { closeSelfClosing: true }) .processSync(text).contents.toString(); } markdown_1.toHtml = toHtml; function fromHtml(html) { return parse(mdFromHtml(html)); } markdown_1.fromHtml = fromHtml; function mdToHtml(md) { return toHtml(md); } markdown_1.mdToHtml = mdToHtml; function mdFromHtml(html) { if (!html) { return html; } return unified().use(rehypeParse) .use(rehypeRemark, { handlers: hast_to_mast_handlers_1.hastToMastHandlers }) .use(remarkStringify, stringifyOptions) .use(custom_compiler_plugin_1.customCompiler) .processSync(html).contents.toString().trim(); } markdown_1.mdFromHtml = mdFromHtml; function normalize(text) { return stringify(parse(text)); } markdown_1.normalize = normalize; function nodeContainsChinese(node) { if (!node) { return false; } if (isLiteral(node)) { return (0, common_1.containsChinese)(node.value); } else if (isLink(node)) { return (0, common_1.containsChinese)(node.title); } else if (isLinkReference(node)) { return (0, common_1.containsChinese)(node.label); } else if (['htmlRaw', 'anchor'].includes(node.type)) { return false; } else if (isParent(node)) { return node.children.some(function (it) { return nodeContainsChinese(it); }); } else { console.warn('nodeContainsChinese: unknown node type:', node.type); return (0, common_1.containsChinese)(contentOf(node)); } } markdown_1.nodeContainsChinese = nodeContainsChinese; var stringifyOptions = { emphasis: '*', listItemIndent: 1, incrementListMarker: false, stringLength: stringWidth, paddedTable: true, fences: true, entities: false, }; function visit(node, parent, visitor) { if (isYaml(node)) { return handleFrontMatter(node, visitor); } else if (isTable(node)) { return handleTable(node, visitor); } else if (isTranslatableUnit(node) && !nodeContainsChinese(node)) { return handleParagraphAndHeadings(node, parent, visitor); } else if (isParent(node)) { return Promise.all(node.children.map(function (it) { return visit(it, node, visitor); })).then(function () { return node; }); } } markdown_1.visit = visit; function handleFrontMatter(yaml, visitor) { var frontMatter = (0, js_yaml_1.safeLoad)(yaml.value) || {}; var entries = Object.entries(frontMatter); var tasks = entries.map(function (_a) { var key = _a[0], value = _a[1]; if (key.endsWith('$$origin')) { // 忽略保存的原文 return; } if ((0, common_1.containsChinese)(value)) { return visitor(frontMatter["".concat(key, "$$origin")], value).then(function (result) { if (result && (0, common_1.containsChinese)(result) && result !== value) { frontMatter[key] = result; } }); } else { return visitor(value, undefined).then(function (result) { if (result && (0, common_1.containsChinese)(result)) { frontMatter[key] = result; frontMatter["".concat(key, "$$origin")] = value; } }); } }); return Promise.all(tasks.filter(function (it) { return !!it; })).then(function () { yaml.value = (0, js_yaml_1.safeDump)(frontMatter); return yaml; }); } function handleTable(table, visitor) { var tasks = []; var _loop_1 = function (rowIndex) { var originalRow = table.children[rowIndex]; var translationRow = table.children[rowIndex + 1]; // 原文和译文按行进行对照,只需要处理原文行,译文行是被动处理的 if (!nodeContainsChinese(originalRow)) { // 有译文行时要提取译文行,没有译文行时要插入译文行 if (nodeContainsChinese(translationRow)) { console.assert(originalRow.children.length === translationRow.children.length); var _loop_2 = function (colIndex) { var originalCell = originalRow.children[colIndex]; var translationCell = translationRow.children[colIndex]; var originalText = stringify(originalCell); var translationText = stringify(translationCell); tasks.push(visitor(originalText, translationText).then(function (result) { if (result && (0, common_1.containsChinese)(result) && result !== translationText) { translationCell.children = parseCellContent(result); } })); }; for (var colIndex = 0; colIndex < originalRow.children.length; colIndex++) { _loop_2(colIndex); } } else { var translationRow_1; var _loop_3 = function (colIndex) { var originalCell = originalRow.children[colIndex]; var originalText = stringify(originalCell); tasks.push(visitor(originalText, undefined).then(function (result) { if (result && (0, common_1.containsChinese)(result)) { if (!translationRow_1) { translationRow_1 = (0, lodash_1.cloneDeep)(originalRow); table.children.splice(rowIndex + 1, 0, translationRow_1); } var translationCell = translationRow_1.children[colIndex]; translationCell.children = parseCellContent(result); } })); }; for (var colIndex = 0; colIndex < originalRow.children.length; colIndex++) { _loop_3(colIndex); } } } }; // 倒序循环,以免插入的新节点影响循环本身 for (var rowIndex = table.children.length - 1; rowIndex >= 0; --rowIndex) { _loop_1(rowIndex); } return Promise.all(tasks).then(function () { return table; }); function parseCellContent(result) { var paragraph = parse(result).children[0]; return paragraph.children; } } function handleParagraphAndHeadings(originalNode, parent, visitor) { // 我们要处理的所有节点都必须是 Parent,因为它至少也会包含一个 text 子节点 var index = parent.children.indexOf(originalNode); var translationNode = parent.children[index + 1]; var originalText = contentOf(originalNode); if (translationNode && originalNode.type === translationNode.type && nodeContainsChinese(translationNode)) { var translationText_1 = contentOf(translationNode); return visitor(originalText, translationText_1).then(function (result) { if (!result || !(0, common_1.containsChinese)(result) || result === translationText_1) { return translationNode; } applyTranslation(translationNode, result); return translationNode; }); } else { return visitor(originalText, undefined).then(function (result) { if (!result || !(0, common_1.containsChinese)(result)) { return originalNode; } var translationNode = createAndInsertTranslation(parent, originalNode); applyTranslation(translationNode, result); return translationNode; }); } function applyTranslation(translationNode, result) { if (isListItem(parent)) { // 如果是 listItem 被翻译了,则需要扩展成阔表模式,以便容纳两个段落 parent.spread = true; } var translation = parse(result).children[0]; Object.assign(translationNode, translation, { type: originalNode.type }); } function createAndInsertTranslation(parent, original) { var node = (0, lodash_1.cloneDeep)(original); var index = parent.children.indexOf(original); parent.children.splice(index + 1, 0, node); return node; } } function contentOf(node) { if (!node) { return; } var cloned = (0, lodash_1.cloneDeep)(node); cloned.type = 'paragraph'; return stringify(cloned); } })(markdown = exports.markdown || (exports.markdown = {})); //# sourceMappingURL=markdown.js.map