OptiTranslate

Three engines: Google, Bing, Yandex. Total coverage.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         OptiTranslate
// @namespace    com.vonkleist.optitranslate
// @version      1488
// @description  Three engines: Google, Bing, Yandex. Total coverage.
// @author       VonKleistL
// @match        *://*/*
// @run-at       document-end
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const TARGET_LANG = navigator.language.split('-')[0] || 'en';

    // Safety: Don't run on translation sites or system pages
    if (window.location.hostname.match(/(translate|googleusercontent|yandex|bing|microsoft|apple|icloud)/)) return;
    
    // Improved Language Detection
    function isPageInTargetLang() {
        const docLang = document.documentElement.lang.toLowerCase();
        const metaLang = document.querySelector('meta[http-equiv="content-language"]')?.content?.toLowerCase();
        const detected = docLang || metaLang || '';
        return detected.startsWith(TARGET_LANG);
    }

    if (isPageInTargetLang()) return;
    if (document.body.innerText.length < 100) return; // Ignore very small pages

    // --- HOST ---
    const host = document.createElement('div');
    host.id = 'opti-translate-host';
    document.documentElement.appendChild(host);
    const shadow = host.attachShadow({mode: 'open'});

    // --- STYLES ---
    const style = document.createElement('style');
    style.textContent = `
        :host {
            all: initial; 
            z-index: 2147483647;
            position: fixed;
            bottom: calc(20px + env(safe-area-inset-bottom));
            left: 50%;
            transform: translateX(-50%);
            font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", sans-serif;
            pointer-events: none;
            width: 100%;
            display: flex;
            justify-content: center;
        }
        
        .opti-panel {
            background: rgba(28, 28, 30, 0.85);
            backdrop-filter: blur(25px) saturate(200%);
            -webkit-backdrop-filter: blur(25px) saturate(200%);
            border: 0.5px solid rgba(255, 255, 255, 0.2);
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
            border-radius: 24px;
            padding: 8px;
            display: flex;
            gap: 8px;
            transform: translateY(150%);
            opacity: 0;
            transition: transform 0.6s cubic-bezier(0.23, 1, 0.32, 1), opacity 0.4s;
            pointer-events: auto;
            max-width: 90vw;
        }

        .opti-panel.visible {
            transform: translateY(0);
            opacity: 1;
        }

        .opti-btn {
            border: none;
            padding: 0 16px;
            height: 44px;
            border-radius: 18px;
            color: #fff;
            font-size: 14px;
            font-weight: 600;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: background 0.2s, transform 0.1s, box-shadow 0.2s;
            -webkit-tap-highlight-color: transparent;
        }
        
        .opti-btn:active {
            transform: scale(0.92);
            filter: brightness(1.2);
        }

        /* Google: Vibrant Blue */
        #btn-google {
            background: linear-gradient(135deg, #007AFF, #0056B3);
            box-shadow: 0 4px 12px rgba(0, 122, 255, 0.3);
        }

        /* Microsoft: Deep Teal */
        #btn-bing {
            background: linear-gradient(135deg, #32D74B, #248A3D);
            box-shadow: 0 4px 12px rgba(50, 215, 75, 0.3);
        }

        /* Yandex: Sunset Orange */
        #btn-yandex {
            background: linear-gradient(135deg, #FF9F0A, #FF3B30);
            box-shadow: 0 4px 12px rgba(255, 159, 10, 0.3);
        }

        .opti-close {
            width: 44px;
            height: 44px;
            border-radius: 50%;
            background: rgba(255, 255, 255, 0.1);
            border: none;
            color: #fff;
            font-size: 22px;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;
            transition: background 0.2s;
        }
        
        .opti-close:active {
            background: rgba(255, 255, 255, 0.2);
        }
    `;
    shadow.appendChild(style);

    // --- BODY ---
    const panel = document.createElement('div');
    panel.className = 'opti-panel';
    panel.innerHTML = `
        <button class="opti-btn" id="btn-google">Google</button>
        <button class="opti-btn" id="btn-bing">Bing</button>
        <button class="opti-btn" id="btn-yandex">Yandex</button>
        <button class="opti-close" id="do-close">×</button>
    `;
    shadow.appendChild(panel);

    // --- NAVIGATION ---
    function navigate(url) {
        // iOS Safari behaves better with simple window.location for same-tab
        // or a real anchor click for new tab. 
        // We'll use window.location.href to translate the current page.
        window.location.href = url;
        closePanel();
    }

    // --- TRIGGERS ---
    shadow.getElementById('btn-google').onclick = (e) => {
        const url = encodeURIComponent(window.location.href);
        navigate(`https://translate.google.com/translate?sl=auto&tl=${TARGET_LANG}&u=${url}`);
    };

    shadow.getElementById('btn-bing').onclick = (e) => {
        const url = encodeURIComponent(window.location.href);
        // Updated Bing/Microsoft translator URL
        navigate(`https://www.bing.com/translator?to=${TARGET_LANG}&url=${url}`);
    };

    shadow.getElementById('btn-yandex').onclick = (e) => {
        const url = encodeURIComponent(window.location.href);
        navigate(`https://translate.yandex.com/translate?url=${url}&lang=auto-${TARGET_LANG}`);
    };

    shadow.getElementById('do-close').onclick = () => closePanel();

    function closePanel() {
        panel.classList.remove('visible');
        setTimeout(() => host.remove(), 600);
    }

    // --- ENTRANCE ---
    setTimeout(() => panel.classList.add('visible'), 800);

})();