Traductor Plus 3.0!

Traduce el texto seleccionado usando la API gratuita de Google Translate y muestra los resultados de manera mejorada con opciones de color personalizadas y configuración de idioma.

// ==UserScript==
// @name         Traductor Plus 3.0!
// @namespace    https://greasyfork.org/es/scripts/486611-traductor-plus-3-0
// @version      0.2
// @icon         data:image/png;base64,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
// @description  Traduce el texto seleccionado usando la API gratuita de Google Translate y muestra los resultados de manera mejorada con opciones de color personalizadas y configuración de idioma.
// @author       PutoElQueLoLea
// @match        *://*/*
// @grant        GM_addStyle
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @license      GPL-3.0-or-later

// ==/UserScript==

(function () {
    'use strict';

    const languages = {
        "Afrikáans": "af",
        "Albanés": "sq",
        "Alemán": "de",
        "Amhárico": "am",
        "Árabe": "ar",
        "Armenio": "hy",
        "Azerbaiyano": "az",
        "Bengalí": "bn",
        "Bielorruso": "be",
        "Birmano": "my",
        "Bosnia": "bs",
        "Búlgaro": "bg",
        "Canarés": "kn",
        "Catalán": "ca",
        "Cebuano": "ceb",
        "Checo": "cs",
        "Chichewa": "ny",
        "Chino simplificado": "zh-CN",
        "Chino tradicional": "zh-TW",
        "Cingalés": "si",
        "Coreano": "ko",
        "Corso": "co",
        "Criollo haitiano": "ht",
        "Croata": "hr",
        "Danés": "da",
        "Eslovaco": "sk",
        "Esloveno": "sl",
        "Español": "es",
        "Esperanto": "eo",
        "Estonio": "et",
        "Euskera": "eu",
        "Finés": "fi",
        "Francés": "fr",
        "Frisón occidental": "fy",
        "Gaélico escocés": "gd",
        "Galés": "cy",
        "Gallego": "gl",
        "Georgiano": "ka",
        "Griego": "el",
        "Gujarati": "gu",
        "Hausa": "ha",
        "Hawaiano": "haw",
        "Hebreo": "iw",
        "Hindi": "hi",
        "Hmong": "hmn",
        "Holandés": "nl",
        "Húngaro": "hu",
        "Igbo": "ig",
        "Indonesio": "id",
        "Inglés": "en",
        "Irlandés": "ga",
        "Islandés": "is",
        "Italiano": "it",
        "Japonés": "ja",
        "Javanés": "jw",
        "Kazajo": "kk",
        "Kirguís": "ky",
        "Kurdo": "ku",
        "Laosiano": "lo",
        "Latín": "la",
        "Letón": "lv",
        "Lituano": "lt",
        "Luxemburgués": "lb",
        "Macedonio": "mk",
        "Malayo": "ms",
        "Malayalam": "ml",
        "Malgache": "mg",
        "Maltés": "mt",
        "Maorí": "mi",
        "Maratí": "mr",
        "Mongol": "mn",
        "Neerlandés": "nl",
        "Nepalí": "ne",
        "Noruego": "no",
        "Panyabí": "pa",
        "Pastún": "ps",
        "Persa": "fa",
        "Polaco": "pl",
        "Portugués": "pt",
        "Rumano": "ro",
        "Ruso": "ru",
        "Samoano": "sm",
        "Serbio": "sr",
        "Sesoto": "st",
        "Shona": "sn",
        "Sindi": "sd",
        "Somalí": "so",
        "Suajili": "sw",
        "Sueco": "sv",
        "Sundanés": "su",
        "Tagalo": "tl",
        "Tailandés": "th",
        "Tamil": "ta",
        "Tayiko": "tg",
        "Telugu": "te",
        "Turco": "tr",
        "Ucraniano": "uk",
        "Urdu": "ur",
        "Uzbeco": "uz",
        "Vietnamita": "vi",
        "Xhosa": "xh",
        "Yidis": "yi",
        "Yoruba": "yo",
        "Zulú": "zu"
    };

    let selectedTextCache = '';
    let translationBox = null;

    let selectedBackgroundColor = GM_getValue('selectedBackgroundColor', '#333');
    let selectedTextColor = GM_getValue('selectedTextColor', 'white');
    let targetLanguage = GM_getValue('config', { targetLanguage: 'es' }).targetLanguage;

    function translateText(text, targetLang) {
        return new Promise((resolve, reject) => {
            const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=${targetLang}&dt=t&q=${encodeURI(text)}`;

            fetch(url)
                .then(response => response.json())
                .then(data => {
                    const translatedText = data[0].map(sentence => sentence[0]).join(' '); // Unimos las traducciones individuales
                    resolve(translatedText);
                })
                .catch(error => {
                    reject(error);
                });
        });
    }

    function createTranslationBox(translatedText) {
        translationBox = document.createElement('div');
        translationBox.style.position = 'fixed';
        translationBox.style.top = '50%';
        translationBox.style.left = '50%';
        translationBox.style.transform = 'translate(-50%, -50%)';
        translationBox.style.padding = '20px';
        translationBox.style.background = selectedBackgroundColor;
        translationBox.style.color = selectedTextColor;
        translationBox.style.borderRadius = '10px';
        translationBox.textContent = translatedText;

        document.body.appendChild(translationBox);
    }

    function clearSelection() {
        selectedTextCache = '';
        if (translationBox) {
            translationBox.remove();
            translationBox = null;
        }
    }

    document.addEventListener('mouseup', async function () {
        let selectedText = window.getSelection().toString().trim();
        if (selectedText !== '') {
            selectedTextCache += selectedText + ';';

            try {
                const translatedText = await translateText(selectedTextCache, targetLanguage);

                // Guardar colores seleccionados
                saveColors();

                createTranslationBox(translatedText);
            } catch (error) {
                console.error('Error al traducir:', error);
            }
        }
    });

    document.addEventListener('click', clearSelection);

    // Configurador de colores y idioma
    GM_registerMenuCommand('Configurar Colores e Idioma', openConfigDialog);

    function openConfigDialog() {
        // Crear la ventana emergente
        const configDialog = document.createElement('div');
        configDialog.id = 'config-dialog';
        configDialog.innerHTML = `
            <h3>Configuración del traductor</h3>
            <div>
                Seleccione color de Fondo:
                <input type="color" id="color-picker-background" value="${selectedBackgroundColor}">
            </div></p></p>
            <div>
                Seleccione color de Texto:
                <input type="color" id="color-picker-text" value="${selectedTextColor}">
            </div></p></p>
            <div>
                <label for="languageList">Seleccione el idioma de traducción:</label><br>
               <center> <select id="languageList"></select></p>
            </div>
           <center> <button id="btnAceptar">Aceptar</button>
            <button id="btnCancelar">Cancelar</button></center>
        `;

        // Agregar opciones de idiomas al listbox
        const languageList = configDialog.querySelector('#languageList');
        for (const language in languages) {
            const option = document.createElement('option');
            option.value = languages[language];
            option.text = language;
            languageList.add(option);
        }

        // Establecer el idioma seleccionado en la configuración actual
        languageList.value = targetLanguage;

        // Establecer estilos
        GM_addStyle(`
            #config-dialog {
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                padding: 20px;
                background: #333;
                color: #FFF;
                border: 2px solid #000;
                border-radius: 25px;
                box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
                z-index: 9999;
            }

            #btnAceptar, #btnCancelar {
                margin-top: 10px;
                padding: 5px 10px;
                cursor: pointer;
                border-radius: 25px;
            }

            #btnAceptar {
                background: #005200;
                color: #fff;
                border: none;
                margin-right: 10px;
            }

            #btnCancelar {
                background: #99c599;
                color: #fff;
                border: none;
            }
        `);

        // Agregar la ventana emergente al cuerpo del documento
        document.body.appendChild(configDialog);

        // Añadir eventos a los botones
        const btnAceptar = document.getElementById('btnAceptar');
        btnAceptar.addEventListener('click', () => {
            // Guardar la configuración
            targetLanguage = languageList.value;
            GM_setValue('config', { targetLanguage: targetLanguage });
            closeConfigDialog(); // Cierra la ventana después de aceptar
            // Actualizar colores en el cuadro de traducción
            updateTranslationBoxColors();
        });

        const btnCancelar = document.getElementById('btnCancelar');
        btnCancelar.addEventListener('click', () => {
            closeConfigDialog(); // Cierra la ventana después de cancelar
        });

        // Añadir evento onchange al selector de color de fondo para actualizar el color del cuadro
        const colorPickerBackground = document.getElementById('color-picker-background');
        colorPickerBackground.addEventListener('input', updateColorBackground);

        // Añadir evento onchange al selector de color de texto para actualizar el color del cuadro
        const colorPickerText = document.getElementById('color-picker-text');
        colorPickerText.addEventListener('input', updateColorText);
    }

    function closeConfigDialog() {
        // Eliminar la ventana emergente del cuerpo del documento
        const configDialog = document.getElementById('config-dialog');
        if (configDialog) {
            configDialog.remove();
        }
    }

    function updateColorBackground() {
        const colorPickerBackground = document.getElementById('color-picker-background');
        selectedBackgroundColor = colorPickerBackground.value;
    }

    function updateColorText() {
        const colorPickerText = document.getElementById('color-picker-text');
        selectedTextColor = colorPickerText.value;
    }

    function updateTranslationBoxColors() {
        if (translationBox) {
            translationBox.style.background = selectedBackgroundColor;
            translationBox.style.color = selectedTextColor;
        }
    }

    function saveColors() {
        GM_setValue('selectedBackgroundColor', selectedBackgroundColor);
        GM_setValue('selectedTextColor', selectedTextColor);
    }

    // Actualizar colores en el cuadro de traducción al inicio
    updateTranslationBoxColors();
})();