Wplace 汉化脚本

将网站 wplace.live 的界面实时翻译成中文,优化中文用户的使用体验。

// ==UserScript==
// @name              Wplace 汉化脚本
// @name:en           Wplace Chinese Localization Script
// @name:zh-CN        Wplace 汉化脚本
// @namespace         http://tampermonkey.net/
// @version           1.2.5
// @description       将网站 wplace.live 的界面实时翻译成中文,优化中文用户的使用体验。
// @description:en    Translates the wplace.live interface into Chinese in real-time for a better user experience.
// @description:zh-CN 将网站 wplace.live 的界面实时翻译成中文,优化中文用户的使用体验。
// @author            Avava_Ava & AI Optimized
// @match             https://wplace.live/*
// @license           MIT
// @run-at            document-body
// @icon              https://wplace.live/img/favicon-96x96.png
//
// @homepageURL       https://greasyfork.org/zh-CN/scripts/546403
// @supportURL        https://greasyfork.org/zh-CN/scripts/546403/feedback
// @source            https://greasyfork.org/zh-CN/scripts/546403/code
//
// @grant             none
// ==/UserScript==

(function() {
    'use strict';

    console.log('[Wplace汉化] 脚本开始加载...');

    // 创建一个翻译字典,将英文原文映射到中文译文
    const translations = {
        // ========== 页面标题与信息 ==========
        "Wplace - Paint the world": "Wplace-描绘这世界",
        "Paint the world": "描绘这世界",
        "Wplace": "Wplace",
        "Feedback and bugs": "提供反馈或汇报问题",
        "Map powered by:": "地图技术由以下项目提供:",
        "©\n\t\t\t\t\t\tOpenMapTiles Data from": "©\n\t\t\t\t\t\tOpenMapTiles 数据来自",
        "Overview": "概览",
        "How to paint faster": "如何画得快一些",
        "Hold": "按住",
        "and move your cursor over the map.": ",随后在地图上移动鼠标。",
        "When painting, click on the button": "在绘制时,点击位于屏幕右上角上的",
        "on the top right corner of the screen. This will lock the screen but it'll also enable painting by moving your finger over the map.": "按钮。点击后屏幕将锁定;此时在屏幕上滑动即可进行绘制。",
        "My map is lagging": "我的地图画面卡顿严重",
        "Verify if": "(如果使用的是 Chrome 浏览器)请查看",
        "is enabled on": "选项是否开启。该选项位于",
        "Email:": "邮箱:",
        "Terms": "服务条款",
        "Privacy": "隐私政策",
        "Show profile": "显示个人资料",

        // ========== 文本 ==========
        "Paint pixel": "放置像素点",
        "Pixels painted": "放置像素点总数",
        "Pixels painted:": "已放置的像素点:",
        "Pixels": "放置像素点总数",
        "painted": " ",
        "Region": "区域",
        "Pixels painted inside the region": "放置于该区域内像素点的总数目",
        "Visit": "去看看",
        "Menu": "菜单",

        // ========== 按钮 & 提示 ==========
        "Info": "信息",
        "Zoom in": "放大",
        "Zoom out": "缩小",
        "Livestreams": "Twitch 相关直播",
        "Refresh": "刷新页面",
        "Previous location": "前一个地点",
        "Toggle art opacity": "切换作品透明度",
        "My location": "我的当前位置",
        "Paint": "绘制",
        "Close": "关闭",
        "Understood": "了解",
        "Store": "商店",
        //必须做i8n才能完全解决这个问题
        //"Move ↑": "移至上方",
        //"Move ↓": "移至下方",
        "Eraser": "擦除",
        "Color Picker": "拾取像素点颜色",
        "Offline": "你已离线",
        "Explore": "看看别处",
        "Favorite": "收藏",
        "Share": "分享",
        "Mute": "禁用音效",
        "Unmute": "启用音效",
        "+2 max. charge/level": "每升一级,像素点储备上限+2",
        "Purchases": "支付信息",
        "Log Out": "退出登录",
        "Alliance": "联盟",
        "Log in": "登录",
        "Edit profile": "编辑个人资料",
        "Name": "昵称",
        "Show last painted pixel on alliance": "在「联盟」页面显示自己最后放置的像素点",
        "Delete Account": "删除账户",
        "Save": "保存",
        "Add profile picture": "添加头像",
        "Draw profile picture": "绘制头像",
        "Upload": "上传",
        "Preferably, use a 16x16 image": "长宽以 16x16 为佳",
        "Preview:": "预览:",
        "Add": "添加",
        "Discord Username": "Discord 用户名",

        // ========== 弹窗 & 标题 ==========
        "Max. Charges": "最大像素点储备",
        "Welcome to": "欢迎来到",
        "Rules": "规则",
        "Important": "重要",
        "📑 Updated rules": "规则(已更新)",
        "Leaderboard": "排行榜",
        "PIX": "像素点",
        "Location favorited": "已收藏该位置",
        "Location unfavorited": "已取消收藏该位置",
        "Share place": "分享该位置",
        "Image": "图像",
        "Copy": "复制",
        "Download": "下载",
        "No internet access or the servers are offline. Try again later.": "当前无网络连接,或本站服务器已离线。请稍后再试。",
        "Can't reach the server. Maybe you are without internet connection or the server is down. Try again later": "无法同服务器进行通讯。可能当前无网络连接,或本站服务器已离线。请稍后再试。",
        "You need to zoom in to select a pixel": "进一步放大地图方可点选像素点",
        "Painted by:": "由该用户绘制:",
        "Not painted": "从未被绘制过",
        "Username copied to clipboard": "已将用户名复制至剪贴板",
        "Zoom in to see the pixels": "放大地图即可看到像素点",
        "Logged out": "已退出登录",
        "Login with Google": "通过 Google 账号进行登录",
        "Login with Twitch": "通过 Twitch 账号进行登录",
        "By continuing, you agree to our": "继续操作,即表明您同意我们的",
        "Terms of Service": "服务条款",
        "and": "和",
        "Privacy Policy": "隐私政策",
        "Leaderboard is temporarily disabled": "排行榜功能已暂时停用",
        "No more charges": "像素点已用尽",
        "You don't have charges to paint.": "你没有像素点了。",
        "You don't have charges to paint. Wait to recharge.": "你没有像素点了。请等待像素点回复。",
        "Pick a color from the map": "在地图上拾取一像素点的颜色",
        "Select a pixel to erase": "选择需要擦除的像素",
        "Click": "点击",
        "or hold": "或按住",
        "to paint,": "按键,即可进行绘制。",
        "Refresh your page to get the latest update": "站点已更新。请刷新本页面",
        "Your account has been banned. Reason: ": "您的账户已被封禁。封禁原因:",
        "Your account has been suspended until": "您的账户已被暂时停用。解除停用状态时间为",
        "Breaking the rules": "违反本站规则",
        ". Reason: Inappropriate conent (+18, inappropriate link, highly suggestive content, ...)": "创作不当内容(成人内容、不当链接、强暗示性内容等)",
        ". Reason: Hate speech (Racism, homophobia, hate groups, ...)": "。封禁原因:发表仇恨言论(发表种族歧视言论、发表恐同言论、隶属于仇恨特定群体的某个团体,或宣扬该团体,等)",
        ". Reason: Inappropriate content (+18, inappropriate link, highly suggestive content, ...)": "。封禁原因:创作不当内容(成人内容、不当链接、强暗示性内容等)",
        ". Reason: Doxxing (Released other's personal information without their consent)": "。封禁原因:擅自传播隐私信息(未经同意即公开他人个人信息)",
        ". Reason: Botting (Use of software to completely automate painting)": "。封禁原因:使用全自动机器人(使用软件放置像素点,且完全无真人参与)",
        ". Reason: Griefing (Messed up artworks for no reason)": "。封禁原因:恶意涂抹(无故破坏他人艺术作品)",
        "You have broken one of Wplace's rules": "您违反了 Wplace 规则之一",
        "Your account has been suspended for breaking the rules": "由于违反本站规则,您的账户已被暂时停用",

        // ========== 规则列表 ==========
        "😈 Do not paint over other artworks using random colors or patterns just to mess things up": "😈 禁止使用随机颜色或图样恶意涂抹他人艺术作品",
        "🚫 No inappropriate content (+18, hate speech, inappropriate links, highly suggestive material, ...)": "🚫 禁止绘制不当内容(如成人内容、仇恨言论、不当链接、强暗示性内容等)",
        "🧑‍🤝‍🧑 Do not paint with more than one account": "🧑‍🤝‍🧑 禁止单人使用多个账户进行绘制",
        "🤖 Use of bots is not allowed": "🤖 禁止使用机器人",
        "🙅 Disclosing other's personal information is not allowed": "🙅 禁止泄露他人个人信息",
        "✅ Painting over other artworks to complement them or create a new drawing is allowed": "✅ 允许在他人作品上进行补充创作或绘制新内容",
        "✅ Griefing political party flags or portraits of politicians is allowed": "✅ 允许涂抹政党旗帜或政治人物肖像",
        "Violations of these rules may result in suspension of your account.": "违反上述规则可能会导致你的账户被封禁。",

        // ========== 举报功能 ==========
        "Report User": "举报该用户",
        "Select the reason:": "选择举报理由:",
        "Inappropriate content:": "创作不当内容",
        "+18, inappropriate link, highly suggestive content, ...": "如成人内容、不当链接、强暗示性内容等",
        "Hate speech:": "发表仇恨言论",
        "Racism, homophobia, hate groups, ...": "如发表种族歧视言论、发表恐同言论、隶属于仇恨特定群体的某个团体,或宣扬该团体,等",
        "Doxxing": "擅自传播隐私信息",
        "Released other's personal information without their consent": "未经同意即公开他人个人信息",
        "Botting": "使用全自动机器人",
        "Use of software to completely automate painting": "使用软件放置像素点,且完全无真人参与",
        "Griefing": "恶意涂抹",
        "Messed up artworks for no reason": "无故破坏他人艺术作品",
        "Other": "其他",
        "Other reason not listed": "存在未列于其上的其他理由",
        "Multi-accounting": "单人使用多个账户",
        "Use more than one account to paint pixels": "使用复数个账户放置像素点",
        "Extra context on what happened": "可在此附加所发生事件的具体信息",
        "Report": "举报",
        "Report sent successfully": "举报已成功发送",
        "Report failed. Please try again later": "举报发送失败。请稍后再试。",

        // ========== 排行榜 & 筛选 ==========
        "Regions": "区域",
        "Countries": "国家和地区",
        "Players": "用户",
        "Alliances": "联盟",
        "Today": "今日",
        "Week": "本周",
        "Month": "本月",
        "All time": "总计",
        "No pixels painted": "无人于此作画",
        "today": "(截至今日)",

        // ========== 国家 & 地区 ==========
        "Country": "国家和地区",
        "Afghanistan": "阿富汗",
        "Åland Islands": "奥兰群岛",
        "Albania": "阿尔巴尼亚",
        "Algeria": "阿尔及利亚",
        "American Samoa": "美属萨摩亚",
        "Andorra": "安道尔",
        "Angola": "安哥拉",
        "Anguilla": "安圭拉",
        "Antarctica": "南极洲",
        "Antigua and Barbuda": "安提瓜和巴布达",
        "Argentina": "阿根廷",
        "Armenia": "亚美尼亚",
        "Aruba": "阿鲁巴",
        "Australia": "澳大利亚",
        "Austria": "奥地利",
        "Azerbaijan": "阿塞拜疆",
        "Bahamas": "巴哈马",
        "Bahrain": "巴林",
        "Bangladesh": "孟加拉国",
        "Barbados": "巴巴多斯",
        "Belarus": "白俄罗斯",
        "Belgium": "比利时",
        "Belize": "伯利兹",
        "Benin": "贝宁",
        "Bermuda": "百慕大",
        "Bhutan": "不丹",
        "Bolivia": "玻利维亚",
        "Bonaire": "博奈尔",
        "Bosnia and Herzegovina": "波斯尼亚和黑塞哥维那",
        "Botswana": "博茨瓦纳",
        "Bouvet Island": "布韦岛",
        "Brazil": "巴西",
        "British Indian Ocean Territory": "英属印度洋领地",
        "British Virgin Islands": "英属维尔京群岛",
        "Brunei Darussalam": "文莱",
        "Bulgaria": "保加利亚",
        "Burkina Faso": "布基纳法索",
        "Burundi": "布隆迪",
        "Cambodia": "柬埔寨",
        "Cameroon": "喀麦隆",
        "Canada": "加拿大",
        "Canary Islands": "加那利群岛",
        "Cabo Verde": "佛得角",
        "Cayman Islands": "开曼群岛",
        "Central African Republic": "中非共和国",
        "Chad": "乍得",
        "Chile": "智利",
        "China": "中国",
        "Christmas Island": "圣诞岛",
        "Cocos (Keeling) Islands": "科科斯(基林)群岛",
        "Colombia": "哥伦比亚",
        "Comoros": "科摩罗",
        "Republic of the Congo": "刚果(金)",
        "Congo": "刚果(布)",
        "Cook Islands": "库克群岛",
        "Costa Rica": "哥斯达黎加",
        "Côte d'Ivoire": "科特迪瓦",
        "Croatia": "克罗地亚",
        "Cuba": "古巴",
        "Curaçao": "库拉索",
        "Cyprus": "塞浦路斯",
        "Czechia": "捷克共和国",
        "Denmark": "丹麦",
        "Djibouti": "吉布提",
        "Dominica": "多米尼克",
        "Dominican Republic": "多米尼加共和国",
        "Ecuador": "厄瓜多尔",
        "Egypt": "埃及",
        "El Salvador": "萨尔瓦多",
        "Equatorial Guinea": "赤道几内亚",
        "Eritrea": "厄立特里亚",
        "Estonia": "爱沙尼亚",
        "Eswatini": "斯威士兰",
        "Ethiopia": "埃塞俄比亚",
        "Falkland Islands (Malvinas)": "福克兰群岛(马尔维纳斯)",
        "Faroe Islands": "法罗群岛",
        "Fiji": "斐济",
        "Finland": "芬兰",
        "France": "法国",
        "French Guiana": "法属圭亚那",
        "French Polynesia": "法属波利尼西亚",
        "French Southern Territories": "法属南部和南极领地",
        "Gabon": "加蓬",
        "Gambia": "冈比亚",
        "Georgia": "格鲁吉亚",
        "Germany": "德国",
        "Ghana": "加纳",
        "Gibraltar": "直布罗陀",
        "Greece": "希腊",
        "Greenland": "格陵兰",
        "Grenada": "格林纳达",
        "Guadeloupe": "瓜德罗普",
        "Guam": "关岛",
        "Guatemala": "危地马拉",
        "Guernsey": "根西",
        "Guinea": "几内亚",
        "Guinea-Bissau": "几内亚比绍",
        "Guyana": "圭亚那",
        "Haiti": "海地",
        "Heard Island and McDonald Islands": "赫德岛和麦克唐纳群岛",
        "Honduras": "洪都拉斯",
        "Hong Kong": "中国香港",
        "Hungary": "匈牙利",
        "Iceland": "冰岛",
        "India": "印度",
        "Indonesia": "印度尼西亚",
        "Iran": "伊朗",
        "Iraq": "伊拉克",
        "Ireland": "爱尔兰",
        "Isle of Man": "马恩岛",
        "Israel": "以色列",
        "Italy": "意大利",
        "Jamaica": "牙买加",
        "Japan": "日本",
        "Jersey": "泽西",
        "Jordan": "约旦",
        "Kazakhstan": "哈萨克斯坦",
        "Kenya": "肯尼亚",
        "Kiribati": "基里巴斯",
        "Kosovo": "科索沃",
        "Kuwait": "科威特",
        "Kyrgyzstan": "吉尔吉斯斯坦",
        "Laos": "老挝",
        "Latvia": "拉脱维亚",
        "Lebanon": "黎巴嫩",
        "Lesotho": "莱索托",
        "Liberia": "利比里亚",
        "Libya": "利比亚",
        "Liechtenstein": "列支敦士登",
        "Lithuania": "立陶宛",
        "Luxembourg": "卢森堡",
        "Macao": "中国澳门",
        "Madagascar": "马达加斯加",
        "Malawi": "马拉维",
        "Malaysia": "马来西亚",
        "Maldives": "马尔代夫",
        "Mali": "马里",
        "Malta": "马耳他",
        "Marshall Islands": "马绍尔群岛",
        "Martinique": "马提尼克",
        "Mauritania": "毛里塔尼亚",
        "Mauritius": "毛里求斯",
        "Mayotte": "马约特",
        "Mexico": "墨西哥",
        "Micronesia": "密克罗尼西亚",
        "Moldova": "摩尔多瓦",
        "Monaco": "摩纳哥",
        "Mongolia": "蒙古",
        "Montenegro": "黑山",
        "Montserrat": "蒙特塞拉特",
        "Morocco": "摩洛哥",
        "Mozambique": "莫桑比克",
        "Myanmar": "缅甸",
        "Namibia": "纳米比亚",
        "Nauru": "瑙鲁",
        "Nepal": "尼泊尔",
        "Netherlands": "荷兰",
        "New Caledonia": "新喀里多尼亚",
        "New Zealand": "新西兰",
        "Nicaragua": "尼加拉瓜",
        "Niger": "尼日尔",
        "Nigeria": "尼日利亚",
        "Niue": "纽埃",
        "Norfolk Island": "诺福克岛",
        "North Korea": "朝鲜",
        "North Macedonia": "北马其顿",
        "Northern Mariana Islands": "北马里亚纳群岛",
        "Norway": "挪威",
        "Oman": "阿曼",
        "Pakistan": "巴基斯坦",
        "Palau": "帕劳",
        "Palestine": "巴勒斯坦",
        "Panama": "巴拿马",
        "Papua New Guinea": "巴布亚新几内亚",
        "Paraguay": "巴拉圭",
        "Peru": "秘鲁",
        "Philippines": "菲律宾",
        "Pitcairn": "皮特凯恩群岛",
        "Poland": "波兰",
        "Portugal": "葡萄牙",
        "Puerto Rico": "波多黎各",
        "Qatar": "卡塔尔",
        "Réunion": "留尼汪",
        "Romania": "罗马尼亚",
        "Russia": "俄罗斯",
        "Rwanda": "卢旺达",
        "Saint Barthélemy": "圣巴泰勒米",
        "Saint Helena": "圣赫勒拿",
        "Saint Kitts and Nevis": "圣基茨和尼维斯",
        "Saint Lucia": "圣卢西亚",
        "Saint Martin (French part)": "法属圣马丁",
        "Saint Pierre and Miquelon": "圣皮埃尔和密克隆",
        "Saint Vincent and the Grenadines": "圣文森特和格林纳丁斯",
        "Samoa": "萨摩亚",
        "San Marino": "圣马力诺",
        "Sao Tome and Principe": "圣多美和普林西比",
        "Saudi Arabia": "沙特阿拉伯",
        "Senegal": "塞内加尔",
        "Serbia": "塞尔维亚",
        "Seychelles": "塞舌尔",
        "Sierra Leone": "塞拉利昂",
        "Singapore": "新加坡",
        "Sint Maarten (Dutch part)": "荷属圣马丁",
        "Slovakia": "斯洛伐克",
        "Slovenia": "斯洛文尼亚",
        "Solomon Islands": "所罗门群岛",
        "Somalia": "索马里",
        "South Africa": "南非",
        "South Georgia and the South Sandwich Islands": "南乔治亚和南桑威奇群岛",
        "South Korea": "韩国",
        "South Sudan": "南苏丹",
        "Spain": "西班牙",
        "Sri Lanka": "斯里兰卡",
        "Sudan": "苏丹",
        "Suriname": "苏里南",
        "Svalbard and Jan Mayen": "斯瓦尔巴和扬马延",
        "Sweden": "瑞典",
        "Switzerland": "瑞士",
        "Syrian Arab Republic": "叙利亚",
        "Taiwan": "中国台湾",
        "Tajikistan": "塔吉克斯坦",
        "Tanzania": "坦桑尼亚",
        "Thailand": "泰国",
        "Timor-Leste": "东帝汶",
        "Togo": "多哥",
        "Tokelau": "托克劳",
        "Tonga": "汤加",
        "Trinidad and Tobago": "特立尼达和多巴哥",
        "Tunisia": "突尼斯",
        "Türkiye": "土耳其",
        "Turkmenistan": "土库曼斯坦",
        "Turks and Caicos Islands": "特克斯和凯科斯群岛",
        "Tuvalu": "图瓦卢",
        "U.S. Virgin Islands": "美属维尔京群岛",
        "Uganda": "乌干达",
        "Ukraine": "乌克兰",
        "United Arab Emirates": "阿拉伯联合酋长国",
        "United Kingdom": "英国",
        "United States": "美国",
        "United States Minor Outlying Islands": "美国本土外小岛屿",
        "Uruguay": "乌拉圭",
        "Uzbekistan": "乌兹别克斯坦",
        "Vanuatu": "瓦努阿图",
        "Vatican City": "梵蒂冈",
        "Venezuela": "委内瑞拉",
        "Viet Nam": "越南",
        "Virgin Islands": "维尔京群岛",
        "Wallis and Futuna": "瓦利斯和富图纳",
        "Western Sahara": "西撒哈拉",
        "Yemen": "也门",
        "Zambia": "赞比亚",
        "Zimbabwe": "津巴布韦",

        // ========== 颜色 ==========
        "Black": "黑色",
        "Dark Gray": "暗灰色",
        "Gray": "灰色",
        "Medium Gray": "中灰色",
        "Light Gray": "浅灰色",
        "White": "白色",
        "Deep Red": "深红色",
        "Dark Red": "暗红色",
        "Red": "红色",
        "Light Red": "浅红色",
        "Dark Orange": "暗橙色",
        "Orange": "橙色",
        "Gold": "金色",
        "Yellow": "黄色",
        "Light Yellow": "浅黄色",
        "Dark Goldenrod": "暗金菊色",
        "Goldenrod": "金菊色",
        "Light Goldenrod": "浅金菊色",
        "Dark Olive": "暗橄榄色",
        "Olive": "橄榄色",
        "Light Olive": "浅橄榄色",
        "Dark Green": "暗绿色",
        "Green": "绿色",
        "Light Green": "浅绿色",
        "Dark Teal": "暗鸭绿色",
        "Teal": "鸭绿色",
        "Light Teal": "浅鸭绿色",
        "Dark Cyan": "暗青色",
        "Cyan": "青色",
        "Light Cyan": "浅青色",
        "Dark Blue": "暗蓝色",
        "Blue": "蓝色",
        "Light Blue": "浅蓝色",
        "Dark Indigo": "暗靛色",
        "Indigo": "靛色",
        "Light Indigo": "浅靛色",
        "Dark Slate Blue": "暗岩蓝色",
        "Slate Blue": "岩蓝色",
        "Light Slate Blue": "浅岩蓝色",
        "Dark Purple": "暗紫色",
        "Purple": "紫色",
        "Light Purple": "浅紫色",
        "Dark Pink": "暗粉红色",
        "Pink": "粉红色",
        "Light Pink": "浅粉红色",
        "Dark Peach": "暗桃色",
        "Peach": "桃色",
        "Light Peach": "浅桃色",
        "Dark Brown": "暗棕色",
        "Brown": "棕色",
        "Light Brown": "浅棕色",
        "Dark Tan": "暗日晒色",
        "Tan": "日晒色",
        "Light Tan": "浅日晒色",
        "Dark Beige": "暗米色",
        "Beige": "米色",
        "Light Beige": "浅米色",
        "Dark Stone": "暗岩棕色",
        "Stone": "岩棕色",
        "Light Stone": "浅岩棕色",
        "Dark Slate": "暗岩灰色",
        "Slate": "岩灰色",
        "Light Slate": "浅岩灰色",
        "Transparent": "透明",

        // ========== 商店页面 & 联盟页面 ==========
        "Droplets": "小液滴",
        //"+5 Max. Charges": "像素点储备上限+5",
        "Increase your maximum paint charges capacity": "让你能够储备更多的像素点",
        //"+30 Paint Charges": "现有可用像素点立即+30",
        "Recharge paint charges": "恢复你的像素点储备",
        "MAX": "最大",
        "Profile": "个人资料",
        "Profile picture": "头像",
        "Add a new 16x16 profile picture": "新建一张大小为 16x16 的头像",
        "Flags": "旗帜",
        "Display your country’s flag next to your username. Plus, when painting in regions where you own the corresponding flag, you recover 10% of the charges spent.": "在自己的用户名一旁展示自己所属国家的旗帜。此外,在该旗帜对应区域境内进行绘制,将返还所消耗像素点的10%。",
        "Show more": "更多",
        "Show less": "收起",
        "Items": "购买项",
        "Get more charges": "让自己多储备一些像素点",
        "You gain 1 droplet per pixel painted and 500 droplets per level": "每放置一个像素点,你将获得一颗小液滴;每升一级,你将获得 500 颗小液滴",
        "Not enough droplets": "液滴数不足",
        "+0 bonus": "无赠送",
        "75,000 Droplets": "75000 颗小液滴",
        "+3,750 bonus": ",购买即多赠 3750 颗",
        "150,000 Droplets": "150000 颗小液滴",
        "+15,000 bonus": ",购买即多赠 15000 颗",
        "250,000 Droplets": "250000 颗小液滴",
        "+37,500 bonus": ",购买即多赠 37500 颗",
        "375,000 Droplets": "375000 颗小液滴",
        "+75,000 bonus": ",购买即多赠 75000 颗",
        "500,000 Droplets": "500000 颗小液滴",
        "+125,000 bonus": ",购买即多赠 125000 颗",
        "Members:": "成员总数:",
        "Headquarters:": "大本营坐标:",
        "Player": "成员",
        "Leave alliance": "离开当前联盟",


        //倒计时
        //不管是正则还是直接写,都没有效果,必须要联系官方做好i18n才可以
        /*"Next charge in 0:29": "将于 0:29 后恢复一像素点储备",
        "Next charge in 0:28": "将于 0:28 后恢复一像素点储备",
        "Next charge in 0:27": "将于 0:79 后恢复一像素点储备",
        "Next charge in 0:26": "将于 0:26 后恢复一像素点储备",
        "Next charge in 0:25": "将于 0:25 后恢复一像素点储备",
        "Next charge in 0:24": "将于 0:24 后恢复一像素点储备",
        "Next charge in 0:23": "将于 0:23 后恢复一像素点储备",
        "Next charge in 0:22": "将于 0:22 后恢复一像素点储备",
        "Next charge in 0:21": "将于 0:21 后恢复一像素点储备",
        "Next charge in 0:20": "将于 0:20 后恢复一像素点储备",
        "Next charge in 0:19": "将于 0:19 后恢复一像素点储备",
        "Next charge in 0:18": "将于 0:18 后恢复一像素点储备",
        "Next charge in 0:17": "将于 0:17 后恢复一像素点储备",
        "Next charge in 0:16": "将于 0:16 后恢复一像素点储备",
        "Next charge in 0:15": "将于 0:15 后恢复一像素点储备",
        "Next charge in 0:14": "将于 0:14 后恢复一像素点储备",
        "Next charge in 0:13": "将于 0:13 后恢复一像素点储备",
        "Next charge in 0:12": "将于 0:12 后恢复一像素点储备",
        "Next charge in 0:11": "将于 0:11 后恢复一像素点储备",
        "Next charge in 0:10": "将于 0:10 后恢复一像素点储备",
        "Next charge in 0:09": "将于 0:09 后恢复一像素点储备",
        "Next charge in 0:08": "将于 0:08 后恢复一像素点储备",
        "Next charge in 0:07": "将于 0:07 后恢复一像素点储备",
        "Next charge in 0:06": "将于 0:06 后恢复一像素点储备",
        "Next charge in 0:05": "将于 0:05 后恢复一像素点储备",
        "Next charge in 0:04": "将于 0:04 后恢复一像素点储备",
        "Next charge in 0:03": "将于 0:03 后恢复一像素点储备",
        "Next charge in 0:02": "将于 0:02 后恢复一像素点储备",
        "Next charge in 0:01": "将于 0:01 后恢复一像素点储备",*/

        // 其他常见文本
        "Version": "当前版本",
        "Unlock": "需解锁",
        "Pixel:": "坐标:",
        "Permanently unlock the color": "一次花费,永久使用",
        "No country found.": "未搜索到相关国家或地区(仅支持搜索英语世界通行称谓或其变体,如 Viet Nam,Türkiye)",
        "Wplace is a collaborative, real-time pixel canvas layered over the world map, where anyone can paint and create art together.": "Wplace 是一片覆盖在世界地图图层之上的协作式实时像素画布,任何人都可以在其上进行绘画,创作艺术。",

        //JS 中的文本
        "Phone verification required": "需验证您的手机号码",
        "Could not install the app:": "未能作为应用安装:",
        "Install App": "作为应用安装:",
        "Hide UI": "隐藏 UI",
        "Change picture": "更换头像",
        "Are you absolutely sure?": "是否确定删除账户?",
        "This will permanently delete your account and all associated data. This action cannot be undone": "进行该操作后,你的账户将被永久删除,所有相关数据也将一并被抹除。该操作无法被撤销。",
        "Does not need to be equipped to provide the bonus": "Does not need to be equipped to provide the bonus",
        "Equipped": "已装备",
        "Equip": "装备",
        "You can paint more than 1 pixel": "你有复数个像素点可用于绘制",
        "Not set": "尚未设置",
        "You are not in an alliance": "您未加入联盟",
        "Get invited to an alliance": "您可以以受邀请的形式加入联盟",
        "OR": "也可以",
        "Create an alliance": "组建一个联盟",
        "Invite link": "联盟邀请链接",
        "Send the link below to everybody you want to invite to the alliance": "您可以把下方链接发送给您希望他们加入自己联盟的人",
        "Copied": "链接已复制",
        "No description": "无描述",
        "Invite": "邀请",
        "this week": "本周",
        "this month": "本月",
        "Last pixel": "最后一个像素点",
        "Create alliance": "组建联盟",
        "Alliance Name": "联盟名称",
        "Create": "组建",
        "Give admin": "授予其联盟管理身份",
        "Ban from alliance": "封禁该成员",
        "No action": "无操作",
        "Unban": "解封",
        "No banned users": "尚无被封禁的成员",
        "Update": "更新",
        "Error giving admin to user": "授予该成员联盟管理身份时出现错误",
        "Users": "Users",
        "Banned": "已封禁",
        "Limit reached": "已达上限",
        "Select the headquarters location": "请选择联盟大本营位置",
        "Pixels painted inside the country": "放置于该国家/区域内像素点的总数目",
        "You are not allowed to use multiple accounts. Use your main account to paint.": "禁止单人使用多个账户进行绘制。请使用你的主账户。",
        "SMS sent to": "已将短信发送至",
        "Phone successfully verified": "手机号码验证成功",
        "Not a valid phone number": "该手机号码无效",
        "Giving admin to user": "正在授予该用户联盟管理身份",
        "Profile updated": "已更新个人资料",
        "Account successfully deleted": "成功删除账户",
        "Could not logout. Try refreshing the page.": "退出登录失败。请尝试刷新页面。",
        "Phone verification": "验证手机号码",
        "Please verify your phone number to continue playing. This helps us keep bots out and ensure a safe, creative experience for everyone.": "如需继续游玩,请您验证手机号码。该操作有助于我们防范机器人账户,为去全体用户创造安全的,洋溢着创造力的游戏环境",
        "Send Code": "发送验证码",
        "Input the code": "输入验证码",
        "Sent to": "发送至",
        "Resend Code": "重新发送",
        "Try another number": "请尝试其他手机号码",
        "Moderation": "Moderation",
        "Clear area": "清理区域",
        "Select the area's first corner": "选择需清理区域的一个顶点",
        "Select the area's opposite corner": "选择需清理区域的对向顶点",

        // chunk 中的 JS 文本
        "Unexpected server error. Try again later.": "服务器发生意外错误。请稍后重试。",
        "You need to be logged in to paint": "登录本站,即可进行绘画",
        "You do not have enough charges to paint. Erase some pixels.": "现有可用像素点不足。请擦除一些像素点。",
        "Error while painting:": "绘制时出现错误:",
        "Invalid phone number": "该手机号码无效",
        "Phone already used": "该手机号码已被使用",
        "You have to wait to resend a code": "请稍作等候,再重新发送验证码",
        "Invalid code": "验证码错误",
        "Operation not allowed. Maybe you have too many favorite locations.": "不允许执行该操作。您收藏的位置可能已达上限。",
        "Location name is too big (max. 128 characters)": "位置名称过程(上限为 128 个英语字符)",
        "Couldn't complete the purchase. This item does not exist.": "购买失败。该购买项不存在。",
        "You do not have enough droplets to buy this item.": "液滴数不足,无法购买该项目。",
        "You already have this item. Please refresh the page.": "您已拥有该购买项。请刷新页面。",
        "Alliance name exceeded the maximum number of characters": "联盟名称超出最大字符上限",
        "Alliance name already taken": "该联盟名称已存在",
        "Alliance with empty name": "联盟名称为空",
        "You are already in an alliance": "您此前已加入联盟",
        "You are not allowed to do this": "您无法做出该操作",
        "You or someone in your network is making a lot of requests to the server. Try again later.": "您或与您处于同一网络中的人向服务器发出了过量请求。请稍后再试。",
        "We’re currently experiencing high traffic. Some requests may not be processed at this time—please try again later. Thank you for your patience": "本站目前处于流量高峰期,部分请求此时可能无法得到处理,请稍后再试。感谢您的耐心等待。",
        "You are not allowed to do this": "您无法做出该操作",
    };

    console.log('[Wplace汉化] 翻译字典已加载,包含', Object.keys(translations).length, '个条目');

    // 标记已翻译的元素,避免重复处理。
    // 注意:此属性现在主要用于标记元素自身的*属性*是否已被处理,
    // 不再用于阻止对该元素内部*文本节点*的独立检查。
    const TRANSLATED_ATTRIBUTE = 'data-wplace-translated';

    // 翻译计数器
    let translationCount = 0;

    /**
     * 翻译文本节点
     * @param {Node} textNode - 文本节点
     */
    function translateTextNode(textNode) {
        if (!textNode || textNode.nodeType !== Node.TEXT_NODE) return;

        const originalText = textNode.textContent.trim();
        if (!originalText) return;

        // --- 现有倒计时文本的正则表达式匹配和翻译 ---
        const countdownRegex = /^Next charge in (\d+):(\d{2})$/;
        const matchCountdown = originalText.match(countdownRegex);

        if (matchCountdown) {
            const minutes = matchCountdown[1];
            const seconds = matchCountdown[2];
            const translatedCountdown = `将于 ${minutes}:${seconds} 后恢复一像素点储备`;

            if (textNode.textContent !== translatedCountdown) {
                textNode.textContent = translatedCountdown;
                translationCount++;
                console.log('[Wplace汉化] 倒计时翻译:', originalText, '->', translatedCountdown);
            }
            return;
        }
        // --- End 现有倒计时部分 ---

        // --- 现有动态 “+N Max. Charges” 和 “+N Paint Charges” 文本的正则表达式匹配和翻译 ---
        const maxChargesRegex = /^\+(\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)\sMax\.\sCharges$/;
        const matchMaxCharges = originalText.match(maxChargesRegex);

        if (matchMaxCharges) {
            const amount = matchMaxCharges[1];
            const translatedText = `像素点储备上限+${amount}`;

            if (textNode.textContent !== translatedText) {
                textNode.textContent = translatedText;
                translationCount++;
                console.log('[Wplace汉化] 动态文本翻译: ', originalText, '->', translatedText);
            }
            return;
        }

        const paintChargesRegex = /^\+(\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)\sPaint\sCharges$/;
        const matchPaintCharges = originalText.match(paintChargesRegex);

        if (matchPaintCharges) {
            const amount = matchPaintCharges[1];
            const translatedText = `现有可用像素点立即+${amount}`;

            if (textNode.textContent !== translatedText) {
                textNode.textContent = translatedText;
                translationCount++;
                console.log('[Wplace汉化] 动态文本翻译: ', originalText, '->', translatedText);
            }
            return;
        }
        // --- End 现有动态 Charges 部分 ---


        // --- 新增:像素坐标文本的正则表达式匹配和翻译 ---
        // 匹配 "Pixel: X, Y" 格式
        const pixelCoordsRegex = /^Pixel:\s*(-?\d+),\s*(-?\d+)$/;
        const matchPixelCoords = originalText.match(pixelCoordsRegex);

        if (matchPixelCoords) {
            const xCoord = matchPixelCoords[1];
            const yCoord = matchPixelCoords[2];
            const translatedText = `坐标:${xCoord}, ${yCoord}`;

            if (textNode.textContent !== translatedText) {
                textNode.textContent = translatedText;
                translationCount++;
                console.log('[Wplace汉化] 像素坐标翻译:', originalText, '->', translatedText);
            }
            return;
        }

        // 匹配 "(Tl X: ..., Tl Y: ..., Px X: ..., Px Y: ...)" 格式
        // 这里的数字也可能是负数,所以使用 -?\d+
        const fullCoordsRegex = /^\(Tl X:\s*(-?\d+),\s*Tl Y:\s*(-?\d+),\s*Px X:\s*(-?\d+),\s*Px Y:\s*(-?\d+)\)$/;
        const matchFullCoords = originalText.match(fullCoordsRegex);

        if (matchFullCoords) {
            const tlX = matchFullCoords[1];
            const tlY = matchFullCoords[2];
            const pxX = matchFullCoords[3];
            const pxY = matchFullCoords[4];
            // 这里我们只翻译前缀,保持数字不变,如果需要更复杂的翻译,可以调整
            const translatedText = `(TlX: ${tlX}, TlY: ${tlY}, Px X: ${pxX}, Px Y: ${pxY})`;
            // 如果希望更简洁,可以将 `瓦片X`, `瓦片Y` 等也定义在字典中,或者直接用变量。
            // 考虑到原始信息为 "Tl X", "Px X", 保持原始前缀结合中文释义可能更清晰。

            if (textNode.textContent !== translatedText) {
                textNode.textContent = translatedText;
                translationCount++;
                console.log('[Wplace汉化] 完整坐标翻译:', originalText, '->', translatedText);
            }
            return;
        }
        // --- End 新增:像素坐标部分 ---


        // 原有的字典查找逻辑:仅当原始文本在字典中,且当前文本内容与翻译后的文本不同时才进行翻译
        if (translations[originalText] && textNode.textContent !== translations[originalText]) {
            textNode.textContent = translations[originalText];
            translationCount++;
            console.log('[Wplace汉化] 文本翻译:', originalText, '->', translations[originalText]);
        }
    }


    /**
     * 翻译元素属性
     * @param {Element} element - DOM元素
     */
    function translateElementAttributes(element) {
        if (!element || element.nodeType !== Node.ELEMENT_NODE) return;

        let translatedAnyAttribute = false;

        // 翻译title属性
        const title = element.getAttribute('title');
        if (title && translations[title] && title !== translations[title]) {
            element.setAttribute('title', translations[title]);
            translatedAnyAttribute = true;
            translationCount++;
            console.log('[Wplace汉化] 标题翻译:', title, '->', translations[title]);
        }

        // 翻译placeholder属性
        const placeholder = element.getAttribute('placeholder');
        if (placeholder && translations[placeholder] && placeholder !== translations[placeholder]) {
            element.setAttribute('placeholder', translations[placeholder]);
            translatedAnyAttribute = true;
            translationCount++;
            console.log('[Wplace汉化] 占位符翻译:', placeholder, '->', translations[placeholder]);
        }

        // 翻译aria-label属性
        const ariaLabel = element.getAttribute('aria-label');
        if (ariaLabel && translations[ariaLabel] && ariaLabel !== translations[ariaLabel]) {
            element.setAttribute('aria-label', translations[ariaLabel]);
            translatedAnyAttribute = true;
            translationCount++;
            console.log('[Wplace汉化] 无障碍标签翻译:', ariaLabel, '->', translations[ariaLabel]);
        }

        // --- 新增:翻译data-tip属性 ---
        const dataTip = element.getAttribute('data-tip');
        if (dataTip && translations[dataTip] && dataTip !== translations[dataTip]) {
            element.setAttribute('data-tip', translations[dataTip]);
            translatedAnyAttribute = true;
            translationCount++;
            console.log('[Wplace汉化] Data-tip翻译:', dataTip, '->', translations[dataTip]);
        }
        // --- End 新增部分 ---

        // 如果有任何属性被翻译,就标记此元素。
        if (translatedAnyAttribute) {
            element.setAttribute(TRANSLATED_ATTRIBUTE, 'true');
        }
    }

    /**
     * 深度遍历并翻译节点
     * @param {Node} node - 要遍历的节点
     */
    function translateNode(node) {
        if (!node) return;

        if (node.nodeType === Node.TEXT_NODE) {
            translateTextNode(node);
        } else if (node.nodeType === Node.ELEMENT_NODE) {
            // 翻译当前元素自身的属性
            translateElementAttributes(node);

            // 遍历子节点
            const walker = document.createTreeWalker(
                node,
                NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT,
                {
                    acceptNode: function(node) {
                        // 优化:移除此过滤器。
                        // 每个文本节点应独立进行翻译检查,不再依赖父元素的 TRANSLATED_ATTRIBUTE。
                        // translateTextNode 内部的 `textNode.textContent !== translations[originalText]` 检查已足够防止重复。
                        return NodeFilter.FILTER_ACCEPT;
                    }
                },
                false
            );

            let currentNode = walker.nextNode();
            while (currentNode) {
                if (currentNode.nodeType === Node.TEXT_NODE) {
                    translateTextNode(currentNode);
                } else if (currentNode.nodeType === Node.ELEMENT_NODE) {
                    // 对子元素的属性进行翻译。
                    // 递归调用 translateElementAttributes 已经包含在此处,因为它在 walker 遍历到的每个 Element 节点上都会被调用
                     translateElementAttributes(currentNode);
                }
                currentNode = walker.nextNode();
            }
        }
    }

    /**
     * 翻译页面元数据
     */
    function translateMetadata() {
        console.log('[Wplace汉化] 开始翻译页面元数据...');

        // 设置语言属性
        if (document.documentElement) {
            document.documentElement.lang = 'zh-CN';
            console.log('[Wplace汉化] 页面语言已设置为 zh-CN');
        }

        // 翻译页面标题
        if (document.title && translations[document.title] && document.title !== translations[document.title]) { // Added check for difference
            const originalTitle = document.title;
            document.title = translations[document.title];
            console.log('[Wplace汉化] 页面标题翻译:', originalTitle, '->', document.title);
            translationCount++;
        }

        // 翻译meta标签
        const metaSelectors = [
            'meta[property="og:title"]',
            'meta[name="twitter:title"]',
            'meta[name="description"]',
            'meta[itemprop="description"]',
            'meta[property="og:description"]',
            'meta[name="twitter:description"]',
            'meta[name="keywords"]',
            'meta[name="apple-mobile-web-app-title"]'
        ];

        metaSelectors.forEach(selector => {
            const metaElement = document.querySelector(selector);
            if (metaElement) {
                const content = metaElement.getAttribute('content');
                if (content && translations[content] && content !== translations[content]) {
                    const originalContent = content;
                    metaElement.setAttribute('content', translations[content]);
                    console.log('[Wplace汉化] Meta标签翻译:', originalContent, '->', translations[content]);
                    translationCount++;
                }
            }
        });
    }

    /**
     * 初始化MutationObserver
     */
    function initMutationObserver() {
        console.log('[Wplace汉化] 初始化DOM变化监听器...');

        const observer = new MutationObserver((mutations) => {
            let hasChanges = false;
            // 优化:避免在每次 mutation 都重新遍历整个 body
            // 遍历 mutaions 时,检查 mutation.target 并根据类型决定如何处理
            mutations.forEach(mutation => {
                if (mutation.type === 'childList') {
                    mutation.addedNodes.forEach(node => {
                        if (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.TEXT_NODE) {
                            translateNode(node); // 深度翻译新添加的节点
                            hasChanges = true;
                        }
                    });
                } else if (mutation.type === 'attributes') {
                    // 仅翻译被修改的元素属性
                    translateElementAttributes(mutation.target);
                    // translatedAnyAttribute logic inside translateElementAttributes already handles console.log
                    hasChanges = true;
                } else if (mutation.type === 'characterData') {
                    // 监听文本节点内容的改变
                    translateTextNode(mutation.target);
                    hasChanges = true;
                }
            });

            if (hasChanges && translationCount > 0) { // Using translationCount for a more granular log when actual translations happen
                console.log('[Wplace汉化] 本轮DOM变化处理完成');
            }
        });

        // 配置观察选项
        const config = {
            childList: true, // 监听子节点的添加或移除
            subtree: true, // 监听所有子孙节点的变化
            attributes: true, // 监听属性变化
            attributeFilter: ['title', 'placeholder', 'aria-label', 'data-tip'], // 过滤特定属性
            characterData: true // 新增:监听文本节点内容的改变
        };

        // 开始观察
        observer.observe(document.body, config);
        console.log('[Wplace汉化] DOM变化监听器已启动');

        return observer;
    }

    /**
     * 翻译现有内容
     */
    function translateExistingContent() {
        console.log('[Wplace汉化] 开始翻译页面现有内容...');
        const startTime = Date.now();

        if (document.body) {
            const initialTranslationCount = translationCount; // 记录开始前的总翻译数
            translateNode(document.body);
            const currentRoundTranslations = translationCount - initialTranslationCount;
            const endTime = Date.now();
            console.log('[Wplace汉化] 现有内容翻译完成,耗时:', (endTime - startTime), 'ms,本轮翻译项目:', currentRoundTranslations, '累计翻译项目:', translationCount);
        }
    }

    /**
     * 主初始化函数
     */
    function init() {
        console.log('[Wplace汉化] 开始初始化...');

        // 立即翻译元数据
        translateMetadata();

        // 当DOM准备就绪时
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', () => {
                console.log('[Wplace汉化] DOM内容已加载,开始处理页面内容...');
                translateExistingContent();
                initMutationObserver();
            });
        } else {
            // DOM已经准备就绪
            console.log('[Wplace汉化] DOM已准备就绪,立即处理页面内容...');
            translateExistingContent();
            initMutationObserver();
        }

        // 监听页面可见性变化,用于SPA路由切换
        document.addEventListener('visibilitychange', () => {
            if (!document.hidden) {
                setTimeout(() => {
                    console.log('[Wplace汉化] 页面重新可见,检查新内容...');
                    translateExistingContent();
                }, 100);
            }
        });

        // 监听pushstate和popstate事件(SPA路由变化)
        const originalPushState = history.pushState;
        const originalReplaceState = history.replaceState;
        // 确保 originalPopState 不为 null,因为 window.onpopstate 默认可能是 null
        const originalPopState = typeof window.onpopstate === 'function' ? window.onpopstate : null;

        history.pushState = function(...args) {
            originalPushState.apply(history, args);
            setTimeout(() => {
                console.log('[Wplace汉化] 路由变化(pushState),重新翻译内容...');
                translateExistingContent();
            }, 200);
        };

        history.replaceState = function(...args) {
            originalReplaceState.apply(history, args);
            setTimeout(() => {
                console.log('[Wplace汉化] 路由变化(replaceState),重新翻译内容...');
                translateExistingContent();
            }, 200);
        };

        window.onpopstate = function(...args) {
            if (originalPopState) { // 仅当原始 onpopstate 存在时才调用
                originalPopState.apply(window, args);
            }
            setTimeout(() => {
                console.log('[Wplace汉化] 路由变化(popstate),重新翻译内容...');
                translateExistingContent();
            }, 200);
        };

        console.log('[Wplace汉化] 初始化完成');
    }

    // 启动脚本
    init();

    // 添加全局状态查询函数(调试用)
    window.wplaceTranslator = {
        getTranslationCount: () => translationCount,
        getTranslations: () => translations,
        retranslate: () => {
            console.log('[Wplace汉化] 手动重新翻译...');
            translateExistingContent();
        }
    };

    console.log('[Wplace汉化] 脚本加载完成!可以通过 window.wplaceTranslator 访问调试功能');

})();