Google Auto Translate (Multilingual + Inline Translation)

Auto-translates pages using an iframe overlay and inline Google Translate.

目前为 2025-03-10 提交的版本。查看 最新版本

// ==UserScript==
// @name         Google Auto Translate (Multilingual + Inline Translation)
// @namespace    https://greasyfork.org/en/users/1030895-universedev
// @author      UniverseDev
// @license     GPL-3.0-or-later
// @version      1.1
// @description  Auto-translates pages using an iframe overlay and inline Google Translate.
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function () {
    "use strict";

    const STORAGE_KEY = "userTranslateLang";
    const DEFAULT_LANG = "en";

    const getUserLanguage = () => localStorage.getItem(STORAGE_KEY) || DEFAULT_LANG;

    const setUserLanguage = (lang) => {
        localStorage.setItem(STORAGE_KEY, lang);
        location.reload();
    };

    const detectPageLanguage = () =>
        document.documentElement.lang || document.querySelector("html")?.getAttribute("lang") || null;

    const isAlreadyTranslated = () => {
        return document.querySelector("body").classList.contains("translated-ltr") ||
               document.querySelector("body").classList.contains("translated-rtl");
    };

    const canEmbedIframe = (url) => {
        const iframe = document.createElement("iframe");
        iframe.style.display = "none";
        iframe.src = url;

        return new Promise((resolve, reject) => {
            iframe.onload = () => resolve(true);
            iframe.onerror = () => reject(false);

            document.body.appendChild(iframe);

            setTimeout(() => {
                document.body.removeChild(iframe);
            }, 2000);
        });
    };

    const createTranslateOverlay = async (targetLang) => {
        const pageLang = detectPageLanguage();
        if (pageLang && pageLang.toLowerCase() === targetLang.toLowerCase()) {
            return;
        }

        const translateUrl = `https://translate.google.com/translate?hl=${targetLang}&sl=auto&tl=${targetLang}&u=${encodeURIComponent(location.href)}`;

        const canEmbed = await canEmbedIframe(translateUrl);
        if (!canEmbed) {
            return;
        }

        if (document.getElementById("googleTranslateIframe")) return;
        const iframe = document.createElement("iframe");
        iframe.id = "googleTranslateIframe";
        iframe.src = translateUrl;
        Object.assign(iframe.style, {
            position: "fixed",
            top: 0,
            left: 0,
            width: "100vw",
            height: "100vh",
            border: "none",
            zIndex: 99999,
            backgroundColor: "#fff",
            visibility: "hidden",  // Hide initially
        });
        document.body.appendChild(iframe);

        iframe.onload = () => iframe.style.visibility = "hidden";  // Hide iframe after translation
    };

    const insertGoogleTranslateWidget = () => {
        if (document.querySelector("script[src*='translate_a/element.js']")) {
            return;
        }

        const translateDiv = document.createElement("div");
        translateDiv.id = "google_translate_element";
        Object.assign(translateDiv.style, {
            position: "fixed",
            bottom: "10px",
            right: "10px",
            zIndex: 100000,
            visibility: "hidden",  // Hide initially
        });
        document.body.appendChild(translateDiv);

        const script = document.createElement("script");
        script.src = "//translate.google.com/translate_a/element.js?cb=googleTranslateInit";
        document.body.appendChild(script);

        script.onload = () => translateDiv.style.visibility = "hidden";  // Hide widget after translation
    };

    window.googleTranslateInit = () => {
        new google.translate.TranslateElement(
            { pageLanguage: "auto", includedLanguages: getUserLanguage(), autoDisplay: true, multilanguagePage: true },
            "google_translate_element"
        );

        const targetLang = getUserLanguage();
        const iframe = document.querySelector("iframe.goog-te-banner-frame");
        if (iframe) {
            const iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
            const langSelect = iframeDocument.querySelector("select.goog-te-combo");
            if (langSelect) {
                langSelect.value = targetLang;
                langSelect.dispatchEvent(new Event("change"));
            }
        }
    };

    const autoTranslateIfNeeded = async () => {
        const targetLang = getUserLanguage();
        const pageLang = detectPageLanguage();

        if (document.readyState === "complete" && (!pageLang || pageLang.toLowerCase() !== targetLang.toLowerCase()) && !isAlreadyTranslated()) {
            await createTranslateOverlay(targetLang);
        } else {
            await insertGoogleTranslateWidget();
        }
    };

    setTimeout(autoTranslateIfNeeded, 1000);
    window.addEventListener("load", autoTranslateIfNeeded);
})();