Greasy Fork

Greasy Fork is available in English.

Backloggd 汉化脚本 (核弹版)

Backloggd 汉化,强制解决 Turbo 跳转/SPA 页面切换失效问题。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Backloggd 汉化脚本 (核弹版)
// @namespace    http://tampermonkey.net/
// @version      1.11
// @description  Backloggd 汉化,强制解决 Turbo 跳转/SPA 页面切换失效问题。
// @author       Gemini & You
// @match        https://www.backloggd.com/*
// @match        https://backloggd.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=backloggd.com
// @run-at       document-start
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // ==========================================
    // 字典配置
    // ==========================================
    const dict = {
        // --- 核心导航与状态 ---
        "Home": "首页",
        "Games": "游戏",
        "Journal": "日志",
        "Reviews": "评测",
        "Lists": "列表",
        "Community": "社区",
        "Search": "搜索游戏...",
        "Log In": "登录",
        "Sign Up": "注册",
        "Register": "注册",
        "Profile": "个人资料",
        "Settings": "设置",
        "Log Out": "退出",

        // --- 截图反馈修复项 ---
        "Released": "已发售", // 状态标签
        "Release Date": "发售日期", // 详情页字段
        "Updates": "更新",
        "Series": "系列",
        "Related Games": "相关游戏",
        "View All": "查看全部",
        "Awards": "奖项",
        "More info on IGDB": "查看 IGDB 更多信息",
        "Stats for all versions": "统计所有版本",

        // --- 统计与列表头部 ---
        "Game Title": "游戏标题",
        "Popularity": "热度",
        "Top Rated": "最高评分",
        "Avg. Play Time": "平均游玩时长",
        "Avg. Finish Time": "平均通关时长",
        "Time to Beat": "通关用时",
        "Date Added": "添加日期",
        "Name": "名称",
        "Filter": "筛选",
        "Sort by": "排序",

        // --- 核心状态 (Side Bar) ---
        "Playing": "在玩",
        "Backlog": "积压",
        "Wishlist": "愿望单",
        "Played": "已玩",
        "Completed": "已通关",
        "Mastered": "全成就",
        "Retired": "弃坑",
        "Shelved": "搁置",
        "Abandoned": "放弃",

        // --- 统计数据标签 ---
        "Plays": "游玩数",
        "Backlogs": "积压数",
        "Wishlists": "愿望单",
        "Ratings": "评分数",
        "Avg Rating": "平均分",

        // --- 游戏类型 (Genres) ---
        "Genres": "游戏类型",
        "Adventure": "冒险",
        "Strategy": "策略",
        "Action": "动作",
        "RPG": "角色扮演",
        "Shooter": "射击",
        "Puzzle": "解谜",
        "Platform": "平台跳跃",
        "Racing": "竞速",
        "Sport": "体育",
        "Fighting": "格斗",
        "Simulation": "模拟",
        "Indie": "独立游戏",
        "Visual Novel": "视觉小说",
        "Turn Based": "回合制",
        "Tactical": "战术",
        "Point-and-click": "点击解谜",
        "Music": "音乐",
        "Card & Board Game": "卡牌桌游",

        // --- 平台 (Platforms) ---
        "Platforms": "游戏平台",
        "Windows PC": "Windows PC", // 保持或汉化
        "Mac": "Mac",
        "Linux": "Linux",
        "PlayStation 4": "PS4",
        "PlayStation 5": "PS5",
        "Nintendo Switch": "Switch",
        "Xbox One": "Xbox One",
        "Xbox Series X|S": "Xbox Series X|S",

        // --- 版本与详情 ---
        "Deluxe Edition": "豪华版",
        "Digital Deluxe Edition": "数字豪华版",
        "Game of the Year Edition": "年度版",
        "Remastered": "重制版",
        "Remake": "重制版",
        "Episodes": "章节",
        "Editions": "版本",
        "More info on": "查看详情于",
        "Trending": "热门",
        "Latest": "最新",
        "Top Liked": "点赞最多",
        "All reviews for": "全部评测",
        "reviewed": "已测评",
        "Open review": "查看评测",
        "See More": "查看更多",
        "See Past Articles": "查看往期文章",
        "No recent notifications": "暂无最新通知",
        "Log a Game": "记录游戏",
        "": "",
        "": "",
        "": "",

        // --- 日历控件 ---
        "Jump to...": "跳转至...",
        "Today": "今天",
        "Start": "开始", // 可能是指跳到开始日期
        "Finish": "结束", // 可能是指跳到结束日期
        "January": "1月",
        "February": "2月",
        "March": "3月",
        "April": "4月",
        "May": "5月",
        "June": "6月",
        "July": "7月",
        "August": "8月",
        "September": "9月",
        "October": "10月",
        "November": "11月",
        "December": "12月",

        // --- 日志/编辑窗口 (Journal & Log) ---
        "Log Title": "记录标题",
        "Replay": "重玩",
        "Edition": "版本",
        "Specify an edition..": "指定版本...",
        "Played on": "游玩平台", // 区分于普通的 Platform
        "Ownership": "所有权",
        "owned, subscription, ...": "拥有、订阅...", // 占位符
        "Started on": "开始于",
        "Finished on": "完成于",
        "Time Played": "游玩时长",
        "Sync sessions": "同步会话",
        "Review": "评测",
        "Formatting": "格式说明",
        "What'd you think...": "你觉得这游戏怎么样...", // 评论框占位符
        "Contains spoilers": "包含剧透",
        "Delete this log": "删除此记录",
        "Use Quick Editor": "使用快速编辑器",
        "Create Log": "创建记录",
        "Time Tracker": "时间追踪",
        "Library": "库",

        // --- 平台字段修复 ---
        // 请检查原来的字典,建议将 "Platform" 改为 "平台"
        // 如果必须保留 "平台跳跃" 翻译,请检查是否应该对应 "Platformer"
        "Platform": "平台",

        // --- 时间追踪器 (Time Tracker Tab) ---
        "Total Playtime": "总游玩时长",
        "Manual input": "手动输入",
        "Enter total playtime manually": "手动输入总时长",
        "Sum log times": "累加记录时间",
        "Total playtime is the sum of all log playtimes": "总时长为所有记录时长之和",
        "Sum journal times": "累加日志时间",
        "Total playtime is the sum of all journal session playtimes": "总时长为所有日志会话时长之和",
        "Time to finish": "通关用时",
        "Time to master": "全成就用时",
        "AVG": "平均", // 表头里的 AVG

        // --- [新增] 个人主页统计与空状态 ---
        "Nothing here!": "暂无内容", // 用于 Bio 为空时
        "Personal Ratings": "个人评分",
        "Total Games Played": "历史游玩总数",
        "Games Backloggd": "积压游戏总数", // 这里的 Backloggd 是名词属性
        "Recently trending": "近期热门",

        // --- [修复] 侧边栏导航 (确保这些独立词汇能被命中) ---
        "Activity": "动态",
        "Friends": "好友",
        "Likes": "喜欢",
        "Bio": "简介",

        // --- 统计面板细节 ---
        "Avg Rating": "平均分",
        "Stats for all versions": "统计所有版本", // 截图右下角那个下拉菜单
        "Released": "已发售",  // 截图1日期左边的那个灰色小标

        // --- 时长统计 (截图3右下角粉色字) ---
        // 注意:这些词通常全是小写
        "average": "平均时长",
        "to finish": "主线通关",
        "to master": "全成就",

        // --- 游戏奖项 (Awards) ---
        "Game of the Year": "年度最佳游戏",
        "Narrative": "最佳叙事",
        "Art Direction": "最佳美术指导",
        "Soundtrack": "最佳配乐",
        "Music": "最佳音乐",
        "Indie Debut": "最佳独立首作", // 预防性补充
        "Multiplayer": "最佳多人",      // 预防性补充

        // --- 游戏奖项 (Awards) ---
        "Game of the Year": "年度最佳游戏",
        "Narrative": "最佳叙事",
        "Art Direction": "最佳美术指导",
        "Soundtrack": "最佳配乐",
        "Music": "最佳音乐",
        "Indie Debut": "最佳独立首作", // 预防性补充
        "Multiplayer": "最佳多人",      // 预防性补充

        // --- 截图中的 Tab 和标题 ---
        "Updates": "更新",
        "Series": "系列",
        "Related Games": "相关游戏",
        "View All": "查看全部",
        "Reviews": "评测",  // 注意:如果是"X Reviews"这种动态文本,需要正则支持

        // --- 个人主页 Dashboard ---
        "Welcome back": "欢迎回来",
        ", your collection awaits...": ",你的游戏库在等你...", // 注意开头的逗号
        "Profile Stats": "个人统计",
        "Game Ratings": "游戏评分分布", // 通常显示在柱状图上方
        "Quick Log": "快速记录",

        "expand": "展开",
        "collapse": "收起",
        "Latest news": "最新动态",
        "Popular lists": "热门列表",
        "Sleeper hits": "冷门佳作", // 或者是 "宝藏游戏",指那些被低估的好游戏
        "Recently anticipated": "近期最受期待",
        "Coming soon": "即将推出",

        "About": "关于",
        "Contact": "联系",
        "Backers": "赞助者", // 指 Patreon 等支持者
        "Roadmap": "路线图", // 指开发计划
        "Terms": "条款",
        "Privacy": "隐私",
        "Powered by": "数据支持", // 上下文通常是 Powered by IGDB

};

    const regexPatterns = [
        { reg: /^([\d\.]+[K|M]?)\s+Likes$/i, repl: "$1 喜欢" },
        { reg: /^([\d\.]+[K|M]?)\s+Reviews$/i, repl: "$1 评测" },
        { reg: /^All reviews for\s+(.+)$/i, repl: "$1 的全部评测" },
        { reg: /^Reviewed on (.+)$/, repl: "评测于 $1" },
        { reg: /^([\d\.]+)h\s+average$/i, repl: "$1小时 平均" },
        { reg: /^([\d\.]+)h\s+to finish$/i, repl: "$1小时 通关" },
        { reg: /^([\d\.]+)h\s+to master$/i, repl: "$1小时 全成就" },
        {
            reg: /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+(\d{1,2}),\s+(\d{4})$/i,
            repl: (match, mon, day, year) => {
                const monthMap = {
                    "Jan": "1月", "Feb": "2月", "Mar": "3月", "Apr": "4月", "May": "5月", "Jun": "6月",
                    "Jul": "7月", "Aug": "8月", "Sep": "9月", "Oct": "10月", "Nov": "11月", "Dec": "12月"
                };
                return `${year}年 ${monthMap[mon]} ${day}日`;
            }
        },
        { reg: /^Nintendo Switch$/, repl: "Switch" },
        { reg: /^PlayStation 5$/, repl: "PS5" },
        { reg: /^Windows PC$/, repl: "PC" }
    ];

    // ==========================================
    // 翻译逻辑核心
    // ==========================================
    function translateText(text) {
        if (!text) return null;
        const cleanText = text.trim();
        if (!cleanText) return null;

        if (dict[cleanText]) return dict[cleanText];

        for (let pattern of regexPatterns) {
            if (pattern.reg.test(cleanText)) {
                return cleanText.replace(pattern.reg, pattern.repl);
            }
        }

        if (/(\s•\s|,\s|\s\.\s)/.test(cleanText)) {
            let separator = "";
            if (cleanText.includes(" • ")) separator = " • ";
            else if (cleanText.includes(", ")) separator = ", ";
            else if (cleanText.includes(" . ")) separator = " . ";

            const parts = cleanText.split(separator);
            let hasTranslation = false;

            const translatedParts = parts.map(part => {
                const pTrim = part.trim();
                let trans = dict[pTrim];
                if (!trans) {
                     for (let pattern of regexPatterns) {
                        if (pattern.reg.test(pTrim)) {
                            trans = pTrim.replace(pattern.reg, pattern.repl);
                            break;
                        }
                    }
                }
                if (trans) hasTranslation = true;
                return trans || part;
            });

            if (hasTranslation) return translatedParts.join(separator);
        }
        return null;
    }

    function traverseAndTranslate(node) {
        if (!node) return;

        if (node.nodeType === 3) { // Text Node
            const val = node.nodeValue;
            if (val && /\S/.test(val)) {
                const translated = translateText(val);
                if (translated) node.nodeValue = node.nodeValue.replace(val.trim(), translated);
            }
        } else if (node.nodeType === 1) { // Element Node
            // 忽略这些标签,提高性能
            if (['SCRIPT', 'STYLE', 'TEXTAREA', 'CODE', 'svg', 'path'].includes(node.tagName)) return;

            if (node.title) {
               const t = translateText(node.title);
               if(t) node.title = t;
            }
            if (node.placeholder) {
               const p = translateText(node.placeholder);
               if(p) node.placeholder = p;
            }

            // 遍历子节点
            let child = node.firstChild;
            while (child) {
                traverseAndTranslate(child);
                child = child.nextSibling;
            }
        }
    }

    // ==========================================
    // 核弹级执行逻辑 (Nuclear Option)
    // ==========================================

    function runTranslation() {
        if(document.body) {
            traverseAndTranslate(document.body);
        }
    }

    // 1. 劫持 History API (应对 Turbo 跳转)
    // ----------------------------------------
    const wrapHistory = (type) => {
        const orig = history[type];
        return function() {
            const rv = orig.apply(this, arguments);
            // URL 变了,延迟一丢丢执行汉化
            setTimeout(runTranslation, 100);
            setTimeout(runTranslation, 500); // 双重保险
            return rv;
        };
    };
    history.pushState = wrapHistory('pushState');
    history.replaceState = wrapHistory('replaceState');
    window.addEventListener('popstate', () => {
        setTimeout(runTranslation, 100);
    });

    // 2. 挂载到 HTML 根节点 (应对 Body 被替换)
    // ----------------------------------------
    const observer = new MutationObserver((mutations) => {
        // 简单防抖,避免卡顿
        runTranslation();
    });

    // 监听 documentElement 而不是 body,因为 html 标签不会被替换
    observer.observe(document.documentElement, {
        childList: true,
        subtree: true
    });

    // 3. 心跳检测 (保底机制)
    // ----------------------------------------
    // 每 800ms 检查一次,如果导航栏变回英文,强制汉化
    // 这是为了解决 MutationObserver 有时在复杂 SPA 渲染中“漏球”的问题
    setInterval(() => {
        const navGames = document.querySelector('nav a[href="/games"]');
        if (navGames && navGames.innerText.trim() === "Games") {
            //console.log("检测到未汉化内容,强制执行...");
            runTranslation();
        }
    }, 800);

    // 4. 初次启动
    // ----------------------------------------
    window.addEventListener('load', runTranslation);
    document.addEventListener('DOMContentLoaded', runTranslation);
    // 针对 Turbo 的特有事件
    window.addEventListener('turbo:load', runTranslation);
    window.addEventListener('turbo:render', runTranslation);

})();