冒险岛宇宙 MSU 网页汉化

汉化 msu.io 等页面,支持自定义词典

当前为 2025-05-17 提交的版本,查看 最新版本

// ==UserScript==
// @name         冒险岛宇宙 MSU 网页汉化
// @namespace    http://tampermonkey.net/
// @version      0.5
// @description  汉化 msu.io 等页面,支持自定义词典
// @author       B站-放肆到底丶
// @homepageURL  https://space.bilibili.com/430674
// @license      MIT
// @match        https://msu.io/*
// @match        https://static.msu.io/inspection
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    
    // 翻译状态控制
    let isTranslationEnabled = localStorage.getItem('msu-translation-enabled') !== 'false';
    
    // 保存翻译状态到localStorage
    function saveTranslationState(enabled) {
        localStorage.setItem('msu-translation-enabled', enabled);
    }
    
    // 数字格式化函数
    function formatNumberToChinese(numStr) {
        const num = parseInt(numStr, 10);
        if (num >= 100000000) {
            return (num / 100000000).toFixed(0) + '亿';
        } else if (num >= 10000) {
            return (num / 10000).toFixed(0) + '万';
        }
        return numStr;
    }

    // 自定义翻译词典(用户可在此添加/修改翻译条目)
    const CUSTOM_DICT = {
        // https://msu.io/maplestoryn/
        'MapleStory N': '冒险岛N',
        'Will start soon!': '即将开始!',
        'Please wait for a moment.': '请稍等.',
        'News': '新闻',
        'New': '新',
        'notices': '公告',
        'update': '更新',
        'Event': '活动',
        'Guide': '指南',
        'Classes & Jobs': '职业 & 转职‌',
        'All': '全部',
        'Explorer': '冒险家',
        'Warrior': '战士',
        'Hero': '英雄',
        'Paladin': '圣骑士',
        'Dark Knight': '黑骑士',
        'magician': '法师',
        'Arch Mage': '魔导师',
        'Fire/Poison': '火/毒',
        'Arch Mage (Fire / Poison)': '魔导师(火/毒)',
        'Ice/Lightning': '冰/雷',
        'Arch Mage (Ice / Lightning)': '魔导师(冰/雷)',
        'Bishop': '主教',
        'bowman': '弓箭手',
        'Bowmaster': '神射手',
        'Marksman': '箭神',
        'thief': '飞侠',
        'Night Lord': '隐士',
        'Shadower': '侠盗',
        'pirate': '海盗',
        'Buccaneer': '冲锋队长',
        'Corsair': '船长',
        'Job Advancement': '职业转职',
        'Beginner': '新手',
        '1st Job': '一转',
        '2nd Job': '二转',
        '3rd Job': '三转',
        '4th Job': '四转',
        'Beginner’s Guide': '新手上路',
        'Download Guide': '下载中心',
        'Game Status': '游戏状态',
        'Ranking': '排名',
        'Dynamic Pricing': '动态定价',
        'Probability Info': '概率信息',
        // https://msu.io/maplestoryn/gamestatus/probabilityitems
        'Equipment Category': '装备分类',
        'Stat': '属性',
        'STR': '力量',
        'DEX': '敏捷',
        'INT': '智力',
        'LUK': '幸运',
        'STR+DEX': '力量+敏捷',
        'STR+INT': '力量+智力',
        'STR+LUK': '力量+幸运',
        'DEX+INT': '敏捷+智力',
        'DEX+LUK': '敏捷+幸运',
        'INT+LUK': '智力+幸运',
        'Max HP': '最大HP',
        'Max MP': '最大MP',
        'Reduced Level Requirement': '降低等级要求',
        'DEF': '防御',
        'ATT': '攻击',
        'Magic ATT': '魔法攻击',
        'DEF Ignored': '无视防御',
        'Damage': '伤害',
        'ALL Stats': '全部属性',
        'Other Equipment': '其他装备',
        'Movement Speed': '移动速度',
        'Jump': '跳跃力',
        'Marketplace': '市场',
        // https://msu.io/marketplace
        'Connect your wallet and use the marketplace!': '连接你的钱包并使用市场!',
        'Recommended Items': '推荐物品',
        'Fortify Your Journey with Unchained Armors!': '解锁无限护甲!',
        'Accelerate Your Adventure with Unchained Weapons!': '解锁无限武器!',
        'Your NFT Collection Grows With Every Step.': '你的 NFT 收藏随着每一步的进展而增长。',
        'RECOMMENDED': '推荐',
        'ITEMS': '物品',
        'Hey!': '嗨!',
        'How about this?': '试试这个?',
        'Past 30 Days': '过去30天',
        'Total Listings': '总列表',
        'Total Active Wallets': '总活跃钱包',
        'Total Sales': '总销售额',
        'Total Trading volume': '总交易量',
        'Sales': '销售额',
        'Recent': '最近',
        'Listings': '列表',
        'Traders': '交易者',
        '7 Days': '7天',
        '30 Days': '30天',
        'Type': '类型',
        'Skill': '技能',
        'Popular Searches': '热门搜索',
        // https://msu.io/marketplace/nft
        'NFT Items': 'NFT 物品',
        'Price: Low to High': '价格: 低到高',
        'Price: High to Low': '价格: 高到低',
        'Time: Ending Soon': '时间: 即将结束',
        'Time: Newly Listed': '时间: 最新发布',
        'Offer': '报价',
        'Price': '价格',
        'Expiration': '到期时间',
        'From': '来自',
        'Price Range': '价格范围',
        'Unique Number': '唯一编号',
        'Item Type': '物品类型',
        'Weapon': '武器',
        'One-handed Weapon': '单手武器',
        'One-handed Sword': '单手剑',
        'One-handed Axe': '单手斧',
        'One-handed Blunt Weapon': '单手锤',
        'Dagger': '匕首',
        'Wand': '魔杖',
        'Staff': '法杖',
        'Two-handed Weapon': '双手武器',
        'Two-handed Sword': '双手剑',
        'Two-handed Axe': '双手斧',
        'Two-handed Blunt': '双手钝器',
        'Spear': '长矛',
        'Polearm': '长柄武器',
        'Bow': '弓',
        'Crossbow': '弩',
        'Claw': '爪',
        'Knuckle': '拳',
        'Gun': '枪',
        'Secondary Weapon': '副手武器',
        'Medal': '勋章',
        'Rosary': '念珠',
        'Iron Chain': '铁链',
        'Magic Book': '魔法书',
        'Arrow Fletching': '箭羽',
        'Bow Thimble': '弓顶针',
        'Dagger Scabbard': '匕首剑鞘',
        'Charm': '符咒',
        'Wrist Band': '腕带',
        'Far Sight': '远视',
        'Armor': '防具',
        'Hat': '帽子',
        'Top': '上衣',
        'Outfit': '套装',
        'Bottom': '下装',
        'Shoes': '鞋子',
        'Gloves': '手套',
        'Cape': '披风',
        'Accessory': '饰品',
        'Face Accessory': '脸部饰品',
        'Eye Accessory': '眼部饰品',
        'Earrings': '耳环',
        'Ring': '戒指',
        'Pendant': '吊坠',
        'Belt': '腰带',
        'Shoulder Accessory': '肩部饰品',
        'Pocket Item': '口袋物品',
        'Badge': '徽章',
        'Emblem': '纹章',
        'Decoration': '装饰',
        'Pet Equipment': '宠物装备',
        'Beauty': '美容',
        'Face': '脸部',
        'Hair': '头发',
        'Skin': '皮肤',
        'Color': '颜色',
        'Select Color': '选择颜色',
        'Utility': '实用',
        'Pet': '宠物',
        'Expanded Auto Move': '扩展自动移动',
        'Expanded Auto Move Skill': '扩展自动移动技能',
        'Magnet Effect': '磁力效果',
        'Magnet Effect Skill': '磁力效果技能',
        'Auto Buff': '自动Buff',
        'Auto Buff Skill': '自动Buff技能',
        'Auto Move': '自动移动',
        'Auto Move Skill': '自动移动技能',
        'Fatten Up Skill': '增强技能',
        'Pet Training Skill': '宠物训练技能',
        'Multi Pet(Can use up to 3 pets at once)': '多宠物(一次最多使用3个)',
        'Item Pouch, Auto HP Potion Pouch,Auto MP Potion Pouch, NESO Magnet': '物品袋,自动HP药水袋,自动MP药水袋,NESO磁力',
        'Set-up': '配置',
        'Chair': '椅子',
        'Mount': '坐骑',
        'Damage Skin': '伤害皮肤',
        'Arrow, Throwing Stars, and Bullets': '箭、飞镖和子弹',
        'Arrow for Bow': '弓用箭矢',
        'Arrow for Crossbow': '弩用箭矢',
        'Throwing Stars': '飞镖',
        'Bullets': '子弹',
        'Class': '基础职业',
        'Job': '职业',
        'Potential': '潜力',
        'Bonus Potential': '额外潜力',
        'None': '无',
        'Rare': '稀有',
        'Epic': '史诗',
        'Unique': '唯一',
        'Legendary' : '传说',
        'Level Range': '等级范围',
        'Star Force Enhancement': '星级强化',
        'Search': '搜索',
        'Reset': '重置',
        'Save Filter': '保存筛选',
        'Preview': '预览',
        'Return to item image': '返回物品图片',
        'History': '历史',
        'There is no history to display.': '没有可显示的历史。',
        'Name': '名称',
        'Character': '角色',
        'Date': '日期',
        'Details': '详情',
        'Circulating Supply': '流通供应量',
        'Max Supply': '最大供应量',
        'Token Standard': '代币标准',
        'Day(s)': '天',
        // https://msu.io/marketplace/ft
        'FT Items': 'FT 物品',
        'Umushroom Coupon (100-Day)': '蘑菇卷 Umushroom Coupon (100天)',
        'Red Florin': '红色弗林 Red Florin',
        'Blue Florin': '蓝色弗林 Blue Florin',
        'Green Florin': '绿色弗林 Green Florin',
        'Vol.': '成交量',
        // https://msu.io/marketplace/character
        'Exchange Currency': '交换货币',
        'Voucher': '兑换券',
        'By Highest Trading Volume': '按最高交易量排序',
        'By Lowest Price': '按最低价格',
        'By Highest Price': '按最高价格',
        'By Highest Increase': '按最高涨幅排序',
        'By Lowest Increase': '按最低涨幅排序',
        'View My Items Only': '只查看我的物品',
        'Normal': '普通',
        'Your holdings': '你的持有',
        'Floor price': '地板价格',
        'Prev Day Avg Price': '昨日平均价',
        '24h Volume': '24小时交易量',
        '24h Volume(NESO)': '24小时交易量 (NESO)',
        'Available Listings': '可用列表',
        'There are no listings.': '没有列表。',
        'Price (NESO)': '价格 (NESO)',
        'Quantity': '数量',
        'Buy': '购买',
        'Buy Now': '立即购买',
        'Available': '可用',
        'The purchase quantity has changed due to the listing status.': '由于列表状态的变化,购买数量已更改。',
        'Expected Price': '预期价格',
        'Automaticallymatches youwithlistings thatcanbepurchased atthelowest price,afterpriceper itemandfees.Calculations exclude items you\'ve listed.': '自动为您匹配在扣除每件物品价格和手续费后可按最低价格购买的列表。计算时排除您已列出的物品。',
        'Average Price per Item': '平均价格/件',
        'You will pay': '你将支付',
        'Sell': '出售',
        'Enter Price per Item': '输入价格/件',
        'Fee': '手续费',
        'You will get': '你将获得',
        'Trade History': '交易历史',
        'Highest Price': '最高价格',
        'Lowest Price': '最低价格',
        'Average Price': '平均价格',
        'Trading Volume': '交易量',
        'Time': '时间',
        'Price History': '价格历史',
        '- Highest Price': '- 最高价格',
        '- Lowest Price': '- 最低价格',
        '- Average Price': '- 平均价格',
        '- Trading Volume': '- 交易量',
        '7Day': '7天',
        '30Day': '30天',
        'Trading Volume(NESO)': '交易量 (NESO)',
        'Average Price(NESO)': '平均价格 (NESO)',
        'No trade history to display': '没有交易历史可显示',
        'My Listings': '我的列表',
        'All Items': '所有物品',
        'Current Item': '当前物品',
        'Log in to check your listings': '登录(不可用)以查看您的列表。',
        'There is no active listings.': '没有活跃列表。',
        'Characters': '角色',
        // https://msu.io/marketplace/bid
        'Advanced Search (5)': '高级搜索 (5)',
        'Select': '选择',
        'Bid': '投标',
        // https://msu.io/marketplace/bid
        'Watching': '关注',
        'Bid Size: Large to Small': '投标大小: 从大到小',
        'Bid Price: High to Low': '投标价格: 从高到低',
        'Total Number of Bids': '总投标数',
        'Highest Bid': '最高投标',
        'All Bids': '所有投标',
        'Place Bid': '投标',
        'Bidder': '投标人',
        'Price per Items': '价格/件',
        'My Order': '我的订单',
        'There is no active order.': '没有活跃订单。',
        'Connect': '连接',
        'Connect Wallet': '连接钱包',
        'Connect your wallet to use MapleStory Universe!': '连接钱包即可使用 冒险岛宇宙!',
        'Continue with': '继续使用',
        'Inventory': '背包',
        'Insufficient Balance': '余额不足',
        'Logout': '登出',
        // https://msu.io/marketplace/inventory/
        'Owned': '拥有',
        'On sale': '出售中',
        'Bookmark': '收藏夹',
        'Activity': '活动',
        // https://msu.io/
        'My Page': '我的页面',
        'Overview': '概览',
        'MapleStory Universe is currently undergoing scheduled maintenance to improve our services.We apologize for the inconvenience and appreciate your patience.Don\'t forget to keep up with our official channels for the latest updates.We\'re excited to see you in MapleStory Universe: The Genesis soon!': '冒险岛N 目前正在进行计划维护以改进我们的服务。\n对于造成的不便我们深表歉意,感谢您的耐心等待。\n请关注我们的官方渠道获取最新消息。\n我们期待在《冒险岛宇宙:起源》中与您相见!',
        'Verification': '验证',
        'Setting': '设置',
        // https://static.msu.io/inspection
        'Server Under Maintenance': '服务器维护中',
        'We are currently undergoing scheduled maintenance to improve our services.We apologize for the inconvenience and appreciate your patience.Don\'t forget to keep up with our official channels for the latest updates.We hope to see you again soon!': '我们目前正在进行计划维护以改进我们的服务。\n对于造成的不便我们深表歉意,感谢您的耐心等待。\n请关注我们的官方渠道获取最新消息。\n期待很快与您再见!',
    };
    
    /**
     * 创建悬浮控制按钮
     */
    function createFloatingButton() {
        const button = document.createElement('button');
        button.id = 'msu-translation-toggle';
        button.className = 'msu-translation-button';
        button.textContent = isTranslationEnabled ? '翻译: 开启' : '翻译: 关闭';
        
        // 按钮样式
        button.style.position = 'fixed';
        button.style.bottom = '20px';
        button.style.right = '20px';
        button.style.zIndex = '9999';
        button.style.padding = '8px 16px';
        button.style.borderRadius = '4px';
        button.style.backgroundColor = isTranslationEnabled ? '#4CAF50' : '#f44336';
        button.style.color = 'white';
        button.style.border = 'none';
        button.style.cursor = 'pointer';
        button.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)';
        
        // 点击事件
        button.addEventListener('click', () => {
            isTranslationEnabled = !isTranslationEnabled;
            button.textContent = isTranslationEnabled ? '翻译: 开启' : '翻译: 关闭';
            button.style.backgroundColor = isTranslationEnabled ? '#4CAF50' : '#f44336';
            
            saveTranslationState(isTranslationEnabled);
            
            if (isTranslationEnabled) {
                translateElement(document.body);
            } else {
                location.reload();
            }
        });
        
        document.body.appendChild(button);
    }

    /**
     * 遍历元素并应用翻译
     * @param {Element} element - 要处理的DOM元素
     */
    function translateElement(element) {
        // 如果翻译已禁用则跳过
        if (!isTranslationEnabled) return;
        
        // 跳过脚本、样式等非文本元素
        if (element.tagName === 'SCRIPT' || element.tagName === 'STYLE') return;

        // 处理文本节点
        if (element.nodeType === Node.TEXT_NODE) {
            const originalText = element.textContent.trim();
            // 查找不区分大小写的匹配项,支持复数形式
            // 处理带日期的特殊文本
            if (originalText.startsWith('Sale ends on ')) {
                const datePart = originalText.substring('Sale ends on '.length);
                if (/\d{4}-\d{2}-\d{2} \d{2}:\d{2}/.test(datePart)) {
                    element.textContent = '销售截止于 ' + datePart;
                    return;
                }
            }
            
            // 先尝试匹配数字
            if (/^\d+$/.test(originalText)) {
                element.textContent = formatNumberToChinese(originalText);
                return;
            }

            // 新增:特殊处理 'Record-' 和 'breaking' 的组合
            // 例如:<span>Record-</span><br><span>breaking</span>
            if (originalText === 'Record-' && element.parentNode && element.parentNode.tagName === 'SPAN') {
                let currentSibling = element.parentNode.nextSibling;
                let breakingSpan = null;

                // 遍历兄弟节点,寻找 'breaking' 所在的 SPAN,可以跳过 BR 标签
                while (currentSibling) {
                    if (currentSibling.nodeType === Node.ELEMENT_NODE) { // 只处理元素节点
                        if (currentSibling.tagName === 'SPAN' && currentSibling.textContent.trim().toLowerCase() === 'breaking') {
                            breakingSpan = currentSibling;
                            break; // 找到了目标 SPAN
                        } else if (currentSibling.tagName !== 'BR') {
                            // 如果遇到非 BR 的其他元素,则停止搜索,说明结构不匹配
                            break;
                        }
                    }
                    currentSibling = currentSibling.nextSibling;
                }

                if (breakingSpan) {
                    element.textContent = ''; // 清空 "Record-" 所在的文本节点
                    breakingSpan.textContent = '历史新高';    // 翻译 "breaking" SPAN 的内容
                    return; // 已处理此特殊组合,提前返回
                }
            }
            
            // 特殊处理'Top'与'Traders'同时出现的情况
            if (originalText === 'Top' && element.parentElement && 
                Array.from(element.parentElement.children).some(child => 
                    child.textContent.includes('Traders')
                )) {
                element.textContent = 'Top榜';
                return;
            }
            
            // 如果不是数字,再尝试匹配字典
            const matchedKey = Object.keys(CUSTOM_DICT).find(
                key => {
                    // 标准化键名和文本,处理特殊字符
                    const normalizedKey = key.toLowerCase().replace(/[’']/g, "'");
                    const normalizedText = originalText.toLowerCase().replace(/[’']/g, "'");
                    const keyWithoutSpaces = normalizedKey.replace(/\s+/g, '');
                    const textWithoutSpaces = normalizedText.replace(/\s+/g, '');
                    // 完全匹配或复数形式匹配(以s结尾)或无空格匹配
                    return normalizedKey === normalizedText || 
                           (normalizedText.endsWith('s') && normalizedKey === normalizedText.slice(0, -1)) ||
                           keyWithoutSpaces === textWithoutSpaces;
                }
            );
            if (matchedKey) {
                element.textContent = element.textContent.replace(originalText, CUSTOM_DICT[matchedKey]);
            }
        }

        // 递归处理子元素
        for (const child of element.childNodes) {
            translateElement(child);
        }
    }

    // 页面加载完成后触发翻译
    window.addEventListener('load', () => {
        createFloatingButton();
        if (isTranslationEnabled) {
            translateElement(document.body);
        }

        // 监听DOM变化(处理动态加载内容和按钮移除)
        const observer = new MutationObserver((mutations) => {
            mutations.forEach((mutation) => {
                // 检查移除的节点
                mutation.removedNodes.forEach((node) => {
                    if (node.id === 'msu-translation-toggle') {
                        createFloatingButton();
                    }
                });
                
                // 处理新增节点和文本变化
                mutation.addedNodes.forEach((node) => {
                    if (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.TEXT_NODE) {
                        translateElement(node);
                    }
                });
                
                // 处理属性变化
                if (mutation.type === 'attributes') {
                    translateElement(mutation.target);
                }
            });
        });

        // 监听整个文档的交互事件
        document.addEventListener('click', (event) => {
            // 延迟执行以确保DOM更新完成
            setTimeout(() => {
                if (isTranslationEnabled) {
                    translateElement(document.body);
                }
            }, 100);
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true,
            characterData: true,
            characterDataOldValue: true,
            attributes: true,
            attributeOldValue: true
        });
    });
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址