修改CurseForge的汉化文本
// ==UserScript== // @name CurseForge汉化文本修正 // @namespace https://www.yesterday17.cn/ // @version 1.0.1 // @description 修改CurseForge的汉化文本 // @author Yesterday17 // @include *://minecraft.curseforge.com/* // @run-at document-start // ==/UserScript== "use strict"; (function() { const translation = { Elerium: { ControlPanel: { AreYouSureYouWantToDeleteName: "你确定要删除{0}吗?" }, Developer: { AreYouSureRemoveRole: "Are you sure you would like to delete {0} from the company?" }, Extension: { DeveloperWritableChannelSegmentVersion: "Developer Writable Channel Segment Version", DeveloperWritableChannelSegmentVersionDesc: "If present - the extension will be inactive unless the version string in the channel\u0027s developer segment matches this value", MobileConfirmDisableHeader: "Are you sure you want to disable mobile support?", MobileConfirmDisableMessage: "When this version is released users will no longer be able access your extension from mobile.", RequestIdentityLinkRequired: "Add Tooltip Copy", RequestIdentityLinkRequiredWithPurchases: "Request Identity Link required with In-Extension Purchases", RequiredPerChannelConfigurations: "Required Per Channel Configuration", RequiredPerChannelConfigurationsDesc: 'If present - this must match the per channel configuration string, for activation to proceed. See the \u003ca href="https://dev.twitch.tv/docs/extensions/reference/#set-extension-required-configuration" target="_blank"\u003eSet Extension Required Configuration\u003c/a\u003e Endpoint.' }, Global: { Favorite: "收藏", Unfavorite: "取消收藏" } }, Global: { Buttons: { Cancel: "取消", Create: "创建", Delete: "删除", Edit: "编辑", Push: "Push", Update: "更新" }, Calendar: { Month: "本月", Today: "今天", Week: "周" }, Common: { Add: "添加", AddCharacter: "添加一个字符", AdvancedSearch: "高级搜索", Apply: "应用", Ascending: "递增", ClickHere: "点击这里", ColonConnector: ":", Comments: "评论", Confirm: "确认", ConfirmDelete: "您确定要删除{0}吗?", Descending: "降序", Description: "描述", EditMyAccount: "编辑我的帐户", EmailErrorMessage: "必须是一个电子邮件地址。", EqualErrorMessage: "{0}必须与{1}相等", ErrorOccured: "抱歉,处理请求时发生错误。", FileContainsVirus: "文件已被病#感染", IntegerValueErrorMessageMaximum: "必须在{0}以下。", IntegerValueErrorMessageMinimum: "必须在{0}以上。", LengthErrorMessageMaximum: "长度最大为{0}。", LengthErrorMessageMinimum: "长度最小为{0}。", Logout: "注销", Milliseconds: "{0}毫秒", More: "更多", MyCharacters: "我的角色", Name: "名字", New: "New", Normal: "正常", NumberOfPrivateMessagesAbbr: "{0}条私信", PageOf: "第{0}页,共{1}页", PageXOfY: "第{0}页,共{1}页", PleaseLogIn: "请登录", PleaseWaitProcessing: "请稍候,正在处理中…", PrivateMessagesAbbr: "PMs", QuoteFrom: "引用{0}", Remove: "删除", RequiredErrorMessage: "此字段是必需的。", RestoreContent: "还原内容", SelectCharacter: "选择一个字符", SimpleSearch: "简单搜索", Submit: "提交", TestStuff: "这只是一个测试。{0}只鸟。", Title: "标题", UserAsCharacter: "{0} as", UserAvatar: "{0}的头像", Username: "用户名", WelcomeUser: "欢迎您,{0}!" }, ContentManagement: { AddMediaGallery: "添加媒体库", ExistingFolders: "现有目录", HideAddGallery: "不要添加媒体库", Insert: "插入", InsertAnImage: "插入图片", OnSelectedTemplate: "应用以选择({0})", PageFormDoNotSetDate: "不设置日期", PageFormSetDate: "设置日期", PublishOnTemplate: "发布{0}", SelectImage: "选择一张图片" }, Contests: { ContestPrizeItemAwardSubject: "你得到了奖励:{0}", ContestPrizeItemHtmlBody: '你得到了奖励:{1}.\r\n\r\n\u003ca href="{2}" target=_blank\u003e{0}\u003c/a\u003e', ContestPrizeItemTextBody: "你得到了奖励:{0}.\r\n\r\n访问{1}以#取奖励。", YouAreDisqualified: "你已被取消资格!" }, ControlPanel: { AddNewHeader: "添加新标题", AddSubNavigationLink: '\u003cdiv class="header"\u003e新增分导航\u003c/div\u003e添加一个分导航链接', BulkConfirm: "你确定要{0}这些项目吗?", CompLegacySubscription: "Issue Comp", "Contactology Campaigns": "Contactology Campaigns", EntitySubscriptionTypes: "Entity Subscription Types", LegacySubscriptions: "Legacy Subscriptions", LegacySubscriptionSearch: "Search Legacy Subscriptions", MenuLegacySubscriptions: "Legacy Subscriptions", MinimumPostCount: "Minimum Post Count", MovePrivateMessagesPrompt: '您确定要将这些私信移动到"${0}"目录内?', PushNotification: "推送通知", RemoveLinkTooltip: '\u003cdiv class="header"\u003e删除链接\u003c/div\u003e删除这从你的网站导航链接。', SubscriptionID: "Subscription ID", SubscriptionTypeEdit: "Subscription Type Edit", SubscriptionTypePush: "Push Subscription Type Notification", SubscriptionTypes: "Subscription Types", SimpleSearch: "Simple Search" }, Dates: { AprilAbbr: "4月", AugustAbbr: "8月", Days: "{0}天", DecemberAbbr: "12月", FebruaryAbbr: "2月", FridayAbbr: "周五", FutureFormat: "{0} from now", Hours: "{0}小时", JanuaryAbbr: "1月", JulyAbbr: "7月", JuneAbbr: "6月", LessThanOneMinute: "不到一分钟", MarchAbbr: "3月", MayAbbr: "5月", Minutes: "{0}分钟", MondayAbbr: "周一", NovemberAbbr: "11月", OctoberAbbr: "10月", OneMinute: "1分钟", PastFormat: "{0}前", SaturdayAbbr: "周六", Seconds: "{0}秒", SeptemberAbbr: "9月", StandardDateFormat: "{2}年{1}{0}日", StandardDateTimeFormat: "{1},{0} {4} {6} {2}:{3}:{5}", SundayAbbr: "周日", ThursdayAbbr: "周四", TuesdayAbbr: "周二", WednesdayAbbr: "周三" }, ErrorMessages: { NumericPrecisionDecimalDigitCountErrorMessageTemplate: "您提供的数值有{0}位小数,而限制为{1}位。", TagEmpty: "您不能添加一个空的标签。" }, Files: { AddAttachment: "添加此附件", ChangeDescription: "更改此附件的说明", DeleteAttachment: "删除此附件", FileTooLarge: "文件太大,请上传小于{0}的文件。" }, Forums: { Add: "添加", CreateForum: "创建论坛", Delete: "删除", EditForum: "编辑论坛", GoToFirstUnreadPost: "转到第一个未读的帖子", JumpToPage: "跳到页", LockThread: "锁定主题", Moderator: "主持人", Move: "移动", OnSelected: "在选择({0})", RestoreContentDescription: "如果上次输入出错,请单击以恢复上次输入的文本", SearchForums: "搜索论坛", SelectAll: "全选", SendMessage: "发送消息", Unread: "未读", ViewPosts: "查看帖子", ViewProfile: "查看用户信息" }, Languages: { Arabic: "阿拉伯语", "Brazillian Portugese": "巴西葡萄牙语", BritishEnglish: "英语(英国)", English: "英语", French: "法语", German: "德语", Greek: "希腊语", Indonesian: "印度#西亚语", Italian: "意大利语", Japanese: "日语", Korean: "汉语", LatinAmericanSpanish: "拉丁美洲西班牙语", Polish: "波兰语", Russian: "俄语", SimplifiedChinese: "简体中文", Spanish: "西班牙语", Swedish: "瑞典语", TraditionalChinese: "繁体中文", Uzbec: "乌兹别克语", Vietnamese: "越南语" }, MailTemplates: { ReportBody: 'Hello {0},\r\n\r\n\u003cp\u003e{6} has reported this \u003ca href="{4}"\u003econtent\u003c/a\u003e on \u003ca href="{7}"\u003e{8}\u003c/a\u003e for the reason {2}.\u003c/p\u003e\r\n\u003cp\u003e{9}\u003c/p\u003e\r\n\u003cp\u003eYou can view the report by \u003ca href="{7}"\u003evisiting the report page\u003c/a\u003e.\u003c/p\u003e\r\n\r\n\u003cp\u003eReported content:\r\n\u003cblockquote\u003e\r\nPosted by \u003ca href="{5}"\u003e{10}\u003c/a\u003e\r\n\u003cp\u003e\r\n{3}\r\n\u003c/p\u003e\r\n\u003c/blockquote\u003e\u003c/p\u003e\r\n\r\n__\r\n\u003cp style="font-size:11px"\u003eTo unsubscribe from these email notifications, go to \u003ca href="{1}"\u003eyour notifications page.\u003c/a\u003e\u003c/p\u003e' }, Polls: { AddChoice: "添加选择", AddPoll: "添加一项民意调查", ChoiceNumberTemplate: "选择#{0}", HideR###lts: "隐藏结果", RemoveChoice: "删除选择", RemovePoll: "不要添加的民意调查", ViewR###lts: "查看结果" }, Ratings: { YouRatedThis: "您的打分是{0}星。{2}名用户的平均打分是{1}星。" }, Reporting: { Report: "报告" }, TinyMCE: { XenonMediaPluginDesc: "从目录中添加文件" }, Translator: { ReportATranslation: "Report a Translation", ReportTranslationInstructions: "要报告翻译,请单击带有虚线下划线的文本。" }, Upsells: { SubscriptionRequiresLogin: "您必须登录才能订阅。" }, UserRegistration: { ConfirmPassword: "确认密码", Password: "密码", RecoverAccountStep2Info2: "输入一个新的帐户密码,然后点击\u0027更改密码\u0027按钮。", Username: "用户名", UsernameIsTaken: "该用户名已被注册。" }, Widgets: { LatestPosts: "最新帖子", LatestNews: "最新新闻", Poll: "调查", WhosOnline: "在线用户", RandomPicture: "随机图片", Calendar: "日历", Recruitment: "招聘" } } }; /** * Add localization script */ const script = document.createElement("script"); script.innerHTML = `Elerium.Localization.populate(7, ${JSON.stringify( translation )});`; /** * 匹配规则 */ const category = /^\/modpacks|customization|mc-addons|mc-mods|texture-packs|worlds(?:\/[a-zA-Z0-9\-]+)*$/; const project = /^\/projects\/[a-zA-Z0-9\-]+$/; const files = /^\/projects\/[a-zA-Z0-9\-]+\/files$/; const dependencies = /^\/projects\/[a-zA-Z0-9\-]+\/relations\/dependencies$/; const dependents = /^\/projects\/[a-zA-Z0-9\-]+\/relations\/dependents$/; const dictionary = { projects: "项目", forum: "论坛", "reward-store": "Reward Store", dashboard: "Dashboard", feedback: "反馈", modpack: "整合包", customization: "Customization", addons: "Addons", mods: "模组", "texture-packs": "材质包", worlds: "世界", search: "搜索", "new-project": "新建项目", popularity: "热度", "date-created": "创建时间", "last-updated": "最近更新", name: "名称", "total-downloads": "总下载量", relations: "依赖关系" }; document.addEventListener("DOMContentLoaded", function(event) { const path = new URL(document.URL).pathname; const root = `/${path.split("/")[1]}/${path.split("/")[2]}`; // 加载修改过的汉化 document.head.appendChild(script); // 修改全局共通的文本 document.querySelector("#nav-projects a span").innerText = dictionary.projects; document.querySelector("#nav-forums a span").innerText = dictionary.forum; document.querySelector("#nav-reward-store a span").innerText = dictionary["reward-store"]; document.querySelector("#nav-dashboard a span").innerText = dictionary.dashboard; document.querySelector("#nav-feedback a span").innerText = dictionary.feedback; document.querySelectorAll("#nav-projects li a span")[0].innerText = dictionary.modpack; document.querySelectorAll("#nav-projects li a span")[1].innerText = dictionary.customization; document.querySelectorAll("#nav-projects li a span")[2].innerText = dictionary.addons; document.querySelectorAll("#nav-projects li a span")[3].innerText = dictionary.mods; document.querySelectorAll("#nav-projects li a span")[4].innerText = dictionary["texture-packs"]; document.querySelectorAll("#nav-projects li a span")[5].innerText = dictionary.worlds; // 搜索框的 placeholder document.querySelector(".b-search-input").placeholder = dictionary.search + "…"; if (path == "/") { } else if (path == "/projects") { // <h2> document.querySelectorAll(".category-info h2")[0].innerText = dictionary.modpack; document.querySelectorAll(".category-info h2")[1].innerText = dictionary.customization; document.querySelectorAll(".category-info h2")[2].innerText = dictionary.addons; document.querySelectorAll(".category-info h2")[3].innerText = dictionary.mods; document.querySelectorAll(".category-info h2")[4].innerText = dictionary["texture-packs"]; document.querySelectorAll(".category-info h2")[5].innerText = dictionary.worlds; // <p>, description const proj_from_reg = /^(\d+) projects by (\d+) authors with more than ([\d,]+) downloads.$/; const proj_to = "已有$2位作者创建了$1个项目,总下载次数已超过$3次。"; for (const node of document.querySelectorAll(".category-info p")) { node.innerText = node.innerText.replace(proj_from_reg, proj_to); } // 按钮:启动项目 -> 新建项目 for (const node of document.querySelectorAll( ".project-category .button span" )) { node.innerText = dictionary["new-project"]; } } else if (path.match(category)) { console.log("category"); // 新建项目 document.querySelector(".project-listing-header li a span").innerText = dictionary["new-project"]; // 排序方式 document.querySelectorAll("#filter-sort option")[0].innerText = dictionary["date-created"]; document.querySelectorAll("#filter-sort option")[1].innerText = dictionary["last-updated"]; document.querySelectorAll("#filter-sort option")[2].innerText = dictionary.name; document.querySelectorAll("#filter-sort option")[3].innerText = dictionary.popularity; document.querySelectorAll("#filter-sort option")[4].innerText = dictionary["total-downloads"]; // Prev -> 上一页 for (let node of document.querySelectorAll('a[rel="prev"]')) { if (node.innerText == "Prev") { node.innerText = "上一页"; } } // Next -> 下一页 for (let node of document.querySelectorAll('a[rel="next"]')) { if (node.innerText == "Next") { node.innerText = "下一页"; } } } else if ( path.match(project) || path.match(files) || path.match(dependencies) || path.match(dependents) ) { // 相同部分同时处理 document.querySelector(`li a[href="${root}"]`).innerText = "简介"; document.querySelector(`li a[href="${root}/files"]`).innerText = "文件"; if (document.querySelector(`li a[href="${root}/images"]`)) { document.querySelector(`li a[href="${root}/images"]`).innerText = "图片"; } document.querySelector( `.e-hasSubmenu>a[href="${root}/relations/dependencies"]` ).innerText = dictionary.relations; // TODO: 对每个页面不同的部分进行细分汉化 if (path.match(project)) { console.log("project"); } else if (path.match(files)) { console.log("files"); } else if (path.match(dependencies)) { console.log("dependencies"); } else if (path.match(dependents)) { console.log("dependents"); } } else { console.log("others"); } }); })();