// ==UserScript== // @name 悬停翻译句子 // @namespace http://tampermonkey.net/ // @version 1.1 // @description 鼠标悬停自动翻译句子 // @author pipizhu // @match http*://*/* // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @license MIT // @downloadURL none // ==/UserScript== // Function to segment the text into sentences and wrap them in span tags with a green hover border color function wrapTextNodes(parent) { // Create a document fragment to hold the new structure const fragment = document.createDocumentFragment(); // Loop through child nodes while (parent.firstChild) { const child = parent.firstChild; if (child.nodeType === Node.TEXT_NODE) { // If the child is a text node, wrap each sentence const sentences = child.textContent.split(/(?<=\.)/); if (sentences) { sentences.forEach((sentence) => { const span = document.createElement("span"); span.className = "sentence"; span.textContent = sentence; fragment.appendChild(span); fragment.appendChild(document.createTextNode(" ")); // Add space between sentences }); } else { fragment.appendChild(child.cloneNode(true)); // Preserve text if no sentences found } } else if (child.nodeType === Node.ELEMENT_NODE) { // If the child is an element, recurse into it // // Handle element nodes (like tags) const newElement = document.createElement(child.tagName.toLowerCase()); newElement.innerHTML = child.innerHTML; // Copy attributes from the original element for (const attr of child.attributes) { newElement.setAttribute(attr.name, attr.value); } // Recursively process child nodes // newElement.appendChild(processNode(child)); fragment.appendChild(newElement); } // Remove the processed child node parent.removeChild(child); } // Return the wrapped structure return fragment; } // Get all

tags on the page const paragraphs = document.querySelectorAll("p"); // Iterate through each

tag paragraphs.forEach((paragraph) => { paragraph.appendChild(wrapTextNodes(paragraph)); }); // Add a style element to the document head for the hover effect const style = document.createElement("style"); style.innerHTML = ` .sentence { position: relative; transition: border-bottom-color 0.3s ease; cursor: pointer; } .sentence:hover { border-bottom: 2px solid #32CD32; /* Beautiful green */ } .t-popover { position: absolute; color: black; top: 100%; width: 100%; left: 0; min-width: 300px; background-color: #fff; padding: 5px 10px; border: 1px solid #ccc; border-radius: 3px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); z-index: 1000; transform: translateY(10px); display: none; } .sentence:hover .t-popover { display: block; } `; document.head.appendChild(style); // Apply the hover effect and translation using JavaScript document.querySelectorAll(".sentence").forEach((span) => { const greenColor = "#32CD32"; // Beautiful green color // Create a popover element const popover = document.createElement("div"); popover.className = "t-popover"; span.appendChild(popover); span.addEventListener("mouseover", function () { this.style.borderBottomColor = greenColor; // Check if the popover already contains translated text if (popover.innerText.trim() !== "") { return; // If it does, do nothing } // Get the original text const originalText = this.innerText; console.log("span", this.innerText); translateText(originalText, "zh") .then((data) => { console.log("result ", data); // Show the translated text in the popover popover.innerText = data; }) .catch((error) => { popover.innerText = "Translation failed"; console.error("Error:", error); }); }); span.addEventListener("mouseout", function () { this.style.borderBottomColor = "transparent"; }); }); const translateText = async (text, targetLanguage) => { return googleTranslate(text, targetLanguage); const url = `https://api.mymemory.translated.net/get?q=${encodeURIComponent( text, )}&langpair=en|${targetLanguage}&de=test@gmail.com`; try { const response = await fetch(url); if (!response.ok) { throw new Error("Network response was not ok"); } const result = await response.json(); const responseData = result.responseData; console.log("Translated Text:", result.responseData.translatedText); return responseData.translatedText; } catch (error) { console.error("There was a problem with the fetch operation:", error); } }; const googleTranslate = async (text, targetLanguage) => { try { const url = `https://translate.googleapis.com/translate_a/t?client=gtx&sl=en&tl=${targetLanguage}&dt=t&q=${encodeURIComponent(text)}&format=html`; const response = await fetch(url, { method: "POST", }); const data = await response.json(); return data[0]; } catch (error) { console.error("There was a problem with the fetch operation:", error); } };