Greasy Fork

来自缓存

Greasy Fork is available in English.

[银河奶牛]组队招募副本信息翻译

将银河奶牛游戏中的招募信息自动翻译为中文

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name:en         [MWI]Recruitment Message Translator:zh-CN
// @name            [银河奶牛]组队招募副本信息翻译
// @namespace       https://cnb.cool/shenhuanjie/skyner-cn/tamper-monkey-script/mwi-recruitment-translator
// @version         1.0.6
// @description:en  Translate in-game recruitment messages to Chinese
// @description     将银河奶牛游戏中的招募信息自动翻译为中文
// @author          shenhuanjie
// @license         MIT
// @match           https://www.milkywayidle.com/*
// @icon            https://www.milkywayidle.com/favicon.svg
// @grant           none
// @run-at          document-end
// @homepage        http://greasyfork.icu/zh-CN/scripts/535683
// @supportURL      http://greasyfork.icu/zh-CN/scripts/535683
// ==/UserScript==

(function() {
    'use strict';

    // ========== 全局配置 ==========
    const CONFIG = {
        enableConsoleLog: false,     // 控制台日志开关,默认关闭
        caseSensitive: false,        // 是否大小写敏感
        wholeWordOnly: true,         // 是否全词匹配
        chatSelector: '.chat-message', // 聊天消息选择器
        logLevel: 'INFO',            // 日志级别: DEBUG, INFO, WARNING, ERROR
        initialScanDelay: 500,       // 初始扫描延迟(ms)
        rescanInterval: 10000,       // 重新扫描间隔(ms)
        maxTranslationDepth: 3       // 最大翻译深度
    };
    // =============================

    // ========== 翻译配置 ==========
    const TRANSLATIONS = new Map([

        // 普通星球副本 - P前缀
        ["Party: Smelly Planet", "P1:臭臭星球"],
        ["Party: Swamp Planet", "P2:沼泽星球"],
        ["Party: Aqua Planet", "P3:海洋星球"],
        ["Party: Jungle Planet", "P4:丛林星球"],
        ["Party: Gobo Planet", "P5:哥布林星球"],
        ["Party: Planet Of The Eyes", "P6:眼球星球"],
        ["Party: Sorcerer's Tower", "P7:巫师之塔"],
        ["Party: Bear With It", "P8:熊熊星球"],
        ["Party: Golem Cave", "P9:魔像洞穴"],
        ["Party: Twilight Zone", "P10:暮光之地"],
        ["Party: Infernal Abyss", "P11:地狱深渊"],

        // 地下城副本 - D前缀
        ["Party: Chimerical Den", "D1:奇幻洞穴"],
        ["Party: Sinister Circus", "D2:阴森马戏团"],
        ["Party: Enchanted Fortress", "D3:秘法要塞"],
        ["Party: Pirate Cove", "D4:海盗基地"],
    ]);
    // =============================

    // 工具函数:日志记录
    function log(message, level = 'INFO') {
        if (!CONFIG.enableConsoleLog) return;

        if (!['DEBUG', 'INFO', 'WARNING', 'ERROR'].includes(level)) {
            level = 'INFO';
        }

        if (['DEBUG', 'INFO'].includes(level) && level !== CONFIG.logLevel) {
            return;
        }

        const logColor = {
            DEBUG: '#888',
            INFO: '#2196F3',
            WARNING: '#FFC107',
            ERROR: '#F44336'
        };

        console.log(`%c[Translator][${level}] ${message}`, `color: ${logColor[level]}`);
    }

    // 工具函数:转义正则特殊字符
    function escapeRegExp(str) {
        return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    }

    // 生成翻译正则表达式模式
    function createTranslationPatterns() {
        return Array.from(TRANSLATIONS).map(([en, zh]) => {
            // 转义原始字符串中的正则特殊字符
            const escaped = escapeRegExp(en);

            // 使用字符串模板构建正则表达式,支持中英文括号的精英标识
            const patternStr = escaped
                .replace(/\((Elite)\)/, '(?:\\(|()$1(?:\\)|))')
                .replace(/((Elite))/, '(?:\\(|()$1(?:\\)|))');

            // 添加全词匹配边界(如果配置为全词匹配)
            const fullPattern = CONFIG.wholeWordOnly
                ? `\\b${patternStr}\\b`
                : patternStr;

            // 编译正则表达式
            const flags = CONFIG.caseSensitive ? 'g' : 'gi';

            return {
                pattern: new RegExp(fullPattern, flags),
                replacement: zh,
                original: en
            };
        }).sort((a, b) => b.pattern.source.length - a.pattern.source.length);
    }

    // 翻译处理器
    function translateTextNode(textNode) {
        if (!textNode || !textNode.nodeValue) return false;

        let content = textNode.nodeValue;
        let translatedContent = content;
        let modified = false;

        try {
            for (const {pattern, replacement, original} of translationPatterns) {
                if (pattern.test(translatedContent)) {
                    const newContent = translatedContent.replace(pattern, replacement);
                    if (newContent !== translatedContent) {
                        log(`替换: ${original} → ${replacement}`, 'DEBUG');
                        translatedContent = newContent;
                        modified = true;
                    }
                }
            }

            if (modified) {
                textNode.nodeValue = translatedContent;
                log(`已翻译节点: ${content.substring(0, 50)}...`, 'INFO');
                return true;
            }
        } catch (error) {
            log(`翻译过程中出错: ${error.message}`, 'ERROR');
        }

        return false;
    }

    // 检查节点是否为聊天消息
    function isChatNode(node) {
        return node.nodeType === Node.ELEMENT_NODE &&
               node.matches(CONFIG.chatSelector);
    }

    // 处理单个DOM节点及其子节点
    function processNode(node, depth = 0) {
        if (depth > CONFIG.maxTranslationDepth) return;

        if (isChatNode(node)) {
            const walker = document.createTreeWalker(
                node,
                NodeFilter.SHOW_TEXT,
                null,
                false
            );

            let translatedCount = 0;
            while (walker.nextNode()) {
                if (translateTextNode(walker.currentNode)) {
                    translatedCount++;
                }
            }

            if (translatedCount > 0) {
                log(`在聊天节点中翻译了 ${translatedCount} 处文本`, 'INFO');
            }
        } else if (node.nodeType === Node.TEXT_NODE) {
            // 直接文本节点
            translateTextNode(node);
        } else if (node.nodeType === Node.ELEMENT_NODE) {
            // 递归处理子节点
            const childNodes = Array.from(node.childNodes);
            childNodes.forEach(child => {
                processNode(child, depth + 1);
            });
        }
    }

    // 扫描并翻译整个DOM
    function scanAndTranslate() {
        log('开始扫描DOM...', 'INFO');
        const startTime = performance.now();

        try {
            const chatNodes = document.querySelectorAll(CONFIG.chatSelector);
            log(`找到 ${chatNodes.length} 个聊天节点`, 'INFO');

            let totalTranslations = 0;
            chatNodes.forEach(node => {
                const walker = document.createTreeWalker(
                    node,
                    NodeFilter.SHOW_TEXT,
                    null,
                    false
                );

                while (walker.nextNode()) {
                    if (translateTextNode(walker.currentNode)) {
                        totalTranslations++;
                    }
                }
            });

            const elapsedTime = performance.now() - startTime;
            log(`扫描完成: ${totalTranslations} 处翻译,耗时 ${elapsedTime.toFixed(2)}ms`, 'INFO');
            return totalTranslations;
        } catch (error) {
            log(`扫描过程中出错: ${error.message}`, 'ERROR');
            return 0;
        }
    }

    // 初始化函数
    function init() {
        log('翻译器初始化中...', 'INFO');

        try {
            // 初始延迟扫描,等待页面完全加载
            setTimeout(() => {
                log('执行初始DOM扫描...', 'INFO');
                const initialTranslations = scanAndTranslate();
                log(`初始扫描完成,翻译了 ${initialTranslations} 处文本`, 'INFO');

                // 动态监听DOM变化
                const observer = new MutationObserver(mutations => {
                    mutations.forEach(mutation => {
                        if (mutation.type === 'childList') {
                            // 处理新增节点
                            mutation.addedNodes.forEach(node => {
                                if (node.nodeType === Node.ELEMENT_NODE) {
                                    processNode(node);

                                    // 处理子节点
                                    const childWalker = document.createTreeWalker(
                                        node,
                                        NodeFilter.SHOW_ELEMENT,
                                        null,
                                        false
                                    );

                                    while (childWalker.nextNode()) {
                                        processNode(childWalker.currentNode);
                                    }
                                } else if (node.nodeType === Node.TEXT_NODE) {
                                    processNode(node);
                                }
                            });
                        } else if (mutation.type === 'characterData') {
                            // 处理文本内容变更
                            const textNode = mutation.target;
                            if (textNode && textNode.parentNode) {
                                if (isChatNode(textNode.parentNode)) {
                                    translateTextNode(textNode);
                                }
                            }
                        }
                    });
                });

                // 开始监听DOM变化
                observer.observe(document.body, {
                    childList: true,
                    subtree: true,
                    characterData: true
                });

                log('翻译器已启动并监听DOM变化', 'INFO');
            }, CONFIG.initialScanDelay);

            // 定期重新扫描整个DOM
            setInterval(() => {
                scanAndTranslate();
            }, CONFIG.rescanInterval);

            log(`翻译器配置: 大小写敏感=${CONFIG.caseSensitive}, 全词匹配=${CONFIG.wholeWordOnly}, 扫描间隔=${CONFIG.rescanInterval/1000}s`, 'INFO');
        } catch (error) {
            log(`初始化失败: ${error.message}`, 'ERROR');
        }
    }

    // 预编译翻译模式
    const translationPatterns = createTranslationPatterns();

    // 启动脚本
    if (document.readyState === 'loading') {
        window.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

    // 打印初始状态信息
    if (CONFIG.enableConsoleLog) {
        console.log('%c[Translator] 翻译器已加载,控制台日志已开启', 'color: #2196F3');
    } else {
        console.log('%c[Translator] 翻译器已加载,控制台日志已关闭', 'color: #888');
    }
})();