Greasy Fork

来自缓存

Greasy Fork is available in English.

智能翻译助手

功能强大的网页翻译工具,支持多语言,可自定义配置,界面精美,支持移动端

当前为 2025-11-23 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name        智能翻译助手
// @name:zh-CN  智能翻译助手
// @name:zh-TW  智能翻譯助手
// @name:ar     Intelligent Translation Assistant
// @name:bg     Intelligent Translation Assistant
// @name:cs     Intelligent Translation Assistant
// @name:da     Intelligent Translation Assistant
// @name:de     Intelligent Translation Assistant
// @name:el     Intelligent Translation Assistant
// @name:en     Intelligent Translation Assistant
// @name:eo     Intelligent Translation Assistant
// @name:es     Intelligent Translation Assistant
// @name:es-419 Intelligent Translation Assistant
// @name:fi     Intelligent Translation Assistant
// @name:fr     Intelligent Translation Assistant
// @name:fr-CA  Intelligent Translation Assistant
// @name:he     Intelligent Translation Assistant
// @name:hr     Intelligent Translation Assistant
// @name:hu     Intelligent Translation Assistant
// @name:id     Intelligent Translation Assistant)
// @name:it     Intelligent Translation Assistant
// @name:ja     Intelligent Translation Assistant
// @name:ka     Intelligent Translation Assistant
// @name:ko     Intelligent Translation Assistant
// @name:nb     Intelligent Translation Assistant
// @name:nl     Intelligent Translation Assistant
// @name:pl     Intelligent Translation Assistant
// @name:pt-BR  Intelligent Translation Assistant
// @name:ro     Intelligent Translation Assistant
// @name:ru     Intelligent Translation Assistant
// @name:sv     Intelligent Translation Assistant
// @name:th     Intelligent Translation Assistant
// @name:tr     Intelligent Translation Assistant
// @name:uk     Intelligent Translation Assistant
// @name:ug     Intelligent Translation Assistant
// @name:vi     Intelligent Translation Assistant
// @namespace    http://tampermonkey.net/
// @version      1.2.1
// @description       功能强大的网页翻译工具,支持多语言,可自定义配置,界面精美,支持移动端
// @description:zh-CN 功能强大的网页翻译工具,支持多语言,可自定义配置,界面精美,支持移动端
// @description:zh-TW 功能強大的網頁翻譯工具,支援多語言,可自訂配置,介面精美,支援行動端
// @description:ar    أداة ترجمة ويب قوية، تدعم لغات متعددة، ويمكن تخصيصها، ولها واجهة جميلة، وتدعم الأجهزة المحمولة
// @description:bg    Мощен инструмент за уеб превод, поддържа множество езици, може да се персонализира, има красив интерфейс и поддържа мобилни терминали
// @description:cs    Výkonný nástroj pro webový překlad, podporuje více jazyků, lze jej přizpůsobit, má krásné rozhraní a podporuje mobilní terminály
// @description:da    Kraftfuldt weboversættelsesværktøj, understøtter flere sprog, kan tilpasses, har en flot brugerflade og understøtter mobile terminaler
// @description:de    Leistungsstarkes Web-Übersetzungstool, unterstützt mehrere Sprachen, kann angepasst werden, hat eine schöne Benutzeroberfläche und unterstützt mobile Endgeräte
// @description:el    Ισχυρό εργαλείο μετάφρασης ιστοσελίδων, υποστηρίζει πολλές γλώσσες, μπορεί να προσαρμοστεί, έχει όμορφο περιβάλλον εργασίας και υποστηρίζει κινητά τερματικά
// @description:eo    Potenca rettradukilo, subtenas plurajn lingvojn, povas esti personigita, havas belan interfacon, kaj subtenas porteblajn terminalojn
// @description:es    Potente herramienta de traducción web, admite varios idiomas, se puede personalizar, tiene una hermosa interfaz y es compatible con terminales móviles.
// @description:fi    Tehokas verkkokäännöstyökalu, tukee useita kieliä, on muokattavissa, siinä on kaunis käyttöliittymä ja se tukee mobiililaitteita
// @description:fr    Outil de traduction Web puissant, prend en charge plusieurs langues, peut être personnalisé, possède une belle interface et prend en charge les terminaux mobiles
// @description:fr-CA Outil de traduction Web puissant, prend en charge plusieurs langues, peut être personnalisé, possède une belle interface et prend en charge les terminaux mobiles
// @description:he    כלי תרגום אינטרנט עוצמתי, תומך בשפות מרובות, ניתן להתאמה אישית, בעל ממשק יפהפה ותומך במסופים ניידים
// @description:hr    Moćan alat za web prevođenje, podržava više jezika, može se prilagoditi, ima prekrasno sučelje i podržava mobilne terminale
// @description:hu    Hatékony weblapfordító eszköz, többnyelvű támogatással, testreszabható beállításokkal, kifinomult felülettel és mobil eszközökre optimalizálva.
// @description:id    Alat penerjemah situs web yang andal, mendukung multi-bahasa, dapat dikonfigurasi sesuai kebutuhan, antarmuka elegan, dan kompatibel dengan perangkat seluler.
// @description:it    Uno strumento di traduzione web potente, supporta più lingue, configurabile, con interfaccia raffinata e compatibile con dispositivi mobili.
// @description:ja    強力なウェブ翻訳ツール。多言語対応、カスタマイズ可能な設定、洗練されたインターフェース、モバイル対応。
// @description:ka    მძლავრი ვებ-გვერდის თარგმნის ინსტრუმენტი, მრავალენოვანი მხარდაჭერით, კონფიგურირებადი პარამეტრებით, დახვეწილი ინტერფეისით და მობილური მოწყობილობებისთვის მხარდაჭერით.
// @description:ko    강력한 웹페이지 번역 도구, 다국어 지원, 사용자 정의 설정 가능, 세련된 인터페이스, 모바일 지원.
// @description:nb    Et kraftig nettstedoversettelsesverktøy som støtter flere språk, kan tilpasses, har et elegant grensesnitt og er egnet for mobilbruk.
// @description:nl    Een krachtige webvertaaltool, ondersteunt meerdere talen, is aanpasbaar, heeft een verfijnde interface en ondersteuning voor mobiele apparaten.
// @description:pl    Potężne narzędzie do tłumaczenia stron internetowych, obsługujące wiele języków, konfigurowalne, z eleganckim interfejsem i obsługą urządzeń mobilnych.
// @description:pt-BR Uma ferramenta de tradução de páginas web poderosa, suporte multilíngue, configurável, interface refinada e compatível com dispositivos móveis.
// @description:ro    Un instrument puternic de traducere a paginilor web, suportă mai multe limbi, configurabil, cu interfață rafinată și suport pentru dispozitive mobile.
// @description:ru    Мощный инструмент для перевода веб-страниц, поддерживает множество языков, настраиваемую конфигурацию, изысканный интерфейс и работу на мобильных устройствах.
// @description:sv    Ett kraftfullt översättningsverktyg för webbsidor, stöder flerspråkighet, anpassningsbara inställningar, sofistikerat gränssnitt och mobilkompatibilitet.
// @description:th    เครื่องมือแปลเว็บเพจอันทรงพลัง รองรับหลายภาษา สามารถกำหนดค่าต่างๆ ได้เอง มีอินเทอร์เฟซที่สวยงาม และรองรับการทำงานบนมือถือ
// @description:tr    Güçlü bir web sayfası çeviri aracı, çok dilli destek, özelleştirilebilir yapılandırma, şık arayüz ve mobil cihaz desteği.
// @description:uk    Потужний інструмент для перекладу веб-сторінок, підтримує багатомовність, налаштування, витончений інтерфейс і сумісність з мобільними пристроями.
// @description:ug    كۈچلۈك توربەت تەرجىمە قورالى، كۆپ تىلنى قوللايدۇ، سەپلىمە تەڭشىكى، زىنھار ئېغىز كۆرۈنۈشى ۋە تەۋەككۈر ئۈسكۈنىسىنى قوللايدۇ.
// @description:vi    Công cụ dịch trang web mạnh mẽ, hỗ trợ đa ngôn ngữ, có thể tùy chỉnh cấu hình, giao diện tinh tế và hỗ trợ thiết bị di động.
// @author       Eray
// @icon      data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAABvBAMAAAApjDIIAAAA82VYSWZNTQAqAAAACAAFAQAAAwAAAAEAcQAAAQEAAwAAAAEAbwAAATEAAgAAABcAAABKh2kABAAAAAEAAABhARIABAAAAAEAAAAAAAAAAEFuZHJvaWQgUEQyMTE4X0FfOS4zLjEAAASQAwACAAAAFAAAAJeSkQACAAAABDc4MgCQEQACAAAABwAAAKuSCAAEAAAAAQAAAAAAAAAAMjAyNTowODoxOSAyMjoxMjoxMAArMDg6MDAAAAMBAAADAAAAAQBxAAABMQACAAAAFwAAANwBAQADAAAAAQBvAAAAAAAAQW5kcm9pZCBQRDIxMThfQV85LjMuMQA+yDmGAAAAFVBMVEVuY8VtacxwXbxub9P///+3s+Pp6Pd/O4+7AAAGzklEQVRYw41Yy3IcNwwEqEhnTljKmTUp57zjjXyOotGeV9bj7NiK/v8TghdJkDu7MWVLpSr1NtBoYMCB/eZJyz6lNC1p6k+cECGCnC3UsoXDSGeCGAlKZwOZ+EvRE31fOjTSP2Ld5Ez8Py3MOXlUFMoI/AW4GS1hhDPxmfhL2JRSGClUPEUSbL/o6dVhjPBSnqrRGU5RaMiShUUQzniCpGqIrgTrsmxxRqvJKeciVdE0CZJ8WYRTNRqRzKecPQyNEyFWIJy3T6pQrFlKyFoUGMSxM20oW5Q5l2cqJdGAhSwqr6IjniKXvTm2GaBA2bEADTVyLnvn2JYmc6pjIbZWgb6WRjk4Vv61cmxyCmVxbBWWfUflVJHsZOikXfbbjp1UG0ZgAYJPcl9rsiRHycGarltVqcIOjhVdyT0IXtcMPadkuRTvFbNymtolrG2BtjxTETalvrNinHoH0Amdtsk7dmmORW0S6NChIltvDY6NpZ2bAwiWGdpxFmia7l5fF+GTaalTNnqFLE+zgIwPETa9fXw8mdtbY6IHwtCXOn6m6WVdnzjBWJVtnITKNVrXlVpMQVqs3nRKmIMh09JGgYWrSJs9XEr0aQbzbRuxTVeNtozY2IvTOBcGE+Ptaz2E/Lf9ths42ULAht2b57581LOua/vl4+gwQY5VZbFHHxFtn103RjRicLVMf55DHl1fZmEsjtfpM13gHAg5z6VO2ekip1WDCZlzVs5kEr19DOd9XQ/8c4e9rkIqo2BSy6ZxbFMQD/wzOliWLBnJT0uxDz841ROlOfGlBNrmFoTqBBnMfVvGyaYdIxEHbSRL42QrDGMEpcHeRdbRPnxm4ZQUhxkrRr9e10fourKlyZxcl/00kEp/3ZBAWBaKOkk4yyBIHbEVFXkcaI+8tEoOWc5BOJnUQbkU0pggaSL68ayxzp6zrQW3VH7GRU3T4UwcaZbs3FdI0/t6eGLON0uzQQP7nT5gFm1PRyyl9w+X892nGQqlxMp5qmfcHInTbxQl6XPNTYLQpal9bfXUseUfJAx5gvhW06R5chRpZzDSeWbOve0hFY4U5g+8ou/PSknhP4A8EkwhcYJbmMoTOn5hdW85WOXkZrNyMoz0Ec6NJYbDPb7UYPnXwy4UYbUuGfQB5CijdtcjB6vy3PBY+CbBiqzGWbYC/5TGO5khBwtWhsw3HQSqkFQljXssW53MsIoqcmSwPcj0Yc7ZOKfFbwW66U/6x0crpnzMQf2uJwtyXH5kGnBqB2uuTzr/LEtVVqNtewxGvdEY53OVluXaaZZSlnDKacvvrQ1oMGnvuVM5RM1zVm07VfVCE23Y/ygCHX9hvcR/YlquDEx+GdUVT4pyKKSZW+YPiljC1EhLPbsNj+Ds2PX5xUiv6Kc0AZQGs2hPt0ok266Pu1slzTIZZvqwzyG0cnqFsGwwYoNnuDLSGw6Uk/0eznLKVgCTUgJwto8QCHMPM33/yymryNSE5TGrWXKCghFpc+DRq8rOpcv6O20sWXI57ngOsbQxZzLS42yB9tGWpbJkCUp6FAfx43ZliXKu4MZpS+XUKCHfHYDDfGQH0Ad+V1F7pGWJJUsdeFev0pz3NDFnFbfFW5CxWNZR0oxdRNqDPfgfpEnGaOVCQqdlqdNVm1PPIecThcw8qBNo50bzJ7+i1CQrEttWedeylMfItUd+nk847dKOXAlPKQ5o5+tYT5Rq2p327rl77nVr2YMLt0RbOCNc7drDSwV61t2IB/8QLbZbUES35/PO8zt3mv7pJ0aGPtpyCwK3iwZ9RrNd5flDf/veSUTIWG5B/tpV9jv2Xubeoq5mF3lk1DuJvveBbvuheLktZ+mteSYf/j1oGxtnjN0+EbQ5deLdmP9atPr+pb9EZ9YnSHP+WnyuLeqQWKrS3Q90oeDmtElA4M5FHC0/DYZbRZbFGTKP2TZ9KICvHSfGliV2nIFuhE9t4NGi8XWoynDx4nVdlvWMaYq+JSF0VcFyeqjV3zYR118tWr13uVpmAfLzErYwXbR9LSun7ltz9tPSc0L/gkGvpbrHzmUT2ULy7AJ0VQliWeUEHepbERMnDO8KtL3siXeZc3jvk7Wly1awjWMk+mYuu2hZl4w2b3PW13E11qCTVra7+RInuqbUNwVSyNn2gq2SFCRi924su11fOMMZpL/IlPulLqLzhWDZxDFif4n2e+zFPCVJ9Pe1fsO7WBU/ffQa5Da8fD7afvronWK+4IGKxOEtVS63PblFnamJaev7MgRXkf/lxPEKpW0ZLqJzZx/jlPvl2TAdZwfVWs7FCxeRLtJQHRt+grN1SQj1dqodtj2ACvI/wZeKnkWuZZ8AAAAASUVORK5CYII=
// @run-at       document-start
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @grant        GM_registerMenuCommand
// @grant        GM_xmlhttpRequest
// @grant        unsafeWindow
// @license       Apache-2.0
// @require       https://unpkg.com/[email protected]/index.js
// ==/UserScript==

(function() {
    'use strict';

    // 尽早注入样式和创建悬浮球
    const earlyInit = () => {
        // 检测是否为移动设备
        const isMobile = () => {
            return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) 
                || window.innerWidth <= 768;
        };

        // 获取保存的配置
        const getConfig = () => {
            const defaultConfig = {
                enabled: true,
                localLanguage: 'english',
                targetLanguage: 'chinese_simplified',
                floatBallSize: isMobile() ? 45 : 50,
                floatBallPosition: { x: 20, y: 100 },
                floatBallOpacity: 0.8,
                autoTranslate: false,
                showFloatBall: true,
                translateService: 'client.edge',
                customServiceUrls: '',
                allowHalfBall: true,
                panelPosition: null,
                panelSize: isMobile() ? 0.9 : 1,
                panelOpacity: 1,
                ignoredClasses: '',
                ignoredIds: '',
                ignoredTags: [],
                customTerms: '',
                enableListener: true,
                enableCache: true,
                translateAttributes: ['title', 'alt', 'placeholder'],
                doubleClickToggle: false,
                enableOffline: false,
                enableSelectionTranslate: false
            };
            const saved = GM_getValue('translateConfig', null);
            return saved ? { ...defaultConfig, ...saved } : defaultConfig;
        };

        const config = getConfig();
        const mobile = isMobile();

        // 检测深色模式
        const isDarkMode = () => {
            return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
        };

        // 注入基础样式
        const baseStyles = `
            #translate-float-ball {
                position: fixed;
                width: ${config.floatBallSize}px;
                height: ${config.floatBallSize}px;
                border-radius: 50%;
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
                cursor: ${mobile ? 'pointer' : 'move'};
                z-index: 2147483647;
                display: ${config.showFloatBall ? 'flex' : 'none'};
                align-items: center;
                justify-content: center;
                opacity: ${config.floatBallOpacity};
                left: ${config.floatBallPosition.x}px;
                top: ${config.floatBallPosition.y}px;
                transition: transform 0.3s ease, box-shadow 0.3s ease;
                user-select: none;
                -webkit-user-select: none;
                touch-action: none;
            }
            #translate-float-ball svg {
                width: ${mobile ? '24px' : '28px'};
                height: ${mobile ? '24px' : '28px'};
                fill: white;
                pointer-events: none;
            }
        `;

        // 创建style标签
        const style = document.createElement('style');
        style.textContent = baseStyles;
        
        // 创建悬浮球
        const ball = document.createElement('div');
        ball.id = 'translate-float-ball';
        ball.innerHTML = `
            <svg viewBox="0 0 24 24">
                <path d="M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"/>
            </svg>
        `;

        // 等待DOM准备好
        if (document.head) {
            document.head.appendChild(style);
        } else {
            document.addEventListener('DOMContentLoaded', () => {
                document.head.appendChild(style);
            });
        }

        if (document.body) {
            document.body.appendChild(ball);
        } else {
            document.addEventListener('DOMContentLoaded', () => {
                document.body.appendChild(ball);
            });
        }
    };

    // 立即执行早期初始化
    earlyInit();

    // 主要功能代码
    (() => {
        // 配置管理器
        class ConfigManager {
            constructor() {
                this.defaultConfig = {
                    enabled: true,
                    localLanguage: 'english',
                    targetLanguage: 'chinese_simplified',
                    floatBallSize: isMobile() ? 45 : 50,
                    floatBallPosition: { x: 20, y: 100 },
                    floatBallOpacity: 0.8,
                    autoTranslate: false,
                    showFloatBall: true,
                    translateService: 'client.edge',
                    customServiceUrls: '',
                    allowHalfBall: true,
                    panelPosition: null,
                    panelSize: isMobile() ? 0.9 : 1,
                    panelOpacity: 1,
                    ignoredClasses: '',
                    ignoredIds: '',
                    ignoredTags: [],
                    customTerms: '',
                    enableListener: true,
                    enableCache: true,
                    translateAttributes: ['title', 'alt', 'placeholder'],
                    doubleClickToggle: false,
                    enableOffline: false,
                    enableSelectionTranslate: false
                };
                this.config = this.loadConfig();
            }

            loadConfig() {
                const saved = GM_getValue('translateConfig', null);
                return saved ? { ...this.defaultConfig, ...saved } : this.defaultConfig;
            }

            saveConfig() {
                GM_setValue('translateConfig', this.config);
            }

            get(key) {
                return this.config[key];
            }

            set(key, value) {
                this.config[key] = value;
                this.saveConfig();
            }

            reset() {
                GM_deleteValue('translateConfig');
                this.config = { ...this.defaultConfig };
            }

            clearCache() {
                // 清除translate.js的缓存
                if (typeof translate !== 'undefined') {
                    try {
                        translate.storage.clear();
                    } catch (e) {
                        console.log('清除translate.js缓存失败:', e);
                    }
                }
                
                // 清除localStorage中的翻译缓存
                const keys = Object.keys(localStorage);
                let cleared = 0;
                keys.forEach(key => {
                    if (key.includes('translate_') || key.includes('hash_')) {
                        localStorage.removeItem(key);
                        cleared++;
                    }
                });
                
                return cleared;
            }
        }

        // 翻译管理器
        class TranslateManager {
            constructor(configManager) {
                this.configManager = configManager;
                this.initialized = false;
                this.listenerStarted = false;
                this.currentLanguage = null;
                this.isTranslating = false;
                this.observer = null;
            }

            init() {
                if (this.initialized || typeof translate === 'undefined') return;
                
                try {
                    // 配置translate.js
                    translate.language.setLocal(this.configManager.get('localLanguage'));
                    
                    // 设置翻译服务
                    const service = this.configManager.get('translateService');
                    translate.service.use(service);
                    
                    // 如果是自定义服务,设置API地址
                    if (service === 'translate.service') {
                        const customUrls = this.configManager.get('customServiceUrls');
                        if (customUrls) {
                            const urls = customUrls.split(',').map(url => url.trim()).filter(url => url);
                            if (urls.length > 0) {
                                translate.request.api.host = urls.length === 1 ? urls[0] : urls;
                            }
                        }
                    }
                    
                    translate.selectLanguageTag.show = false;
                    
                    // 设置忽略的类和ID
                    this.applyIgnoreSettings();
                    
                    // 设置自定义术语
                    this.applyCustomTerms();

                    // 设置要翻译的属性
                    const translateAttributes = this.configManager.get('translateAttributes');
                    if (translateAttributes.length > 0) {
                        translate.translateAttributes = translateAttributes;
                    }

                    this.initialized = true;
                    console.log('翻译管理器初始化完成');
                } catch (error) {
                    console.error('翻译初始化失败:', error);
                }
            }

            applyIgnoreSettings() {
                if (typeof translate === 'undefined') return;
                
                // 清空现有设置
                translate.ignore.class = [];
                translate.ignore.id = [];
                
                // 应用忽略的Class
                const ignoredClasses = this.configManager.get('ignoredClasses');
                if (ignoredClasses) {
                    const classes = ignoredClasses.split(',').map(c => c.trim()).filter(c => c);
                    classes.forEach(cls => {
                        translate.ignore.class.push(cls);
                    });
                }
                
                // 应用忽略的ID
                const ignoredIds = this.configManager.get('ignoredIds');
                if (ignoredIds) {
                    const ids = ignoredIds.split(',').map(id => id.trim()).filter(id => id);
                    ids.forEach(id => {
                        translate.ignore.id.push(id);
                    });
                }
            }

            applyCustomTerms() {
                if (typeof translate === 'undefined') return;
                
                const customTerms = this.configManager.get('customTerms');
                if (!customTerms) return;
                
                const localLang = this.configManager.get('localLanguage');
                const targetLang = this.configManager.get('targetLanguage');
                
                // 直接使用用户输入的格式
                translate.nomenclature.append(localLang, targetLang, customTerms);
            }

            startListener() {
                if (!this.listenerStarted && typeof translate !== 'undefined') {
                    try {
                        if (this.configManager.get('enableListener')) {
                            translate.listener.start();
                            this.listenerStarted = true;
                            console.log('动态内容监听已启动');
                        }
                    } catch (error) {
                        if (!error.message?.includes('已经启动')) {
                            console.error('启动监听失败:', error);
                        }
                    }
                }
            }

            changeLanguage(targetLang) {
                if (!this.initialized) this.init();
                if (typeof translate === 'undefined') return;
                
                try {
                    // 避免重复翻译到相同语言
                    if (this.currentLanguage === targetLang && this.isTranslating) {
                        return;
                    }
                    
                    this.currentLanguage = targetLang;
                    this.isTranslating = true;
                    
                    // 重新应用忽略设置和自定义术语
                    this.applyIgnoreSettings();
                    this.applyCustomTerms();
                    
                    // 确保监听器已启动
                    this.startListener();
                    
                    translate.changeLanguage(targetLang);
                    
                    // 翻译完成后重置状态
                    setTimeout(() => {
                        this.isTranslating = false;
                    }, 1000);
                } catch (error) {
                    console.error('切换语言失败:', error);
                    this.isTranslating = false;
                }
            }

            toggle(enabled) {
                if (enabled && !this.initialized) {
                    this.init();
                    this.startListener();
                    if (this.configManager.get('autoTranslate')) {
                        setTimeout(() => {
                            this.changeLanguage(this.configManager.get('targetLanguage'));
                        }, 100);
                    }
                } else if (!enabled && this.initialized) {
                    this.isTranslating = false;
                    this.changeLanguage(this.configManager.get('localLanguage'));
                }
            }

            execute() {
                if (!this.initialized) this.init();
                if (typeof translate !== 'undefined') {
                    try {
                        // 重新应用设置
                        this.applyIgnoreSettings();
                        this.applyCustomTerms();
                        
                        this.startListener();
                        translate.execute();
                    } catch (error) {
                        console.error('执行翻译失败:', error);
                    }
                }
            }

            startSelectionTranslate() {
                if (!this.initialized) this.init();
                if (typeof translate !== 'undefined') {
                    try {
                        translate.language.setDefaultTo(this.configManager.get('targetLanguage'));
                        translate.selectionTranslate.start();
                        console.log('鼠标划词翻译已启动');
                    } catch (error) {
                        console.error('启动划词翻译失败:', error);
                    }
                }
            }

            stopSelectionTranslate() {
                if (typeof translate !== 'undefined' && translate.selectionTranslate) {
                    try {
                        translate.selectionTranslate.stop();
                        console.log('鼠标划词翻译已停止');
                    } catch (error) {
                        console.error('停止划词翻译失败:', error);
                    }
                }
            }
        }

        // 提示管理器
        class ToastManager {
            constructor() {
                this.container = null;
                this.init();
            }

            init() {
                this.container = document.createElement('div');
                this.container.id = 'translate-toast-container';
                this.container.style.cssText = `
                    position: fixed;
                    top: 20px;
                    right: 20px;
                    z-index: 2147483647;
                    pointer-events: none;
                `;
                document.body.appendChild(this.container);
            }

            show(message, type = 'success', duration = 2000) {
                const toast = document.createElement('div');
                const bgColor = type === 'success' ? '#4caf50' : type === 'error' ? '#f44336' : '#2196f3';
                
                toast.style.cssText = `
                    background: ${bgColor};
                    color: white;
                    padding: 12px 20px;
                    border-radius: 8px;
                    margin-bottom: 10px;
                    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
                    animation: slideInRight 0.3s ease;
                    pointer-events: auto;
                    font-size: 14px;
                `;
                
                toast.textContent = message;
                this.container.appendChild(toast);

                setTimeout(() => {
                    toast.style.animation = 'slideOutRight 0.3s ease';
                    setTimeout(() => {
                        this.container.removeChild(toast);
                    }, 300);
                }, duration);
            }
        }

        // UI管理器
        class UIManager {
            constructor(configManager, translateManager) {
                this.configManager = configManager;
                this.translateManager = translateManager;
                this.floatBall = document.getElementById('translate-float-ball');
                this.panel = null;
                this.toast = new ToastManager();
                this.isDragging = false;
                this.isPanelDragging = false;
                this.dragOffset = { x: 0, y: 0 };
                this.panelDragOffset = { x: 0, y: 0 };
                this.touchStartPos = { x: 0, y: 0 };
                this.touchStartTime = 0;
                this.lastClickTime = 0;
                this.clickCount = 0;
                this.clickTimer = null;
                
                this.init();
            }

            init() {
                this.injectStyles();
                this.setupFloatBall();
                this.createPanel();
                this.bindEvents();
                
                // 初始化翻译
                if (this.configManager.get('enabled')) {
                    setTimeout(() => {
                        this.translateManager.toggle(true);
                    }, 1000);
                }
                
                // 初始化鼠标划词翻译
                if (this.configManager.get('enableSelectionTranslate') && !isMobile()) {
                    setTimeout(() => {
                        this.translateManager.startSelectionTranslate();
                    }, 1500);
                }
            }

            injectStyles() {
                const mobile = isMobile();
                const darkMode = isDarkMode();
                
                GM_addStyle(`
                    /* 动画定义 */
                    @keyframes slideInRight {
                        from {
                            transform: translateX(100%);
                            opacity: 0;
                        }
                        to {
                            transform: translateX(0);
                            opacity: 1;
                        }
                    }
                    
                    @keyframes slideOutRight {
                        from {
                            transform: translateX(0);
                            opacity: 1;
                        }
                        to {
                            transform: translateX(100%);
                            opacity: 0;
                        }
                    }
                    
                    /* 深色模式支持 */
                    ${darkMode ? `
                        #translate-panel {
                            background: #1e1e1e !important;
                            color: #e0e0e0 !important;
                        }
                        
                        .translate-panel-header {
                            background: linear-gradient(135deg, #4a5eb7 0%, #5a3d7a 100%) !important;
                        }
                        
                        .translate-control-label {
                            color: #e0e0e0 !important;
                        }
                        
                        .translate-select, .translate-input, .translate-textarea {
                            background: #2d2d2d !important;
                            color: #e0e0e0 !important;
                            border-color: #444 !important;
                        }
                        
                        .translate-select:focus, .translate-input:focus, .translate-textarea:focus {
                            border-color: #667eea !important;
                        }
                        
                        .translate-select option {
                            background: #2d2d2d !important;
                            color: #e0e0e0 !important;
                        }
                        
                        .translate-slider {
                            background: #444 !important;
                        }
                        
                        .translate-slider-value {
                            color: #b0b0b0 !important;
                        }
                        
                        .translate-section-title {
                            color: #e0e0e0 !important;
                            border-bottom-color: #444 !important;
                        }
                        
                        .translate-info {
                            background: #2d2d2d !important;
                            color: #b0b0b0 !important;
                        }
                        
                        .translate-description {
                            color: #999 !important;
                        }
                    ` : ''}
                    
                    /* 悬浮球动画样式 */
                    #translate-float-ball:active {
                        transform: scale(0.95);
                    }

                    #translate-float-ball.dragging {
                        transition: none !important;
                        transform: scale(1.1);
                        box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6);
                    }

                    #translate-float-ball:hover {
                        transform: scale(1.05);
                        box-shadow: 0 6px 20px rgba(102, 126, 234, 0.5);
                    }

                    /* 控制面板样式 */
                    #translate-panel {
                        position: fixed;
                        background: white;
                        border-radius: 12px;
                        box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15);
                        z-index: 2147483646;
                        display: none;
                        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
                        overflow: hidden;
                        touch-action: none;
                        user-select: none;
                        -webkit-user-select: none;
                    }

                    #translate-panel.show {
                        display: block;
                        animation: slideIn 0.3s ease;
                    }

                    #translate-panel.dragging {
                        transition: none !important;
                        box-shadow: 0 15px 50px rgba(0, 0, 0, 0.2);
                    }

                    @keyframes slideIn {
                        from {
                            opacity: 0;
                            transform: translateY(-20px);
                        }
                        to {
                            opacity: 1;
                            transform: translateY(0);
                        }
                    }

                    .translate-panel-header {
                        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                        color: white;
                        padding: ${mobile ? '15px' : '20px'};
                        display: flex;
                        justify-content: space-between;
                        align-items: center;
                        cursor: move;
                    }

                    .translate-panel-title {
                        font-size: ${mobile ? '16px' : '18px'};
                        font-weight: 600;
                        user-select: none;
                    }

                    .translate-panel-close {
                        width: 30px;
                        height: 30px;
                        border-radius: 50%;
                        background: rgba(255, 255, 255, 0.2);
                        border: none;
                        cursor: pointer;
                        display: flex;
                        align-items: center;
                        justify-content: center;
                        transition: background 0.3s;
                        font-size: 18px;
                        color: white;
                    }

                    .translate-panel-close:hover {
                        background: rgba(255, 255, 255, 0.3);
                    }

                    .translate-panel-close:active {
                        transform: scale(0.95);
                    }

                    .translate-panel-body {
                        padding: ${mobile ? '15px' : '20px'};
                        max-height: ${mobile ? '60vh' : '500px'};
                        overflow-y: auto;
                        -webkit-overflow-scrolling: touch;
                        cursor: default;
                    }

                    .translate-panel-body::-webkit-scrollbar {
                        width: 6px;
                    }

                    .translate-panel-body::-webkit-scrollbar-thumb {
                        background: rgba(0,0,0,0.2);
                        border-radius: 3px;
                    }

                    .translate-panel-body::-webkit-scrollbar-track {
                        background: transparent;
                    }

                    .translate-control-group {
                        margin-bottom: ${mobile ? '15px' : '20px'};
                    }

                    .translate-control-label {
                        display: block;
                        margin-bottom: 8px;
                        font-size: 14px;
                        font-weight: 500;
                        color: #333;
                    }

                    .translate-description {
                        font-size: 12px;
                        color: #666;
                        margin-top: 4px;
                        font-weight: normal;
                    }

                    .translate-switch {
                        position: relative;
                        display: inline-block;
                        width: 50px;
                        height: 24px;
                    }

                    .translate-switch input {
                        opacity: 0;
                        width: 0;
                        height: 0;
                    }

                    .translate-switch-slider {
                        position: absolute;
                        cursor: pointer;
                        top: 0;
                        left: 0;
                        right: 0;
                        bottom: 0;
                        background-color: #ccc;
                        transition: .4s;
                        border-radius: 24px;
                    }

                    .translate-switch-slider:before {
                        position: absolute;
                        content: "";
                        height: 18px;
                        width: 18px;
                        left: 3px;
                        bottom: 3px;
                        background-color: white;
                        transition: .4s;
                        border-radius: 50%;
                    }

                    .translate-switch input:checked + .translate-switch-slider {
                        background-color: #667eea;
                    }

                    .translate-switch input:checked + .translate-switch-slider:before {
                        transform: translateX(26px);
                    }

                    .translate-select, .translate-input {
                        width: 100%;
                        padding: ${mobile ? '12px' : '10px'};
                        border: 1px solid #ddd;
                        border-radius: 8px;
                        font-size: ${mobile ? '16px' : '14px'};
                        background: white;
                        cursor: pointer;
                        transition: border-color 0.3s;
                        color: #333;
                        box-sizing: border-box;
                    }

                    .translate-select:focus, .translate-input:focus {
                        outline: none;
                        border-color: #667eea;
                    }

                    .translate-textarea {
                        width: 100%;
                        min-height: 100px;
                        padding: ${mobile ? '12px' : '10px'};
                        border: 1px solid #ddd;
                        border-radius: 8px;
                        font-size: ${mobile ? '14px' : '13px'};
                        background: white;
                        transition: border-color 0.3s;
                        color: #333;
                        box-sizing: border-box;
                        resize: vertical;
                        font-family: monospace;
                        line-height: 1.5;
                    }

                    .translate-textarea:focus {
                        outline: none;
                        border-color: #667eea;
                    }

                    .translate-slider-container {
                        display: flex;
                        align-items: center;
                        gap: 10px;
                    }

                    .translate-slider {
                        flex: 1;
                        -webkit-appearance: none;
                        height: 6px;
                        border-radius: 3px;
                        background: #ddd;
                        outline: none;
                    }

                    .translate-slider::-webkit-slider-thumb {
                        -webkit-appearance: none;
                        appearance: none;
                        width: 18px;
                        height: 18px;
                        border-radius: 50%;
                        background: #667eea;
                        cursor: pointer;
                    }

                    .translate-slider::-moz-range-thumb {
                        width: 18px;
                        height: 18px;
                        border-radius: 50%;
                        background: #667eea;
                        cursor: pointer;
                        border: none;
                    }

                    .translate-slider-value {
                        min-width: 45px;
                        text-align: center;
                        font-size: 14px;
                        color: #666;
                    }

                    .translate-button {
                        width: 100%;
                        padding: ${mobile ? '14px' : '12px'};
                        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                        color: white;
                        border: none;
                        border-radius: 8px;
                        font-size: ${mobile ? '16px' : '14px'};
                        font-weight: 500;
                        cursor: pointer;
                        transition: transform 0.3s, box-shadow 0.3s;
                        -webkit-tap-highlight-color: transparent;
                    }

                    .translate-button:hover {
                        transform: translateY(-1px);
                        box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
                    }

                    .translate-button:active {
                        transform: scale(0.98);
                    }

                    .translate-button-group {
                        display: flex;
                        gap: 10px;
                        margin-bottom: ${mobile ? '15px' : '20px'};
                    }

                    .translate-button-group .translate-button {
                        flex: 1;
                    }

                    .translate-section-title {
                        font-size: ${mobile ? '15px' : '16px'};
                        font-weight: 600;
                        color: #333;
                        margin-bottom: 15px;
                        padding-bottom: 10px;
                        border-bottom: 2px solid #f0f0f0;
                    }

                    .translate-info {
                        background: #f8f9fa;
                        padding: 12px;
                        border-radius: 8px;
                        font-size: ${mobile ? '12px' : '13px'};
                        color: #666;
                        margin-top: 10px;
                        line-height: 1.5;
                    }

                    /* 响应式优化 */
                    @media (max-width: 768px) {
                        .translate-control-group {
                            margin-bottom: 15px;
                        }
                    }
                `);
            }

            setupFloatBall() {
                if (!this.floatBall) return;
                
                const size = this.configManager.get('floatBallSize');
                const position = this.configManager.get('floatBallPosition');
                const opacity = this.configManager.get('floatBallOpacity');
                
                this.floatBall.style.width = `${size}px`;
                this.floatBall.style.height = `${size}px`;
                this.floatBall.style.opacity = opacity;
                
                // 确保在可视区域内
                this.ensureInViewport();
            }

            createPanel() {
                const panel = document.createElement('div');
                panel.id = 'translate-panel';
                
                // 获取支持的语言列表
                const languages = this.getSupportedLanguages();
                
                // 获取翻译服务列表
                const services = [
                    { value: 'client.edge', name: 'Microsoft Edge' },
                    { value: 'client.google', name: 'Google Translate' },
                    { value: 'siliconflow', name: 'SiliconFlow AI' },
                    { value: 'translate.service', name: '自定义服务' }
                ];

                const mobile = isMobile();
                const config = this.configManager.config;

                panel.innerHTML = `
                    <div class="translate-panel-header">
                        <div class="translate-panel-title">🌐 智能翻译助手</div>
                        <button class="translate-panel-close" id="translate-panel-close">✕</button>
                    </div>
                    <div class="translate-panel-body">
                        <!-- 立即翻译按钮 - 放在最上面 -->
                        <div class="translate-control-group">
                            <button class="translate-button" id="translate-now-btn">🚀 立即翻译</button>
                        </div>

                        <!-- 基础设置 -->
                        <div class="translate-section-title">基础设置</div>
                        
                        <div class="translate-control-group">
                            <label class="translate-control-label">
                                源语言
                                <div class="translate-description">当前页面的语言</div>
                            </label>
                            <select class="translate-select" id="translate-local-lang">
                                ${languages.map(lang => `
                                    <option value="${lang.value}" ${config.localLanguage === lang.value ? 'selected' : ''}>
                                        ${lang.name}
                                    </option>
                                `).join('')}
                            </select>
                        </div>

                        <div class="translate-control-group">
                            <label class="translate-control-label">
                                目标语言
                                <div class="translate-description">要翻译成什么语言</div>
                            </label>
                            <select class="translate-select" id="translate-target-lang">
                                ${languages.map(lang => `
                                    <option value="${lang.value}" ${config.targetLanguage === lang.value ? 'selected' : ''}>
                                        ${lang.name}
                                    </option>
                                `).join('')}
                            </select>
                        </div>

                        <div class="translate-control-group">
                            <label class="translate-control-label">启用翻译</label>
                            <label class="translate-switch">
                                <input type="checkbox" id="translate-enable" ${config.enabled ? 'checked' : ''}>
                                <span class="translate-switch-slider"></span>
                            </label>
                        </div>

                        <div class="translate-control-group">
                            <label class="translate-control-label">
                                自动翻译
                                <div class="translate-description">页面加载时自动翻译</div>
                            </label>
                            <label class="translate-switch">
                                <input type="checkbox" id="translate-auto" ${config.autoTranslate ? 'checked' : ''}>
                                <span class="translate-switch-slider"></span>
                            </label>
                        </div>

                        <!-- 界面设置 -->
                        <div class="translate-section-title" style="margin-top: 25px;">界面设置</div>

                        <div class="translate-control-group">
                            <label class="translate-control-label">显示悬浮球</label>
                            <label class="translate-switch">
                                <input type="checkbox" id="translate-show-ball" ${config.showFloatBall ? 'checked' : ''}>
                                <span class="translate-switch-slider"></span>
                            </label>
                        </div>

                        <div class="translate-control-group">
                            <label class="translate-control-label">
                                允许悬浮球超出边缘
                                <div class="translate-description">允许悬浮球一半超出屏幕边缘</div>
                            </label>
                            <label class="translate-switch">
                                <input type="checkbox" id="translate-allow-half" ${config.allowHalfBall ? 'checked' : ''}>
                                <span class="translate-switch-slider"></span>
                            </label>
                        </div>

                        <div class="translate-control-group">
                            <label class="translate-control-label">
                                双击悬浮球开关翻译
                                <div class="translate-description">快速双击悬浮球开启/关闭翻译</div>
                            </label>
                            <label class="translate-switch">
                                <input type="checkbox" id="translate-double-click" ${config.doubleClickToggle ? 'checked' : ''}>
                                <span class="translate-switch-slider"></span>
                            </label>
                        </div>

                        <div class="translate-control-group">
                            <label class="translate-control-label">悬浮球大小</label>
                            <div class="translate-slider-container">
                                <input type="range" class="translate-slider" id="translate-ball-size" 
                                    min="30" max="80" value="${config.floatBallSize}">
                                <span class="translate-slider-value">${config.floatBallSize}px</span>
                            </div>
                        </div>

                        <div class="translate-control-group">
                            <label class="translate-control-label">悬浮球透明度</label>
                            <div class="translate-slider-container">
                                <input type="range" class="translate-slider" id="translate-ball-opacity" 
                                    min="30" max="100" value="${config.floatBallOpacity * 100}">
                                <span class="translate-slider-value">${Math.round(config.floatBallOpacity * 100)}%</span>
                            </div>
                        </div>

                        <div class="translate-control-group">
                            <label class="translate-control-label">控制面板大小</label>
                            <div class="translate-slider-container">
                                <input type="range" class="translate-slider" id="translate-panel-size" 
                                    min="50" max="120" value="${config.panelSize * 100}">
                                <span class="translate-slider-value">${Math.round(config.panelSize * 100)}%</span>
                            </div>
                        </div>

                        <div class="translate-control-group">
                            <label class="translate-control-label">控制面板透明度</label>
                            <div class="translate-slider-container">
                                <input type="range" class="translate-slider" id="translate-panel-opacity" 
                                    min="50" max="100" value="${config.panelOpacity * 100}">
                                <span class="translate-slider-value">${Math.round(config.panelOpacity * 100)}%</span>
                            </div>
                        </div>

                        <div class="translate-button-group">
                            <button class="translate-button" id="translate-reset-ball-btn" style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);">
                                重置悬浮球位置
                            </button>
                            <button class="translate-button" id="translate-reset-panel-btn" style="background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);">
                                重置面板位置
                            </button>
                        </div>

                        <!-- 高级设置 -->
                        <div class="translate-section-title" style="margin-top: 25px;">高级设置</div>

                        <div class="translate-control-group">
                            <label class="translate-control-label">
                                翻译服务
                                <div class="translate-description">选择翻译服务通道</div>
                            </label>
                            <select class="translate-select" id="translate-service">
                                ${services.map(service => `
                                    <option value="${service.value}" ${config.translateService === service.value ? 'selected' : ''}>
                                        ${service.name}
                                    </option>
                                `).join('')}
                            </select>
                        </div>

                        <div class="translate-control-group" id="custom-service-group" style="display: ${config.translateService === 'translate.service' ? 'block' : 'none'};">
                            <label class="translate-control-label">
                                自定义翻译接口地址
                                <div class="translate-description">支持多个地址,用英文逗号分隔</div>
                            </label>
                            <input type="text" class="translate-input" id="custom-service-urls" 
                                placeholder="例如: https://api1.com/,https://api2.com/" 
                                value="${config.customServiceUrls}">
                            <button class="translate-button" id="save-custom-service" style="margin-top: 8px;">保存接口地址</button>
                        </div>

                        <div class="translate-control-group">
                            <label class="translate-control-label">
                                忽略的Class
                                <div class="translate-description">添加不需要翻译的CSS类名,用英文逗号分隔</div>
                            </label>
                            <input type="text" class="translate-input" id="ignore-class-input" 
                                placeholder="例如: class1,class2,class3" 
                                value="${config.ignoredClasses}">
                            <button class="translate-button" id="save-ignore-class" style="margin-top: 8px;">保存Class设置</button>
                        </div>

                        <div class="translate-control-group">
                            <label class="translate-control-label">
                                忽略的ID
                                <div class="translate-description">添加不需要翻译的元素ID,用英文逗号分隔</div>
                            </label>
                            <input type="text" class="translate-input" id="ignore-id-input" 
                                placeholder="例如: id1,id2,id3" 
                                value="${config.ignoredIds}">
                            <button class="translate-button" id="save-ignore-id" style="margin-top: 8px;">保存ID设置</button>
                        </div>

                        <div class="translate-control-group">
                            <label class="translate-control-label">
                                自定义术语
                                <div class="translate-description">每行一个术语,格式: 原文=翻译</div>
                            </label>
                            <textarea class="translate-textarea" id="custom-terms-input" 
                                placeholder="例如:&#10;网市场云建站系统=wangmarket CMS&#10;国际化=GuoJiHua">${config.customTerms}</textarea>
                            <button class="translate-button" id="save-custom-terms" style="margin-top: 8px;">保存术语设置</button>
                        </div>

                        ${!mobile ? `
                        <div class="translate-control-group">
                            <label class="translate-control-label">
                                鼠标划词翻译
                                <div class="translate-description">选中文字自动显示翻译(仅PC端)</div>
                            </label>
                            <label class="translate-switch">
                                <input type="checkbox" id="translate-selection" ${config.enableSelectionTranslate ? 'checked' : ''}>
                                <span class="translate-switch-slider"></span>
                            </label>
                        </div>
                        ` : ''}

                        <!-- 性能优化 -->
                        <div class="translate-section-title" style="margin-top: 25px;">性能优化</div>

                        <div class="translate-control-group">
                            <label class="translate-control-label">
                                动态内容监听
                                <div class="translate-description">自动翻译动态加载的内容</div>
                            </label>
                            <label class="translate-switch">
                                <input type="checkbox" id="translate-listener" ${config.enableListener ? 'checked' : ''}>
                                <span class="translate-switch-slider"></span>
                            </label>
                        </div>

                        <div class="translate-control-group">
                            <label class="translate-control-label">
                                缓存优化
                                <div class="translate-description">缓存翻译结果,提升响应速度</div>
                            </label>
                            <label class="translate-switch">
                                <input type="checkbox" id="translate-cache" ${config.enableCache ? 'checked' : ''}>
                                <span class="translate-switch-slider"></span>
                            </label>
                        </div>

                        <div class="translate-button-group">
                            <button class="translate-button" id="translate-clear-cache" style="background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%);">
                                清除翻译缓存
                            </button>
                            <button class="translate-button" id="translate-reset-all" style="background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);">
                                重置所有设置
                            </button>
                        </div>

                        <div class="translate-info">
                            💡 提示:${mobile ? '长按' : '拖动'}悬浮球或面板标题栏可调整位置,设置会自动保存<br><br>
                            🚀 支持100+种语言互译,采用AI翻译引擎,翻译质量更优<br>
                            ⚡ 内置多层缓存机制,二次访问毫秒级响应<br>
                            🔒 完全本地运行,保护您的隐私安全
                        </div>
                    </div>
                `;
                
                document.body.appendChild(panel);
                this.panel = panel;

                // 设置面板初始大小和透明度
                this.updatePanelSize();
                this.panel.style.opacity = config.panelOpacity;

                // 恢复面板位置
                if (config.panelPosition) {
                    this.panel.style.left = `${config.panelPosition.x}px`;
                    this.panel.style.top = `${config.panelPosition.y}px`;
                }
            }

            getSupportedLanguages() {
                return [
                    { value: 'chinese_simplified', name: '简体中文' },
                    { value: 'chinese_traditional', name: '繁體中文' },
                    { value: 'english', name: 'English' },
                    { value: 'spanish', name: 'Español' },
                    { value: 'french', name: 'Français' },
                    { value: 'german', name: 'Deutsch' },
                    { value: 'japanese', name: '日本語' },
                    { value: 'korean', name: '한국어' },
                    { value: 'russian', name: 'Русский' },
                    { value: 'arabic', name: 'العربية' },
                    { value: 'portuguese', name: 'Português' },
                    { value: 'italian', name: 'Italiano' },
                    { value: 'dutch', name: 'Nederlands' },
                    { value: 'polish', name: 'Polski' },
                    { value: 'turkish', name: 'Türkçe' },
                    { value: 'vietnamese', name: 'Tiếng Việt' },
                    { value: 'hindi', name: 'हिन्दी' },
                    { value: 'hebrew', name: 'עברית' },
                    { value: 'thai', name: 'ไทย' },
                    { value: 'indonesian', name: 'Bahasa Indonesia' }
                ];
            }

            updatePanelSize() {
                const mobile = isMobile();
                const size = this.configManager.get('panelSize');
                const baseWidth = mobile ? window.innerWidth * 0.9 : 420;
                const baseHeight = mobile ? window.innerHeight * 0.8 : 650;
                
                const width = Math.min(baseWidth * size, mobile ? window.innerWidth * 0.95 : 650);
                const maxHeight = baseHeight * size;
                
                this.panel.style.width = `${width}px`;
                this.panel.style.maxHeight = `${maxHeight}px`;
                
                // 更新body的最大高度
                const body = this.panel.querySelector('.translate-panel-body');
                if (body) {
                    body.style.maxHeight = `${maxHeight - 60}px`;
                }
            }

            bindEvents() {
                const mobile = isMobile();

                if (mobile) {
                    this.bindMobileEvents();
                } else {
                    this.bindDesktopEvents();
                }

                this.bindCommonEvents();
                this.bindPanelDragEvents();
            }

            bindPanelDragEvents() {
                const header = this.panel.querySelector('.translate-panel-header');
                const mobile = isMobile();

                if (mobile) {
                    // 移动端面板拖动
                    let isDragging = false;
                    let startX, startY, initialX, initialY;
                    let longPressTimer = null;

                    header.addEventListener('touchstart', (e) => {
                        if (e.target.id === 'translate-panel-close') return;
                        
                        const touch = e.touches[0];
                        startX = touch.clientX;
                        startY = touch.clientY;
                        initialX = this.panel.offsetLeft;
                        initialY = this.panel.offsetTop;
                        
                        longPressTimer = setTimeout(() => {
                            isDragging = true;
                            this.panel.classList.add('dragging');
                            if (navigator.vibrate) {
                                navigator.vibrate(50);
                            }
                        }, 300);
                        
                        e.preventDefault();
                    });

                    header.addEventListener('touchmove', (e) => {
                        if (!isDragging) {
                            if (longPressTimer) {
                                const touch = e.touches[0];
                                const moveDistance = Math.sqrt(
                                    Math.pow(touch.clientX - startX, 2) + 
                                    Math.pow(touch.clientY - startY, 2)
                                );
                                if (moveDistance > 10) {
                                    clearTimeout(longPressTimer);
                                    longPressTimer = null;
                                }
                            }
                            return;
                        }
                        
                        const touch = e.touches[0];
                        const dx = touch.clientX - startX;
                        const dy = touch.clientY - startY;
                        
                        let newX = initialX + dx;
                        let newY = initialY + dy;
                        
                        const maxX = window.innerWidth - this.panel.offsetWidth;
                        const maxY = window.innerHeight - this.panel.offsetHeight;
                        
                        newX = Math.max(0, Math.min(newX, maxX));
                        newY = Math.max(0, Math.min(newY, maxY));
                        
                        this.panel.style.left = `${newX}px`;
                        this.panel.style.top = `${newY}px`;
                        
                        e.preventDefault();
                    });

                    header.addEventListener('touchend', () => {
                        if (longPressTimer) {
                            clearTimeout(longPressTimer);
                            longPressTimer = null;
                        }
                        
                        if (isDragging) {
                            isDragging = false;
                            this.panel.classList.remove('dragging');
                            
                            this.configManager.set('panelPosition', {
                                x: parseInt(this.panel.style.left),
                                y: parseInt(this.panel.style.top)
                            });
                        }
                    });
                } else {
                    // PC端面板拖动
                    let isDragging = false;
                    let startX, startY, initialX, initialY;

                    header.addEventListener('mousedown', (e) => {
                        if (e.target.id === 'translate-panel-close') return;
                        
                        isDragging = true;
                        startX = e.clientX;
                        startY = e.clientY;
                        initialX = this.panel.offsetLeft;
                        initialY = this.panel.offsetTop;
                        
                        this.panel.classList.add('dragging');
                        e.preventDefault();
                    });

                    document.addEventListener('mousemove', (e) => {
                        if (!isDragging) return;
                        
                        const dx = e.clientX - startX;
                        const dy = e.clientY - startY;
                        
                        let newX = initialX + dx;
                        let newY = initialY + dy;
                        
                        const maxX = window.innerWidth - this.panel.offsetWidth;
                        const maxY = window.innerHeight - this.panel.offsetHeight;
                        
                        newX = Math.max(0, Math.min(newX, maxX));
                        newY = Math.max(0, Math.min(newY, maxY));
                        
                        this.panel.style.left = `${newX}px`;
                        this.panel.style.top = `${newY}px`;
                    });

                    document.addEventListener('mouseup', () => {
                        if (isDragging) {
                            isDragging = false;
                            this.panel.classList.remove('dragging');
                            
                            this.configManager.set('panelPosition', {
                                x: parseInt(this.panel.style.left),
                                y: parseInt(this.panel.style.top)
                            });
                        }
                    });
                }
            }

            bindMobileEvents() {
                let longPressTimer = null;
                let isDragging = false;
                let hasMoved = false;

                this.floatBall.addEventListener('touchstart', (e) => {
                    e.preventDefault();
                    const touch = e.touches[0];
                    this.touchStartPos = { x: touch.clientX, y: touch.clientY };
                    this.touchStartTime = Date.now();
                    hasMoved = false;
                    
                    longPressTimer = setTimeout(() => {
                        isDragging = true;
                        this.floatBall.classList.add('dragging');
                        if (navigator.vibrate) {
                            navigator.vibrate(50);
                        }
                    }, 300);

                    this.dragOffset.x = touch.clientX - this.floatBall.offsetLeft;
                    this.dragOffset.y = touch.clientY - this.floatBall.offsetTop;
                });

                this.floatBall.addEventListener('touchmove', (e) => {
                    e.preventDefault();
                    const touch = e.touches[0];
                    
                    const moveDistance = Math.sqrt(
                        Math.pow(touch.clientX - this.touchStartPos.x, 2) + 
                        Math.pow(touch.clientY - this.touchStartPos.y, 2)
                    );
                    
                    if (moveDistance > 10) {
                        hasMoved = true;
                        if (longPressTimer) {
                            clearTimeout(longPressTimer);
                            longPressTimer = null;
                        }
                    }

                    if (isDragging) {
                        let newX = touch.clientX - this.dragOffset.x;
                        let newY = touch.clientY - this.dragOffset.y;
                        
                        if (!this.configManager.get('allowHalfBall')) {
                            const maxX = window.innerWidth - this.floatBall.offsetWidth;
                            const maxY = window.innerHeight - this.floatBall.offsetHeight;
                            newX = Math.max(0, Math.min(newX, maxX));
                            newY = Math.max(0, Math.min(newY, maxY));
                        } else {
                            const halfSize = this.floatBall.offsetWidth / 2;
                            const maxX = window.innerWidth - halfSize;
                            const maxY = window.innerHeight - halfSize;
                            newX = Math.max(-halfSize, Math.min(newX, maxX));
                            newY = Math.max(-halfSize, Math.min(newY, maxY));
                        }
                        
                        this.floatBall.style.left = `${newX}px`;
                        this.floatBall.style.top = `${newY}px`;
                    }
                });

                this.floatBall.addEventListener('touchend', (e) => {
                    e.preventDefault();
                    
                    if (longPressTimer) {
                        clearTimeout(longPressTimer);
                        longPressTimer = null;
                    }

                    this.floatBall.classList.remove('dragging');

                    if (isDragging) {
                        this.configManager.set('floatBallPosition', {
                            x: parseInt(this.floatBall.style.left),
                            y: parseInt(this.floatBall.style.top)
                        });
                    } else if (!hasMoved) {
                        this.handleBallClick();
                    }

                    isDragging = false;
                    hasMoved = false;
                });
            }

            bindDesktopEvents() {
                this.floatBall.addEventListener('click', (e) => {
                    if (!this.isDragging) {
                        this.handleBallClick();
                    }
                });

                this.floatBall.addEventListener('mousedown', (e) => {
                    this.isDragging = false;
                    this.dragOffset.x = e.clientX - this.floatBall.offsetLeft;
                    this.dragOffset.y = e.clientY - this.floatBall.offsetTop;
                    this.floatBall.classList.add('dragging');
                    
                    const mouseMoveHandler = (e) => {
                        this.isDragging = true;
                        let newX = e.clientX - this.dragOffset.x;
                        let newY = e.clientY - this.dragOffset.y;
                        
                        if (!this.configManager.get('allowHalfBall')) {
                            const maxX = window.innerWidth - this.floatBall.offsetWidth;
                            const maxY = window.innerHeight - this.floatBall.offsetHeight;
                            newX = Math.max(0, Math.min(newX, maxX));
                            newY = Math.max(0, Math.min(newY, maxY));
                        } else {
                            const halfSize = this.floatBall.offsetWidth / 2;
                            const maxX = window.innerWidth - halfSize;
                            const maxY = window.innerHeight - halfSize;
                            newX = Math.max(-halfSize, Math.min(newX, maxX));
                            newY = Math.max(-halfSize, Math.min(newY, maxY));
                        }
                        
                        this.floatBall.style.left = `${newX}px`;
                        this.floatBall.style.top = `${newY}px`;
                    };
                    
                    const mouseUpHandler = () => {
                        document.removeEventListener('mousemove', mouseMoveHandler);
                        document.removeEventListener('mouseup', mouseUpHandler);
                        this.floatBall.classList.remove('dragging');
                        
                        if (this.isDragging) {
                            this.configManager.set('floatBallPosition', {
                                x: parseInt(this.floatBall.style.left),
                                y: parseInt(this.floatBall.style.top)
                            });
                        }
                        
                        setTimeout(() => {
                            this.isDragging = false;
                        }, 100);
                    };
                    
                    document.addEventListener('mousemove', mouseMoveHandler);
                    document.addEventListener('mouseup', mouseUpHandler);
                });
            }

            handleBallClick() {
                const doubleClickEnabled = this.configManager.get('doubleClickToggle');
                const currentTime = Date.now();
                
                if (doubleClickEnabled) {
                    this.clickCount++;
                    
                    if (this.clickCount === 1) {
                        // 第一次点击,等待第二次点击
                        this.clickTimer = setTimeout(() => {
                            // 超时,只是单击,打开设置面板
                            this.togglePanel();
                            this.clickCount = 0;
                        }, 300);
                    } else if (this.clickCount === 2) {
                        // 第二次点击,是双击
                        clearTimeout(this.clickTimer);
                        this.clickCount = 0;
                        
                        // 执行双击开关翻译
                        const enabled = this.configManager.get('enabled');
                        if (!enabled) {
                            // 当前未启用,开启翻译(执行立即翻译)
                            this.configManager.set('enabled', true);
                            this.translateManager.toggle(true);
                            const targetLang = this.configManager.get('targetLanguage');
                            this.translateManager.changeLanguage(targetLang);
                            this.updateUI();
                            this.toast.show('✅ 翻译已开启');
                        } else {
                            // 当前已启用,关闭翻译
                            this.configManager.set('enabled', false);
                            this.translateManager.toggle(false);
                            this.updateUI();
                            this.toast.show('❌ 翻译已关闭');
                        }
                    }
                } else {
                    // 未启用双击功能,直接打开设置面板
                    this.togglePanel();
                }
            }

            bindCommonEvents() {
                // 面板关闭按钮
                document.getElementById('translate-panel-close').addEventListener('click', () => {
                    this.togglePanel();
                });

                // 立即翻译按钮
                document.getElementById('translate-now-btn').addEventListener('click', () => {
                    const targetLang = this.configManager.get('targetLanguage');
                    this.translateManager.changeLanguage(targetLang);
                    this.toast.show('🚀 正在翻译...');
                    this.togglePanel();
                });

                // 启用翻译开关
                document.getElementById('translate-enable').addEventListener('change', (e) => {
                    this.configManager.set('enabled', e.target.checked);
                    this.translateManager.toggle(e.target.checked);
                    this.updateUI();
                    this.toast.show(e.target.checked ? '✅ 翻译已启用' : '❌ 翻译已禁用');
                });

                // 自动翻译开关
                document.getElementById('translate-auto').addEventListener('change', (e) => {
                    this.configManager.set('autoTranslate', e.target.checked);
                    this.toast.show(e.target.checked ? '✅ 自动翻译已启用' : '❌ 自动翻译已禁用');
                });

                // 本地语言选择
                document.getElementById('translate-local-lang').addEventListener('change', (e) => {
                    this.configManager.set('localLanguage', e.target.value);
                    if (typeof translate !== 'undefined') {
                        translate.language.setLocal(e.target.value);
                    }
                    this.toast.show('✅ 源语言已更新');
                });

                // 目标语言选择
                document.getElementById('translate-target-lang').addEventListener('change', (e) => {
                    this.configManager.set('targetLanguage', e.target.value);
                    this.toast.show('✅ 目标语言已更新');
                });

                // 显示悬浮球开关
                document.getElementById('translate-show-ball').addEventListener('change', (e) => {
                    this.configManager.set('showFloatBall', e.target.checked);
                    this.floatBall.style.display = e.target.checked ? 'flex' : 'none';
                    this.toast.show(e.target.checked ? '✅ 悬浮球已显示' : '❌ 悬浮球已隐藏');
                });

                // 允许悬浮球超出边缘
                document.getElementById('translate-allow-half').addEventListener('change', (e) => {
                    this.configManager.set('allowHalfBall', e.target.checked);
                    this.ensureInViewport();
                    this.toast.show(e.target.checked ? '✅ 允许超出边缘' : '❌ 禁止超出边缘');
                });

                // 双击开关翻译
                document.getElementById('translate-double-click').addEventListener('change', (e) => {
                    this.configManager.set('doubleClickToggle', e.target.checked);
                    this.toast.show(e.target.checked ? '✅ 双击开关翻译已启用' : '❌ 双击开关翻译已禁用');
                });

                // 悬浮球大小滑块
                const sizeSlider = document.getElementById('translate-ball-size');
                if (sizeSlider) {
                    sizeSlider.addEventListener('input', (e) => {
                        const size = parseInt(e.target.value);
                        this.configManager.set('floatBallSize', size);
                        this.floatBall.style.width = `${size}px`;
                        this.floatBall.style.height = `${size}px`;
                        e.target.nextElementSibling.textContent = `${size}px`;
                        this.ensureInViewport();
                    });
                }

                // 悬浮球透明度滑块
                const opacitySlider = document.getElementById('translate-ball-opacity');
                if (opacitySlider) {
                    opacitySlider.addEventListener('input', (e) => {
                        const opacity = parseInt(e.target.value) / 100;
                        this.configManager.set('floatBallOpacity', opacity);
                        this.floatBall.style.opacity = opacity;
                        e.target.nextElementSibling.textContent = `${e.target.value}%`;
                    });
                }

                // 控制面板大小滑块
                const panelSizeSlider = document.getElementById('translate-panel-size');
                if (panelSizeSlider) {
                    panelSizeSlider.addEventListener('input', (e) => {
                        const size = parseInt(e.target.value) / 100;
                        this.configManager.set('panelSize', size);
                        this.updatePanelSize();
                        e.target.nextElementSibling.textContent = `${e.target.value}%`;
                        this.ensurePanelInViewport();
                    });
                }

                // 控制面板透明度滑块
                const panelOpacitySlider = document.getElementById('translate-panel-opacity');
                if (panelOpacitySlider) {
                    panelOpacitySlider.addEventListener('input', (e) => {
                        const opacity = parseInt(e.target.value) / 100;
                        this.configManager.set('panelOpacity', opacity);
                        this.panel.style.opacity = opacity;
                        e.target.nextElementSibling.textContent = `${e.target.value}%`;
                    });
                }

                // 翻译服务选择
                document.getElementById('translate-service').addEventListener('change', (e) => {
                    this.configManager.set('translateService', e.target.value);
                    if (typeof translate !== 'undefined') {
                        translate.service.use(e.target.value);
                    }
                    
                    // 显示/隐藏自定义服务地址输入框
                    const customServiceGroup = document.getElementById('custom-service-group');
                    if (customServiceGroup) {
                        customServiceGroup.style.display = e.target.value === 'translate.service' ? 'block' : 'none';
                    }
                    
                    this.toast.show('✅ 翻译服务已更新');
                });

                // 保存自定义服务地址
                document.getElementById('save-custom-service').addEventListener('click', () => {
                    const input = document.getElementById('custom-service-urls');
                    const value = input.value.trim();
                    this.configManager.set('customServiceUrls', value);
                    
                    // 立即应用设置
                    if (value && typeof translate !== 'undefined') {
                        const urls = value.split(',').map(url => url.trim()).filter(url => url);
                        if (urls.length > 0) {
                            translate.request.api.host = urls.length === 1 ? urls[0] : urls;
                        }
                    }
                    
                    this.toast.show('✅ 自定义服务地址已保存');
                });

                // 保存忽略的Class
                document.getElementById('save-ignore-class').addEventListener('click', () => {
                    const input = document.getElementById('ignore-class-input');
                    const value = input.value.trim();
                    this.configManager.set('ignoredClasses', value);
                    this.translateManager.applyIgnoreSettings();
                    this.toast.show('✅ 忽略Class设置已保存');
                });

                // 保存忽略的ID
                document.getElementById('save-ignore-id').addEventListener('click', () => {
                    const input = document.getElementById('ignore-id-input');
                    const value = input.value.trim();
                    this.configManager.set('ignoredIds', value);
                    this.translateManager.applyIgnoreSettings();
                    this.toast.show('✅ 忽略ID设置已保存');
                });

                // 保存自定义术语
                document.getElementById('save-custom-terms').addEventListener('click', () => {
                    const input = document.getElementById('custom-terms-input');
                    const value = input.value.trim();
                    this.configManager.set('customTerms', value);
                    this.translateManager.applyCustomTerms();
                    this.toast.show('✅ 自定义术语已保存');
                });

                // 鼠标划词翻译(仅PC端)
                const selectionToggle = document.getElementById('translate-selection');
                if (selectionToggle) {
                    selectionToggle.addEventListener('change', (e) => {
                        this.configManager.set('enableSelectionTranslate', e.target.checked);
                        if (e.target.checked) {
                            this.translateManager.startSelectionTranslate();
                            this.toast.show('✅ 鼠标划词翻译已启用');
                        } else {
                            this.translateManager.stopSelectionTranslate();
                            this.toast.show('❌ 鼠标划词翻译已禁用');
                        }
                    });
                }

                // 动态内容监听
                document.getElementById('translate-listener').addEventListener('change', (e) => {
                    this.configManager.set('enableListener', e.target.checked);
                    if (e.target.checked && !this.translateManager.listenerStarted) {
                        this.translateManager.startListener();
                    }
                    this.toast.show(e.target.checked ? '✅ 动态内容监听已启用' : '❌ 动态内容监听已禁用');
                });

                // 缓存优化
                document.getElementById('translate-cache').addEventListener('change', (e) => {
                    this.configManager.set('enableCache', e.target.checked);
                    if (typeof translate !== 'undefined' && translate.storage) {
                        if (e.target.checked) {
                            translate.storage.enable();
                        } else {
                            translate.storage.disable();
                        }
                    }
                    this.toast.show(e.target.checked ? '✅ 缓存优化已启用' : '❌ 缓存优化已禁用');
                });

                // 重置悬浮球位置按钮
                document.getElementById('translate-reset-ball-btn').addEventListener('click', () => {
                    const defaultPosition = { x: 20, y: 100 };
                    this.floatBall.style.left = `${defaultPosition.x}px`;
                    this.floatBall.style.top = `${defaultPosition.y}px`;
                    this.configManager.set('floatBallPosition', defaultPosition);
                    this.toast.show('✅ 悬浮球位置已重置');
                });

                // 重置面板位置按钮
                document.getElementById('translate-reset-panel-btn').addEventListener('click', () => {
                    this.configManager.set('panelPosition', null);
                    this.positionPanel();
                    this.toast.show('✅ 面板位置已重置');
                });

                // 清除缓存按钮
                document.getElementById('translate-clear-cache').addEventListener('click', () => {
                    const cleared = this.configManager.clearCache();
                    this.toast.show(`✅ 已清除 ${cleared} 个翻译缓存项`);
                });

                // 重置所有设置按钮
                document.getElementById('translate-reset-all').addEventListener('click', () => {
                    if (confirm('确定要重置所有设置吗?此操作不可撤销。')) {
                        this.configManager.reset();
                        this.toast.show('✅ 所有设置已重置,即将刷新页面...', 'success', 1500);
                        setTimeout(() => {
                            location.reload();
                        }, 1500);
                    }
                });

                // 监听窗口大小变化
                window.addEventListener('resize', () => {
                    this.ensureInViewport();
                    this.ensurePanelInViewport();
                });

                // 监听方向变化
                window.addEventListener('orientationchange', () => {
                    setTimeout(() => {
                        this.ensureInViewport();
                        this.ensurePanelInViewport();
                        this.updatePanelSize();
                    }, 300);
                });
            }

            updateUI() {
                const enabled = this.configManager.get('enabled');
                const enableCheckbox = document.getElementById('translate-enable');
                if (enableCheckbox) {
                    enableCheckbox.checked = enabled;
                }
            }

            togglePanel() {
                if (this.panel.classList.contains('show')) {
                    this.panel.classList.remove('show');
                } else {
                    this.panel.classList.add('show');
                    const savedPosition = this.configManager.get('panelPosition');
                    if (!savedPosition) {
                        this.positionPanel();
                    } else {
                        this.ensurePanelInViewport();
                    }
                }
            }

            positionPanel() {
                const mobile = isMobile();
                
                if (mobile) {
                    // 移动端居中显示
                    const panelWidth = this.panel.offsetWidth;
                    const panelHeight = this.panel.offsetHeight;
                    
                    const left = (window.innerWidth - panelWidth) / 2;
                    const top = (window.innerHeight - panelHeight) / 2;
                    
                    this.panel.style.left = `${left}px`;
                    this.panel.style.top = `${top}px`;
                } else {
                    // PC端根据悬浮球位置定位
                    const ballRect = this.floatBall.getBoundingClientRect();
                    const panelWidth = this.panel.offsetWidth;
                    const panelHeight = this.panel.offsetHeight;
                    
                    let left = ballRect.right + 10;
                    let top = ballRect.top;
                    
                    if (left + panelWidth > window.innerWidth) {
                        left = ballRect.left - panelWidth - 10;
                    }
                    
                    if (left < 0) {
                        left = (window.innerWidth - panelWidth) / 2;
                    }
                    
                    if (top < 10) {
                        top = 10;
                    }
                    
                    if (top + panelHeight > window.innerHeight - 10) {
                        top = window.innerHeight - panelHeight - 10;
                    }
                    
                    this.panel.style.left = `${left}px`;
                    this.panel.style.top = `${top}px`;
                }
            }

            ensureInViewport() {
                const position = this.configManager.get('floatBallPosition');
                const size = this.configManager.get('floatBallSize');
                const allowHalf = this.configManager.get('allowHalfBall');
                
                let x = position.x;
                let y = position.y;
                
                if (allowHalf) {
                    const halfSize = size / 2;
                    const maxX = window.innerWidth - halfSize;
                    const maxY = window.innerHeight - halfSize;
                    x = Math.max(-halfSize, Math.min(x, maxX));
                    y = Math.max(-halfSize, Math.min(y, maxY));
                } else {
                    const maxX = window.innerWidth - size;
                    const maxY = window.innerHeight - size;
                    x = Math.max(0, Math.min(x, maxX));
                    y = Math.max(0, Math.min(y, maxY));
                }
                
                this.floatBall.style.left = `${x}px`;
                this.floatBall.style.top = `${y}px`;
                
                if (x !== position.x || y !== position.y) {
                    this.configManager.set('floatBallPosition', { x, y });
                }
            }

            ensurePanelInViewport() {
                if (!this.panel.classList.contains('show')) return;
                
                const position = this.configManager.get('panelPosition');
                if (!position) return;
                
                const panelWidth = this.panel.offsetWidth;
                const panelHeight = this.panel.offsetHeight;
                
                let x = position.x;
                let y = position.y;
                
                const maxX = window.innerWidth - panelWidth;
                const maxY = window.innerHeight - panelHeight;
                
                x = Math.max(0, Math.min(x, maxX));
                y = Math.max(0, Math.min(y, maxY));
                
                this.panel.style.left = `${x}px`;
                this.panel.style.top = `${y}px`;
                
                if (x !== position.x || y !== position.y) {
                    this.configManager.set('panelPosition', { x, y });
                }
            }
        }

        // 工具函数
        function isMobile() {
            return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) 
                || window.innerWidth <= 768;
        }

        function isDarkMode() {
            return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
        }

        // 初始化
        async function init() {
            // 等待DOM加载
            if (document.readyState === 'loading') {
                await new Promise(resolve => {
                    document.addEventListener('DOMContentLoaded', resolve);
                });
            }

            try {
                // 检查是否已加载translate.js
                if (typeof translate === 'undefined') {
                    console.error('translate.js未加载,请检查@require配置');
                    return;
                }
                
                // 初始化组件
                const configManager = new ConfigManager();
                const translateManager = new TranslateManager(configManager);
                const uiManager = new UIManager(configManager, translateManager);

                // 注册菜单命令
                GM_registerMenuCommand('打开翻译设置', () => {
                    uiManager.togglePanel();
                });

                // 全局对象
                window.translateHelper = {
                    config: configManager,
                    translate: translateManager,
                    ui: uiManager
                };

                console.log('智能翻译助手已加载完成');
                console.log('使用说明:');
                console.log('- 单击悬浮球打开设置面板');
                console.log('- 拖拽悬浮球调整位置');
                console.log('- 支持100+种语言互译');
                console.log('- 可通过window.translateHelper访问API');
            } catch (error) {
                console.error('翻译脚本初始化失败:', error);
            }
        }

        // 延迟初始化主功能,确保悬浮球已显示
        setTimeout(init, 100);
    })();
})();