Persistent Translator Tooltip with Sidebar and Local Storage

Translate words on click, show in a tooltip, add to a sidebar list, and store in local storage

当前为 2023-12-06 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Persistent Translator Tooltip with Sidebar and Local Storage
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Translate words on click, show in a tooltip, add to a sidebar list, and store in local storage
// @include      *://*/*
// @grant        GM_xmlhttpRequest
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // Add CSS for the tooltip, sidebar, clear button, and entry layout
    const styleElement = document.createElement('style');
    styleElement.type = 'text/css';
    styleElement.innerHTML = `
        .translator-tooltip {
            font-weight: 700;
            color: #000000;
            position: absolute;
            z-index: 10000;
            padding: 2px;
            max-width: 300px;
            border-radius: 0.3em;
            background-color: #ffffdb;
            border: 1px solid #ccc;
            box-shadow: 0 2px 4px rgba(0,0,0,0.2);
            text-align: center;
            font-size: 18px;
            line-height: 1.2;
            visibility: hidden;
            opacity: 0;
            transition: visibility 0s linear 300ms, opacity 300ms;
        }

        .translator-tooltip.visible {
            visibility: visible;
            opacity: 1;
        }

        .translator-sidebar {
            position: fixed;
            top: 0;
            right: 0;
            width: 250px;
            height: 100%;
            background-color: #ffffdb;
            overflow-y: auto;
            border-left: 1px solid #ccc;
            padding: 10px;
            z-index: 10000;
            font-size: 16px;
        }

        .translator-entry {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 5px;
        }

        .translator-entry span:first-child {
            flex: 1;
            text-align: left;
        }

        .translator-entry span:last-child {
            flex: 1;
            text-align: right;
        }

        .translator-entry hr {
            width: 100%;
            margin-top: 5px;
        }

        .clear-button {
            position: fixed;
            bottom: 20px;
            right: 20px;
            z-index: 10001;
            cursor: pointer;
            padding: 5px 10px;
            background-color: #f5f5f5;
            border: 1px solid #ccc;
            border-radius: 5px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.2);
            font-size: 16px;
        }
    `;
    document.head.appendChild(styleElement);

    // Create tooltip element
    const tooltip = document.createElement('div');
    tooltip.className = 'translator-tooltip';
    document.body.appendChild(tooltip);

    // Create sidebar element
    const sidebar = document.createElement('div');
    sidebar.className = 'translator-sidebar';
    document.body.appendChild(sidebar);

    // Create clear button element
    const clearButton = document.createElement('button');
    clearButton.innerHTML = '🗑️ Clear Translations';
    clearButton.className = 'clear-button';
    document.body.appendChild(clearButton);

    // Function to show the tooltip
    function showTooltip(text, x, y) {
        tooltip.textContent = text;
        tooltip.style.left = `${x}px`;
        tooltip.style.top = `${y - 30}px`;
        tooltip.classList.add('visible');
    }

    // Function to hide the tooltip
    function hideTooltip() {
        tooltip.classList.remove('visible');
    }

    // Function to add word to sidebar list and store in local storage
    function addToSidebar(originalWord, translatedWord) {
        const entry = document.createElement('div');
        entry.className = 'translator-entry';
        entry.innerHTML = `
            <span>${originalWord}</span>
            <span>${translatedWord}</span>
        `;

        sidebar.appendChild(entry);

        // Add a horizontal line after each entry
        const separator = document.createElement('hr');
        sidebar.appendChild(separator);

        // Store in local storage
        const translations = JSON.parse(localStorage.getItem('translations') || '{}');
        translations[originalWord] = translatedWord;
        localStorage.setItem('translations', JSON.stringify(translations));
    }

    // Function to translate word
    function translateWord(word, x, y) {
        GM_xmlhttpRequest({
            method: "GET",
            url: "https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=fa&dj=1&dt=t&dt=rm&q=" + encodeURIComponent(word),
            onload: function(response) {
                const data = JSON.parse(response.responseText);
                const translatedText = data.sentences[0].trans;
                showTooltip(translatedText, x, y);
                addToSidebar(word, translatedText);
            }
        });
    }

    // Load translations from local storage and add to sidebar
    function loadTranslations() {
        const translations = JSON.parse(localStorage.getItem('translations') || '{}');
        Object.keys(translations).forEach(word => {
            const translatedWord = translations[word];
            if (typeof translatedWord === 'string') {
                const entry = document.createElement('div');
                entry.className = 'translator-entry';
                entry.innerHTML = `
                    <span>${word}</span>
                    <span>${translatedWord}</span>
                `;
                sidebar.appendChild(entry);

                // Add a horizontal line after each entry
                const separator = document.createElement('hr');
                sidebar.appendChild(separator);
            }
        });
    }

    // Function to clear translations from sidebar and local storage
    function clearTranslations() {
        sidebar.innerHTML = '';
        localStorage.removeItem('translations');
    }

    // Event listener for clear button
    clearButton.addEventListener('click', function() {
        clearTranslations();
    });

// Event listener for mouseup to detect text selection
document.addEventListener('mouseup', function(event) {
    const selection = window.getSelection().toString().trim();
    if (selection) { // Remove the condition that checks for a single word
        const rect = window.getSelection().getRangeAt(0).getBoundingClientRect();
        translateWord(selection, rect.left + window.scrollX, rect.top + window.scrollY);
    }
});

    // Event listener to hide tooltip when clicking anywhere on the page
    document.addEventListener('mousedown', function(event) {
        if (!tooltip.contains(event.target)) {
            hideTooltip();
        }
    }, true);

    // Load stored translations on page load
    loadTranslations();
})();