// ==UserScript== // @name CurseForge 界面汉化 // @namespace https://github.com/Chuc-Jie/curseforge-chinese // @version 1.3.1 // @description 汉化 CurseForge 网站界面,仅完全匹配词典条目,避免混合翻译。优化性能与动态路由支持。 // @author 友野YouyEr // @icon https://www.curseforge.com/favicon.ico // @match *://*.curseforge.com/* // @match https://www.curseforge.com/* // @grant none // @noframes // @license GPL-3.0 // @run-at document-end // ==/UserScript== (function() { 'use strict'; // ======================= 忽略区域配置 ======================= const ignoredSelectors = [ 'code', 'pre', 'script', 'style', 'textarea', 'kbd', '.CodeMirror', '.monaco-editor', '.cm-editor', '.codemirror-textarea', 'input[type="text"]', 'input[type="password"]', 'input[type="email"]', '[data-do-not-translate]', '[data-translation-ignore]', '.file-list', '.version-table', '.hash-value', '.project-file-list', '.game-version-select', '.mod-detail__hash', '.mod-detail__filename', '.mod-card__version', '.mod-card__game-version', '.mod-detail__file-info', '[data-version]', '[data-file-id]', '.mod-author__name', '.mod-title__name', '.mod-description__content', '.file-row .name', '.project-name', '.game-version', '.version-badge', '.overlay-link' // '.dropdown-list li' 注释掉以让下拉菜单被翻译 ]; // 改用 Set 并精确匹配 class(基于 classList) const ignoredClassesSet = new Set([ 'CodeBlock', 'gitSha', 'monospace', 'file-list', 'version-info', 'mod-author', 'mod-name', 'mod-detail__hash', 'game-version', 'mod-relations', 'mod-issues', 'mod-source', 'mod-version-number', 'project-id', 'file-name', 'version-number' ]); // ======================= 翻译词典 ======================= const i18n = new Map([ // 导航栏 ['Browse','浏览'], ['Create','创作'], ['MOD AUTHORS', '模组作者'], ['Become an Author', '成为作者'], ['Start a Project', '创建项目'], ['Project Submission Guide', '项目提交指南'], ['MODDING TOOL DEVELOPERS', '模组工具开发者'], ['Project submission guide','项目提交指南'], ['Author Rewards Program','作者奖励计划'], ['Apply for an API Key', '申请 API 密钥'], ['3rd Party API T&C','第三方API条款'], ['Documentation', '文档'], ['Terms & Conditions', '条款与规则'], ['SOCIAL', '社交'], ['Join Our Discord!', '加入我们的 Discord!'], ['Authors Discord', '作者 Discord'], ['Hytale New Worlds Contest', 'Hytale 新世界创作大赛'], ['Studios','工作室'], ['GAME DEVELOPERS', '游戏开发者'], ['Unlock Modding for Your Game', '为你的游戏开放模组功能'], ['Documentation', '文档'], ['Hytale New Worlds Contest', 'Hytale 新世界大赛'], ['Go Premium','开通高级版'], ['Get CurseForge App','获取 CurseForge 应用'], ['Help Center','帮助中心'], ['Our Blog','我们的博客'], ['Surprise me','随机推荐'], ['Legacy','旧版站点'], ['Login','登录'], // 底部导航栏 ['Games', '游戏'], ['All games','全部游戏'], ['Minecraft','我的世界'], ['World of Warcraft','魔兽世界'], ['The Sims 4','模拟人生4'], ['Starcraft II','星际争霸2'], ['Kerbal Space Program','坎巴拉太空计划'], ['Minecraft Dungeons','我的世界:地下城'], ['World of Tanks','坦克世界'], ['Create','创作'], ['Start a project','创建项目'], ['Project submission guide','项目提交指南'], ['Author Rewards Program','作者奖励计划'], ['Apply for an API Key','申请API密钥'], ['3rd Party API T&C','第三方API条款'], ['Community','社区'], ['Join Our Discord!','加入我们的Discord!'], ['Ideas Portal','建议反馈'], ['CF blog','CurseForge博客'], ['Newsletter','订阅通讯'], ['Roadmap','发展路线'], ['Bukkit forums','Bukkit论坛'], ['CurseForge Servers','CurseForge服务器'], ['Support','支持'], ['Knowledge base','知识库'], ['Troubleshooting','故障排除'], ['Contact us','联系我们'], ['Companions','合作伙伴'], ['Overwolf','Overwolf'], ['CurseForge for Studios','面向工作室的CurseForge'], ['Tebex','Tebex'], ['Nitro','Nitro'], ['Terms of Service','服务条款'], ['Privacy Policy','隐私政策'], ['Licenses','许可协议'], ['Mod Author Terms','模组作者条款'], // ================================== 分割线 ================================== // 主页 ['Explore Thousands of Legendary Mods','探索数千款传奇模组'], ['Discover endless mods for your favorite games, or forge your own and share them with millions.','发现海量适用于你喜爱游戏的模组,或是亲手打造专属模组,与数百万玩家分享'], ['CurseForge makes modding easy, safe, and rewarding.','CurseForge 让模组创作变得简单、安全且富有成就感'], ['MODS','模组'], ['DOWNLOADS','下载'], ['MOD AUTHORS','模组作者'], ['PAID TO CREATORS','创作者收益'], ['Search for a game...','搜索游戏...'], ['View all games','查看所有游戏'], ['The Easiest Way to Manage Your Mods','管理模组的最简方式'], ['Download the CurseForge app to install, update, and manage your mods in one click. It’s fast, safe, and built for the games you love – no setup, no stress, just play.','下载CurseForge应用,一键安装、更新和管理你的模组。它快速、安全,专为你喜爱的游戏打造——无需复杂设置,轻松无忧,即刻畅玩。'], ['One-Click Installs','一键安装'], ['Add mods with a single click – easy installation, no manual setup, no waiting.','一键添加模组,安装简便,无需手动配置,无需漫长等待'], ['Easy Mod Management','轻松管理模组'], ['Clean updates and reliable support for the games you love – Minecraft, The Sims 4, World of Warcraft, and more.','为你喜爱的游戏提供清爽更新与稳定支持,包括《我的世界》《模拟人生4》《魔兽世界》等'], ['Safe & Secure','安全可靠'], ['CurseForge scans and moderates every mod, giving you fast, worry-free installs and total peace of mind.','CurseForge会扫描审核每一个模组,让你安装快速无忧,安心使用'], ['Create, Share, and Earn','创作、分享并赚取收益'], ['Ready to share your creation? Publish on CurseForge, reach millions of players, and earn rewards with one of the industry\'s most trusted built-in monetization programs.','准备好分享你的创作了吗?在CurseForge发布作品,触达数百万玩家,并通过业内最值得信赖的内置变现计划获取奖励'], ['Creation & Management Tools','创作与管理工具'], ['Publish and manage your mods with tools designed specifically for creators.','使用专为创作者打造的工具发布并管理你的模组'], ['Multi-Platform Exposure','多平台曝光'], ['Reach players across PC, Mac, and Linux from one unified platform.','通过统一平台触达PC、Mac及Linux端的玩家'], ['Paid To Creators','创作者收益'], ['Join thousands of authors already earning on CurseForge.','加入数千位已在CurseForge获得收益的作者行列'], ['Integrate UGC Into Your Game','将UGC内容融入你的游戏'], ['CurseForge for Studios helps game studios launch and scale thriving modding ecosystems. From discovery to cross-platform delivery, we provide tools to keep UGC secure, curated, and engaging – so your game stays fresh, valuable, and exciting for players over time.','面向游戏工作室的CurseForge助力工作室搭建并拓展繁荣的模组生态。从内容发现到跨平台分发,我们提供安全、精选且富有趣味性的UGC管理工具,让游戏持续保持新鲜、优质与活力。'], ['Safe & Curated','安全精选'], ['A vetted ecosystem that keeps content safe, secure, and compliant.','经过严格审核的生态系统,保障内容安全合规'], ['Cross-Platform Reach','跨平台覆盖'], ['Seamless distribution across PC, console, and mobile.','在PC、主机及移动端无缝分发'], ['Seeding & Scaling','生态启动与拓展'], ['Launch with ready-to-play mods from day one, and expand your ecosystem with scalable monetization options.','上线即拥有可直接体验的模组,并通过可拓展的变现方案壮大生态'], ['Get in Touch with Our Team','联系我们的团队'], ['Stay Connected with the Modding Community','与模组社区保持联动'], ['Follow us for the latest mods, creator highlights, and community updates – stay in the loop wherever you play or create.','关注我们获取最新模组、创作者风采及社区动态,随时随地不错过任何资讯'], ['Explore Updates, Tips & Stories on the CurseForge Blog','在CurseForge博客查看更新、技巧与故事'], ['Discover new features, modding tips, creator stories, and community news – all straight from the source.','了解全新功能、模组制作技巧、创作者故事与社区资讯,一手消息直达'], ['CurseForge Blog','CurseForge博客'], ['Go Ad-Free and Support Creators with','开启无广告体验,支持创作者'], ['CurseForge Premium','CurseForge高级版'], ['Enjoy ad-free browsing, a customizable app, and a way to support your favorite creators – all with CurseForge Premium. Upgrade your experience today.','畅享无广告浏览、个性化定制应用,并支持你喜爱的创作者——尽在CurseForge高级版。立即升级体验。'], ['Go Premium','开通高级版'], // ================================== 分割线 ================================== // 浏览 > 我的世界 // 发现 ['Minecraft Mods', '我的世界模组'], ['projects', '个项目'], [`Minecraft Mods on CurseForge - The Home for the Best Minecraft Mods Discover the best Minecraft Mods and Modpacks around. Minecraft is an action-adventure sandbox game where players can build pretty much anything they like, explore their surroundings, craft items, and even engage in combat. MC has one of the biggest modding communities in the world, and on this very page - you'll be able to become a part of it. If you've been looking around some Minecraft forums recently, you probably know that this is the home for all the best Minecraft mods. Here, you'll be able to easily find and download the best Minecraft mods and modpacks around. From mods that change Minecraft's game interface, through mods that optimize its gameplay, or even mods that offer various tools for improved building, combating, or exploration. Browse through the selection of MC mods and modpacks, check out their descriptions and photos, and find out which ones are best for you. Always keep in mind that each and every mod is completely free, so you can try them all until you find your favorite Minecraft mods and modpacks. And of course, the important thing is to have fun with these Minecraft mods - using them to create a personalized game experience that's best for you.`, ` CurseForge上的我的世界模组——优质我的世界模组聚集地 发现全网优质的我的世界模组与整合包。我的世界是一款动作冒险沙盒游戏,玩家可随心建造、探索世界、合成物品,甚至参与战斗。 我的世界拥有全球最庞大的模组社区之一,而在这个页面,你就能成为其中一员。如果你最近逛过我的世界论坛,就会知道这里是所有优质我的世界模组的大本营。在这里,你可以轻松找到并下载全网最好的我的世界模组和整合包。从更改游戏界面的模组,到优化游戏运行的模组,甚至是提供各类工具、让建造、战斗和探索更便捷的模组应有尽有。 浏览精选的我的世界模组与整合包,查看介绍和截图,找到最适合你的那一款。 请记住,所有模组均完全免费,你可以尽情尝试,直到找到心仪的我的世界模组与整合包。 当然,最重要的是体验这些我的世界模组带来的乐趣,用它们打造专属你的个性化游戏体验。` ], ['Read more', '查看更多'], ['Read less','收起内容'], ['Discover','发现'], ['Browse All', '浏览全部'], ['+ Projects found', '+ 个项目被找到'], ['Minecraft Mods Community Picks','我的世界模组 社区精选'], ['Discover top Mods from previous Minecraft community picks and explore even more curated content through our archive','查看往期我的世界社区精选热门模组,并通过存档探索更多精选内容'], ['View Collections','查看合集'], ['Monthly Theme - Fantasy','每月主题 - 奇幻'], ['Popular Categories','热门分类'], ['Modpacks','整合包'], ['Shaders', '光影'], ['Mods', '模组'], ['Bukkit Plugins','Bukkit插件'], ['Addons', '插件'], ['Worlds', '地图'], ['Resource Packs', '资源包'], ['Customization', '自定义'], ['From Top Authors','顶尖作者作品'], ['Latest Mods','最新模组'], ['Latest Modpacks','最新整合包'], ['Latest Resource Packs','最新资源包'], ['Latest Worlds','最新存档地图'], ['Popular Resource Packs','热门资源包'], ['Popular Modpacks','热门整合包'], ['Popular Mods','热门模组'], ['Popular Worlds','热门地图'], // 浏览全部 ['All','全部'], ['Filters','筛选'], ['Game Version','游戏版本'], // 排序方式>相关度 ['Relevancy','相关性'], ['Popularity','热门度'], ['Latest update','最近更新'], ['Creation Date','创建日期'], ['Total Downloads','总下载量'], ['A-Z', 'A到Z'], ['Browse by', '按类别浏览'], ['Popular Categories', '热门分类'], ['Browse all', '浏览全部'], // ================================== 分割线 ================================== // 全大写变体(解决大小写敏感) ['DOWNLOAD', '下载'], ['INSTALL', '安装'], ['LOGIN', '登录'], ['PAGE', '页'], // 用于全大写场景 ['CLEAR ALL', '全部清除'], // 原有词条 // ['',''], ['Minecraft Bedrock', '我的世界基岩版'], // 搜索栏 ['Search for Minecraft mods...', '搜索 我的世界 模组...'], // 二级导航栏 ['Description','简介'],['Files','文件(在这里下载)'],['Gallery','图库'],['Relations','关联'],['Issues','问题'], // 右侧悬浮导航 ['Details','详情'], ['Downloads','下载量'],['Created','创建时间'], ['Updated','更新时间'],['Project ID','项目 ID'], ['Game Versions','游戏版本'], ['Mod Loaders','模组加载器'], ['Categories','分类'], ['Game version', '游戏版本'], ['Sort by', '排序方式 '], ['Relevancy', '相关度 '], ['Main File','主文件'], ['Recent Files','最近文件'], ['Server Packs','服务端整合包'], ['View all','查看全部'], ['Show alpha files','显示 alpha 版本文件'], ['Page','页'], ['Show per page','每页显示'], ['All Game Versions','全部游戏版本'], ['All Mod Loaders','全部模组加载器'], ['Type','类型'], ['Name','名称'], ['Size','大小'], ['Game Ver.','游戏版本'], ['Download','下载'], ['Install','安装'], ['Favorite','收藏'], ['Follow','关注'], ['Report','举报'], ['Links','链接'], ['License','许可证'], ['All Rights Reserved','保留所有权利'], // 月份 ['Jan','1月'],['Feb','2月'],['Mar','3月'],['Apr','4月'],['May','5月'],['Jun','6月'], ['Jul','7月'],['Aug','8月'],['Sep','9月'],['Oct','10月'],['Nov','11月'],['Dec','12月'], // 时间 ['months ago','月前'], ['hours ago','小时前'], // ['Team', '团队'], ['Owner', '作者'], ['Followers', '关注者'], ['Projects', '个项目'], ['Downloads','下载量'], ['Donate', '捐赠'], ['Members', '成员'], ['Author', '作者'], ['Contributor', '贡献者'], // ['More from', '更多来自'], // ['CurseForge - a world of endless gaming possibilities for modders and gamers alike.','CurseForge—— 为模组作者与玩家打造,充满无限游戏可能的世界。'], ['Download the best mods and addons!','下载优质模组与扩展插件!'], // 下载页面提示 ['STILL DOWNLOADING MANUALLY??','还在手动下载吗?'], ['Join over 10 million players who use the CurseForge app!','加入超千万使用 CurseForge 客户端的玩家吧!'], ]); // ---------- 构建完全匹配映射 ---------- const fullMatchMap = new Map(); // 键 -> 译文(大小写敏感) for (const [key, value] of i18n.entries()) { fullMatchMap.set(key, value); } // ---------- 忽略节点检查(带缓存)---------- const ignoreCache = new WeakMap(); function shouldIgnoreNode(node) { if (!node || node.nodeType !== 1) return false; if (ignoreCache.has(node)) return ignoreCache.get(node); if (ignoredSelectors.some(selector => node.matches && node.matches(selector))) { ignoreCache.set(node, true); return true; } if (node.classList) { for (let cls of node.classList) { if (ignoredClassesSet.has(cls)) { ignoreCache.set(node, true); return true; } } } let parent = node.parentNode; while (parent && parent !== document.body && parent.nodeType === 1) { if (ignoredSelectors.some(selector => parent.matches && parent.matches(selector))) { ignoreCache.set(node, true); return true; } if (parent.classList) { for (let cls of parent.classList) { if (ignoredClassesSet.has(cls)) { ignoreCache.set(node, true); return true; } } } parent = parent.parentNode; } ignoreCache.set(node, false); return false; } // ---------- 核心翻译函数(仅完全匹配)---------- function translateTextNode(node) { if (!node || node.nodeType !== 3) return; const original = node.nodeValue; if (!original || original.trim() === '') return; // 避免翻译纯数字 if (/^\d+$/.test(original.trim())) return; const trimmed = original.trim(); if (fullMatchMap.has(trimmed)) { const translation = fullMatchMap.get(trimmed); // 保留原文本前后的空白(如果有) const leading = original.match(/^\s*/)[0]; const trailing = original.match(/\s*$/)[0]; node.nodeValue = leading + translation + trailing; } } function translateAttribute(element, attrName) { if (!element || !element.hasAttribute(attrName)) return; const attrValue = element.getAttribute(attrName); if (!attrValue || attrValue.trim() === '') return; if (/^\d+$/.test(attrValue.trim())) return; const trimmed = attrValue.trim(); if (fullMatchMap.has(trimmed)) { element.setAttribute(attrName, fullMatchMap.get(trimmed)); } } // 翻译一个节点及其后代(增量) function translateNode(node) { if (!node) return; if (node.nodeType === 3) { translateTextNode(node); return; } if (node.nodeType !== 1) return; if (shouldIgnoreNode(node)) return; // 翻译属性 if (node.hasAttribute('title')) translateAttribute(node, 'title'); if (node.hasAttribute('placeholder')) translateAttribute(node, 'placeholder'); if (node.hasAttribute('aria-label')) translateAttribute(node, 'aria-label'); if ((node.tagName === 'INPUT' || node.tagName === 'BUTTON') && node.hasAttribute('value') && node.getAttribute('type') !== 'password') { translateAttribute(node, 'value'); } // 遍历子节点 const children = node.childNodes; for (let i = 0; i < children.length; i++) { const child = children[i]; if (child.nodeType === 3) { translateTextNode(child); } else if (child.nodeType === 1 && !shouldIgnoreNode(child)) { translateNode(child); } } } // 全量翻译(用于初始化、路由变化) function fullTranslate() { translateNode(document.body); } // ---------- 监听动态内容 ---------- let translationTimer = null; const observer = new MutationObserver(mutations => { clearTimeout(translationTimer); translationTimer = setTimeout(() => { for (const mutation of mutations) { for (const node of mutation.addedNodes) { if (node.nodeType === 1) { translateNode(node); } else if (node.nodeType === 3 && node.nodeValue.trim()) { translateTextNode(node); } } if (mutation.type === 'attributes' && ['title', 'placeholder', 'aria-label'].includes(mutation.attributeName)) { translateAttribute(mutation.target, mutation.attributeName); } if (mutation.type === 'characterData' && mutation.target) { translateTextNode(mutation.target); } } }, 80); }); observer.observe(document.body, { childList: true, subtree: true, characterData: true, attributes: true, attributeFilter: ['title', 'placeholder', 'aria-label'] }); // ---------- 监听 SPA 路由变化 ---------- function onUrlChange() { setTimeout(fullTranslate, 200); } const originalPushState = history.pushState; const originalReplaceState = history.replaceState; history.pushState = function(...args) { originalPushState.apply(this, args); onUrlChange(); }; history.replaceState = function(...args) { originalReplaceState.apply(this, args); onUrlChange(); }; window.addEventListener('popstate', onUrlChange); window.addEventListener('hashchange', onUrlChange); // 点击处理:针对动态弹窗 document.addEventListener('click', (e) => { setTimeout(() => { const target = e.target; if (target && (target.closest('button') || target.closest('[role="button"]') || target.closest('a'))) { setTimeout(() => { document.querySelectorAll('.modal, .dropdown-menu, .popover, .dialog').forEach(el => { if (el.style.display !== 'none') translateNode(el); }); }, 150); } }, 100); }, true); // ---------- 初始化 ---------- if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { fullTranslate(); }); } else { fullTranslate(); } window.addEventListener('load', () => { setTimeout(fullTranslate, 300); }); window.addEventListener('beforeunload', () => { observer.disconnect(); }); })();