Atcoder 中文版

翻译

// ==UserScript==
// @name         Atcoder 中文版
// @namespace    http://tampermonkey.net/
// @version      2024-08-15
// @description  翻译
// @author       You
// @match        https://atcoder.jp/*
// @run-at       document-start
// @grant        none
// @license      GNU GPL v3
// ==/UserScript==
(function () {
    const TEXT = {
        "(local time)": "(本地时间)",
        "Active Users": "活跃用户",
        "Affiliation": "工作单位",
        "Algorithm": "算法竞赛",
        "All": "全部",
        "All Submissions": "所有提交",
        "All Users": "所有用户",
        "Auto Refresh": "自动刷新",
        "Back to Home": "返回主页",
        "Birth Year": "出生年份",
        "Category": "类别",
        "Change Password": "更换密码",
        "Change Photo": "更换头像",
        "Change/Verify Email address": "更改/验证电子邮件地址",
        "Clarifications": "提问",
        "Company": "公司信息",
        "Competition History": "历史比赛",
        "Contact": "联系方式",
        "Contest": "比赛",
        "Contest Archive": "比赛记录",
        "Contest Name": "比赛名字",
        "Contest Status": "比赛记录",
        "Country/Region": "国家/地区",
        "Custom Test": "自定义测试",
        "Customize": "自定义",
        "Duration": "持续时间",
        "Editorial": "题解",
        "Email Notifications": "邮箱提醒",
        "FAQ": "常见问题",
        "General Settings": "基本设置",
        "Glossary": "术语",
        "Heuristic": "启发式竞赛",
        "Heuristic Contest": "启发式比赛",
        "Highest Rating": "最高等级分",
        "Home": "首页",
        "Information": "公告",
        "Information Protection Policy": "信息保护政策",
        "Last Contest Result": "上次比赛结果",
        "Manage Fav": " 管理收藏",
        "More...": "更多...",
        "My Profile": "我的主页",
        "My Score": "我的分数",
        "My Submissions": "我的提交",
        "Nickname": "昵称",
        "Other": "其他",
        "Page Top": "页首",
        "Past Contests": "往届比赛",
        "Permanent Contests": "永久性比赛",
        "Present Contests": "当前比赛",
        "Privacy Policy": "隐私政策",
        "Profile": "简介",
        "Rank": "排名",
        "Ranking": "排名",
        "Rated Range": "等级范围",
        "Rating": "等级分",
        "Rating Distribution": "评级分布",
        "Recent Contests": "最近的比赛",
        "Refresh": "刷新",
        "Register": "报名",
        "Reset": "重置",
        "Restructuring of contests": "比赛调整",
        "Results": "结果",
        "Rule": "规则",
        "Search": "搜索",
        "Search in Archive": "在存档中搜索",
        "Settings": "设置",
        "Sign In": "登录",
        "Sign Out": "退出登录",
        "Sign Up": "注册",
        "Sponsored ABC": "赞助入门赛(ABC)",
        "Sponsored ARC": "赞助常规赛(ARC)",
        "Sponsored Heuristic Contest": "赞助启发式比赛",
        "Sponsored Parallel(rated)": "赞助平行赛(评级)",
        "Sponsored Parallel(unrated)": "赞助平行赛(未评级)",
        "Sponsored Tournament": "赞助锦标赛",
        "Standings": "排名",
        "Start Time": "开始时间",
        "Submit": "提交",
        "Tasks": "题目",
        "Terms of service": "服务条款",
        "The file size must be at most 1MB.": "文件大小不得超过1MB。",
        "The width and height must be at most 512px.": "宽度和高度不得超过512px。",
        "There is no clarifications yet.": "目前还没有提示。",
        "This user has not competed in a rated contest yet.": "该用户没有参加过有评级的比赛。",
        "This user has not competed yet.": "该用户没有参加过比赛。",
        "Top": "首页",
        "Unofficial(unrated)": "非官方(未评级)",
        "Upcoming Contests": "即将到来的比赛",
        "Update": "更新",
        "Upload": "上传",
        "User": "用户",
        "View all": "查看全部",
        "Virtual Participation": "虚拟参与",
        "Virtual Standings": "虚拟排名",
        "You can use only jpg/png files.": "您只能使用jpg/png文件。",
        "last update": "上次更新",
        "【Important Notice】 Please beware of fake sites impersonating AtCoder": "【重要提示】请注意假冒AtCoder的虚假网站"
    }
    function ObjSort(arys) {
        var newkey = Object.keys(arys).sort();
        var newObj = {};
        for (var i = 0; i < newkey.length; i++) newObj[newkey[i]] = arys[newkey[i]];
        return newObj; //返回排好序的新对象
    }
    console.log("词汇表:");
    console.log(ObjSort(TEXT));
    let cnt = 0, id, flag = sessionStorage["translate"], bflag = 0;
    if (flag == undefined) {
        flag = 1;
        sessionStorage["translate"] = 1;
    }
    function translate(x) {
        if (x.nodeType == 3) {
            let str = x.nodeValue, l = 0, ls = "", r = 0, rs = "";
            while (" \n\t".includes(str[l])) ls += str[l], l++;
            while (" \n\t".includes(str[str.length - 1 - r]) && str.length - 1 - r >= l) rs += str[str.length - 1 - r], r++;
            if (str[str.length - 1 - r] == ":") rs += ":", r++;
            if (TEXT[str.substring(l, str.length - r)] != undefined) {
                str = TEXT[str.substring(l, str.length - r)];
                x.old = x.nodeValue;
                x.nodeValue = ls + str + rs;
            }
            return;
        }
        let c = Array.from(x.childNodes)
        for (let i of c) translate(i);
    }
    function back(x) {
        if (x.nodeType == 3) {
            if (x.old != undefined) {
                x.nodeValue = x.old
                x.old = undefined;
            }
            return;
        }
        let c = Array.from(x.childNodes)
        for (let i of c) back(i);
    }
    function main() {
        if (bflag == 0) {
            let a = document.getElementsByClassName("nav navbar-nav navbar-right")[0];
            if (a != undefined) {
                bflag = 1;
                let bu = document.createElement("button");
                bu.innerText = (flag == 1) ? "关闭翻译" : "开启翻译";
                bu.onclick = function () {
                    if (bu.innerText == "关闭翻译") {
                        bu.innerText = "开启翻译";
                        back(document.body);
                        flag = 0;
                    } else {
                        bu.innerText = "关闭翻译";
                        flag = 1;
                    }
                    sessionStorage["translate"] = flag;
                }
                a.appendChild(bu);
            }
        }
        if (flag != 0) translate(document.body);
        cnt++;
        if (cnt == 1000) {
            // 网页启动时高频刷新,启动后 1 秒降低刷新频率,降低压力
            clearInterval(id);
            setInterval(main, 100);
        }
    }
    id = setInterval(main, 1);
})();