From a7509c4a35422e50c6b88f204c2bf5a5f3d9c238 Mon Sep 17 00:00:00 2001 From: sub-hub Date: Sat, 4 May 2024 22:44:28 +0900 Subject: [PATCH] Add: Sentence html Merge Translation Feature --- src/ts/translator/translator.ts | 63 +++++++++++++++++++++++++++++++-- src/ts/util.ts | 28 +++++++++++++++ 2 files changed, 88 insertions(+), 3 deletions(-) diff --git a/src/ts/translator/translator.ts b/src/ts/translator/translator.ts index ed0f7fbe..e9f15e5d 100644 --- a/src/ts/translator/translator.ts +++ b/src/ts/translator/translator.ts @@ -8,7 +8,8 @@ import { doingChat } from "../process" import type { simpleCharacterArgument } from "../parser" import { selectedCharID } from "../stores" import { getModuleRegexScripts } from "../process/modules" -import { sleep } from "../util" +import { getNodetextWithNewline, sleep } from "../util" +import { processScriptFull } from "../process/scripts" let cache={ origin: [''], @@ -298,7 +299,7 @@ export async function translateHTML(html: string, reverse:boolean, charArg:simpl } - async function translateNodeText(node:Node) { + async function translateNodeText(node:Node, reapplyDisplayScript:boolean = false) { if(node.textContent.trim().length !== 0){ if(needSuperChunkedTranslate()){ const prm = new Promise((resolve) => { @@ -311,7 +312,32 @@ export async function translateHTML(html: string, reverse:boolean, charArg:simpl return } - node.textContent = await translate(node.textContent || '', reverse); + // node.textContent = await translate(node.textContent || '', reverse); + let translated = await translate(node.textContent || "", reverse); + if (!reapplyDisplayScript) { + node.textContent = translated; + return; + } + + const { data: processedTranslated } = await processScriptFull( + alwaysExistChar, + translated, + "editdisplay", + chatID + ); + + // If the translation is the same, don't replace the node + if (translated == processedTranslated) { + node.textContent = processedTranslated; + return; + } + + // Replace the old node with the new one + const newNode = document.createElement( + node.nodeType === Node.TEXT_NODE ? "span" : node.nodeName + ); + newNode.innerHTML = processedTranslated; + node.parentNode.replaceChild(newNode, node); } } @@ -336,6 +362,37 @@ export async function translateHTML(html: string, reverse:boolean, charArg:simpl if(node.nodeName.toLowerCase() === 'script' || node.nodeName.toLowerCase() === 'style'){ return } + // Check If a paragraph is a set of pure sentences + if ( + node.nodeName.toLowerCase() === "p" && + node instanceof HTMLElement + ) { + const children = Array.from(node.childNodes); + const blacklist = ["img", "iframe", "script", "style", "div"]; + const hasBlacklistChild = children.some((child) => + blacklist.includes(child.nodeName.toLowerCase()) + ); + if (!hasBlacklistChild) { + const text = getNodetextWithNewline(node); + const sentences = text.split("\n"); + if (sentences.length > 1) { + // Multiple sentences seperated by
tags + // reconstruct the p tag + node.innerHTML = ""; + for (const sentence of sentences) { + const newNode = document.createElement("span"); + newNode.textContent = sentence; + node.appendChild(newNode); + await translateNodeText(newNode, true); + node.appendChild(document.createElement("br")); + } + } else { + // Single sentence + await translateNodeText(node, true); + } + return; + } + } for (const child of Array.from(node.childNodes)) { if(node.nodeType === Node.ELEMENT_NODE && (node as Element)?.getAttribute('translate') === 'no'){ diff --git a/src/ts/util.ts b/src/ts/util.ts index 8c74681c..c3a596f3 100644 --- a/src/ts/util.ts +++ b/src/ts/util.ts @@ -522,4 +522,32 @@ export function appendLastPath(url, lastPath) { // Concat the url and lastPath return url + '/' + lastPath; +} + +/** + * Retrieves the text content of a given Node object, including line breaks represented by
elements. + * + * @param {Node} node - The Node object from which the text content will be extracted. + * @returns {string} The text content of the Node, with line breaks represented by newline characters ('\n'). + * + * @example + * const div = document.createElement('div'); + * div.innerHTML = 'Hello
World'; + * const text = getNodetextWithNewline(div); + * console.log(text); // Output: "Hello\nWorld" + */ +export function getNodetextWithNewline(node: Node) { + let result = ''; + for (const child of node.childNodes) { + if (child.nodeType === Node.TEXT_NODE) { + result += child.textContent; + } else if (child.nodeType === Node.ELEMENT_NODE) { + if (child.nodeName === 'BR') { + result += '\n'; + } else { + result += getNodetextWithNewline(child); + } + } + } + return result; } \ No newline at end of file