Maybe 财务软件界面翻译(增强版)

翻译 maybe 网站界面为中文,支持 SPA 页面跳转与日期翻译等增强功能。

当前为 2025-07-03 提交的版本,查看 最新版本

// ==UserScript==
// @name         Maybe 财务软件界面翻译(增强版)
// @namespace    http://tampermonkey.net/
// @version      2.19
// @description  翻译 maybe 网站界面为中文,支持 SPA 页面跳转与日期翻译等增强功能。
// @author       ChatGPT
// @match        *://*/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function () {
  'use strict';
  /* -------- ① 早退判断 -------- */
  if (!/Maybe/i.test(document.title)) return;
  /* --------------------------------------------------
     静态文本翻译表(完整,不遗漏任何键)
  -------------------------------------------------- */
const translations = {
  // 常规 ——————————————————————————————————
  "Transaction": "交易", // 已添加
  "Category": "分类", // 已添加
  "Amount": "金额", // 已添加
  "Home": "首页",
  "Default": "默认",
  "Account": "账户",
  "name": "名称",
  "Enter asset details": "输入资产明细",
  "Dashboard": "仪表盘",
  "Transactions": "交易",
  "Budgets": "预算",
  "Assets": "资产",
  "Debts": "负债",
  "All": "全部",
  "New debt": "新增负债",
  "New budget": "新增预算",
  "New transaction": "新增交易",
  "New account": "新增账户",
  "New asset": "新增资产",
  "New import": "新增导入",
  "New rule": "新增规则",
  "New tag": "新增标签",
  "New category": "新增分类",
  "New merchant": "新增商家",
  "Import": "导入",
  "Edit rules": "编辑规则",
  "Edit categories": "编辑分类",
  "Edit tags": "编辑标签",
  "Edit merchants": "编辑商家",
  "Edit imports": "编辑导入",
  "Total transactions": "交易总数",
  "No entries found": "未找到记录",
  "Try adding an entry, editing filters or refining your search": "请尝试添加记录、调整筛选或优化搜索",
  "Welcome back": "欢迎回来",
  "Welcome back, xiangshan": "欢迎回来,xiangshan",
  "Here's what's happening with your finances": "您的财务概况",
  "No accounts yet": "暂无账户",
  "Add account": "添加账户",
  "Add accounts to display net worth data": "添加账户以显示净资产",
  "Preferences": "偏好设置",
  "Security": "安全设置",
  "Self hosting": "自托管",
  "Accounts": "账户",
  "Account": "账户",
  "Imports": "数据导入",
  "Tags": "标签",
  "Categories": "分类",
  "Rules": "规则",
  "Merchants": "商家",
  "More": "更多",
  "What's new": "更新日志",
  "Feedback": "反馈",
  "Logout": "退出登录(不可用)",
  "Save": "保存",
  "Reset account": "重置账户",
  "Delete account": "删除账户",
  "Amount": "金额",
  "Date format": "日期格式",
  "Default Period": "默认周期",
  "Country": "国家/地区",
  "Language": "语言",
  "Timezone": "时区",
  "Currency": "货币",
  "Chinese Renminbi Yuan (CNY)": "人民币 (CNY)",
  "Chinese (Simplified) (zh-CN)": "中文(简体)",
  "Today": "今天",
  "Oops!": "哎呀!",
  "Use defaults (recommended)": "使用默认分类(推荐)",
  "Add an account either via connection, importing or entering manually.": "通过连接、导入或手动方式添加账户。",
  "AI-enabled rule actions will cost money. Be sure to filter as narrowly as possible to avoid unnecessary costs.": "启用 AI 的规则会产生费用,请尽量精确过滤条件以避免不必要的支出。",
  "Set up rules to perform actions to your transactions and other data on every account sync.": "设置规则,在每次账户同步时自动处理交易等数据。",
  "Imports · 1": "导入 · 1",
  "View": "查看",
  "Delete": "删除",
  "Require invite code for signup": "注册(不可用)需邀请码",
  "Every new user that joins your instance of Maybe can only do so via an invite code": "新用户注册(不可用)必须使用邀请码",
  "Require email confirmation": "需要邮箱验证",
  "Generated codes": "已生成的邀请码",
  "Generate new code": "生成新邀请码",
  "Clear data cache": "清除数据缓存",
  "Clearing the data cache will remove all exchange rates, security prices, account balances, and other data. This will not delete accounts, transactions, categories, or other user-owned data.": "此操作会清除汇率、证券价格、账户余额等缓存,不会删除账户、交易和分类等用户数据。",
  "Hostings": "托管",
  "Self-Hosting": "自托管",
  "General Settings": "通用设置",
  "Synth Settings": "Synth 设置",
  "Input the API key provided by Synth": "输入 Synth 提供的 API Key",
  "API Key": "API Key",
  "Enter your API key here": "在此输入 API Key",
  "In progress": "进行中",

  // 仪表盘 ——————————————————————————
  "Net Worth": "净资产",
  "vs. last month": "较上月",
  "No Liabilities yet": "暂无负债",
  "Add your Liabilities accounts to see a full breakdown": "添加负债账户以查看完整明细",
  "No cash flow data for this time period": "该周期暂无现金流数据",
  "Add transactions to display cash flow data or expand the time period": "添加交易以查看现金流,或扩大时间范围",
  "Add transaction": "新增交易",
  "Weight": "占比",
  "Value": "价值",
  // 预算设置——Setup your budget
  "Setup your budget": "设置预算",
  "Enter your monthly earnings and planned spending below to setup your budget.": "请输入您的月收入和计划支出以设置预算。",
  "Budgeted spending": "预算支出",
  "Expected income": "预期收入",
  "Autosuggest income & spending budget": "自动推荐收入和支出预算",
  "This will be based on transaction history. AI can make mistakes, verify before continuing.": "此功能基于交易历史,AI 可能出错,请核对后继续。",
  "Continue": "继续",

  // 编辑分类预算——Edit your category budgets
  "Edit your category budgets": "编辑分类预算",
  "Adjust category budgets to set spending limits. Unallocated funds will be automatically assigned as uncategorized.":
    "调整各分类预算以设置支出限额。未分配资金将自动归为未分类。",
  "% set": "% 已设置",
  "left to allocate": "剩余可分配",
  "Confirm": "确认",
  // 时间段控件 ——————————————————————
  "1D": "1 天",
  "7D": "7 天",
  "30D": "30 天",
  "90D": "90 天",
  "365D": "365 天",
  "5Y": "5 年",
  "WTD": "本周",
  "MTD": "本月",
  "YTD": "年初至今",

  // AI 提示 —————————————————————————
  "Enable Maybe AI": "启用 Maybe AI",
  "AI responses are informational only and are not financial advice.": "AI 回答仅供参考,并非财务建议。",
  "To use the AI assistant, you need to set the OPENAI_ACCESS_TOKEN environment variable in your self-hosted instance.": "要使用 AI 助手,请在自托管实例中设置环境变量 OPENAI_ACCESS_TOKEN。",
  "Disable anytime. All data sent to our LLM providers is anonymized.": "可随时停用。发送至大模型服务商的数据均已匿名化。",

  // 导航辅助 ————————————————————————
  "Back": "返回",
  "Next": "下一步",
  "esc": "关闭",
  "Filter": "筛选",
  "Clear filters": "清空筛选",
  "Tag": "标签",
  "Merchant": "商户",
  // 规则页面 ————————————————————————
  "New transaction rule": "新增交易规则",
  "Rule name (optional)": "规则名称(可选)",
  "Enter a name for this rule": "请输入规则名称",
  "IF": "如果",
  "Add condition": "添加条件",
  "Add condition group": "添加条件组",
  "THEN": "那么",
  "Add action": "添加动作",
  "FOR": "作用范围",
  "All past and future transactions": "所有历史及未来交易",
  "Starting from": "起始日期",
  "yyyy/mm/日": "年/月/日",

  // 分类设置 ————————————————————————
  "unassigned": "未分配",
  "categories": "分类",
  "Income categories": "收入分类",
  "Expense categories": "支出分类",
  "Name": "名称",
  "Edit": "编辑",
  "Classification": "分类类型",

  // 账户类型选择 —————————————————————
  "Enter": "输入",
  "account balance": "账户余额",
  "balance": "余额",
  "Select account type": "选择账户类型",
  "Select": "选择",
  "None": "无",
  "Checking": "支票账户",
  "Savings": "储蓄账户",
  "Health Savings Account": "健康储蓄账户 (HSA)",
  "Certificate of Deposit": "定期存款 (CD)",
  "Money Market": "货币市场账户",

  // 账户添加 ————————————————————————
  "What would you like to add?": "请选择要添加的账户类型",
  "Cash": "现金账户",
  "Investment": "投资账户",
  "Crypto": "加密资产",
  "Property": "房产",
  "Vehicle": "车辆",
  "Credit Card": "信用卡",
  "Loan": "贷款",
  "Other Asset": "其他资产",
  "Other Liability": "其他负债",
  "Import accounts": "导入账户",
  "Select": "选择",
  "Navigate": "导航",
  "Close": "关闭",

  // 规则设置 ————————————————————————
  "Rule": "规则",
  "Transaction name": "交易名称",
  "Transaction amount": "交易金额",
  "Transaction merchant": "交易商户",
  "Contains": "包含",
  "Equal to": "等于",
  "match": "满足",
  "all": "全部条件",
  "any": "任一条件",
  "none": "不包含",
  "enter a value": "输入值",
  "of the following conditions": "以下条件",
  "Set transaction category": "设置交易分类",
  "Set transaction tags": "设置交易标签",
  "Set transaction merchant": "设置交易商户",
  "Set transaction name": "设置交易名称",

  // 转账 / 新增交易 ————————————————————
  "New transfer": "新增转账",
  "Expense": "支出",
  "Income": "收入",
  "Expenses": "支出",
  "Transfer": "转账",
  "From": "转出账户",
  "To": "转入账户",
  "Select account": "选择账户",
  "Date": "日期",
  "Create transfer": "创建转账",

  // 交易字段 ————————————————————————
  "Description": "交易说明",
  "Description*": "交易说明 *",
  "Description *": "交易说明 *",
  "Describe transaction": "请输入交易说明",
  "Account*": "账户 *",
  "Select an Account": "选择账户",
  "Category": "分类",
  "Select a Category": "选择分类",
  "Details": "详细信息",
  "Notes": "备注",
  "Enter a note": "请输入备注",
  "(none)": "无",

  // 账户详情 ————————————————————————
  "Other Assets": "其他资产",
  "Cash Flow": "现金流",
  "Balance": "余额",
  "no change vs. last month": "与上月持平",
  "Import transactions": "导入交易",
  "Activity": "活动",
  "Search entries by name": "按名称搜索条目",
  "New": "新增",
  "Delete Account?": "删除账户?",
  "Are you sure you want to delete account?": "确定要删除账户吗?",
  "This is not reversible.": "此操作不可撤销。",
  "Delete Account": "删除账户",
  "BALANCE": "余额",
  // 房产相关 ————————————————————————————
  "Select property type": "选择房产类型",
  "Single Family Home": "独立住宅",
  "Multi-Family Home": "多户住宅",
  "Condominium": "公寓",
  "Townhouse": "联排别墅",
  "Investment Property": "投资房产",
  "Second Home": "第二住宅",
  "Year built": "建造年份",
  "Living area": "居住面积",
  "Street address": "街道地址",
  "City": "城市",
  "ZIP/Postal code": "邮政编码",
  "Unit of measurement": "计量单位",
  "Square Feet": "平方英尺",
  "State/Province": "州/省",
  // 其他 ————————————————————————————
  "Liabilities": "负债",
  "Cashflow": "现金流",
  "Confirm": "确认",
// 导入 ————————————————————————————
  "No imports yet.": "尚未导入数据。",
  "New CSV Import": "新的 CSV 导入",
  "You can manually import various types of data via CSV or use one of our import templates like Mint.": "您可以通过 CSV 手动导入各种数据,或使用我们的导入模板,如 Mint。",
  "SOURCES": "来源",
  "Import investments": "导入投资",
  "Import from Mint": "从 Mint 导入",
  "Import your data": "导入您的数据",
  "Paste or upload your CSV file below. Please review the instructions in the table below before beginning.": "在下方粘贴或上传您的 CSV 文件。请在开始之前查看表格中的说明。",
  "Upload CSV Copy & Paste": "上传 CSV 或复制粘贴",
  "Browse to add your CSV file here": "浏览以添加您的 CSV 文件",
  "Upload CSV": "上传 CSV",
  "Download a sample CSV to see the required CSV format": "下载样本 CSV 查看所需的 CSV 格式",
  "Resume Account Import": "恢复账户导入",
  "Please finalize your file upload.": "请完成文件上传。",
  "Account (optional)": "账户(可选)",
  "Multi-account import": "多账户导入",
  "Paste your CSV file contents here": "在此粘贴您的 CSV 文件内容",
  "Configure your import": "配置您的导入",
  "Select the columns that correspond to each field in your CSV.": "选择与 CSV 中每个字段对应的列。",
  "Custom column": "自定义列",
  "Amount type strategy": "金额类型设置", // 更加准确的翻译
  "Signed amount": "带符号金额", // 更加准确的翻译
  "Incomes are positive": "收入为正数",
  "Incomes are negative": "收入为负数",
  "Leave empty": "留空",
  "Apply configuration": "应用配置",
  "Sample data from your uploaded CSV": "来自您上传的 CSV 的示例数据",
  "Please configure your import before proceeding": "请在继续之前配置您的导入",
  "as amount type column": "将其设置为金额类型列",
  "Set": "设置",
  "Select column": "选择列",
  "Upload": "上传",
  "Configure": "配置",
  "Clean": "清理",
  "Map": "映射",
  // CSV 相关术语
  "Comma (,)": "逗号 (,)",
  "Semicolon (;)": "分号 (;)",
  "Col sep": "列分隔符",
  "IMPORTS": "导入",
  "Import": "导入",
  "Transaction": "交易",
  "Account": "账户",
  "Revert import?": "撤销导入?",
  "This will delete transactions that were imported, but you will still be able to review and re-import your data at any time.":
    "这将删除已导入的交易,但您仍然可以随时查看并重新导入数据。",
  "Revert": "撤销",
    // 页面中的动态日期翻译
    "Depositories": "存款账户",
    "Current Balance": "当前余额",
    "Initial Balance": "初始余额",
    "Activity": "活动",
    "Amount": "金额",
    "Remaining": "剩余金额",
    "Search entries by name": "按名称搜索记录",
    "New": "新增",
    "Date": "日期",
      // 分类弹窗 ————————————————————————
  "Uncategorized": "未分类",
  "OVERVIEW": "概览",
  "Monthly average spending": "平均月支出",
  "Monthly median spending": "月支出中位数",
  "RECENT TRANSACTIONS": "最近交易",
  "No transactions found for this budget period.": "此预算周期内未找到交易。"

};



  /* --------------------------------------------------
     月份 & 星期映射(含缩写)
  -------------------------------------------------- */
  const monthMap = {
    January: '1月',  Jan: '1月',
    February: '2月', Feb: '2月',
    March: '3月',    Mar: '3月',
    April: '4月',    Apr: '4月',
    May: '5月',
    June: '6月',     Jun: '6月',
    July: '7月',     Jul: '7月',
    August: '8月',   Aug: '8月',
    September: '9月',Sep: '9月', Sept: '9月',
    October: '10月', Oct: '10月',
    November: '11月',Nov: '11月',
    December: '12月',Dec: '12月'
  };

  const weekdayMap = {
    Monday: '星期一',    Mon: '星期一',
    Tuesday: '星期二',   Tue: '星期二',
    Wednesday: '星期三', Wed: '星期三',
    Thursday: '星期四',  Thu: '星期四',
    Friday: '星期五',    Fri: '星期五',
    Saturday: '星期六',  Sat: '星期六',
    Sunday: '星期日',    Sun: '星期日'
  };

  /* --------------------------------------------------
     动态文本翻译函数
  -------------------------------------------------- */
  // 金额 + avg   e.g. "¥0.00 avg"
  const translateAmountAvg = txt => {
    const m = txt.match(/^(.+?)\s+avg$/i);
    return m ? `${m[1]} 平均` : null;
  };
  // AM/PM 转换
  const timeMap = {
    "AM": "上午",
    "PM": "下午"
  };
  // 日期翻译函数
  const translateFullDate = txt => {
    const m = txt.match(
      /^(Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:t(?:ember)?)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\s+(\d{1,2}),\s+(\d{4})\s+at\s+(\d{1,2}):(\d{2})\s(AM|PM)$/i
    );
    if (m) {
      return `${m[3]}年${monthMap[m[1]]}${parseInt(m[2], 10)}日 ${timeMap[m[6]]} ${m[4]}:${m[5]}`;
    }
    return null;
  };

  // "Jun 2025 spending"
  const translateMonthlySpending = txt => {
    const m = txt.match(
      /^(Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:t(?:ember)?)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\s(\d{4})\sspending$/i
    );
    return m ? `${m[2]}年${monthMap[m[1]]}支出` : null;
  };

  // "May 2025"
  const translateYearMonth = txt => {
    const m = txt.match(
      /^(Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:t(?:ember)?)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\s(\d{4})$/i
    );
    return m ? `${m[2]}年${monthMap[m[1]]}` : null;
  };

  // on or after / before YYYY-MM-DD
  const translateDateRange = txt => {
    const after = txt.match(/^on or after (\d{4}-\d{2}-\d{2})$/);
    if (after) return `起始日期:${after[1]}`;
    const before = txt.match(/^on or before (\d{4}-\d{2}-\d{2})$/);
    return before ? `结束日期:${before[1]}` : null;
  };

  // 30D / 1W / 12M / 1Y
  const translateShorthandPeriod = txt => {
    const m = txt.match(/^(\d+)([DWMY])$/);
    if (!m) return null;
    const map = { D: "天", W: "周", M: "月", Y: "年" };
    return `${m[1]}${map[m[2]]}`;
  };

  // Last 30 days
  const translateLastPeriod = txt => {
    const m = txt.match(/^Last (\d+) (days?|weeks?|months?|years?)$/i);
    if (!m) return null;
    const unit = m[2].toLowerCase().startsWith("day")
      ? "天"
      : m[2].startsWith("week")
      ? "周"
      : m[2].startsWith("month")
      ? "个月"
      : "年";
    return `最近${m[1]}${unit}`;
  };

const translateTransactionImport = txt => {
  const m = txt.match(/^Transaction Import: (.*) at (\d{1,2}):(\d{2}) (AM|PM)$/i);
  if (m) {
    const monthDayYear = `${m[1].replace(/\d{4}/, (match) => `${match}年`)}`; // 修改为包含中文年份
    const time = `${m[2]}:${m[3]} ${m[4] === 'AM' ? '上午' : '下午'}`;
    return `交易导入:${monthDayYear} ${time} 完成`;
  }
  return null;
};

// "¥0/m avg" -> "¥0.00/月 平均"
const translatePerMonthAvg = txt => {
  const m = txt.match(/^(.+?)\/m avg$/i);
  return m ? `${m[1]}/月 平均` : null;
};

// ---------------------------------------------
// 动态翻译函数列表更新
// ---------------------------------------------
const dynamicFns = [
  translateTransactionImport,
  translatePerMonthAvg,
  translateAmountAvg,
  translateFullDate,
  translateMonthlySpending,
  translateYearMonth,
  translateDateRange,
  translateShorthandPeriod,
  translateLastPeriod
];

  /* --------------------------------------------------
     文本节点翻译入口
  -------------------------------------------------- */
  // 动态文本翻译函数
  const translateTextNode = node => {
    if (!node || node.nodeType !== 3) return;
    const raw = node.textContent;
    const txt = raw.trim();
    if (!txt) return;

    // 1) 静态翻译(大小写不敏感)
    const cand =
      translations[txt] ||
      translations[txt.toUpperCase()] ||
      translations[txt.toLowerCase()];
    if (cand) {
      node.textContent = raw.replace(txt, cand);
      return;
    }

    // 2) 动态翻译: 日期
    const dateTranslated = translateFullDate(txt);
    if (dateTranslated) {
      node.textContent = raw.replace(txt, dateTranslated);
      return;
    }

    // 3) 单独月份或星期
    if (monthMap[txt]) {
      node.textContent = raw.replace(txt, monthMap[txt]);
    } else if (weekdayMap[txt]) {
      node.textContent = raw.replace(txt, weekdayMap[txt]);
    }
  };

  const translatePage = () => {
    const walker = document.createTreeWalker(
      document.body,
      NodeFilter.SHOW_TEXT,
      null,
      false
    );
    let n;
    while ((n = walker.nextNode())) translateTextNode(n);
  };

  // 初始 + 轮询
  translatePage();
  const INTERVAL = 300;
  setInterval(translatePage, INTERVAL);

  // 监听 SPA 路由变化
  let lastUrl = location.href;
  setInterval(() => {
    if (location.href !== lastUrl) {
      lastUrl = location.href;
      setTimeout(translatePage, 500);
    }
  }, 500);
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址