WhatsApp Translator

Translate selected WhatsApp messages

// ==UserScript==
// @name         WhatsApp Translator
// @name:zh-CN   WhatsApp 翻译器
// @namespace    http://tampermonkey.net/
// @version      1.4.0
// @description  Translate selected WhatsApp messages
// @description:zh-CN 将 WhatsApp 选中的文本翻译成中文
// @author       HeT
// @match        https://web.whatsapp.com/*
// @grant        GM_xmlhttpRequest
// @connect      translator-api-lovat.vercel.app
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const targetLang = 'en'; // 默认翻译成英文
    const serverUrl = 'https://translator-api-lovat.vercel.app/api/translate';

    document.body.addEventListener('click', function (e) {
        const bubble = e.target.closest('.message-in, .message-out');
        if (!bubble) return;

        const messageTextElement = bubble.querySelector('span.selectable-text');
        if (!messageTextElement) return;

        const originalText = messageTextElement.innerText.trim();
        if (!originalText) return;

        translate(originalText, false, (translated) => {
            if (translated) {
                messageTextElement.innerText = translated;
            }
        });
    });

// ========== 1. 添加翻译输入框 ==========
    function addTranslateBox() {
        const chatFooter = document.querySelector('footer');
        if (!chatFooter || document.getElementById('translator-input')) return;

        const translateBox = document.createElement('textarea');
        translateBox.id = 'translator-input';
        translateBox.placeholder = '在这里输入中文,然后猛敲回车键会翻译成英文并填充上方输入框...';
        translateBox.style.width = '100%';
        translateBox.style.height = '40px';
        translateBox.style.marginTop = '5px';
        translateBox.style.padding = '5px';
        translateBox.style.border = '1px solid #ccc';
        translateBox.style.borderRadius = '6px';
        translateBox.style.resize = 'none';

        chatFooter.appendChild(translateBox);

        // ========== 3. 回车事件 ==========
        translateBox.addEventListener('keydown', (e) => {
            if (e.key === 'Enter') {
                if (e.ctrlKey) {
                    // Ctrl+Enter 换行
                    e.preventDefault();
                    const start = translateBox.selectionStart;
                    const end = translateBox.selectionEnd;
                    translateBox.value =
                        translateBox.value.substring(0, start) + "\n" + translateBox.value.substring(end);
                    translateBox.selectionStart = translateBox.selectionEnd = start + 1;
                } else {
                    e.preventDefault();
                    const text = translateBox.value.trim();
                    if (!text) return;

                    translate(text, true, (translated) => {
                        if (translated) {
                            fillWhatsAppInput(translated); 
                            translateBox.value = ''; // 清空下方输入框
                        }
                    });
                }
            }
        });
    }


    function getWAInput() {
        return document.querySelector('[data-testid="conversation-compose-box-input"]')
        || document.querySelector('footer div[contenteditable="true"][role="textbox"]')
        || document.querySelector('footer [contenteditable="true"][data-tab]');
    }

    // 将翻译后的英文填充到 WhatsApp 输入框
    function fillWhatsAppInput(text) {
        const waInput = getWAInput();
        const translatorBox = document.getElementById('translator-input');
        if (!waInput) return;

        // 聚焦输入框
        waInput.focus();


        // 插入新的文本
        const ok = document.execCommand('insertText', false, text);

        // 如果 execCommand 失败,则用 fallback
        if (!ok) {
            waInput.textContent = text;
        }

        // 聚焦回下方翻译框,方便继续输入中文
        if (translatorBox) {
            setTimeout(() => translatorBox.focus(), 0);
        }
    }



    function translate(text, isInput, callback) {
        GM_xmlhttpRequest({
            method: 'POST',
            url: serverUrl,
            headers: { 'Content-Type': 'application/json' },
            data: JSON.stringify({ q: text, to: isInput ? targetLang : 'zh-CHS' }),
            onload: function(response) {
                try {
                    const data = JSON.parse(response.responseText);
                    if (data.translation && data.translation.length) {
                        callback(data.translation[0]);
                    } else {
                        console.error("翻译API返回异常", data);
                        callback(null);
                    }
                } catch (e) {
                    console.error("解析返回数据失败", e, response.responseText);
                    callback(null);
                }
            },
            onerror: function(err) {
                console.error("请求失败", err);
                callback(null);
            }
        });
    }



    // ========== 入口 ==========
    setInterval(() => {
        addTranslateBox();

    }, 1000);



    // ==============================
    // 🔥 预热 API,避免第一次延迟
    // ==============================
    setTimeout(() => {
        translate("ping", () => {
        });
    }, 2000);

})();
长期地址
遇到问题?请前往 GitHub 提 Issues。