diff --git a/.gitignore b/.gitignore index 8b9981d..d860810 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ node_modules/ *.vsix .vscode/ +__pycache__/ +新建文件夹 (3)/ diff --git a/.vscodeignore b/.vscodeignore index 7eed9c0..656a461 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -1,4 +1,22 @@ .vscode .DS_Store +.git +# 开发 / 构建脚本(不需要打入 vsix) patch_zh.py +clean_injects.py +generate_dict.py +search_strings.py +test_poc.py +refactor.js +build_v2.js +build_v3_hybrid.js +# 空的/未使用的翻译文件 +translations/main.i18n.json + +# 旧版遗留 / PoC 文件 +poc_observer.js +v2_observer.js +# 备份文件 +*.bak +# 打包产物本身 *.vsix diff --git a/AGENTS.MD b/AGENTS.MD new file mode 100644 index 0000000..46604a5 --- /dev/null +++ b/AGENTS.MD @@ -0,0 +1,91 @@ +# Antigravity IDE 汉化覆盖范围说明 + +本文档详细列出了 **AntigravityChinesePack** 对 Antigravity IDE 各项功能和模块的中文汉化覆盖范围。本语言包专为 Antigravity 独有 UI 和专属功能设计。 + +--- + +## 📦 1. NLS 标准本地化翻译 + +本插件通过标准扩展本地化机制(配置于 `package.json` 中的 `localizations` 贡献点),覆盖了以下内置核心扩展的 UI 元素: + +| 扩展名称 / ID | 汉化覆盖模块与功能 | 翻译条目数 | +| :--- | :--- | :--- | +| **Antigravity 核心**
`google.antigravity` | AI 基础交互、谷歌账户登录与认证流程、设置导入/导出面板、通知提示 | 25+ | +| **内置浏览器**
`google.antigravity-browser-launcher` | 内置浏览器启动面板、无头浏览器环境切换交互 | 3 | +| **代码执行器**
`google.antigravity-code-executor` | 代码块在编辑器中直接运行的控制按钮及提示 | 1 | +| **开发容器**
`google.antigravity-dev-containers` | 开发容器 (Dev Containers) 创建、启动与关联配置项 | 8 | +| **远程连接 SSH**
`google.antigravity-remote-openssh` | 远程 SSH 连接管理、主机配置解析、身份认证交互 | 19 | +| **远程连接 WSL**
`google.antigravity-remote-wsl` | WSL 子系统连接生命周期管理、路径映射提示 | 17 | + +--- + +## 🔍 2. 硬编码补丁汉化覆盖 + +由于以下模块的配置项和界面文本是 React/TypeScript 混合硬编码(未提取为 NLS 翻译),本插件通过**补丁引擎**对它们的目标代码进行了源码级的中文替换: + +### 📁 Settings 配置项 (`out/jetskiAgent/main.js`) +覆盖了 IDE “设置”面板中所有关于 AI 助手、代码补全、浏览器和安全的特有配置,共包含 **150+ 处** 翻译: + +* **Agent 核心设置**: + * `Agent Auto-Fix Lints` $\rightarrow$ **Agent 自动修复 Lint**(自动感知编辑引入的错误并尝试修复) + * `Strict Mode` $\rightarrow$ **严格模式**(限制自主漏洞探测,所有高风险动作需要人工审核) + * `Review Policy` $\rightarrow$ **审查策略**(控制何时打断并请求用户审查) + * `Terminal Command Auto Execution` $\rightarrow$ **终端命令自动执行** + * `Agent Gitignore/Non-Workspace Access` $\rightarrow$ **Agent Gitignore/非工作区文件访问** + * `Auto-Continue` $\rightarrow$ **自动继续**(到达推理限制时自动开始下一轮调用) + * `Enable Sounds for Agent` $\rightarrow$ **Agent 声音提示** + * `Auto-Expand Changes Overview` $\rightarrow$ **自动展开更改概览** +* **Editor 编辑器与 Tab 代码补全**: + * `Suggestions in Editor` $\rightarrow$ **编辑器中的建议** + * `Tab Speed` $\rightarrow$ **Tab 速度**(设置 Tab 键补全提示的呈现速度) + * `Tab to Jump` $\rightarrow$ **Tab 跳转**(预测并一键跳转到下一个建议的编辑位置) + * `Tab to Import` $\rightarrow$ **Tab 导入**(一键快速添加或更新依赖导入) + * `Highlight After Accept` $\rightarrow$ **接受后高亮** +* **Browser 浏览器辅助**: + * `Enable Browser Tools` $\rightarrow$ **启用浏览器工具**(允许 Agent 访问外部 URL 和抓取网页) + * `Chrome Binary Path` $\rightarrow$ **Chrome 可执行文件路径** + * `Browser User Profile Path` $\rightarrow$ **浏览器用户配置路径** + * `Browser CDP Port` $\rightarrow$ **浏览器 CDP 端口** + * `Browser URL Allowlist` $\rightarrow$ **浏览器 URL 允许列表** + +--- + +### 💬 Cascade 聊天面板 (`extensions/antigravity/out/media/chat.js`) +覆盖了右侧 Agent 聊天 Webview 视窗中的所有交互组件与状态,共包含 **800+ 处** 替换: + +* **对话模式切换(Conversation Mode)**: + * `Planning` $\rightarrow$ **规划模式**(执行前进行深度调研并输出 Implementation Plan) + * `Fast` $\rightarrow$ **快速直跑模式**(简单任务直接执行,不生成规划文档) +* **思考过程展示(Thought Process)**: + * `Thinking for [time]` $\rightarrow$ **思考中 [时间]** / `Thought for [time]` $\rightarrow$ **思考了 [时间]** + * `Background Steps` $\rightarrow$ **后台步骤** + * `Auto-proceeded/Manually proceeded under review policy` $\rightarrow$ **已根据您的审查策略自动继续/手动继续** +* **产物管理器(Artifacts Manager)**: + * `Artifacts` $\rightarrow$ **产物** + * 描述文案 $\rightarrow$ **“产物是 Agent 在对话中创建的文件,用于帮助执行较长时间运行的任务并允许用户提供高级反馈。点击在编辑器中打开。”** + * 表格属性:`Artifact Name` $\rightarrow$ **产物名称** / `Last Updated` $\rightarrow$ **最后更新** +* **自定义与工作流管理**: + * `Customizations` $\rightarrow$ **自定义** + * `Rules` $\rightarrow$ **规则**(Edit rule $\rightarrow$ **编辑规则**,Refresh rules $\rightarrow$ **刷新规则**) + * `Workflows` $\rightarrow$ **工作流**(Edit workflow $\rightarrow$ **编辑工作流**) + * `MCP Servers` $\rightarrow$ **MCP 服务器**(Manage MCP Servers $\rightarrow$ **管理 MCP 服务器**) +* **交互按钮与反馈**: + * `Accept all` $\rightarrow$ **全部接受** / `Discard changes` $\rightarrow$ **放弃更改** + * `Good response / Bad response` $\rightarrow$ **好的响应 / 差的响应** + * `Connect to an existing conversation` $\rightarrow$ **连接到现有对话** + * `Capture screenshot` $\rightarrow$ **截取屏幕** / `Capture console logs` $\rightarrow$ **捕获控制台日志** + +--- + +### 🖥️ Workbench 主框架 (`out/vs/workbench/workbench.desktop.main.js`) +覆盖了全局应用框架相关的 AI 设置与快捷选项,共包含 **120+ 处** 替换: + +* **全局设置开关状态**: + * `On/Off` 枚举值 $\rightarrow$ **“开/关”**(影响全部二元开关的文本显示) +* **底栏与面板信息**: + * `AI Shortcuts` $\rightarrow$ **AI 快捷键** + * `Advanced Settings` $\rightarrow$ **高级设置** + * `Terminal execution policy` $\rightarrow$ **终端执行策略** + * `Review policy` $\rightarrow$ **审查策略** + * `JavaScript execution policy` $\rightarrow$ **JavaScript 执行策略** + * `Always Proceed / Agent Decides / Request Review` $\rightarrow$ **始终继续 / Agent 决定 / 请求审查** diff --git a/CHANGELOG.md b/CHANGELOG.md index 85d2110..39cb5b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,43 @@ # Changelog +## 1.41.2 (2026-06-07) + +### ✨ 新增翻译(~170 条) +- **精准扫描补全**:通过读取实际安装文件 `workbench.desktop.main.js.bak` 原始英文内容,提取 300 个 `label` + 数百个 `children` 字符串,与现有翻译对比后精准补充 +- **Settings 面板**:补充 `Strict Mode`、`Verbose agent chat`、`Enable Sounds for Agent`、`Import from VS Code/Cursor/Windsurf/Cider`、`Enable Terminal Sandbox`、`Enable Remote Control`、`Enable Overages` 等 19 条新设置项 +- **对话管理**:补充 `Archive this conversation`、`Mark as Read/Unread`、`Open Conversation History`、`Copy conversation markdown` 等 10 条 +- **Toggle 操作**:补充 `Toggle Developer Tools`、`Toggle Fullscreen`、`Toggle Voice Recording`、`Toggle Environment Selector` 等 6 条 +- **MCP / 知识库**:补充 `MCP Servers Disabled`、`Knowledge feature is not available.`、`Manage MCP Servers` 等 8 条 +- **时间分组**:补充 `Today`(今天)、`Yesterday`(昨天)、`Past Conversations`(过去的对话) +- **空状态提示**:补充 `No background tasks`、`No artifacts generated.`、`No internet. Agent features may not work.` 等 6 条 +- **规则/技能/工作流**:补充 `Refresh rules/workflows/skills`、`Skills are instructions...` 等 8 条 +- **通用操作按钮**:补充 `Save`、`Rename`、`Restore`、`Expand`、`Filter`、`Preview`、`Install`、`Launch` 等 30+ 条 + +### 📊 覆盖率提升 +- 汉化覆盖率从约 **65%** 提升至约 **85%** +- `patch_zh.py` 从 1069 行扩展至 1237 行 + +--- + +## 1.41.1 (2026-06-03) + + +### ✨ 新增翻译 +- **Settings 面板**:新增 150+ 条硬编码字符串翻译,覆盖 Agent 安全模式、插件、MCP 服务器、模型配额、外观主题、通知设置、快捷键等所有子页面 +- **Chat 面板**:新增 800+ 条翻译,覆盖对话模式切换(规划/快速)、思考过程展示、产物管理器、反馈按钮、调试工具、Screen Recording 等全部交互组件 +- **Workbench 主框架**:新增 120+ 条翻译,覆盖底栏策略开关(终端执行/审查/JS 执行策略)、快捷键面板、AI Shortcuts 标签、反馈表单 +- 新增 `切换屏蔽 Antigravity 自动更新` 命令,支持命令面板、状态栏图标和设置面板三入口 +- 新增 `v2_observer.js`(V2 DOM 监听器)和 V3 混合模式,目前插件使用静态补丁引擎(零性能损耗) + +### 🔧 引擎改进 +- 补丁版本控制:`PATCH_MARKER = zh-hans-patched-vN`,支持跨版本增量重打补丁 +- 自动 Checksum 清除:清空 `product.json` 中的 checksums 消除"安装损坏"警告 +- Windows 路径探测扩展:支持 `%LOCALAPPDATA%\Programs`、`Program Files`、`Program Files(x86)` 三种安装位置 +- `patchFile()` 加入去重逻辑,防止重复规则引发链式误替换 +- 修复 `isAutoUpdateBlocked()` 逻辑 Bug(移除永远为 false 的 `BLOCKED_UPDATE_URL` 分支) + +--- + ## 1.0.0 (2026-02-08) ### 🎉 初始版本 diff --git a/build_v2.js b/build_v2.js new file mode 100644 index 0000000..ed9507e --- /dev/null +++ b/build_v2.js @@ -0,0 +1,280 @@ +const fs = require('fs'); +const path = require('path'); +const crypto = require('crypto'); + +console.log("🚀 [1/4] 开始提取旧版硬编码翻译词典..."); + +const extCode = fs.readFileSync('extension.js', 'utf-8'); +const dict = {}; + +function getInsideQuotes(s) { + const match = s.match(/(?:children|label|title|placeholder|description|text|tooltip|tooltipText|aria-label|textContent):(?:`([^`]+)`|"([^"]+)"|'([^']+)')/); + if (match) return match[1] || match[2] || match[3]; + const pureMatch = s.match(/^"([^"]+)"$/); + if (pureMatch) return pureMatch[1]; + return null; +} + +const regex = /\[\s*'([^']*)'\s*,\s*'([^']*)'\s*\]/g; +let match; +let count = 0; + +while ((match = regex.exec(extCode)) !== null) { + let engRaw = match[1].replace(/\\"/g, '"'); + let zhRaw = match[2].replace(/\\"/g, '"').replace(/\\u([0-9a-fA-F]{4})/g, (m, c) => String.fromCharCode(parseInt(c, 16))); + + let eng = getInsideQuotes(engRaw); + let zh = getInsideQuotes(zhRaw); + + if (!eng && engRaw.startsWith('{') && engRaw.includes('label:"')) { + eng = engRaw.match(/label:"([^"]+)"/)?.[1]; + zh = zhRaw.match(/label:"([^"]+)"/)?.[1]; + } + if (!eng) { + eng = engRaw.match(/"([^"]+)"/)?.[1]; + zh = zhRaw.match(/"([^"]+)"/)?.[1]; + } + + if (eng && zh && eng !== zh && !eng.startsWith('${') && !eng.includes('"+')) { + dict[eng.trim()] = zh.trim(); + count++; + } +} + +// 追加难以被正则自动提取的动态词及界面专属词汇 +const manualAdditions = { + "Thinking for ": "思考中 ", + "Thought for ": "思考了 ", + "Changes Overview": "更改概览", + "Settings - ": "设置 - ", + "Customizations": "自定义", + "Manage": "管理", + "Snooze": "暂停", + "Advanced Settings": "高级设置", + "Terminal execution policy": "终端执行策略", + "Review policy": "审查策略", + "JavaScript execution policy": "JavaScript 执行策略", + "Always Proceed": "始终继续", + "Request Review": "请求审查", + "Agent Decides": "Agent 决定", + "Disabled": "已禁用" +}; +Object.assign(dict, manualAdditions); +count += Object.keys(manualAdditions).length; + +console.log("✅ 成功提取 " + count + " 个翻译对!"); + +console.log("🚀 [2/4] 正在生成强健且极速的 DOM TreeWalker 监听器..."); + +const observerCode = ` +// [AntigravityChinesePack V2 DOM Observer Injected] +(function() { + // 避免在某些纯 worker 或不含 DOM 的环境中报错 + if (typeof document === 'undefined' || !document.body) return; + + console.log("[AntigravityChinesePack] V2 Dynamic DOM Observer Active"); + const dict = ${JSON.stringify(dict, null, 2)}; + + function translateTextNode(node) { + if (node.nodeType === Node.TEXT_NODE) { + const originalText = node.nodeValue; + let text = originalText.trim(); + if (!text) return; + + if (dict[text]) { + node.nodeValue = originalText.replace(text, dict[text]); + return; + } + + // 动态前缀匹配 + if (text.startsWith("Thinking for ")) { + node.nodeValue = originalText.replace(text, "思考中 " + text.substring("Thinking for ".length)); + return; + } + if (text.startsWith("Thought for ")) { + node.nodeValue = originalText.replace(text, "思考了 " + text.substring("Thought for ".length)); + return; + } + if (text.startsWith("Changes Overview (")) { + node.nodeValue = originalText.replace(text, text.replace("Changes Overview", "更改概览")); + return; + } + if (text.startsWith("Terminal (") && text.includes(")")) { + node.nodeValue = originalText.replace(text, text.replace("Terminal", "终端")); + return; + } + } + } + + function translateAttributes(node) { + if (node.nodeType === Node.ELEMENT_NODE) { + ['aria-label', 'title', 'placeholder'].forEach(attr => { + if (node.hasAttribute(attr)) { + const val = node.getAttribute(attr); + if (val && dict[val]) { + node.setAttribute(attr, dict[val]); + } + } + }); + } + } + + // 使用 C++ 级的 TreeWalker 进行极速文本遍历,解决界面卡顿问题 + function processTree(root) { + if (root.nodeType === Node.TEXT_NODE) { + translateTextNode(root); + return; + } + + const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false); + let node; + while (node = walker.nextNode()) { + translateTextNode(node); + } + + if (root.nodeType === Node.ELEMENT_NODE) { + translateAttributes(root); + const elements = root.querySelectorAll('*'); + for (let i = 0; i < elements.length; i++) { + translateAttributes(elements[i]); + } + } + } + + let isTranslating = false; + const observer = new MutationObserver((mutations) => { + if (isTranslating) return; + isTranslating = true; + + // 批量处理 mutations 以提升性能 + const targetNodes = new Set(); + mutations.forEach((mutation) => { + if (mutation.type === 'childList') { + mutation.addedNodes.forEach(node => { + if (node.tagName !== 'SCRIPT' && node.tagName !== 'STYLE') { + targetNodes.add(node); + } + }); + } else if (mutation.type === 'characterData') { + translateTextNode(mutation.target); + } else if (mutation.type === 'attributes') { + const node = mutation.target; + const attr = mutation.attributeName; + const val = node.getAttribute(attr); + if (val && dict[val]) { + node.setAttribute(attr, dict[val]); + } + } + }); + + targetNodes.forEach(node => processTree(node)); + + isTranslating = false; + }); + + function init() { + if (document.body) { + processTree(document.body); + observer.observe(document.body, { childList: true, subtree: true, characterData: true, attributes: true, attributeFilter: ['aria-label', 'title', 'placeholder'] }); + } + } + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } +})(); +`; + +fs.writeFileSync('v2_observer.js', observerCode, 'utf-8'); +console.log("✅ 生成 v2_observer.js 成功!"); + +console.log("🚀 [3/4] 开始将新代码注入 Antigravity IDE..."); + +function getAppBase() { + const localappdata = process.env.LOCALAPPDATA; + if (localappdata) { + const winCandidate = path.join(localappdata, 'Programs', 'Antigravity IDE', 'resources', 'app'); + if (fs.existsSync(winCandidate)) return winCandidate; + } + return null; +} + +const base = getAppBase(); +if (!base) { + console.error("❌ 找不到 Antigravity IDE 安装目录!"); + process.exit(1); +} + +const targets = [ + { name: "Chat Panel", path: path.join(base, 'extensions', 'antigravity', 'out', 'media', 'chat.js') }, + { name: "Settings Panel", path: path.join(base, 'out', 'jetskiAgent', 'main.js') }, + { name: "Workbench (全局/自定义UI)", path: path.join(base, 'out', 'vs', 'workbench', 'workbench.desktop.main.js') } +]; + +const TAG = "// [AntigravityChinesePack V2 DOM Observer Injected]"; +const OLD_TAG = "// [AntigravityChinesePack PoC injected]"; + +for (const t of targets) { + if (!fs.existsSync(t.path)) { + console.warn("⚠️ " + t.name + " 未找到: " + t.path); + continue; + } + + // 自动恢复旧版本的备份(如果有)以确保干净 + const backupPath = t.path + ".backup"; + if (fs.existsSync(backupPath)) { + console.log("[" + t.name + "] 检测到备份文件,自动恢复以清除旧补丁..."); + const original = fs.readFileSync(backupPath, 'utf-8'); + fs.writeFileSync(t.path, original, 'utf-8'); + } else { + // 创建新备份 + console.log("[" + t.name + "] 创建初始备份..."); + fs.copyFileSync(t.path, backupPath); + } + + let content = fs.readFileSync(t.path, 'utf-8'); + if (content.includes(TAG)) { + console.log("[" + t.name + "] V2 已注入!"); + } else { + content = content.replace(OLD_TAG, ""); // 移除旧 PoC 标记 + fs.writeFileSync(t.path, content + "\n\n" + observerCode, 'utf-8'); + console.log("✅ [" + t.name + "] 成功注入 V2 动态监听器!"); + } +} + +console.log("🚀 [4/4] 修复 IDE 校验值 (消除安装损坏提示)..."); +function updateChecksums() { + const productJsonPath = path.join(base, 'product.json'); + if (!fs.existsSync(productJsonPath)) return; + + let product = JSON.parse(fs.readFileSync(productJsonPath, 'utf-8')); + let checksums = product.checksums || {}; + let updated = 0; + + for (let key in checksums) { + let filePath = path.join(base, 'out', key); + if (!fs.existsSync(filePath)) { + filePath = path.join(base, key); + } + if (fs.existsSync(filePath)) { + let data = fs.readFileSync(filePath); + let hash = crypto.createHash('sha256').update(data).digest('base64').replace(/=+$/, ''); + if (hash !== checksums[key]) { + checksums[key] = hash; + updated++; + } + } + } + + if (updated > 0) { + fs.writeFileSync(productJsonPath, JSON.stringify(product, null, '\t'), 'utf-8'); + console.log("✅ 已更新 " + updated + " 个文件校验值!"); + } else { + console.log("✅ 校验值已经是最新。"); + } +} +updateChecksums(); + +console.log("\n🎉 全部优化完成!解决了卡顿、补全了UI、消除了损坏提示。请在 IDE 中按 Ctrl+Shift+P 运行 'Developer: Reload Window' 查看效果。"); diff --git a/build_v3_hybrid.js b/build_v3_hybrid.js new file mode 100644 index 0000000..e65638c --- /dev/null +++ b/build_v3_hybrid.js @@ -0,0 +1,158 @@ +const fs = require('fs'); +const path = require('path'); +const crypto = require('crypto'); + +console.log("🚀 [1/3] 开始构建 V3 混合模式 (静态全覆盖 + 动态轻量捕获)..."); + +// 1. 获取原有的所有静态替换对 +const extCode = fs.readFileSync('extension.js', 'utf-8'); +const replacements = []; +const regex = /\[\s*'([^']*)'\s*,\s*'([^']*)'\s*\]/g; +let match; +while ((match = regex.exec(extCode)) !== null) { + let engRaw = match[1].replace(/\\"/g, '"'); + let zhRaw = match[2].replace(/\\"/g, '"').replace(/\\u([0-9a-fA-F]{4})/g, (m, c) => String.fromCharCode(parseInt(c, 16))); + replacements.push({ old: engRaw, new: zhRaw }); +} + +console.log("✅ 成功提取 " + replacements.length + " 个底层静态替换规则。"); + +// 2. 轻量级动态监听器 (仅针对静态替换无法处理的动态拼接字符串) +const tinyObserverCode = ` +// [AntigravityChinesePack V3 Hybrid Observer Injected] +(function() { + if (typeof document === 'undefined' || !document.body) return; + + function translateDynamicText(node) { + if (node.nodeType === Node.TEXT_NODE) { + let text = node.nodeValue; + if (!text) return; + + if (text.startsWith("Thinking for ")) { + node.nodeValue = text.replace("Thinking for ", "思考中 "); + } else if (text.startsWith("Thought for ")) { + node.nodeValue = text.replace("Thought for ", "思考了 "); + } else if (text.startsWith("Changes Overview (")) { + node.nodeValue = text.replace("Changes Overview", "更改概览"); + } else if (text.startsWith("Terminal (") && text.includes(")")) { + node.nodeValue = text.replace("Terminal", "终端"); + } + } + } + + const observer = new MutationObserver(mutations => { + mutations.forEach(m => { + if (m.type === 'characterData') { + translateDynamicText(m.target); + } else if (m.type === 'childList') { + m.addedNodes.forEach(node => { + if (node.nodeType === Node.TEXT_NODE) { + translateDynamicText(node); + } else if (node.nodeType === Node.ELEMENT_NODE && node.tagName !== 'SCRIPT' && node.tagName !== 'STYLE') { + const walker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT, null, false); + let n; + while (n = walker.nextNode()) translateDynamicText(n); + } + }); + } + }); + }); + + observer.observe(document.body, { childList: true, subtree: true, characterData: true }); +})(); +`; + +console.log("🚀 [2/3] 开始应用底层静态替换并注入动态监听器..."); + +function getAppBase() { + const localappdata = process.env.LOCALAPPDATA; + if (localappdata) { + const winCandidate = path.join(localappdata, 'Programs', 'Antigravity IDE', 'resources', 'app'); + if (fs.existsSync(winCandidate)) return winCandidate; + } + return null; +} + +const base = getAppBase(); +if (!base) { + console.error("❌ 找不到 Antigravity IDE 安装目录!"); + process.exit(1); +} + +const targets = [ + { name: "Chat Panel", path: path.join(base, 'extensions', 'antigravity', 'out', 'media', 'chat.js') }, + { name: "Settings Panel", path: path.join(base, 'out', 'jetskiAgent', 'main.js') }, + { name: "Workbench Panel", path: path.join(base, 'out', 'vs', 'workbench', 'workbench.desktop.main.js') } +]; + +const V3_TAG = "// [AntigravityChinesePack V3 Hybrid Observer Injected]"; +const V2_TAG = "// [AntigravityChinesePack V2 DOM Observer Injected]"; +const POC_TAG = "// [AntigravityChinesePack PoC injected]"; + +for (const t of targets) { + if (!fs.existsSync(t.path)) { + console.warn("⚠️ " + t.name + " 未找到: " + t.path); + continue; + } + + const backupPath = t.path + ".backup"; + if (fs.existsSync(backupPath)) { + // 恢复原始文件,确保不叠加执行 + const original = fs.readFileSync(backupPath, 'utf-8'); + fs.writeFileSync(t.path, original, 'utf-8'); + } else { + fs.copyFileSync(t.path, backupPath); + } + + let content = fs.readFileSync(t.path, 'utf-8'); + + // 执行底层的静态硬编码替换 (解决自定义UI、ShadowDOM 和 WebComponent 等不暴露给DOM的问题,且零性能损耗) + let replaceCount = 0; + for (const rule of replacements) { + if (content.includes(rule.old)) { + content = content.split(rule.old).join(rule.new); + replaceCount++; + } + } + + // 注入轻量动态监听器 + content = content + "\n\n" + tinyObserverCode; + fs.writeFileSync(t.path, content, 'utf-8'); + + console.log("✅ [" + t.name + "] 底层静态替换完成 (" + replaceCount + " 处),并成功注入极速 V3 动态监听器!"); +} + +console.log("🚀 [3/3] 更新 IDE 文件校验值..."); +function updateChecksums() { + const productJsonPath = path.join(base, 'product.json'); + if (!fs.existsSync(productJsonPath)) return; + + let product = JSON.parse(fs.readFileSync(productJsonPath, 'utf-8')); + let checksums = product.checksums || {}; + let updated = 0; + + for (let key in checksums) { + let filePath = path.join(base, 'out', key); + if (!fs.existsSync(filePath)) { + filePath = path.join(base, key); + } + if (fs.existsSync(filePath)) { + let data = fs.readFileSync(filePath); + let hash = crypto.createHash('sha256').update(data).digest('base64').replace(/=+$/, ''); + if (hash !== checksums[key]) { + checksums[key] = hash; + updated++; + } + } + } + + if (updated > 0) { + fs.writeFileSync(productJsonPath, JSON.stringify(product, null, '\t'), 'utf-8'); + console.log("✅ 已更新 " + updated + " 个文件校验值,消除“安装损坏”提示!"); + } else { + console.log("✅ 校验值已经是最新。"); + } +} +updateChecksums(); + +console.log("\n🎉 V3 终极版构建完成!结合了“静态替换的零卡顿/全覆盖”与“动态监听的无遗漏”,请在 IDE 中按 Ctrl+Shift+P 运行 'Developer: Reload Window' 查看效果!"); diff --git a/build_vsix.py b/build_vsix.py new file mode 100644 index 0000000..130085a --- /dev/null +++ b/build_vsix.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python3 +""" +纯 Python VSIX 打包脚本 —— 不依赖 npm/vsce +VSIX 格式 = ZIP 压缩包 + [Content_Types].xml + extension/package.json 等文件 +""" +import os +import json +import zipfile +import shutil +from datetime import datetime + +# ============================================================ +# 配置 +# ============================================================ +PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) +VSCODEIGNORE_PATH = os.path.join(PROJECT_ROOT, '.vscodeignore') + +# 读取 package.json 获取版本号和包名 +with open(os.path.join(PROJECT_ROOT, 'package.json'), 'r', encoding='utf-8') as f: + pkg = json.load(f) + +VERSION = pkg['version'] +NAME = pkg['name'] +PUBLISHER = pkg.get('publisher', 'unknown') +OUTPUT_FILENAME = f"{PUBLISHER}.{NAME}-{VERSION}.vsix" +OUTPUT_PATH = os.path.join(PROJECT_ROOT, OUTPUT_FILENAME) + +# ============================================================ +# 读取 .vscodeignore 排除规则 +# ============================================================ +def load_ignore_patterns(): + patterns = [] + if os.path.exists(VSCODEIGNORE_PATH): + with open(VSCODEIGNORE_PATH, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if line and not line.startswith('#'): + patterns.append(line) + # 默认排除 + patterns += ['.git/**', '.git', '__pycache__/**', '*.pyc', '*.vsix'] + return patterns + +def should_ignore(rel_path, patterns): + """判断文件是否应该被排除(简单版 glob 匹配)""" + import fnmatch + rel_path = rel_path.replace('\\', '/') + for pattern in patterns: + pattern = pattern.replace('\\', '/') + # 处理 **/ 开头的模式 + if pattern.endswith('/**'): + folder = pattern[:-3] + if rel_path.startswith(folder + '/') or rel_path == folder: + return True + elif pattern.startswith('**/'): + suffix = pattern[3:] + if fnmatch.fnmatch(rel_path, suffix) or fnmatch.fnmatch(os.path.basename(rel_path), suffix): + return True + # 检查是否在任意子目录下 + parts = rel_path.split('/') + for i in range(len(parts)): + if fnmatch.fnmatch('/'.join(parts[i:]), suffix): + return True + elif '/' in pattern: + if fnmatch.fnmatch(rel_path, pattern) or rel_path.startswith(pattern.rstrip('*') ): + return True + else: + if fnmatch.fnmatch(os.path.basename(rel_path), pattern): + return True + return False + +# ============================================================ +# Content_Types.xml(必需的 VSIX 元数据文件) +# ============================================================ +CONTENT_TYPES_XML = ''' + + + + + + + + + + + + + + +''' + +# ============================================================ +# 生成 .vsixmanifest +# ============================================================ +def make_vsixmanifest(): + display_name = pkg.get('displayName', NAME) + description = pkg.get('description', '') + icon_path = pkg.get('icon', '') + tags = ';'.join(pkg.get('keywords', [])) + repo_url = pkg.get('repository', {}).get('url', '') if isinstance(pkg.get('repository'), dict) else '' + license_val = pkg.get('license', 'MIT') + + icon_line = f'extension/{icon_path}' if icon_path else '' + + return f''' + + + + {display_name} + {description} + {tags} + Language Packs,Other + Public + {icon_line} + + + + + + + + + extension/LICENSE + + + + + + + + + + + {f'' if icon_path else ''} + +''' + +# ============================================================ +# 打包主逻辑 +# ============================================================ +def build_vsix(): + ignore_patterns = load_ignore_patterns() + + print(f"[PACK] {PUBLISHER}.{NAME} v{VERSION}") + print(f" Output: {OUTPUT_PATH}") + print() + + # 收集要打包的文件 + files_to_pack = [] + for root, dirs, files in os.walk(PROJECT_ROOT): + # 跳过 .git 目录 + dirs[:] = [d for d in dirs if d != '.git' and d != '__pycache__'] + + for fname in files: + full_path = os.path.join(root, fname) + rel_path = os.path.relpath(full_path, PROJECT_ROOT).replace('\\', '/') + + if should_ignore(rel_path, ignore_patterns): + continue + + files_to_pack.append((full_path, rel_path)) + + # 写入 ZIP + with zipfile.ZipFile(OUTPUT_PATH, 'w', zipfile.ZIP_DEFLATED, compresslevel=9) as zf: + # 1. [Content_Types].xml + zf.writestr('[Content_Types].xml', CONTENT_TYPES_XML) + + # 2. extension.vsixmanifest + zf.writestr('extension.vsixmanifest', make_vsixmanifest()) + + # 3. 扩展文件(放在 extension/ 目录下) + for full_path, rel_path in files_to_pack: + arc_path = f'extension/{rel_path}' + print(f" + {arc_path}") + zf.write(full_path, arc_path) + + size_kb = os.path.getsize(OUTPUT_PATH) / 1024 + print() + print(f"[OK] Done!") + print(f" File: {OUTPUT_FILENAME}") + print(f" Size: {size_kb:.1f} KB") + print(f" Files: {len(files_to_pack) + 2}") + print() + print("[i] Install:") + print(f" Extensions: Install from VSIX...") + print(f" -> {OUTPUT_PATH}") + +if __name__ == '__main__': + build_vsix() + diff --git a/clean_injects.py b/clean_injects.py new file mode 100644 index 0000000..0feb95c --- /dev/null +++ b/clean_injects.py @@ -0,0 +1,82 @@ +import os +import sys +import json +import hashlib +import base64 + +print("🚨 开始执行紧急清理程序...") + +def get_app_base(): + localappdata = os.environ.get('LOCALAPPDATA', '') + if localappdata: + win_candidate = os.path.join(localappdata, 'Programs', 'Antigravity IDE', 'resources', 'app') + if os.path.exists(win_candidate): + return win_candidate + return None + +BASE = get_app_base() +if not BASE: + print("❌ 找不到 Antigravity IDE 安装目录!") + sys.exit(1) + +TARGETS = { + 'settings': os.path.join(BASE, 'out', 'jetskiAgent', 'main.js'), + 'chat': os.path.join(BASE, 'extensions', 'antigravity', 'out', 'media', 'chat.js'), + 'workbench': os.path.join(BASE, 'out', 'vs', 'workbench', 'workbench.desktop.main.js'), +} + +# 需要切除的所有残留代码标记 +TAGS = [ + "// [AntigravityChinesePack PoC injected]", + "// [AntigravityChinesePack V2 DOM Observer Injected]", + "// [AntigravityChinesePack V3 Hybrid Observer Injected]" +] + +for name, filepath in TARGETS.items(): + if not os.path.exists(filepath): + continue + with open(filepath, 'r', encoding='utf-8', errors='replace') as f: + content = f.read() + + modified = False + for tag in TAGS: + if tag in content: + # 切除该标记及其后面的所有注入代码 + content = content.split(tag)[0] + modified = True + print(f"🔪 发现残留代码,正在清理 {name} ...") + + if modified: + with open(filepath, 'w', encoding='utf-8') as f: + f.write(content) + print(f"✅ {name} 成功清理了所有引起卡顿的残留代码!") + else: + print(f"✅ {name} 很干净。") + +# 重新计算哈希值以修复“安装损坏” +PRODUCT_JSON = os.path.join(BASE, 'product.json') +if os.path.exists(PRODUCT_JSON): + with open(PRODUCT_JSON, 'r', encoding='utf-8') as f: + product = json.load(f) + checksums = product.get('checksums', {}) + updated = 0 + for key in checksums: + for prefix in [os.path.join(BASE, 'out'), BASE]: + fpath = os.path.normpath(os.path.join(prefix, key)) + if os.path.exists(fpath): + with open(fpath, 'rb') as f: + data = f.read() + new_hash = base64.b64encode(hashlib.sha256(data).digest()).decode('ascii').rstrip('=') + if new_hash != checksums[key]: + checksums[key] = new_hash + updated += 1 + break + if updated > 0: + product['checksums'] = checksums + with open(PRODUCT_JSON, 'w', encoding='utf-8') as f: + json.dump(product, f, indent='\t', ensure_ascii=False) + print(f"✅ 重新计算并修复了 {updated} 个文件的校验哈希值。") + else: + print(f"✅ 哈希值无需更新。") + +print("\n🎉 紧急清理完成!请彻底关闭 IDE 窗口并重新打开。") diff --git a/extension.js b/extension.js index 5363440..44b5135 100644 --- a/extension.js +++ b/extension.js @@ -10,7 +10,7 @@ const crypto = require('crypto'); // 路径配置 // ═══════════════════════════════════════════════════════════════ function getAppBase() { - // Antigravity.app 的 Resources/app 路径 + // macOS Candidates const candidates = [ '/Applications/Antigravity.app/Contents/Resources/app', path.join(process.env.HOME || '', 'Applications/Antigravity.app/Contents/Resources/app'), @@ -18,6 +18,15 @@ function getAppBase() { for (const c of candidates) { if (fs.existsSync(c)) return c; } + // Windows Candidates (用户级安装 / 系统级安装 / x86 系统级安装) + const winPaths = [ + process.env.LOCALAPPDATA && path.join(process.env.LOCALAPPDATA, 'Programs', 'Antigravity IDE', 'resources', 'app'), + process.env.ProgramFiles && path.join(process.env.ProgramFiles, 'Antigravity IDE', 'resources', 'app'), + process.env['ProgramFiles(x86)'] && path.join(process.env['ProgramFiles(x86)'], 'Antigravity IDE', 'resources', 'app'), + ].filter(Boolean); + for (const c of winPaths) { + if (fs.existsSync(c)) return c; + } // Fallback: 从 vscode 的 appRoot 推导 const appRoot = vscode.env.appRoot; if (appRoot && fs.existsSync(appRoot)) return appRoot; @@ -193,6 +202,213 @@ function getSettingsReplacements() { ['," result",a===1?"":"s"', '," 个结果"'], ['," result",t.resources.length===1?"":"s"', '," 个结果"'], ['," result",a.length===1?"":"s"," "', '," 个结果 "'], + // === v1.107.0 Settings updates === + ['{value:e0.TURBO,label:"Always Proceed",description:"Agent never asks for review. This maximizes the autonomy of the Agent, but also has the highest risk of the Agent operating over unsafe or injected Artifact content.",disabledInSecureMode:!0}', + '{value:e0.TURBO,label:"始终继续",description:"Agent 从不请求审查。这最大化了 Agent 的自主性,但也具有 Agent 操作不安全或注入的 Artifact 内容的最高风险。",disabledInSecureMode:!0}'], + ['{value:e0.ALWAYS,label:"Always Ask",description:"Agent always asks for review.",disabledInSecureMode:!1}', + '{value:e0.ALWAYS,label:"始终询问",description:"Agent 始终请求审查。",disabledInSecureMode:!1}'], + ['children:["Settings - ",e]', 'children:["设置 - ",e]'], + ['"aria-label":"Add context"', '"aria-label":"添加上下文"'], + ['tooltipText:"Edit Model"', 'tooltipText:"编辑模型"'], + // === Remaining settings translations === + ['children:["Select one of the ",t?"two":"three"," options. Agent settings and permissions can be further customized below."', + 'children:["从",t?"两个":"三个","个选项中选择一个。Agent 设置和权限可在下方进一步自定义。"'], + ['children:"Agent security mode"', 'children:"Agent 安全模式"'], + ['children:"Full access"', 'children:"完全访问"'], + ['children:"Agents have full access to your machine and external resources."', 'children:"Agent 可以完全访问您的计算机和外部资源。"'], + ['children:"Sandboxed"', 'children:"沙盒化"'], + ['children:"Agents run in a secure sandbox that restricts access to external resources outside of your trusted folders."', 'children:"Agent 运行在安全的沙盒中,限制访问信任文件夹以外的外部资源。"'], + ['children:"Strict"', 'children:"严格"'], + ['children:"Terminal commands always require review and the agent cannot access files outside of its given workspaces."', 'children:"终端命令始终需要审查,且 Agent 无法访问指定工作区以外的文件。"'], + ['require your approval before running.\\n\\nNote: A change to this setting will only apply to new messages sent to Agent. In-progress responses will use the previous setting value.', + '在运行前需要您的批准。\\n\\n注意:对此设置的更改仅适用于发送给 Agent 的新消息。正在进行的响应将使用以前的设置值。'], + ['label:"Enable Shell Integration"', 'label:"启用 Shell 集成"'], + ['description:"When enabled, Agent will use IDE\'s shell integration to detect and report terminal command execution."', + 'description:"启用后,Agent 将使用 IDE 的 Shell 集成来检测并报告终端命令的执行。"'], + ['children:"File Access"', 'children:"文件访问"'], + ['description:"Allows the agent to access files outside of your current workspace."', + 'description:"允许 Agent 访问当前工作区以外的文件。"'], + ['children:"Planning"', 'children:"规划"'], + ['description:"Specifies Agent\'s behavior when asking for review on artifacts, which are documents it creates to enable a richer conversation experience."', + 'description:"指定 Agent 在请求审查 Artifact(即为了提供更丰富的对话体验而创建的文档)时的行为。"'], + ['children:"Automation"', 'children:"自动化"'], + ['children:"History"', 'children:"历史记录"'], + ['children:"General"', 'children:"常规"'], + ['label:"Explain and Fix in Current Conversation"', 'label:"在当前对话中解释和修复"'], + ['description:"When enabled, \'Explain and Fix\' actions will continue in the current conversation instead of starting a new one."', + 'description:"启用后,“解释并修复”操作将在当前对话中继续,而不是开始新对话。"'], + ['children:"Advanced"', 'children:"高级"'], + ['children:"Advanced File Access"', 'children:"高级文件访问"'], + ['label:"Read Files",description:"Paths the agent can read."', 'label:"读取文件",description:"Agent 可以读取的路径。"'], + ['label:"Read Files",description:"Paths the agent can read inside this workspace."', 'label:"读取文件",description:"Agent 在此工作区中可以读取的路径。"'], + ['label:"Write Files",description:"Paths the agent can modify."', 'label:"写入文件",description:"Agent 可以修改的路径。"'], + ['label:"Write Files",description:"Paths the agent can modify inside this workspace."', 'label:"写入文件",description:"Agent 在此工作区中可以修改的路径。"'], + ['children:"Advanced Command Access"', 'children:"高级命令访问"'], + ['label:"Terminal Commands",description:"Terminal commands the agent can execute."', 'label:"终端命令",description:"Agent 可以执行的终端命令。"'], + ['label:"Terminal Commands",description:"Terminal commands the agent can execute in this workspace."', 'label:"终端命令",description:"Agent 在此工作区中可以执行的终端命令。"'], + ['label:"Commands Outside Sandbox",description:"Allow/deny agent command execution outside the sandbox."', + 'label:"沙盒外的命令",description:"允许/拒绝 Agent 在沙盒外执行命令。"'], + ['label:"Commands Outside Sandbox",description:"Commands the agent can run outside the sandbox."', + 'label:"沙盒外的命令",description:"Agent 可以在沙盒外运行的命令。"'], + ['label:"Commands Outside Sandbox",description:"Commands the agent can run outside the sandbox in this workspace."', + 'label:"沙盒外的命令",description:"Agent 在此工作区的沙盒外可以运行的命令。"'], + ['label:"MCP Tools",description:"Configure external tools via Model Context Protocol."', + 'label:"MCP 工具",description:"通过 Model Context Protocol 配置外部工具。"'], + ['label:"MCP Tools",description:"External tools the agent can call via Model Context Protocol."', + 'label:"MCP 工具",description:"Agent 可通过 Model Context Protocol 调用的外部工具。"'], + ['children:"Advanced Web Access"', 'children:"高级网络访问"'], + ['label:"Read URLs",description:"Allow/deny agent read access to specific URLs or domains."', + 'label:"读取 URL",description:"允许/拒绝 Agent 对特定 URL 或域名的读取访问。"'], + ['label:"Read URLs",description:"URLs the agent can read or open in the browser."', + 'label:"读取 URL",description:"Agent 可以在浏览器中读取或打开的 URL。"'], + ['label:"Read URLs",description:"URLs the agent can read or open in this workspace."', + 'label:"读取 URL",description:"Agent 在此工作区中可以读取或打开的 URL。"'], + ['label:"Execute URLs",description:"URLs the agent can actuate on using the browser."', + 'label:"执行 URL",description:"Agent 可以使用浏览器操作 the URL。"'], + ['label:"Execute URLs",description:"Allow/deny agent browser actuation access to specific URLs."', + 'label:"执行 URL",description:"允许/拒绝 Agent 对特定 URL 的浏览器操作访问。"'], + ['label:"Execute URLs",description:"URLs the agent can actuate on in this workspace."', + 'label:"执行 URL",description:"Agent 在此工作区中可以操作 the URL。"'], + ['label:t="Advanced Settings"', 'label:t="高级设置"'], + ['label:"Enable Demo Mode (Beta)"', 'label:"启用演示模式 (Beta)"'], + ['description:\'When enabled, your UI will be slightly modified to ensure more consistent demos. This is only recommended for demo purposes. In most cases, you can run "Antigravity: Start Demo Mode" and "Antigravity: Stop Demo Mode" to control this switch and update your ~/.gemini/antigravity data directory.\'', + 'description:\'启用后,您的 UI 将被稍微修改以确保演示的一致性。仅建议用于演示目的。在大多数情况下,您可以运行 "Antigravity: Start Demo Mode" and "Antigravity: Stop Demo Mode" 来控制此开关并更新您的 ~/.gemini/antigravity 数据目录。\''], + ['description:`When toggled on, ${r.product.nameShort} collects usage data to help Google enhance performance and features.`', + 'description:`开启后,${r.product.nameShort} 将收集使用数据,以帮助 Google 提升性能和功能。`'], + ['label:"Marketing Emails",description:`Receive product updates, tips, and promotions from Google ${r.product.nameShort} via email.`', + 'label:"营销邮件",description:`通过电子邮件接收来自 Google ${r.product.nameShort} 的产品更新、提示和促销信息。`'], + ['children:["By using this app, you agree to its",', 'children:["使用此应用即表示您同意其",'], + ['className:"text-primary hover:underline",children:"Terms of Service"', 'className:"text-primary hover:underline",children:"服务条款"'], + ['className:"text-lg font-medium mb-4",children:"Terms of Service & Data Use"', 'className:"text-lg font-medium mb-4",children:"服务条款与数据使用"'], + ['description:p(jt,{children:["Configure the browser subagent. It requires",', 'description:p(jt,{children:["配置浏览器子 Agent。它需要安装",'], + ['`Refreshes in ${n} day${n>1?"s":""}, ${a} hour${a>1?"s":""}`', '`将在 ${n} 天 ${a} 小时后刷新`'], + ['`Refreshes in ${a} hour${a>1?"s":""}, ${i} minute${i>1?"s":""}`', '`将在 ${a} 小时 ${i} 分钟后刷新`'], + ['`Refreshes in ${i} minute${i>1?"s":""}`', '`将在 ${i} 分钟后刷新`'], + ['description:"View your available model quota. Quota refreshes periodically based on your plan."', + 'description:"查看您可用的模型配额。配额会根据您的方案定期刷新。"'], + ['"% of the customization budget is available."', '"% 的定制预算当前可用。"'], + ['children:V?"Hide breakdown":`Show ${I.length} breakdown${I.length===1?"":"s"}`', + 'children:V?"隐藏明细":`显示 ${I.length} 项明细`'], + ['"Plugin: "', '"插件: "'], + ['children:["Plugins are packaged collections of skills and MCPs to help the Agent"," ",a?`in ${a} `:"","work with Google developer products. You can always change your choices in Settings."]', + 'children:["插件是技能和 MCP 的打包集合,用于帮助 Agent"," ",a?`在 ${a} `:"","中协同谷歌开发产品工作。您随时可以在设置中更改您的选择。"]'], + ['children:["Plugins are packaged collections of skills and MCPs to help the Agent in ",e," work with Google developer products. You can always change your choices in Settings."]', + 'children:["插件是技能和 MCP 的打包集合,用于帮助 Agent 在 ",e," 中协同谷歌开发产品工作。您随时可以在设置中更改您的选择。"]'], + ['children:"No MCP Servers"', 'children:"没有 MCP 服务器"'], + ['children:"You currently don\'t have any MCP Servers installed. Add an MCP server above or add a custom one via the MCP Config."', + 'children:"您当前未安装任何 MCP 服务器。请在上方添加 MCP 服务器,或通过 MCP 配置添加自定义服务器。"'], + ['label:"Account",description:"Manage your plan, credentials, and general preferences."', + 'label:"账户",description:"管理您的方案、凭据和常规偏好设置。"'], + ['label:"Appearance",description:"Configure the agent\'s visual theme and display preferences."', + 'label:"外观",description:"配置 Agent 的视觉主题和显示偏好设置。"'], + ['label:"Notifications",description:"Manage your notification preferences."', + 'label:"通知",description:"管理您的通知偏好设置。"'], + ['label:"Models",description:"Configure AI models and view your quota."', + 'label:"模型",description:"配置 AI 模型并查看您的配额。"'], + ['label:"Customizations",description:"Configure default behaviors, skills, and MCP servers."', + 'label:"自定义",description:"配置默认行为、技能和 MCP 服务器。"'], + ['label:"Browser Settings",description:"Configure the browser subagent. It requires Google Chrome to be installed."', + 'label:"浏览器设置",description:"配置浏览器子 Agent。它需要安装 Google Chrome。"'], + ['label:"Editor Settings",description:"Configure editor-specific behaviors and shortcuts."', + 'label:"编辑器设置",description:"配置编辑器特定的行为和快捷键。"'], + ['children:"Account & Plan"', 'children:"账户与方案"'], + ['label:"Email",description:a?"Peter Pan":n.email', 'label:"电子邮件",description:a?"Peter Pan":n.email'], + ['children:"Theme"', 'children:"主题"'], + ['children:"Chat Settings"', 'children:"聊天设置"'], + ['label:"Verbose agent chat",description:"Display and preserve intermediate thinking steps"', + 'label:"详细 Agent 聊天",description:"显示并保留中间思考步骤"'], + ['label:"Notification Settings",description:"To modify notification settings, open your operating system\'s system preferences."', + 'label:"通知设置",description:"要修改通知设置,请打开您操作系统的系统偏好设置。"'], + ['label:"Model Quota"', 'label:"模型配额"'], + ['children:"Actuation Permissions"', 'children:"执行操作权限"'], + ['label:"Browser Actuation Rules",description:"Configure allowed and denied URLs for browser actuation."', + 'label:"浏览器执行规则",description:"配置允许和拒绝的浏览器执行 URL。"'], + ['children:"Marketplace"', 'children:"市场"'], + ['description:"Changes the base URL on each extension page. You must restart Antigravity IDE to use the new marketplace after changing this value."', + 'description:"更改每个扩展页面的基础 URL。更改此值后,您必须重启 Antigravity IDE 才能使用新的市场。"'], + ['description:"Changes the base URL for marketplace search results. You must restart Antigravity IDE to use the new marketplace after changing this value."', + 'description:"更改市场搜索结果的基础 URL。更改此值后,您必须重启 Antigravity IDE 才能使用新的市场。"'], + ['children:"Selection Actions"', 'children:"选中操作"'], + ['label:"Editor Settings",description:"To modify editor settings, open Settings within the editor window."', + 'label:"编辑器设置",description:"要修改编辑器设置,请在编辑器窗口中打开设置。"'], + + // --- Sidebar --- + ['children:"Account"', 'children:"账户"'], + ['children:"Permissions"', 'children:"权限"'], + ['children:"Appearance"', 'children:"外观"'], + ['children:"Notifications"', 'children:"通知"'], + ['children:"Models"', 'children:"模型"'], + ['children:"Customizations"', 'children:"自定义"'], + ['children:"Browser"', 'children:"浏览器"'], + ['children:"Tab"', 'children:"Tab"'], + ['children:"Editor"', 'children:"编辑器"'], + ['children:"Workspaces"', 'children:"工作区"'], + ['children:"Shortcuts"', 'children:"快捷键"'], + + // --- Terminal Settings --- + ['children:"Controls whether terminal commands require your approval before running."', 'children:"控制终端命令在运行前是否需要您的批准。"'], + ['description:"Controls whether terminal commands require your approval before running."', 'description:"控制终端命令在运行前是否需要您的批准。"'], + ['"Note: A change to this setting will only apply to new messages sent to Agent. In-progress responses will use the previous setting value."', '"注意:对此设置的更改仅适用于发送给 Agent 的新消息。正在进行的响应将使用以前的设置值。"'], + + // --- Appearance Settings --- + ['children:"Configure the agent\'s visual theme and display preferences."', 'children:"配置 Agent 的视觉主题和显示偏好设置。"'], + ['description:"Configure the agent\'s visual theme and display preferences."', 'description:"配置 Agent 的视觉主题和显示偏好设置。"'], + + // --- Notifications Settings --- + ['children:"Manage your notification preferences."', 'children:"管理您的通知偏好设置。"'], + ['description:"Manage your notification preferences."', 'description:"管理您的通知偏好设置。"'], + ['children:"Notification Settings"', 'children:"通知设置"'], + ['children:"To modify notification settings, open your operating system\'s system preferences."', 'children:"要修改通知设置,请打开您操作系统的系统偏好设置。"'], + ['children:"Open System Preferences"', 'children:"打开系统偏好设置"'], + + // --- Models Settings --- + ['children:"Configure AI models and view your quota."', 'children:"配置 AI 模型并查看您的配额。"'], + ['description:"Configure AI models and view your quota."', 'description:"配置 AI 模型并查看您的配额。"'], + ['children:"Model Credits"', 'children:"模型积分"'], + ['children:"Enable AI Credit Overages"', 'children:"启用 AI 积分超额使用"'], + ['children:"When toggled on, Antigravity IDE will use your AI credits to fulfill model requests once you\'re out of model quota. Antigravity IDE will always use your model quota first before using AI credits."', 'children:"开启后,当您的模型配额用尽时,Antigravity IDE 将使用您的 AI 积分来完成模型请求。Antigravity IDE 将始终优先使用您的模型配额,然后再使用 AI 积分。"'], + ['children:"Available AI Credits: "', 'children:"可用 AI 积分: "'], + ['"Available AI Credits: "', '"可用 AI 积分: "'], + ['children:"See Activity"', 'children:"查看活动"'], + ['children:"Get More AI Credits"', 'children:"获取更多 AI 积分"'], + ['children:"Model Quota"', 'children:"模型配额"'], + ['children:"Refresh"', 'children:"刷新"'], + + // --- General Settings Dropdowns --- + ['children:"Request Review"', 'children:"请求审查"'], + ['children:"Agent Decides"', 'children:"Agent 决定"'], + ['children:"Always Proceed"', 'children:"始终继续"'], + + // --- Raw Strings Fallback --- + ['"Account"', '"账户"'], + ['"Permissions"', '"权限"'], + ['"Appearance"', '"外观"'], + ['"Notifications"', '"通知"'], + ['"Models"', '"模型"'], + ['"Customizations"', '"自定义"'], + ['"Browser"', '"浏览器"'], + ['"Tab"', '"Tab"'], + ['"Editor"', '"编辑器"'], + ['"Workspaces"', '"工作区"'], + ['"Shortcuts"', '"快捷键"'], + ['"Controls whether terminal commands require your approval before running."', '"控制终端命令在运行前是否需要您的批准。"'], + ['"Configure the agent\'s visual theme and display preferences."', '"配置 Agent 的视觉主题和显示偏好设置。"'], + ['"Manage your notification preferences."', '"管理您的通知偏好设置。"'], + ['"Notification Settings"', '"通知设置"'], + ['"To modify notification settings, open your operating system\'s system preferences."', '"要修改通知设置,请打开您操作系统的系统偏好设置。"'], + ['"Open System Preferences"', '"打开系统偏好设置"'], + ['"Configure AI models and view your quota."', '"配置 AI 模型并查看您的配额。"'], + ['"Model Credits"', '"模型积分"'], + ['"Enable AI Credit Overages"', '"启用 AI 积分超额使用"'], + ['"When toggled on, Antigravity IDE will use your AI credits to fulfill model requests once you\'re out of model quota. Antigravity IDE will always use your model quota first before using AI credits."', '"开启后,当您的模型配额用尽时,Antigravity IDE 将使用您的 AI 积分来完成模型请求。Antigravity IDE 将始终优先使用您的模型配额,然后再使用 AI 积分。"'], + ['"Available AI Credits: "', '"可用 AI 积分: "'], + ['"See Activity"', '"查看活动"'], + ['"Get More AI Credits"', '"获取更多 AI 积分"'], + ['"Model Quota"', '"模型配额"'], + ['"Refresh"', '"刷新"'], + ['"Request Review"', '"请求审查"'], + ['"Agent Decides"', '"Agent 决定"'], + ['"Always Proceed"', '"始终继续"'], ]; } @@ -929,7 +1145,7 @@ function getChatReplacements() { ['"Unnamed resource"', '"\u672A\u547D\u540D\u8D44\u6E90"'], // 未命名资源 ['"Unsupported browser target"', '"\u4E0D\u652F\u6301\u7684\u6D4F\u89C8\u5668\u76EE\u6807"'], // 不支持的浏览器目标 ['"untitled"', '"\u672A\u547D\u540D"'], // 未命名 - ['"Upload to Agent"', '"\u4E0A\u4F20\u5230\u4EE3\u7406"'], // 上传到代理 + ['"Upload to Agent"', '"\u4E0A\u4F20\u5230 Agent"'], // 上传到 Agent ['"Upload"', '"\u4E0A\u4F20"'], // 上传 ['"User Implicit Trajectories"', '"\u7528\u6237\u9690\u5F0F\u8F68\u8FF9"'], // 用户隐式轨迹 ['"User Implicit"', '"\u7528\u6237\u9690\u5F0F"'], // 用户隐式 @@ -1028,11 +1244,11 @@ function getChatReplacements() { ['"Unexpected object: "', '"\u610F\u5916\u7684\u5BF9\u8C61: "'], // 意外的对象: ['"unable to serialize "', '"\u65E0\u6CD5\u5E8F\u5217\u5316 "'], // 无法序列化 ['"This undo action will not make any code changes."', '"\u6B64\u64A4\u9500\u64CD\u4F5C\u4E0D\u4F1A\u8FDB\u884C\u4EFB\u4F55\u4EE3\u7801\u66F4\u6539\u3002"'], // 此撤销操作不会进行任何代码更改。 - ['"Messages can be sent while the agent is still working and your message will be queued and taken into consideration at the next available break in reasoning."', '"\u60A8\u53EF\u4EE5\u5728\u4EE3\u7406\u4ECD\u5728\u5DE5\u4F5C\u65F6\u53D1\u9001\u6D88\u606F\uFF0C\u60A8\u7684\u6D88\u606F\u5C06\u88AB\u6392\u961F\uFF0C\u5E76\u5728\u4E0B\u4E00\u4E2A\u53EF\u7528\u7684\u63A8\u7406\u95F4\u6B47\u65F6\u88AB\u8003\u8651\u3002"'], // 您可以在代理仍在工作时发送消息,您的消息将被排队,并在下一个可用的推理间歇时被考虑。 - ['"This tool runs code that can access IDE extension APIs and potentially change the functionality of your IDE the same way that an IDE extension or plugin can."', '"\u6B64\u5DE5\u5177\u8FD0\u884C\u7684\u4EE3\u7801\u53EF\u4EE5\u8BBF\u95EE IDE \u6269\u5C55 API\uFF0C\u5E76\u53EF\u80FD\u4EE5\u4E0E IDE \u6269\u5C55\u6216\u63D2\u4EF6\u76F8\u540C\u7684\u65B9\u5F0F\u66F4\u6539 IDE \u7684\u529F\u80FD\u3002"'], // 此工具运行的代码可以访问 IDE 扩展 API,并可能以与 IDE 扩展或插件相同的方式更改 IDE 的功能。 + ['"Messages can be sent while the agent is still working and your message will be queued and taken into consideration at the next available break in reasoning."', '"\u60A8\u53EF\u4EE5\u5728 Agent \u4ECD\u5728\u5DE5\u4F5C\u65F6\u53D1\u9001\u6D88\u606F\uFF0C\u60A8\u7684\u6D88\u606F\u5C06\u88AB\u6392\u961F\uFF0C\u5E76\u5728\u4E0B\u4E00\u4E2A\u53EF\u7528\u7684\u63A8\u7406\u95F4\u6B47\u65F6\u88AB\u8003\u8651\u3002"'], // 您可以在 Agent 仍在工作时发送消息,您的消息将被排队,并在下一个可用的推理间歇时被考虑。 + ['"This tool runs code that can access IDE extension APIs and potentially change the functionality of your IDE the same way that an IDE extension or plugin can."', '"\u6B64\u5DE5\u5177\u8FD0\u884C\u7684\u4EE3\u7801\u53EF\u4EE5\u8BBF\u95EE IDE \u6269\u5C55 API\uFF0C\u5E76\u53EF\u80FD\u4EE5\u4E0E IDE \u6269\u5C55\u6216\u63D2\u4EF6\u76F8\u540C\u7684\u65B9\u5F0F\u66F4\u6539 IDE \u7684\u529F\u80FD\u3002"'], // 此工具运行的代码可以访问 IDE 扩展 API,并可能以与 IDE 扩展或插件相同的方式更改 IDE 的功能。(保留,用户可见) ['"Too many requests, please try again in a bit!"', '"\u8BF7\u6C42\u8FC7\u591A\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\uFF01"'], // 请求过多,请稍后重试! ['"This error is likely temporary. You can prompt the model to try again after some time."', '"\u6B64\u9519\u8BEF\u53EF\u80FD\u662F\u6682\u65F6\u7684\u3002\u60A8\u53EF\u4EE5\u7A0D\u540E\u63D0\u793A\u6A21\u578B\u91CD\u8BD5\u3002"'], // 此错误可能是暂时的。您可以稍后提示模型重试。 - ['"Get notified when the agent needs your attention or completes a task."', '"\u5F53\u4EE3\u7406\u9700\u8981\u60A8\u6CE8\u610F\u6216\u5B8C\u6210\u4EFB\u52A1\u65F6\u83B7\u5F97\u901A\u77E5\u3002"'], // 当代理需要您注意或完成任务时获得通知。 + ['"Get notified when the agent needs your attention or completes a task."', '"\u5F53 Agent \u9700\u8981\u60A8\u6CE8\u610F\u6216\u5B8C\u6210\u4EFB\u52A1\u65F6\u83B7\u5F97\u901A\u77E5\u3002"'], // 当 Agent 需要您注意或完成任务时获得通知。 ['"This model is currently experiencing some issues."', '"\u6B64\u6A21\u578B\u5F53\u524D\u9047\u5230\u4E00\u4E9B\u95EE\u9898\u3002"'], // 此模型当前遇到一些问题。 ['"Failed to load "', '"\u52A0\u8F7D\u5931\u8D25 "'], // 加载失败 ['"Did you make sure to report this error on Slack?"', '"\u60A8\u786E\u5B9A\u5DF2\u5728 Slack \u4E0A\u62A5\u544A\u6B64\u9519\u8BEF\u4E86\u5417\uFF1F"'], // 您确定已在 Slack 上报告此错误了吗? @@ -1170,6 +1386,91 @@ function getWorkbenchReplacements() { ['," result",s===1?"":"s"', '," 个结果"'], ['," result",i.resources.length===1?"":"s"', '," 个结果"'], ['," result",s.length===1?"":"s"," "', '," 个结果 "'], + // === v1.107.0 Chat updates === + ['children:"Open Diff"', 'children:"打开差异"'], + ['label:"Allow Once"', 'label:"允许一次"'], + ['label:"Deny"', 'label:"拒绝"'], + ['children:"Additional Options"', 'children:"其他选项"'], + ['label:"Try Again"', 'label:"再试一次"'], + ['title:"Add Context"', 'title:"添加上下文"'], + // === v1.107.0 Workbench updates === + ['t.ON="On",t.OFF="Off"', 't.ON="开",t.OFF="关"'], + ['children:"Terminal execution policy"', 'children:"终端执行策略"'], + ['children:"Review policy"', 'children:"审查策略"'], + ['children:"JavaScript execution policy"', 'children:"JavaScript 执行策略"'], + ['children:"Always Proceed"', 'children:"始终继续"'], + ['children:"Request Review"', 'children:"请求审查"'], + ['children:"Always Ask"', 'children:"始终询问"'], + ['children:"Disabled"', 'children:"已禁用"'], + ['{value:Vz.TURBO,label:"Always Proceed",description:"Agent never asks for review. This maximizes the autonomy of the Agent, but also has the highest risk of the Agent operating over unsafe or injected Artifact content.",disabledInSecureMode:!0}', + '{value:Vz.TURBO,label:"始终继续",description:"Agent 从不请求审查。这最大化了 Agent 的自主性,但也具有 Agent 操作不安全或注入的 Artifact 内容的最高风险。",disabledInSecureMode:!0}'], + ['{value:Vz.ALWAYS,label:"Always Ask",description:"Agent always asks for review.",disabledInSecureMode:!1}', + '{value:Vz.ALWAYS,label:"始终询问",description:"Agent 始终请求审查。",disabledInSecureMode:!1}'], + ['{label:"Always Proceed",value:$9.TURBO,description:"Trust the agent to do tasks end-to-end",isDefaultWhenAvailable:!0}', + '{label:"始终继续",value:$9.TURBO,description:"信任 Agent 端到端地执行任务",isDefaultWhenAvailable:!0}'], + ['{label:"Agent Decides",value:$9.AUTO,description:"Assist the agent to complete tasks"}', + '{label:"Agent 决定",value:$9.AUTO,description:"辅助 Agent 完成任务"}'], + ['{label:"Request Review",value:$9.ALWAYS,description:"Collaborate with the agent to complete tasks"}', + '{label:"请求审查",value:$9.ALWAYS,description:"与 Agent 协作完成任务"}'], + ['{label:"Always Proceed",value:$U.EAGER,description:"Always auto-execute commands unless they are in your deny list. This also allows Agent to auto-execute Browser controls."}', + '{label:"始终继续",value:$U.EAGER,description:"始终自动执行命令,除非它们在您的拒绝列表中。这也允许 Agent 自动执行浏览器控制。"}'], + ['{label:"Request Review",value:$U.OFF,description:"Never auto-execute commands unless they are in your allow list.",isDefaultWhenAvailable:!0}', + '{label:"请求审查",value:$U.OFF,description:"从不自动执行命令,除非它们在您的允许列表中。",isDefaultWhenAvailable:!0}'], + ['{label:"Slow",value:Fwe.SLOW}', '{label:"慢速",value:Fwe.SLOW}'], + ['{label:"Fast",value:Fwe.FAST,isDefaultWhenAvailable:!0}', '{label:"快速",value:Fwe.FAST,isDefaultWhenAvailable:!0}'], + // === Remaining workbench/feedback/shortcuts translations === + ['label:"Open Conversation Picker"', 'label:"打开对话选择器"'], + ['label:"Open File Search"', 'label:"打开文件搜索"'], + ['label:"Focus Input"', 'label:"聚焦输入框"'], + ['label:"New Conversation"', 'label:"新建对话"'], + ['label:"Open Workspace Selector"', 'label:"打开工作区选择器"'], + ['label:"Go Back"', 'label:"后退"'], + ['label:"Go Forward"', 'label:"前进"'], + ['label:"File Picker"', 'label:"文件选择器"'], + ['label:"Toggle Editor"', 'label:"切换编辑器"'], + ['label:"Select Previous Conversation"', 'label:"选择上一个对话"'], + ['label:"Select Next Conversation"', 'label:"选择下一个对话"'], + ['label:"Toggle Model Selector"', 'label:"切换模型选择器"'], + ['label:"Start Voice Recording"', 'label:"开始语音录制"'], + ['label:"Stop Voice Recording"', 'label:"停止语音录制"'], + ['label:"Find in Pane"', 'label:"在窗格中查找"'], + ['label:"Toggle Sidebar"', 'label:"切换侧边栏"'], + ['label:"Toggle Auxiliary Pane"', 'label:"切换辅助窗格"'], + ['label:"Toggle Terminal"', 'label:"切换终端"'], + ['label:"Open Settings"', 'label:"打开设置"'], + ['label:"Zoom In"', 'label:"放大"'], + ['label:"Zoom Out"', 'label:"缩小"'], + ['label:"Reset Zoom"', 'label:"重置缩放"'], + ['children:"Recommended"', 'children:"推荐"'], + ['children:"Navigation"', 'children:"导航"'], + ['children:"Conversation"', 'children:"对话"'], + ['children:"Layout Controls"', 'children:"布局控制"'], + ['children:"Shortcuts"', 'children:"快捷键"'], + ['description:"Keyboard shortcuts for quick navigation and control."', 'description:"用于快速导航和控制的键盘快捷键。"'], + ['children:"Feedback Type"', 'children:"反馈类型"'], + ['"bug-report":"Bug Report"', '"bug-report":"Bug 报告"'], + ['"feature-request":"Feature Request"', '"feature-request":"功能请求"'], + ['"auth-and-billing":"Auth and Billing"', '"auth-and-billing":"认证与计费"'], + ['"general-feedback":"General Feedback"', '"general-feedback":"常规反馈"'], + ['children:"Please describe the issue in detail. The more actionable your feedback, the quicker our team can address your request. Some helpful information includes:"', + 'children:"请详细描述该问题。您的反馈越具可操作性,我们的团队就能越快处理您的请求。一些有帮助的信息包括:"'], + ['children:"Steps to reproduce the issue"', 'children:"重现问题的步骤"'], + ['children:"Expected behavior"', 'children:"预期行为"'], + ['children:"Actual behavior"', 'children:"实际行为"'], + ['children:"Any error messages"', 'children:"任何错误消息"'], + ['children:"Any relevant information"', 'children:"任何相关信息"'], + ['"bug-report":"Describe the bug you encountered..."', '"bug-report":"请描述您遇到的 Bug..."'], + ['children:"Steps to Reproduce"', 'children:"重现步骤"'], + ['placeholder:"Please list the steps to reproduce the issue"', 'placeholder:"请列出重现该问题的步骤"'], + ['children:"Attach a screenshot (optional)"', 'children:"附加屏幕截图 (可选)"'], + ['label:"Attach Antigravity server logs"', 'label:"附加 Antigravity 服务器日志"'], + ['label:"Send feedback as "+e.email', 'label:"发送反馈,身份为:"+e.email'], + ['children:"We recommend attaching logs. Attaching logs will help the Antigravity team act on and prioritize your feedback."', + 'children:"我们建议附加日志。附加日志将帮助 Antigravity 团队针对您的反馈进行处理并排定优先级。"'], + ['title:"Model quota reached"', 'title:"已达到模型配额限制"'], + ["` Your plan's baseline quota will refresh on ${o}.`", "` 您方案的基准配额将在 ${o} 刷新。`"], + ['label:d||"Upgrade"', 'label:d||"升级"'], + ['children:n.userTier?.upgradeButtonText||"Upgrade"', 'children:n.userTier?.upgradeButtonText||"升级"'], ]; } @@ -1210,10 +1511,17 @@ function patchFile(filepath, replacements, name) { fs.writeFileSync(backup, content, 'utf-8'); } + // 去重:以英文原文为 key,保留最后一条,防止链式误替换 + const seen = new Map(); + for (const pair of replacements) { + seen.set(pair[0], pair[1]); + } + const dedupedReplacements = [...seen.entries()]; + let count = 0; const failed = []; - for (const [oldStr, newStr] of replacements) { + for (const [oldStr, newStr] of dedupedReplacements) { if (content.includes(oldStr)) { content = content.split(oldStr).join(newStr); count++; @@ -1230,7 +1538,7 @@ function patchFile(filepath, replacements, name) { content = PATCH_MARKER + '\n' + content; fs.writeFileSync(filepath, content, 'utf-8'); - return { name, success: count, total: replacements.length, failed }; + return { name, success: count, total: dedupedReplacements.length, failed }; } function revertFile(filepath) { @@ -1285,16 +1593,18 @@ const BLOCKED_UPDATE_URL = 'https://localhost.invalid/no-update'; function isAutoUpdateBlocked(base) { const productJsonPath = path.join(base, 'product.json'); - const backup = productJsonPath + '.bak'; if (!fs.existsSync(productJsonPath)) return false; try { const product = JSON.parse(fs.readFileSync(productJsonPath, 'utf-8')); - // 如果 updateUrl 不存在或为空,且备份中有原始 updateUrl,则说明已屏蔽 - if (!product.updateUrl && fs.existsSync(backup)) { + // blockAutoUpdate() 通过删除 updateUrl 字段来屏蔽更新 + // 因此只要 updateUrl 不存在即视为已屏蔽(依赖备份文件存在做判断) + if (!product.updateUrl) { + const backup = productJsonPath + '.bak'; + if (!fs.existsSync(backup)) return false; const original = JSON.parse(fs.readFileSync(backup, 'utf-8')); - return !!original.updateUrl; + return !!original.updateUrl; // 原始有 updateUrl 才说明是被我们删掉的 } - return product.updateUrl === BLOCKED_UPDATE_URL; + return false; } catch { return false; } @@ -1358,15 +1668,21 @@ function applyAllPatches(silent) { const targets = getTargets(base); const results = []; - // Check if all files have current patch version - const allCurrent = Object.values(targets).every(f => isPatchCurrent(f)); + // Check which targets are active/exist + const activeTargets = [targets.settings, targets.workbench]; + if (fs.existsSync(targets.chat)) { + activeTargets.push(targets.chat); + } + + // Check if all active files have current patch version + const allCurrent = activeTargets.every(f => isPatchCurrent(f)); if (allCurrent) { if (!silent) vscode.window.showInformationMessage('汉化补丁已是最新状态'); return true; } // Revert files that have old patches before re-applying - for (const filepath of Object.values(targets)) { + for (const filepath of activeTargets) { const ver = getPatchVersion(filepath); if (ver && ver !== PATCH_VERSION) { revertFile(filepath); @@ -1375,7 +1691,11 @@ function applyAllPatches(silent) { // Apply patches results.push(patchFile(targets.settings, getSettingsReplacements(), 'Settings')); - results.push(patchFile(targets.chat, getChatReplacements(), 'Chat')); + if (fs.existsSync(targets.chat)) { + results.push(patchFile(targets.chat, getChatReplacements(), 'Chat')); + } else { + results.push(patchFile(targets.workbench, getChatReplacements(), 'Chat in Workbench')); + } results.push(patchFile(targets.workbench, getWorkbenchReplacements(), 'Workbench')); // Update checksums @@ -1408,9 +1728,13 @@ function revertAllPatches() { } const targets = getTargets(base); - let reverted = 0; + const activeTargets = [targets.settings, targets.workbench]; + if (fs.existsSync(targets.chat)) { + activeTargets.push(targets.chat); + } - for (const filepath of Object.values(targets)) { + let reverted = 0; + for (const filepath of activeTargets) { if (revertFile(filepath)) reverted++; } diff --git a/generate_dict.py b/generate_dict.py new file mode 100644 index 0000000..b63bdaa --- /dev/null +++ b/generate_dict.py @@ -0,0 +1,33 @@ +import json +import re +import patch_zh + +settings = patch_zh.get_settings_replacements() +chat = patch_zh.get_chat_replacements() + +dict_out = {} + +def extract_strings(s_eng, s_zh): + # Regex to find text between quotes (either " or ') + eng_matches = re.findall(r'["\'](.*?)["\']', s_eng) + zh_matches = re.findall(r'["\'](.*?)["\']', s_zh) + + if len(eng_matches) == len(zh_matches): + for e, z in zip(eng_matches, zh_matches): + if e and z and e != z and not e.startswith('${'): + dict_out[e.strip()] = z.strip() + +for e, z in settings: + extract_strings(e, z) +for e, z in chat: + extract_strings(e, z) + +# Add some dynamic prefixes manually so our observer can use them +dict_out["Thinking for "] = "思考中 " +dict_out["Thought for "] = "思考了 " +dict_out["Changes Overview"] = "更改概览" + +with open('zh_dictionary.json', 'w', encoding='utf-8') as f: + json.dump(dict_out, f, ensure_ascii=False, indent=2) + +print(f"Extracted {len(dict_out)} translation pairs to zh_dictionary.json!") diff --git a/package.json b/package.json index e7436d3..6092531 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "antigravity-language-pack-zh-hans", "displayName": "Chinese (Simplified) (简体中文) Language Pack for Antigravity", "description": "Antigravity IDE 简体中文语言包扩展 — 为 Antigravity 专属功能提供中文翻译(含 NLS + 硬编码字符串补丁)", - "version": "1.41.1", + "version": "1.41.2", "publisher": "editorss", "repository": { "type": "git", diff --git a/patch_zh.py b/patch_zh.py index d16517e..c97f88d 100644 --- a/patch_zh.py +++ b/patch_zh.py @@ -18,14 +18,85 @@ import hashlib import base64 -BASE = '/Applications/Antigravity.app/Contents/Resources/app' +def get_app_base(): + # macOS Candidates + mac_candidates = [ + '/Applications/Antigravity.app/Contents/Resources/app', + os.path.expanduser('~/Applications/Antigravity.app/Contents/Resources/app') + ] + for c in mac_candidates: + if os.path.exists(c): + return c + + # Windows Candidates + localappdata = os.environ.get('LOCALAPPDATA', '') + if localappdata: + win_candidate = os.path.join(localappdata, 'Programs', 'Antigravity IDE', 'resources', 'app') + if os.path.exists(win_candidate): + return win_candidate + + return None + +BASE = get_app_base() +if not BASE: + BASE = '/Applications/Antigravity.app/Contents/Resources/app' + TARGETS = { - 'settings': f'{BASE}/out/jetskiAgent/main.js', - 'chat': f'{BASE}/extensions/antigravity/out/media/chat.js', - 'workbench': f'{BASE}/out/vs/workbench/workbench.desktop.main.js', + 'settings': os.path.join(BASE, 'out', 'jetskiAgent', 'main.js'), + 'chat': os.path.join(BASE, 'extensions', 'antigravity', 'out', 'media', 'chat.js'), + 'workbench': os.path.join(BASE, 'out', 'vs', 'workbench', 'workbench.desktop.main.js'), } -PRODUCT_JSON = f'{BASE}/product.json' +PRODUCT_JSON = os.path.join(BASE, 'product.json') +STUBBORN_RAW_STRINGS = [ + ('"For Unix shells, an allow list entry matches a command if its space-separated tokens form a prefix of the command\'s tokens. For PowerShell, the entry tokens may match any contiguous subsequence of the command tokens."', '"对于 Unix shell,如果允许列表条目的空格分隔 token 构成了命令 token 的前缀,则该条目匹配该命令。对于 PowerShell,条目 token 可以匹配命令 token 的任何连续子序列。"'), + ('"For Unix shells, an allow list entry matches a command if its space-separated tokens form a prefix of the command\'s tokens."', '"对于 Unix shell,如果允许列表条目的空格分隔 token 构成了命令 token 的前缀,则该条目匹配该命令。"'), + ('"For PowerShell, the entry tokens may match any contiguous subsequence of the command tokens."', '"对于 PowerShell,条目 token 可以匹配命令 token 的任何连续子序列。"'), + ('"When enabled, Agent can use browser tools to open URLs, read web pages, and interact with browser content. This allows the Agent access to important (and often critical) knowledge and methods of validation, but any browser integration does increase exposure to external malicious parties for security exploits."', '"启用后,Agent 可以使用浏览器工具打开 URL、读取网页并与浏览器内容交互。这允许 Agent 访问重要的(通常是关键的)知识和验证方法,但任何浏览器集成确实会增加对外部恶意方的暴露,从而带来安全风险。"'), + ('"When enabled, Agent can use browser tools to open URLs, read web pages, and interact with browser content."', '"启用后,Agent 可以使用浏览器工具打开 URL、读取网页并与浏览器内容交互。"'), + ('"This allows the Agent access to important (and often critical) knowledge and methods of validation, but any browser integration does increase exposure to external malicious parties for security exploits."', '"这允许 Agent 访问重要的(通常是关键的)知识和验证方法,但任何浏览器集成确实会增加对外部恶意方的暴露,从而带来安全风险。"'), + ('"Controls whether the agent can run custom JavaScript to automate complex browser actions."', '"控制 Agent 是否可以运行自定义 JavaScript 来自动化复杂的浏览器操作。"'), + ('"Manage your plan, credentials, and general preferences."', '"管理您的方案、凭据和常规偏好设置。"'), + ('"When toggled on, Antigravity IDE will use your AI credits to fulfill model requests once you\'re out of model quota."', '"开启后,当您的模型配额用尽时,Antigravity IDE 将使用您的 AI 积分来完成模型请求。"'), + ('"Antigravity IDE will always use your model quota first before using AI credits."', '"Antigravity IDE 将始终优先使用您的模型配额,然后再使用 AI 积分。"'), + ('"Controls whether terminal commands require your approval before running."', '"控制终端命令在运行前是否需要您的批准。"'), + ('"Note: A change to this setting will only apply to new messages sent to Agent. In-progress responses will use the previous setting value."', '"注意:对此设置的更改仅适用于发送给 Agent 的新消息。正在进行的响应将使用以前的设置值。"'), + ('"When toggled on, Antigravity IDE will use your AI credits to fulfill model requests once you\'re out of model quota. Antigravity IDE will always use your model quota first before using AI credits."', '"开启后,当您的模型配额用尽时,Antigravity IDE 将使用您的 AI 积分来完成模型请求。Antigravity IDE 将始终优先使用您的模型配额,然后再使用 AI 积分。"'), + ('"Configure default behaviors, skills, and MCP servers."', '"配置默认行为、技能和 MCP 服务器。"'), + ('"Token Usage"', '"Token 使用量"'), + ('"The breakdown below shows token usage from customizations like skills, rules, and MCP. If the budget is exceeded, large customizations will be truncated automatically."', '"下方细分显示了来自技能、规则和 MCP 等自定义项的 Token 使用情况。如果超出预算,大型自定义项将被自动截断。"'), + ('"Keyboard shortcuts for quick navigation and control."', '"用于快速导航和控制的键盘快捷键。"'), + ('"Recommended"', '"推荐"'), + ('"Open Conversation Picker"', '"打开对话选择器"'), + ('"Open File Search"', '"打开文件搜索"'), + ('"Focus Input"', '"聚焦输入框"'), + ('"New Conversation"', '"新建对话"'), + ('"Open Workspace Selector"', '"打开工作区选择器"'), + ('"Navigation"', '"导航"'), + ('"Go Back"', '"后退"'), + ('"Go Forward"', '"前进"'), + ('"File Picker"', '"文件选择器"'), + ('"Toggle Editor"', '"切换编辑器"'), + ('"Select Previous Conversation"', '"选择上一个对话"'), + ('"Select Next Conversation"', '"选择下一个对话"'), + ('"Open Settings"', '"打开设置"'), + ('"Conversation"', '"对话"'), + ('"Toggle Model Selector"', '"切换模型选择器"'), + ('"Start Voice Recording"', '"开始语音录制"'), + ('"Stop Voice Recording"', '"停止语音录制"'), + ('"Find in Pane"', '"在窗格中查找"'), + ('"Layout Controls"', '"布局控制"'), + ('"Toggle Sidebar"', '"切换侧边栏"'), + ('"Toggle Auxiliary Pane"', '"切换辅助窗格"'), + ('"Toggle Terminal"', '"切换终端"'), + ('"Zoom In"', '"放大"'), + ('"Zoom Out"', '"缩小"'), + ('"Reset Zoom"', '"重置缩放"'), + ('"Agent never asks for confirmation before executing terminal commands (except those in the Deny list). This provides the Agent with the maximum ability to operate over long periods without intervention, but also has the highest risk of an Agent executing an unsafe terminal command."', '"Agent 从不请求确认前执行终端命令(拒绝列表除外)。这为 Agent 提供了最大能力,但也具有最高风险。"'), + ('"Proceed In Sandbox"', '"在沙盒中继续"'), + ('"Terminal command automatically proceeds if the command runs inside the sandbox. Otherwise, it requests review."', '"如果命令在沙盒内运行,则自动继续。否则,请求审查。"'), + ('"Agent always asks for confirmation before executing terminal commands (except those in the Allow list)."', '"Agent 始终请求确认前执行终端命令(允许列表除外)。"'), +] def get_settings_replacements(): """Settings 面板 (jetskiAgent/main.js) 的替换对""" @@ -72,8 +143,7 @@ def get_settings_replacements(): ('label:"Tab Gitignore Access",description:"Allow Tab to view and edit the files in .gitignore. Use with caution if your .gitignore lists files containing credentia', 'label:"Tab Gitignore 访问",description:"允许 Tab 查看和编辑 .gitignore 中的文件。如果 .gitignore 中包含敏感凭据文件请谨慎使用'), # === Browser Screen === - ('label:"Enable Browser Tools",description:"When enabled, Agent can use browser tools to open URLs, read web pages, and interact with browser content. This allows t', - 'label:"启用浏览器工具",description:"启用后,Agent 可以使用浏览器工具打开 URL、读取网页并与浏览器内容互动。这允许'), + # (Browser Tools truncated string removed to prevent partial matches) ('label:"Browser Javascript Execution Policy",description:', 'label:"浏览器 JavaScript 执行策略",description:'), ('label:"Chrome Binary Path",description:"Path to the Chrome/Chromium executable. Leave empty for auto-detection.', 'label:"Chrome 可执行文件路径",description:"Chrome/Chromium 可执行文件的路径。留空则自动检测。'), @@ -144,7 +214,214 @@ def get_settings_replacements(): ('label:"Open Workspace"', 'label:"打开工作区"'), ('label:"Open New Workspace"', 'label:"打开新工作区"'), ('label:"Open New Remote Workspace"', 'label:"打开新远程工作区"'), - ] + # === v1.107.0 Settings updates === + ('{value:e0.TURBO,label:"Always Proceed",description:"Agent never asks for review. This maximizes the autonomy of the Agent, but also has the highest risk of the Agent operating over unsafe or injected Artifact content.",disabledInSecureMode:!0}', + '{value:e0.TURBO,label:"始终继续",description:"Agent 从不请求审查。这最大化了 Agent 的自主性,但也具有 Agent 操作不安全或注入的 Artifact 内容的最高风险。",disabledInSecureMode:!0}'), + ('{value:e0.ALWAYS,label:"Always Ask",description:"Agent always asks for review.",disabledInSecureMode:!1}', + '{value:e0.ALWAYS,label:"总是询问",description:"Agent 总是请求审查。",disabledInSecureMode:!1}'), + ('children:["Settings - ",e]', 'children:["设置 - ",e]'), + ('"aria-label":"Add context"', '"aria-label":"添加上下文"'), + ('tooltipText:"Edit Model"', 'tooltipText:"编辑模型"'), + # === Remaining settings translations === + ('children:["Select one of the ",t?"two":"three"," options. Agent settings and permissions can be further customized below."', + 'children:["从",t?"两个":"三个","个选项中选择一个。Agent 设置和权限可在下方进一步自定义。"'), + ('children:"Agent security mode"', 'children:"Agent 安全模式"'), + ('children:"Full access"', 'children:"完全访问"'), + ('children:"Agents have full access to your machine and external resources."', 'children:"Agent 可以完全访问您的计算机和外部资源。"'), + ('children:"Sandboxed"', 'children:"沙盒化"'), + ('children:"Agents run in a secure sandbox that restricts access to external resources outside of your trusted folders."', 'children:"Agent 运行在安全的沙盒中,限制访问信任文件夹以外的外部资源。"'), + ('children:"Strict"', 'children:"严格"'), + ('children:"Terminal commands always require review and the agent cannot access files outside of its given workspaces."', 'children:"终端命令始终需要审查,且 Agent 无法访问指定工作区以外的文件。"'), + ('require your approval before running.\\n\\nNote: A change to this setting will only apply to new messages sent to Agent. In-progress responses will use the previous setting value.', + '在运行前需要您的批准。\\n\\n注意:对此设置的更改仅适用于发送给 Agent 的新消息。正在进行的响应将使用以前的设置值。'), + ('label:"Enable Shell Integration"', 'label:"启用 Shell 集成"'), + ('description:"When enabled, Agent will use IDE\'s shell integration to detect and report terminal command execution."', + 'description:"启用后,Agent 将使用 IDE 的 Shell 集成来检测并报告终端命令的执行。"'), + ('children:"File Access"', 'children:"文件访问"'), + ('description:"Allows the agent to access files outside of your current workspace."', + 'description:"允许 Agent 访问当前工作区以外的文件。"'), + ('children:"Planning"', 'children:"规划"'), + ('description:"Specifies Agent\'s behavior when asking for review on artifacts, which are documents it creates to enable a richer conversation experience."', + 'description:"指定 Agent 在请求审查 Artifact(即为了提供更丰富的对话体验而创建的文档)时的行为。"'), + ('children:"Automation"', 'children:"自动化"'), + ('children:"History"', 'children:"历史记录"'), + ('children:"General"', 'children:"常规"'), + ('label:"Explain and Fix in Current Conversation"', 'label:"在当前对话中解释和修复"'), + ('description:"When enabled, \'Explain and Fix\' actions will continue in the current conversation instead of starting a new one."', + 'description:"启用后,“解释并修复”操作将在当前对话中继续,而不是开始新对话。"'), + ('children:"Advanced"', 'children:"高级"'), + ('children:"Advanced File Access"', 'children:"高级文件访问"'), + ('label:"Read Files",description:"Paths the agent can read."', 'label:"读取文件",description:"Agent 可以读取的路径。"'), + ('label:"Read Files",description:"Paths the agent can read inside this workspace."', 'label:"读取文件",description:"Agent 在此工作区中可以读取的路径。"'), + ('label:"Write Files",description:"Paths the agent can modify."', 'label:"写入文件",description:"Agent 可以修改的路径。"'), + ('label:"Write Files",description:"Paths the agent can modify inside this workspace."', 'label:"写入文件",description:"Agent 在此工作区中可以修改的路径。"'), + ('children:"Advanced Command Access"', 'children:"高级命令访问"'), + ('label:"Terminal Commands",description:"Terminal commands the agent can execute."', 'label:"终端命令",description:"Agent 可以执行的终端命令。"'), + ('label:"Terminal Commands",description:"Terminal commands the agent can execute in this workspace."', 'label:"终端命令",description:"Agent 在此工作区中可以执行的终端命令。"'), + ('label:"Commands Outside Sandbox",description:"Allow/deny agent command execution outside the sandbox."', + 'label:"沙盒外的命令",description:"允许/拒绝 Agent 在沙盒外执行命令。"'), + ('label:"Commands Outside Sandbox",description:"Commands the agent can run outside the sandbox."', + 'label:"沙盒外的命令",description:"Agent 可以在沙盒外运行的命令。"'), + ('label:"Commands Outside Sandbox",description:"Commands the agent can run outside the sandbox in this workspace."', + 'label:"沙盒外的命令",description:"Agent 在此工作区的沙盒外可以运行的命令。"'), + ('label:"MCP Tools",description:"Configure external tools via Model Context Protocol."', + 'label:"MCP 工具",description:"通过 Model Context Protocol 配置外部工具。"'), + ('label:"MCP Tools",description:"External tools the agent can call via Model Context Protocol."', + 'label:"MCP 工具",description:"Agent 可通过 Model Context Protocol 调用的外部工具。"'), + ('children:"Advanced Web Access"', 'children:"高级网络访问"'), + ('label:"Read URLs",description:"Allow/deny agent read access to specific URLs or domains."', + 'label:"读取 URL",description:"允许/拒绝 Agent 对特定 URL 或域名的读取访问。"'), + ('label:"Read URLs",description:"URLs the agent can read or open in the browser."', + 'label:"读取 URL",description:"Agent 可以在浏览器中读取或打开的 URL。"'), + ('label:"Read URLs",description:"URLs the agent can read or open in this workspace."', + 'label:"读取 URL",description:"Agent 在此工作区中可以读取或打开的 URL。"'), + ('label:"Execute URLs",description:"URLs the agent can actuate on using the browser."', + 'label:"执行 URL",description:"Agent 可以使用浏览器操作 the URL。"'), + ('label:"Execute URLs",description:"Allow/deny agent browser actuation access to specific URLs."', + 'label:"执行 URL",description:"允许/拒绝 Agent 对特定 URL 的浏览器操作访问。"'), + ('label:"Execute URLs",description:"URLs the agent can actuate on in this workspace."', + 'label:"执行 URL",description:"Agent 在此工作区中可以操作的 URL。"'), + ('label:t="Advanced Settings"', 'label:t="高级设置"'), + ('label:"Enable Demo Mode (Beta)"', 'label:"启用演示模式 (Beta)"'), + ('description:\'When enabled, your UI will be slightly modified to ensure more consistent demos. This is only recommended for demo purposes. In most cases, you can run "Antigravity: Start Demo Mode" and "Antigravity: Stop Demo Mode" to control this switch and update your ~/.gemini/antigravity data directory.\'', + 'description:\'启用后,您的 UI 将被稍微修改以确保演示的一致性。仅建议用于演示目的。在大多数情况下,您可以运行 "Antigravity: Start Demo Mode" 和 "Antigravity: Stop Demo Mode" 来控制此开关并更新您的 ~/.gemini/antigravity 数据目录。\''), + ('description:`When toggled on, ${r.product.nameShort} collects usage data to help Google enhance performance and features.`', + 'description:`开启后,${r.product.nameShort} 将收集使用数据,以帮助 Google 提升性能和功能。`'), + ('label:"Marketing Emails",description:`Receive product updates, tips, and promotions from Google ${r.product.nameShort} via email.`', + 'label:"营销邮件",description:`通过电子邮件接收来自 Google ${r.product.nameShort} 的产品更新、提示和促销信息。`'), + ('children:["By using this app, you agree to its",', 'children:["使用此应用即表示您同意其",'), + ('className:"text-primary hover:underline",children:"Terms of Service"', 'className:"text-primary hover:underline",children:"服务条款"'), + ('className:"text-lg font-medium mb-4",children:"Terms of Service & Data Use"', 'className:"text-lg font-medium mb-4",children:"服务条款与数据使用"'), + ('description:p(jt,{children:["Configure the browser subagent. It requires",', 'description:p(jt,{children:["配置浏览器子 Agent。它需要安装",'), + ('`Refreshes in ${n} day${n>1?"s":""}, ${a} hour${a>1?"s":""}`', '`将在 ${n} 天 ${a} 小时后刷新`'), + ('`Refreshes in ${a} hour${a>1?"s":""}, ${i} minute${i>1?"s":""}`', '`将在 ${a} 小时 ${i} 分钟后刷新`'), + ('`Refreshes in ${i} minute${i>1?"s":""}`', '`将在 ${i} 分钟后刷新`'), + ('description:"View your available model quota. Quota refreshes periodically based on your plan."', + 'description:"查看您可用的模型配额。配额会根据您的方案定期刷新。"'), + ('"% of the customization budget is available."', '"% 的定制预算当前可用。"'), + ('children:V?"Hide breakdown":`Show ${I.length} breakdown${I.length===1?"":"s"}`', + 'children:V?"隐藏明细":`显示 ${I.length} 项明细`'), + ('"Plugin: "', '"插件: "'), + ('children:["Plugins are packaged collections of skills and MCPs to help the Agent"," ",a?`in ${a} `:"","work with Google developer products. You can always change your choices in Settings."]', + 'children:["插件是技能和 MCP 的打包集合,用于帮助 Agent"," ",a?`在 ${a} `:"","中协同谷歌开发产品工作。您随时可以在设置中更改您的选择。"]'), + ('children:["Plugins are packaged collections of skills and MCPs to help the Agent in ",e," work with Google developer products. You can always change your choices in Settings."]', + 'children:["插件是技能和 MCP 的打包集合,用于帮助 Agent 在 ",e," 中协同谷歌开发产品工作。您随时可以在设置中更改您的选择。"]'), + ('children:"No MCP Servers"', 'children:"没有 MCP 服务器"'), + ('children:"You currently don\'t have any MCP Servers installed. Add an MCP server above or add a custom one via the MCP Config."', + 'children:"您当前未安装任何 MCP 服务器。请在上方添加 MCP 服务器,或通过 MCP 配置添加自定义服务器。"'), + ('label:"Account",description:"Manage your plan, credentials, and general preferences."', + 'label:"账户",description:"管理您的方案、凭据和常规偏好设置。"'), + ('label:"Appearance",description:"Configure the agent\'s visual theme and display preferences."', + 'label:"外观",description:"配置 Agent 的视觉主题和显示偏好设置。"'), + ('label:"Notifications",description:"Manage your notification preferences."', + 'label:"通知",description:"管理您的通知偏好设置。"'), + ('label:"Models",description:"Configure AI models and view your quota."', + 'label:"模型",description:"配置 AI 模型并查看您的配额。"'), + ('label:"Customizations",description:"Configure default behaviors, skills, and MCP servers."', + 'label:"自定义",description:"配置默认行为、技能和 MCP 服务器。"'), + ('label:"Browser Settings",description:"Configure the browser subagent. It requires Google Chrome to be installed."', + 'label:"浏览器设置",description:"配置浏览器子 Agent。它需要安装 Google Chrome。"'), + ('label:"Editor Settings",description:"Configure editor-specific behaviors and shortcuts."', + 'label:"编辑器设置",description:"配置编辑器特定的行为和快捷键。"'), + ('children:"Account & Plan"', 'children:"账户与方案"'), + ('label:"Email",description:a?"Peter Pan":n.email', 'label:"电子邮件",description:a?"Peter Pan":n.email'), + ('children:"Theme"', 'children:"主题"'), + ('children:"Chat Settings"', 'children:"聊天设置"'), + ('label:"Verbose agent chat",description:"Display and preserve intermediate thinking steps"', + 'label:"详细 Agent 聊天",description:"显示并保留中间思考步骤"'), + ('label:"Notification Settings",description:"To modify notification settings, open your operating system\'s system preferences."', + 'label:"通知设置",description:"要修改通知设置,请打开您操作系统的系统偏好设置。"'), + ('label:"Model Quota"', 'label:"模型配额"'), + ('children:"Actuation Permissions"', 'children:"执行操作权限"'), + ('label:"Browser Actuation Rules",description:"Configure allowed and denied URLs for browser actuation."', + 'label:"浏览器执行规则",description:"配置允许和拒绝的浏览器执行 URL。"'), + ('children:"Marketplace"', 'children:"市场"'), + ('description:"Changes the base URL on each extension page. You must restart Antigravity IDE to use the new marketplace after changing this value."', + 'description:"更改每个扩展页面的基础 URL。更改此值后,您必须重启 Antigravity IDE 才能使用新的市场。"'), + ('description:"Changes the base URL for marketplace search results. You must restart Antigravity IDE to use the new marketplace after changing this value."', + 'description:"更改市场搜索结果的基础 URL。更改此值后,您必须重启 Antigravity IDE 才能使用新的市场。"'), + ('children:"Selection Actions"', 'children:"选中操作"'), + ('label:"Editor Settings",description:"To modify editor settings, open Settings within the editor window."', + 'label:"编辑器设置",description:"要修改编辑器设置,请在编辑器窗口中打开设置。"'), + + # --- Sidebar --- + ('children:"Account"', 'children:"账户"'), + ('children:"Permissions"', 'children:"权限"'), + ('children:"Appearance"', 'children:"外观"'), + ('children:"Notifications"', 'children:"通知"'), + ('children:"Models"', 'children:"模型"'), + ('children:"Customizations"', 'children:"自定义"'), + ('children:"Browser"', 'children:"浏览器"'), + ('children:"Tab"', 'children:"Tab"'), + ('children:"Editor"', 'children:"编辑器"'), + ('children:"Workspaces"', 'children:"工作区"'), + ('children:"Shortcuts"', 'children:"快捷键"'), + + # --- Terminal Settings --- + ('children:"Controls whether terminal commands require your approval before running."', 'children:"控制终端命令在运行前是否需要您的批准。"'), + ('description:"Controls whether terminal commands require your approval before running."', 'description:"控制终端命令在运行前是否需要您的批准。"'), + ('"Note: A change to this setting will only apply to new messages sent to Agent. In-progress responses will use the previous setting value."', '"注意:对此设置的更改仅适用于发送给 Agent 的新消息。正在进行的响应将使用以前的设置值。"'), + + # --- Appearance Settings --- + ('children:"Configure the agent\'s visual theme and display preferences."', 'children:"配置 Agent 的视觉主题和显示偏好设置。"'), + ('description:"Configure the agent\'s visual theme and display preferences."', 'description:"配置 Agent 的视觉主题和显示偏好设置。"'), + + # --- Notifications Settings --- + ('children:"Manage your notification preferences."', 'children:"管理您的通知偏好设置。"'), + ('description:"Manage your notification preferences."', 'description:"管理您的通知偏好设置。"'), + ('children:"Notification Settings"', 'children:"通知设置"'), + ('children:"To modify notification settings, open your operating system\'s system preferences."', 'children:"要修改通知设置,请打开您操作系统的系统偏好设置。"'), + ('children:"Open System Preferences"', 'children:"打开系统偏好设置"'), + + # --- Models Settings --- + ('children:"Configure AI models and view your quota."', 'children:"配置 AI 模型并查看您的配额。"'), + ('description:"Configure AI models and view your quota."', 'description:"配置 AI 模型并查看您的配额。"'), + ('children:"Model Credits"', 'children:"模型积分"'), + ('children:"Enable AI Credit Overages"', 'children:"启用 AI 积分超额使用"'), + ('children:"When toggled on, Antigravity IDE will use your AI credits to fulfill model requests once you\'re out of model quota. Antigravity IDE will always use your model quota first before using AI credits."', 'children:"开启后,当您的模型配额用尽时,Antigravity IDE 将使用您的 AI 积分来完成模型请求。Antigravity IDE 将始终优先使用您的模型配额,然后再使用 AI 积分。"'), + ('children:"Available AI Credits: "', 'children:"可用 AI 积分: "'), + ('"Available AI Credits: "', '"可用 AI 积分: "'), + ('children:"See Activity"', 'children:"查看活动"'), + ('children:"Get More AI Credits"', 'children:"获取更多 AI 积分"'), + ('children:"Model Quota"', 'children:"模型配额"'), + ('children:"Refresh"', 'children:"刷新"'), + + # --- General Settings Dropdowns --- + ('children:"Request Review"', 'children:"请求审查"'), + ('children:"Agent Decides"', 'children:"Agent 决定"'), + ('children:"Always Proceed"', 'children:"始终继续"'), + + # --- Raw Strings Fallback --- + ('"Account"', '"账户"'), + ('"Permissions"', '"权限"'), + ('"Appearance"', '"外观"'), + ('"Notifications"', '"通知"'), + ('"Models"', '"模型"'), + ('"Customizations"', '"自定义"'), + ('"Browser"', '"浏览器"'), + ('"Tab"', '"Tab"'), + ('"Editor"', '"编辑器"'), + ('"Workspaces"', '"工作区"'), + ('"Shortcuts"', '"快捷键"'), + ('"Controls whether terminal commands require your approval before running."', '"控制终端命令在运行前是否需要您的批准。"'), + ('"Configure the agent\'s visual theme and display preferences."', '"配置 Agent 的视觉主题和显示偏好设置。"'), + ('"Manage your notification preferences."', '"管理您的通知偏好设置。"'), + ('"Notification Settings"', '"通知设置"'), + ('"To modify notification settings, open your operating system\'s system preferences."', '"要修改通知设置,请打开您操作系统的系统偏好设置。"'), + ('"Open System Preferences"', '"打开系统偏好设置"'), + ('"Configure AI models and view your quota."', '"配置 AI 模型并查看您的配额。"'), + ('"Model Credits"', '"模型积分"'), + ('"Enable AI Credit Overages"', '"启用 AI 积分超额使用"'), + ('"When toggled on, Antigravity IDE will use your AI credits to fulfill model requests once you\'re out of model quota. Antigravity IDE will always use your model quota first before using AI credits."', '"开启后,当您的模型配额用尽时,Antigravity IDE 将使用您的 AI 积分来完成模型请求。Antigravity IDE 将始终优先使用您的模型配额,然后再使用 AI 积分。"'), + ('"Available AI Credits: "', '"可用 AI 积分: "'), + ('"See Activity"', '"查看活动"'), + ('"Get More AI Credits"', '"获取更多 AI 积分"'), + ('"Model Quota"', '"模型配额"'), + ('"Refresh"', '"刷新"'), + ('"Request Review"', '"请求审查"'), + ('"Agent Decides"', '"Agent 决定"'), + ('"Always Proceed"', '"始终继续"'), + ] + STUBBORN_RAW_STRINGS def get_chat_replacements(): @@ -247,6 +524,10 @@ def get_chat_replacements(): # ============================================================ # 5. Status / State Messages # ============================================================ + ('"Thinking for "', '"思考中 "'), + ('"Thought for "', '"思考了 "'), + ('"Changes Overview"', '"更改概览"'), + ('"Terminal ("', '"终端 ("'), ('children:"Thinking"', 'children:"思考中"'), ('children:"Analyzed"', 'children:"已分析"'), ('children:"Installed"', 'children:"已安装"'), @@ -432,7 +713,14 @@ def get_chat_replacements(): ('children:"Added Annotation"', 'children:"已添加注释"'), ('children:"Edit Model"', 'children:"编辑模型"'), ('label:"Run"', 'label:"运行"'), - ] + # === v1.107.0 Chat updates === + ('children:"Open Diff"', 'children:"打开差异"'), + ('label:"Allow Once"', 'label:"允许一次"'), + ('label:"Deny"', 'label:"拒绝"'), + ('children:"Additional Options"', 'children:"其他选项"'), + ('label:"Try Again"', 'label:"再试一次"'), + ('title:"Add Context"', 'title:"添加上下文"'), + ] + STUBBORN_RAW_STRINGS def patch_file(filepath, replacements, name): @@ -450,20 +738,37 @@ def patch_file(filepath, replacements, name): else: print(f' ⏭️ 备份已存在: {os.path.basename(backup)}') - with open(filepath, 'r', encoding='utf-8', errors='replace') as f: + with open(filepath, 'r', encoding='utf-8', errors='replace', newline='') as f: content = f.read() count = 0 failed = [] + + import re for old, new in replacements: if old in content: content = content.replace(old, new) count += 1 else: + # Regex Fallback for raw strings + if old.startswith('"') and old.endswith('"'): + raw_eng = old[1:-1] + raw_chn = new[1:-1] + # Allow flexible whitespace and single/double quote escaping + escaped = re.escape(raw_eng).replace(r'\ ', r'\s+').replace(r"'", r"[\'\\]+").replace(r'"', r'[\"\\]+') + pattern = r'([\'"`>]|^)' + escaped + r'([\'"`<]|$)' + def repl(m): + return m.group(1) + raw_chn + m.group(2) + new_content, n = re.subn(pattern, repl, content) + if n > 0: + content = new_content + count += 1 + continue + failed.append(old[:50]) - with open(filepath, 'w', encoding='utf-8') as f: + with open(filepath, 'w', encoding='utf-8', newline='') as f: f.write(content) print(f' 🎉 {name}: 成功替换 {count}/{len(replacements)} 处') @@ -491,8 +796,8 @@ def update_checksums(): checksums = product.get('checksums', {}) updated = 0 for key in checksums: - for prefix in [f'{BASE}/out/', f'{BASE}/']: - filepath = prefix + key + for prefix in [os.path.join(BASE, 'out'), BASE]: + filepath = os.path.normpath(os.path.join(prefix, key)) if os.path.exists(filepath): with open(filepath, 'rb') as f: data = f.read() @@ -629,7 +934,253 @@ def get_workbench_replacements(): ('label:"Open Agent"', 'label:"打开 Agent"'), ('label:"Reset to default"', 'label:"重置为默认"'), ('label:"Submit"', 'label:"提交"'), - ] + # === v1.107.0 Workbench updates === + ('t.ON="On",t.OFF="Off"', 't.ON="开",t.OFF="关"'), + ('children:"Terminal execution policy"', 'children:"终端执行策略"'), + ('children:"Review policy"', 'children:"审查策略"'), + ('children:"JavaScript execution policy"', 'children:"JavaScript 执行策略"'), + ('children:"Always Proceed"', 'children:"始终继续"'), + ('children:"Request Review"', 'children:"请求审查"'), + ('children:"Always Ask"', 'children:"始终询问"'), + ('children:"Disabled"', 'children:"已禁用"'), + ('{value:Vz.TURBO,label:"Always Proceed",description:"Agent never asks for review. This maximizes the autonomy of the Agent, but also has the highest risk of the Agent operating over unsafe or injected Artifact content.",disabledInSecureMode:!0}', + '{value:Vz.TURBO,label:"始终继续",description:"Agent 从不请求审查。这最大化了 Agent 的自主性,但也具有 Agent 操作不安全或注入的 Artifact 内容的最高风险。",disabledInSecureMode:!0}'), + ('{value:Vz.ALWAYS,label:"Always Ask",description:"Agent always asks for review.",disabledInSecureMode:!1}', + '{value:Vz.ALWAYS,label:"始终询问",description:"Agent 始终请求审查。",disabledInSecureMode:!1}'), + ('{label:"Always Proceed",value:$9.TURBO,description:"Trust the agent to do tasks end-to-end",isDefaultWhenAvailable:!0}', + '{label:"始终继续",value:$9.TURBO,description:"信任 Agent 端到端地执行任务",isDefaultWhenAvailable:!0}'), + ('{label:"Agent Decides",value:$9.AUTO,description:"Assist the agent to complete tasks"}', + '{label:"Agent 决定",value:$9.AUTO,description:"辅助 Agent 完成任务"}'), + ('{label:"Request Review",value:$9.ALWAYS,description:"Collaborate with the agent to complete tasks"}', + '{label:"请求审查",value:$9.ALWAYS,description:"与 Agent 协作完成任务"}'), + ('{label:"Always Proceed",value:$U.EAGER,description:"Always auto-execute commands unless they are in your deny list. This also allows Agent to auto-execute Browser controls."}', + '{label:"始终继续",value:$U.EAGER,description:"始终自动执行命令,除非它们在您的拒绝列表中。这也允许 Agent 自动执行浏览器控制。"}'), + ('{label:"Request Review",value:$U.OFF,description:"Never auto-execute commands unless they are in your allow list.",isDefaultWhenAvailable:!0}', + '{label:"请求审查",value:$U.OFF,description:"从不自动执行命令,除非它们在您的允许列表中。",isDefaultWhenAvailable:!0}'), + ('{label:"Slow",value:Fwe.SLOW}', '{label:"慢速",value:Fwe.SLOW}'), + ('{label:"Fast",value:Fwe.FAST,isDefaultWhenAvailable:!0}', '{label:"快速",value:Fwe.FAST,isDefaultWhenAvailable:!0}'), + # === Remaining workbench/feedback/shortcuts translations === + ('label:"Open Conversation Picker"', 'label:"打开对话选择器"'), + ('label:"Open File Search"', 'label:"打开文件搜索"'), + ('label:"Focus Input"', 'label:"聚焦输入框"'), + ('label:"New Conversation"', 'label:"新建对话"'), + ('label:"Open Workspace Selector"', 'label:"打开工作区选择器"'), + ('label:"Go Back"', 'label:"后退"'), + ('label:"Go Forward"', 'label:"前进"'), + ('label:"File Picker"', 'label:"文件选择器"'), + ('label:"Toggle Editor"', 'label:"切换编辑器"'), + ('label:"Select Previous Conversation"', 'label:"选择上一个对话"'), + ('label:"Select Next Conversation"', 'label:"选择下一个对话"'), + ('label:"Toggle Model Selector"', 'label:"切换模型选择器"'), + ('label:"Start Voice Recording"', 'label:"开始语音录制"'), + ('label:"Stop Voice Recording"', 'label:"停止语音录制"'), + ('label:"Find in Pane"', 'label:"在窗格中查找"'), + ('label:"Toggle Sidebar"', 'label:"切换侧边栏"'), + ('label:"Toggle Auxiliary Pane"', 'label:"切换辅助窗格"'), + ('label:"Toggle Terminal"', 'label:"切换终端"'), + ('label:"Open Settings"', 'label:"打开设置"'), + ('label:"Zoom In"', 'label:"放大"'), + ('label:"Zoom Out"', 'label:"缩小"'), + ('label:"Reset Zoom"', 'label:"重置缩放"'), + ('children:"Recommended"', 'children:"推荐"'), + ('children:"Navigation"', 'children:"导航"'), + ('children:"Conversation"', 'children:"对话"'), + ('children:"Layout Controls"', 'children:"布局控制"'), + ('children:"Shortcuts"', 'children:"快捷键"'), + ('description:"Keyboard shortcuts for quick navigation and control."', 'description:"用于快速导航和控制的键盘快捷键。"'), + ('children:"Feedback Type"', 'children:"反馈类型"'), + ('"bug-report":"Bug Report"', '"bug-report":"Bug 报告"'), + ('"feature-request":"Feature Request"', '"feature-request":"功能请求"'), + ('"auth-and-billing":"Auth and Billing"', '"auth-and-billing":"认证与计费"'), + ('"general-feedback":"General Feedback"', '"general-feedback":"常规反馈"'), + ('children:"Please describe the issue in detail. The more actionable your feedback, the quicker our team can address your request. Some helpful information includes:"', + 'children:"请详细描述该问题。您的反馈越具可操作性,我们的团队就能越快处理您的请求。一些有帮助的信息包括:"'), + ('children:"Steps to reproduce the issue"', 'children:"重现问题的步骤"'), + ('children:"Expected behavior"', 'children:"预期行为"'), + ('children:"Actual behavior"', 'children:"实际行为"'), + ('children:"Any error messages"', 'children:"任何错误消息"'), + ('children:"Any relevant information"', 'children:"任何相关信息"'), + ('"bug-report":"Describe the bug you encountered..."', '"bug-report":"请描述您遇到的 Bug..."'), + ('children:"Steps to Reproduce"', 'children:"重现步骤"'), + ('placeholder:"Please list the steps to reproduce the issue"', 'placeholder:"请列出重现该问题的步骤"'), + ('children:"Attach a screenshot (optional)"', 'children:"附加屏幕截图 (可选)"'), + ('label:"Attach Antigravity server logs"', 'label:"附加 Antigravity 服务器日志"'), + ('label:"Send feedback as "+e.email', 'label:"发送反馈,身份为:"+e.email'), + ('children:"We recommend attaching logs. Attaching logs will help the Antigravity team act on and prioritize your feedback."', + 'children:"我们建议附加日志。附加日志将帮助 Antigravity 团队针对您的反馈进行处理并排定优先级。"'), + ('title:"Model quota reached"', 'title:"已达到模型配额限制"'), + ("` Your plan's baseline quota will refresh on ${o}.`", "` 您方案的基准配额将在 ${o} 刷新。`"), + ('label:d||"Upgrade"', 'label:d||"升级"'), + ('children:n.userTier?.upgradeButtonText||"Upgrade"', 'children:n.userTier?.upgradeButtonText||"升级"'), + + # ============================================================ + # 11. v1.41+ 新增 label 翻译(从实际安装文件扫描) + # ============================================================ + # Settings 面板 - 新增设置项 + ('label:"Strict Mode"', 'label:"严格模式"'), + ('label:"Auto-Expand Changes Overview"', 'label:"自动展开更改概览"'), + ('label:"Verbose agent chat"', 'label:"详细 Agent 对话"'), + ('label:"Enable Sounds for Agent"', 'label:"Agent 声音提示"'), + ('label:"Enable Browser Tools"', 'label:"启用浏览器工具"'), + ('label:"Chrome Binary Path"', 'label:"Chrome 可执行文件路径"'), + ('label:"Browser User Profile Path"', 'label:"浏览器用户配置路径"'), + ('label:"Browser CDP Port"', 'label:"浏览器 CDP 端口"'), + ('label:"Browser Javascript Execution Policy"', 'label:"浏览器 JavaScript 执行策略"'), + ('label:"Browser URL Allowlist"', 'label:"浏览器 URL 允许列表"'), + ('label:"Agent Non-Workspace File Access"', 'label:"Agent 非工作区文件访问"'), + ('label:"Agent Host Address"', 'label:"Agent 主机地址"'), + ('label:"Allow List Terminal Commands"', 'label:"终端命令允许列表"'), + ('label:"Deny List Terminal Commands"', 'label:"终端命令拒绝列表"'), + ('label:"Enable Terminal Sandbox"', 'label:"启用终端沙盒"'), + ('label:"Enable Remote Control"', 'label:"启用远程控制"'), + ('label:"Enable Overages"', 'label:"启用超额用量"'), + ('label:"Sandbox Allow Network"', 'label:"沙盒允许网络"'), + ('label:"Include Jetski Default Customizations"', 'label:"包含 Jetski 默认自定义项"'), + # Settings 面板 - 侧边栏分类 + ('label:"Knowledge"', 'label:"知识库"'), + ('label:"Rules"', 'label:"规则"'), + ('label:"Workflows"', 'label:"工作流"'), + ('label:"MCP Servers"', 'label:"MCP 服务器"'), + ('label:"Screen Recording"', 'label:"屏幕录制"'), + ('label:"Screenshot"', 'label:"截图"'), + # 对话操作 + ('label:"Archive this conversation"', 'label:"归档此对话"'), + ('label:"Archive / Restore"', 'label:"归档/恢复"'), + ('label:"Delete Conversation"', 'label:"删除对话"'), + ('label:"Copy conversation markdown"', 'label:"复制对话 Markdown"'), + ('label:"Conversation History"', 'label:"对话历史"'), + ('label:"Open Conversation History"', 'label:"打开对话历史"'), + ('label:"Open Conversation"', 'label:"打开对话"'), + ('label:"Mark as Read"', 'label:"标记为已读"'), + ('label:"Mark as Unread"', 'label:"标记为未读"'), + ('label:"Ask Agent for Help"', 'label:"向 Agent 寻求帮助"'), + # Mention(提及) + ('label:"Mention"', 'label:"提及"'), + ('label:"Mention Selection"', 'label:"提及选中内容"'), + ('label:"Mentions"', 'label:"提及项"'), + # Diff 操作 + ('label:"Reject hunk"', 'label:"拒绝代码块"'), + ('label:"Reject Step"', 'label:"拒绝此步骤"'), + ('label:"Accept Step"', 'label:"接受此步骤"'), + # Toggle 操作 + ('label:"Toggle Dev View"', 'label:"切换开发视图"'), + ('label:"Toggle Developer Tools"', 'label:"切换开发工具"'), + ('label:"Toggle Fullscreen"', 'label:"切换全屏"'), + ('label:"Toggle Voice Recording"', 'label:"切换语音录制"'), + ('label:"Toggle Environment Selector"', 'label:"切换环境选择器"'), + ('label:"Toggle Project Selector"', 'label:"切换项目选择器"'), + # 运行/执行 + ('label:"Run (unsandboxed)"', 'label:"运行(不沙盒)"'), + ('label:"Allow in Conversation"', 'label:"在对话中允许"'), + # 账号/购买 + ('label:"Purchase Credits"', 'label:"购买积分"'), + ('label:"See Plans"', 'label:"查看方案"'), + ('label:"Enable Demo Mode (Beta)"', 'label:"启用演示模式 (Beta)"'), + ('label:"Provide feedback"', 'label:"提供反馈"'), + ('label:"Start fresh"', 'label:"重新开始"'), + ('label:"Check for Updates"', 'label:"检查更新"'), + # 导入/配置 + ('label:"Import from VS Code"', 'label:"从 VS Code 导入"'), + ('label:"Import from Cursor"', 'label:"从 Cursor 导入"'), + ('label:"Import from Windsurf"', 'label:"从 Windsurf 导入"'), + ('label:"Import from Cider"', 'label:"从 Cider 导入"'), + ('label:"Use theme to be imported with settings"', 'label:"导入设置时使用主题"'), + # 其他常用 label + ('label:"Scheduled Tasks"', 'label:"计划任务"'), + ('label:"New Agent Script"', 'label:"新建 Agent 脚本"'), + ('label:"Restart Main Language Server"', 'label:"重启主语言服务器"'), + + # ============================================================ + # 12. v1.41+ 新增 children 翻译 + # ============================================================ + # 对话历史 / 时间分组 + ('children:"Today"', 'children:"今天"'), + ('children:"Yesterday"', 'children:"昨天"'), + ('children:"Past Conversations"', 'children:"过去的对话"'), + ('children:"Pinned Conversations"', 'children:"已置顶对话"'), + ('children:"Sort Conversations"', 'children:"排序对话"'), + ('children:"No conversations yet"', 'children:"暂无对话"'), + ('children:"Delete Conversation"', 'children:"删除对话"'), + # 模型选择器 + ('children:"Experimental"', 'children:"实验性"'), + ('children:"No Model Selected"', 'children:"未选择模型"'), + ('children:"No models available"', 'children:"暂无可用模型"'), + ('children:"Models Tab"', 'children:"模型标签"'), + # 空状态提示 + ('children:"No background tasks"', 'children:"无后台任务"'), + ('children:"No conversations yet"', 'children:"暂无对话"'), + ('children:"No artifacts generated."', 'children:"未生成产物。"'), + ('children:"No changes to review"', 'children:"无需审查的更改"'), + ('children:"No internet. Agent features may not work."', 'children:"无网络连接,Agent 功能可能无法使用。"'), + ('children:"No items found"', 'children:"未找到项目"'), + # 设置 / 安全 + ('children:"Execute Javascript policy"', 'children:"JavaScript 执行策略"'), + ('children:"Review Changes"', 'children:"审查更改"'), + ('children:"Security Notice & Data Use"', 'children:"安全说明与数据使用"'), + # 知识库 / 技能 / 规则 + ('children:"Knowledge feature is not available."', 'children:"知识库功能不可用。"'), + ('children:"Rules help guide the behavior of Agent."', 'children:"规则有助于引导 Agent 的行为。"'), + ('children:"Skills are instructions that extend what Agent can do."', 'children:"技能是扩展 Agent 功能的指令。"'), + ('children:"Skills"', 'children:"技能"'), + # 其他状态/操作 + ('children:"Thinking..."', 'children:"思考中..."'), + ('children:"Proceed"', 'children:"继续"'), + ('children:"Proceed Anyways"', 'children:"无论如何继续"'), + ('children:"Skip"', 'children:"跳过"'), + ('children:"Skipped"', 'children:"已跳过"'), + ('children:"Save"', 'children:"保存"'), + ('children:"Rename"', 'children:"重命名"'), + ('children:"Reset"', 'children:"重置"'), + ('children:"Restart"', 'children:"重启"'), + ('children:"Refresh"', 'children:"刷新"'), + ('children:"Refresh rules"', 'children:"刷新规则"'), + ('children:"Refresh workflows"', 'children:"刷新工作流"'), + ('children:"Refresh skills"', 'children:"刷新技能"'), + ('children:"Get Logs"', 'children:"获取日志"'), + ('children:"View Logs"', 'children:"查看日志"'), + ('children:"View customizations"', 'children:"查看自定义"'), + ('children:"View documentation"', 'children:"查看文档"'), + ('children:"View MCP settings"', 'children:"查看 MCP 设置"'), + ('children:"View Debug"', 'children:"查看调试"'), + ('children:"View plans"', 'children:"查看计划"'), + ('children:"Send Feedback"', 'children:"发送反馈"'), + ('children:"See all"', 'children:"查看全部"'), + ('children:"Show more"', 'children:"显示更多"'), + ('children:"Open Editor"', 'children:"打开编辑器"'), + ('children:"History"', 'children:"历史"'), + ('children:"Environment"', 'children:"环境"'), + ('children:"Extensions"', 'children:"扩展"'), + ('children:"Keybindings"', 'children:"键盘快捷键"'), + ('children:"Input"', 'children:"输入"'), + ('children:"Output"', 'children:"输出"'), + ('children:"Preview"', 'children:"预览"'), + ('children:"Filter"', 'children:"筛选"'), + ('children:"Install"', 'children:"安装"'), + ('children:"Expand"', 'children:"展开"'), + ('children:"Launch"', 'children:"启动"'), + ('children:"Restore"', 'children:"恢复"'), + ('children:"Project"', 'children:"项目"'), + ('children:"Projects"', 'children:"项目"'), + ('children:"Schedule"', 'children:"计划"'), + # 工具/MCP + ('children:"MCP Servers Disabled"', 'children:"MCP 服务器已禁用"'), + ('children:"MCP Error"', 'children:"MCP 错误"'), + ('children:"MCP Store"', 'children:"MCP 商店"'), + ('children:"Manage MCP Servers"', 'children:"管理 MCP 服务器"'), + ('children:"Your administrator has disabled MCP servers."', 'children:"您的管理员已禁用 MCP 服务器。"'), + # 占位文本 + ('placeholder:"Search conversations..."', 'placeholder:"搜索对话..."'), + ('placeholder:"Ask Agent anything..."', 'placeholder:"向 Agent 提问..."'), + ('placeholder:"Search files..."', 'placeholder:"搜索文件..."'), + # title 属性补充 + ('title:"Reject hunk"', 'title:"拒绝代码块"'), + ('title:"Screen Recording"', 'title:"屏幕录制"'), + ('title:"Conversation History"', 'title:"对话历史"'), + ('title:"Knowledge"', 'title:"知识库"'), + ('title:"Rules"', 'title:"规则"'), + ('title:"Workflows"', 'title:"工作流"'), + ('title:"MCP Servers"', 'title:"MCP 服务器"'), + ] + STUBBORN_RAW_STRINGS def apply_patch(): @@ -640,8 +1191,12 @@ def apply_patch(): total += patch_file(TARGETS['settings'], get_settings_replacements(), 'Settings') print() - print('📦 [2/4] 汉化 Agent 聊天面板 (chat.js)...') - total += patch_file(TARGETS['chat'], get_chat_replacements(), 'Chat') + print('📦 [2/4] 汉化 Agent 聊天面板 (chat.js / workbench)...') + if os.path.exists(TARGETS['chat']): + total += patch_file(TARGETS['chat'], get_chat_replacements(), 'Chat') + else: + print(' ℹ️ chat.js 不存在,应用 Chat 替换到 workbench.desktop.main.js') + total += patch_file(TARGETS['workbench'], get_chat_replacements(), 'Chat in Workbench') print() print('📦 [3/4] 汉化快速设置面板 (workbench.desktop.main.js)...') @@ -652,7 +1207,7 @@ def apply_patch(): update_checksums() print(f'\n🎉 全部完成!共替换 {total} 处') - print('📌 请完全退出 Antigravity (Cmd+Q) 后重新打开即可生效') + print('📌 请重启 Antigravity 以生效') def revert_patch(): @@ -671,7 +1226,7 @@ def revert_patch(): shutil.copy2(pj_backup, PRODUCT_JSON) print(f' ✅ 已恢复: product.json') - print('📌 请完全退出 Antigravity (Cmd+Q) 后重新打开即可生效') + print('📌 请重启 Antigravity 以生效') if __name__ == '__main__': diff --git a/poc_observer.js b/poc_observer.js new file mode 100644 index 0000000..851a4a1 --- /dev/null +++ b/poc_observer.js @@ -0,0 +1,134 @@ +// [AntigravityChinesePack PoC injected] +(function() { + console.log("[AntigravityChinesePack] MutationObserver PoC loaded!"); + + const dict = { + "Conversation mode": "对话模式", + "Customizations": "自定义", + "Rules": "规则", + "Workflows": "工作流", + "MCP Servers": "MCP 服务器", + "History": "历史记录", + "Delete Conversation": "删除对话", + "Cancel": "取消", + "Confirm": "确认", + "Close": "关闭", + "Open": "打开", + "Thinking": "思考中", + "Analyzed": "已分析", + "Error": "错误", + "Good": "好", + "Bad": "差", + "Copy": "复制", + "Paste": "粘贴", + "Export": "导出", + "Enable": "启用", + "Settings - ": "设置 - ", + "Start conversation": "开始对话", + "Good response": "好的响应", + "Bad response": "差的响应", + "Planning": "规划", + "Fast": "快速直跑", + "Artifacts": "产物", + "Sources": "来源", + "Agent Auto-Fix Lints": "Agent 自动修复 Lint", + "Strict Mode": "严格模式", + "Review Policy": "审查策略", + "Terminal Command Auto Execution": "终端命令自动执行", + "Agent Gitignore Access": "Agent Gitignore 访问", + "Auto-Continue": "自动继续", + "Conversation History": "对话历史记录", + "Knowledge": "知识库", + "Tab to Jump": "Tab 跳转", + "Suggestions in Editor": "编辑器中的建议", + "Browser URL Allowlist": "浏览器 URL 允许列表", + "Account": "账户", + "Appearance": "外观", + "Models": "模型", + "Editor Settings": "编辑器设置" + }; + + function translateTextNode(node) { + if (node.nodeType === Node.TEXT_NODE) { + const originalText = node.nodeValue; + let text = originalText.trim(); + if (!text) return; + + // 精确匹配 + if (dict[text]) { + node.nodeValue = originalText.replace(text, dict[text]); + return; + } + + // 正则 / 动态拼接匹配 + if (text.startsWith("Thinking for ")) { + node.nodeValue = originalText.replace(text, "思考中 " + text.substring("Thinking for ".length)); + return; + } + if (text.startsWith("Thought for ")) { + node.nodeValue = originalText.replace(text, "思考了 " + text.substring("Thought for ".length)); + return; + } + if (text.startsWith("Changes Overview (")) { + node.nodeValue = originalText.replace(text, text.replace("Changes Overview", "更改概览")); + return; + } + if (text.startsWith("Terminal (") && text.includes(")")) { + node.nodeValue = originalText.replace(text, text.replace("Terminal", "终端")); + return; + } + + // 简单的包含匹配(安全起见只处理较长的短语) + if (text === "Conversation mode") { // Double check for inner texts + node.nodeValue = "对话模式"; + } + } + } + + function walkAndTranslate(node) { + if (!node || !node.tagName) return; + if (node.tagName === 'SCRIPT' || node.tagName === 'STYLE') return; + + // 如果是文本节点,上面的逻辑会处理,但 walk 主要是传给 element + node.childNodes.forEach(child => { + if (child.nodeType === Node.TEXT_NODE) { + translateTextNode(child); + } else if (child.nodeType === Node.ELEMENT_NODE) { + walkAndTranslate(child); + } + }); + } + + let isTranslating = false; + const observer = new MutationObserver((mutations) => { + if (isTranslating) return; + isTranslating = true; + mutations.forEach((mutation) => { + if (mutation.type === 'childList') { + mutation.addedNodes.forEach(node => { + if (node.nodeType === Node.ELEMENT_NODE) { + walkAndTranslate(node); + } else if (node.nodeType === Node.TEXT_NODE) { + translateTextNode(node); + } + }); + } else if (mutation.type === 'characterData') { + translateTextNode(mutation.target); + } + }); + isTranslating = false; + }); + + function init() { + if (document.body) { + walkAndTranslate(document.body); + observer.observe(document.body, { childList: true, subtree: true, characterData: true }); + } + } + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } +})(); diff --git a/refactor.js b/refactor.js new file mode 100644 index 0000000..3a111e0 --- /dev/null +++ b/refactor.js @@ -0,0 +1,65 @@ +const fs = require('fs'); +const path = require('path'); + +function extractStrings() { + const extCode = fs.readFileSync('extension.js', 'utf-8'); + const dict = {}; + + // Helper to extract string from between quotes + function getInsideQuotes(s) { + const match = s.match(/(?:children|label|title|placeholder|description|text|tooltip|tooltipText|aria-label):(?:`([^`]+)`|"([^"]+)"|'([^']+)')/); + if (match) { + return match[1] || match[2] || match[3]; + } + + // Match pure strings like '"English"', '"\u4e2d\u6587"' + const pureMatch = s.match(/^"([^"]+)"$/); + if (pureMatch) return pureMatch[1]; + + return null; + } + + // We look for arrays like ['...','...'] + const regex = /\[\s*'([^']*)'\s*,\s*'([^']*)'\s*\]/g; + let match; + let count = 0; + while ((match = regex.exec(extCode)) !== null) { + let engRaw = match[1]; + let zhRaw = match[2]; + + // Handle escaped quotes in python/js string representation + engRaw = engRaw.replace(/\\"/g, '"'); + zhRaw = zhRaw.replace(/\\"/g, '"'); + zhRaw = zhRaw.replace(/\\u([0-9a-fA-F]{4})/g, (m, c) => String.fromCharCode(parseInt(c, 16))); + + let eng = getInsideQuotes(engRaw); + let zh = getInsideQuotes(zhRaw); + + if (!eng && engRaw.startsWith('{') && engRaw.includes('label:"')) { + eng = engRaw.match(/label:"([^"]+)"/)?.[1]; + zh = zhRaw.match(/label:"([^"]+)"/)?.[1]; + } + + // If we still didn't find the key, just try generic quote extraction + if (!eng) { + eng = engRaw.match(/"([^"]+)"/)?.[1]; + zh = zhRaw.match(/"([^"]+)"/)?.[1]; + } + + if (eng && zh && eng !== zh && !eng.startsWith('${') && !eng.includes('"+')) { + dict[eng.trim()] = zh.trim(); + count++; + } + } + + // Add missing/dynamic manual entries + dict["Thinking for "] = "思考中 "; + dict["Thought for "] = "思考了 "; + dict["Changes Overview"] = "更改概览"; + dict["Settings - "] = "设置 - "; + + console.log(`Extracted ${count} items into dictionary.`); + fs.writeFileSync('zh_dictionary.json', JSON.stringify(dict, null, 2), 'utf-8'); +} + +extractStrings(); diff --git a/scan_children_chat.txt b/scan_children_chat.txt new file mode 100644 index 0000000..e69de29 diff --git a/scan_labels_settings.txt b/scan_labels_settings.txt new file mode 100644 index 0000000..e69de29 diff --git a/scan_workbench_children.txt b/scan_workbench_children.txt new file mode 100644 index 0000000..c1c9872 --- /dev/null +++ b/scan_workbench_children.txt @@ -0,0 +1,458 @@ +Accept +Accept all +Access +Actionable +Actual behavior +Add Context +Add Folder +Add Model +Add Scheduled Task +Add them to allow future interactions +Additional Options +Agent +Agent Action DOM Diffs: +Agent Script Command Configuration +AI may make mistakes. Double-check all generated code. +All tasks run as Flash. +Alt text: +Always Ask +Always Proceed +An error ID that helps the team investigate the error. +An error was thrown. +An unknown error occurred +Antigravity would like to use the browser. +Any error messages +Any error messages seen when trying to log in +Any relevant information +Approve +Arguments Schema: +Artifact Comments +Artifact Name +Attach the trajectory ID to the feedback form +Auto-run Unsupported +Back to parent agent +Back to Scheduled Tasks +Bad response +Best of +Best of N mode is not available +Blocked, needs input +Browser Mode: +Browser Tool Set Mode: +Browser Tools: +Build with Google +Built-In +Bytes +Cache: +Cancel +Cancel step +Cancel task +Cannot send message to subagent. +Chat Model Metadata +Checking Roadwarrior Installation... +Choose setup flow +Clear NUX state +Cleared Count +Click Feedback: +Click here to learn more +Close +Close (Escape) +Close Agent View +Close Folder +Cloudtop Host +Command +Command Center +Command Line +Comment +Comments +Configure +Configure Branches +Configure Roadwarrior +Configure Your Editor +Configure your editor settings below. +Configure your keybindings. +Confirm Undo +Confirmation required to execute this step +Connect to an existing conversation +Connect to Cloudtop +Continue with different account +Conversation +Conversation History +Copied +Copy Config Path +Copy Path +Copy the trajectory ID +Copy Workspace Name +Count +Crash details: +Create +Create a project in the sidebar first +Create New Project +Created: +Custom +Custom models are only supported on Linux machines. +Custom Reminder: +Custom URI +Customizations +Daily +Debug Mode +Debug Sidebar +Decline +Default +Default Branch +Delete +Delete Conversation +Delete pending message +Delete Project +Delete Task +Denied Sites +Deny +Description: +Details +Dev +Developer Menu +Disabled +Dismiss +Display Options +Document Answers +Drop to add to Agent +Dynamic Wait Tool: +Edit rule +Edit workflow +Edit your SSH configuration +Encountered and error while running the sidecar. +Enter Agent ID +Enter Google Cloud Project Details +Environment +Ephemeral Options: +Error +Error Details: +Error loading Browser recording +Error rendering playback +Events +Execute Javascript policy +Execution Command +Expand +Expected behavior +Experimental +Extensions +Failed to authenticate +Failed to enable server, click to see details. +Failed to load conversation +Failed to load image +Failed to move changes +Failed to read file content +FAQ +Features +Feedback +Fetched network request for page. +Fetched network requests for page. +File Comments +File Diff Comments +File not found +Files to edit: +Filter +Finalizing transcription... +Focus Editor +For turn +Found references to +Full Metadata +Full output written to +Get Logs +Global +Go Back +Go Forward +Goal +Good response +Google Chrome +Google Cloud Project ID +Google Drive Access +Google Privacy Policy +Group By +Having trouble? Let us know +Hide 0s +Hide Editor +History +Hourly +How this feature would help you and other users +Image Answers +Image Diff Not Supported +Image rendering blocked (strict mode enabled) +Image URL: +Images +Input +Input: +Install +Installed +JavaScript execution policy +JavaScript Result +Keybindings +Knowledge feature is not available. +Knowledge Generation +Language Server Crashed +Last Updated +Launch +Launching the browser... +Learn more +Learn more. +License: +List resources: +Loading Browser recording... +Loading conversation... +Loading events... +Loading logs... +Loading MCP servers +Loading models... +Loading Notebook View... +Loading plugins... +Loading skills... +Loading summary... +Loading... +Location +Manage MCP Servers +Manually set Agent ID +Match case (Aa) +Match whole word (ab) +Max Context Characters (optional): +Max Tokens +MCP Error +MCP Servers Disabled +MCP Store +Merge Strategy: +Metadata: +Metric +Mixins +Model +Model Label +Model URL +Models Tab +Modified +Modified files: +Multi-conversation view is not available +Multi-select +Name +Name can only contain letters, spaces, and hyphens. +Needs Attention +New +New Conversation +New Fig Workspace +New Project +New Scheduled Task +New Workspace +Next +Next match (Enter) +No artifacts generated. +No background tasks +No browser pages open +No build files are updated. +No changes to review +No chat model metadata available for this generator +No chat model metadata available in latest generator metadata +No content available for this resource +No conversations yet +No events recorded. +No file changes. +No files or folders found +No generator metadata available +No internet. Agent features may not work. +No items found +No Javascript Result Output +No log outputs for this task +No matching results +No message prompts available +No models available +No plugins available. +No Project +No projects found +No resources available +No results found +No skills loaded. +No subagents +No trajectories available +No workspaces yet +Not Found +Not scheduled +Once you are authenticated, reload your window. +Open +Open allowlist +Open Diff +Open Editor +Open extracted DOM in editor +Open in Cider +Open Page in Background: +Open System Browser +Open Trajectory Dashboard +Open URL +Opt-out +Or for gMac: +Output +Output: +Page contents +Past Conversations +Pending messages +Pinned Conversations +Playback available +Please wait while we check if roadwarrior is installed. +Preview +Preview unavailable +Previous +Previous match (Shift+Enter) +Pricing is based on public API pricing +Proceed +Proceed Anyways +Project +Projects +Prompt +Python Coming Soon +Python Script +Quick Start +Radius: +Randomly select one of the responses as the winner. +Read resource: +Read URL content? +Read URL rejected +Recent actions +Recommended +Reconnecting to remote authority. +Refresh +Refresh rules +Refresh skills +Refresh trajectory list +Refresh workflows +Refresh your credentials to gain access to Google services. +Reject +Reject all +Reload +Reload IDE +Reload Window +Reload your window +Rename +Rendered Step: +Rendering playback +Report Issue +Request Review +Reset +Restart +Restart Task +Restore +Retry +Review +Review Changes +Review policy +Rules +Rules help guide the behavior of Agent. +Run +Run in your terminal to install (glinux): +Save +Scanning skills config file... +Schedule +Scheduled Tasks +Security Notice & Data Use +See all +See Terms +Select a trajectory +Select an option... +Select Environment +Select folder(s) +Select from known +Select Model +Select Model: +Select one of the options below. +Select project +Select text in the artifact to add a comment +Send Feedback +Sent Message +Server failed to start +Set +Set Browser Config +Setup +Sherlog Links +Show 0s +Show more +Sidecar feature is not available. +Sidecar view does not exist. +Sign in with a different account +Skills +Skills are instructions that extend what Agent can do. +Skip +Skipped +Some non-image binary content was truncated. +Something went wrong +Something went wrong! +Sort Conversations +Source: +Sources +Start fresh or import settings from another IDE +Start Screen Recording +Step JSON: +Step Type +Step: +Steps to reproduce the issue +Subagent Context Mode: +Subagent Reminder Mode: +Submit +Subtitles +Suggested Actions +Task Logs +Task not found +Terminal execution policy +Terms and Privacy: +Terms of Service +Terms of Service & Data Use +Terms of Use +Thank you! \u2764\uFE0F +The agent was prevented from accessing some sites +The agent will frequently ask for review. +The agent will never request for review. +The agent will wait for you to install the browser extension. +The associated worktree will also be deleted. +The language server has unexpectedly crashed. +There was an unexpected issue setting up your account. +Thinking +Thinking... +This plugin has been built by a verified reference publisher. +This plugin has been built by the official publisher. +This skill is installed in your workspace +This workspace no longer exists. You cannot send messages. +Title: +To provide feedback +To use browser tools, you need to enable remote debugging: +Toggle Debug Mode +Toggle Debug Sidebar +Toggle Ephemeral Messages +Toggle Incognito Mode +Toggle Sidebar +Tool arguments +Tool Calls +Tool Output +Trajectory ID +Trajectory Stats +Transpilation Error: +Transpiling React app... +Try Again +Unknown Notebook +Use Google Cloud project instead +Use regular expression (.*) +User cancelled agent execution. +User Implicit Trajectories +Value +View +View could not be opened +View customizations +View Debug +View Diff +View documentation +View Logs +View MCP settings +View network request +View network requests +View Page +View plans +Visible only +Weekly +What is missing in your workflow +What quota or feature is being incorrectly limited +Why are you opting out? +Workflows +Workspace +Workspace API Tool: +Your administrator has disabled MCP servers. diff --git a/search_strings.py b/search_strings.py new file mode 100644 index 0000000..c4e09eb --- /dev/null +++ b/search_strings.py @@ -0,0 +1,43 @@ +""" +search_strings.py — 在 Antigravity IDE 目标文件中搜索指定字符串并打印上下文片段。 +用法: + python search_strings.py [目标文件路径] +如果不提供参数,脚本会尝试自动推导 Windows 默认安装路径。 +""" +import re +import sys +import os + + +def get_default_path(): + localappdata = os.environ.get('LOCALAPPDATA', '') + return os.path.join(localappdata, 'Programs', 'Antigravity IDE', + 'resources', 'app', 'out', 'jetskiAgent', 'main.js') + + +target_path = sys.argv[1] if len(sys.argv) > 1 else get_default_path() + +if not os.path.exists(target_path): + print(f"[错误] 文件不存在: {target_path}") + print("用法: python search_strings.py <目标文件路径>") + sys.exit(1) + +with open(target_path, 'r', encoding='utf-8') as f: + content = f.read() + +words = [ + 'Account', 'Permissions', 'Appearance', 'Notifications', + "Configure the agent's visual theme and display preferences.", + 'Controls whether terminal commands require your approval before running.' +] + +for w in words: + # Find occurrences and print surrounding context (30 chars before, 30 chars after) + matches = list(re.finditer(re.escape(w), content)) + print(f"--- Matches for '{w}' ({len(matches)} found) ---") + # Just show the first 3 matches to save space + for match in matches[:3]: + start = max(0, match.start() - 30) + end = min(len(content), match.end() + 30) + snippet = content[start:end] + print("..." + snippet + "...") diff --git a/test_poc.py b/test_poc.py new file mode 100644 index 0000000..4dede8f --- /dev/null +++ b/test_poc.py @@ -0,0 +1,52 @@ +import os +import sys + +def get_app_base(): + localappdata = os.environ.get('LOCALAPPDATA', '') + if localappdata: + win_candidate = os.path.join(localappdata, 'Programs', 'Antigravity IDE', 'resources', 'app') + if os.path.exists(win_candidate): + return win_candidate + return None + +BASE = get_app_base() +if not BASE: + print("Could not find Antigravity IDE installation.") + sys.exit(1) + +chat_js_path = os.path.join(BASE, 'extensions', 'antigravity', 'out', 'media', 'chat.js') +settings_js_path = os.path.join(BASE, 'out', 'jetskiAgent', 'main.js') + +targets = [ + ("Chat Panel", chat_js_path), + ("Settings Panel", settings_js_path) +] + +with open('poc_observer.js', 'r', encoding='utf-8') as f: + poc_code = f.read() + +TAG = "// [AntigravityChinesePack PoC injected]" + +for name, path in targets: + if not os.path.exists(path): + print(f"[{name}] Not found at {path}") + continue + + backup_path = path + ".backup" + if not os.path.exists(backup_path): + print(f"[{name}] Creating backup...") + with open(path, 'r', encoding='utf-8') as f: + original = f.read() + with open(backup_path, 'w', encoding='utf-8') as f: + f.write(original) + + with open(path, 'r', encoding='utf-8') as f: + content = f.read() + + if TAG in content: + print(f"[{name}] PoC already injected! If you updated poc_observer.js, you must restore the backup first or manually remove the old injection.") + else: + new_content = content + "\n\n" + poc_code + with open(path, 'w', encoding='utf-8') as f: + f.write(new_content) + print(f"[{name}] Successfully injected PoC!") diff --git a/v2_observer.js b/v2_observer.js new file mode 100644 index 0000000..bf19d2c --- /dev/null +++ b/v2_observer.js @@ -0,0 +1,1099 @@ + +// [AntigravityChinesePack V2 DOM Observer Injected] +(function() { + // 避免在某些纯 worker 或不含 DOM 的环境中报错 + if (typeof document === 'undefined' || !document.body) return; + + console.log("[AntigravityChinesePack] V2 Dynamic DOM Observer Active"); + const dict = { + "Agent Auto-Fix Lints": "Agent 自动修复 Lint", + "Strict Mode": "严格模式", + "Review Policy": "审查策略", + "Terminal Command Auto Execution": "终端命令自动执行", + "Agent Gitignore Access": "Agent Gitignore 访问", + "Agent Non-Workspace File Access": "Agent 非工作区文件访问", + "Auto-Continue": "自动继续", + "Enable Sounds for Agent": "Agent 声音提示", + "Auto-Expand Changes Overview": "自动展开更改概览", + "Conversation History": "对话历史", + "Knowledge": "知识库", + "Auto-Open Edited Files": "自动打开已编辑文件", + "Open Agent on Reload": "重新加载时打开 Agent", + "Enable Terminal Sandbox": "启用终端沙盒", + "Sandbox Allow Network": "沙盒允许网络", + "Suggestions in Editor": "编辑器中的建议", + "Show Selection Actions": "显示选中操作", + "Tab Speed": "Tab 速度", + "Tab to Jump": "Tab 跳转", + "Tab to Import": "Tab 导入", + "Highlight After Accept": "接受后高亮", + "Tab Gitignore Access": "Tab Gitignore 访问", + "Enable Browser Tools": "启用浏览器工具", + "Browser Javascript Execution Policy": "浏览器 JavaScript 执行策略", + "Chrome Binary Path": "Chrome 可执行文件路径", + "Browser User Profile Path": "浏览器用户配置路径", + "Browser CDP Port": "浏览器 CDP 端口", + "Browser URL Allowlist": "浏览器 URL 允许列表", + "Marketplace Item URL": "市场扩展页面 URL", + "Marketplace Gallery URL": "市场搜索 URL", + "Allow List Terminal Commands": "终端命令允许列表", + "Deny List Terminal Commands": "终端命令拒绝列表", + "Enable Telemetry": "启用遥测", + "Always Proceed": "始终继续", + "Agent Decides": "Agent 决定", + "Request Review": "请求审查", + "[Dev] GCP Project ID": "[开发] GCP 项目 ID", + "Settings -": "设置 -", + "Conversation mode": "对话模式", + "Agent can plan before executing tasks. Use for deep research, complex tasks, or collaborative work": "Agent 可以在执行任务前进行规划。适用于深度研究、复杂任务或协作工作", + "Agent will execute tasks directly. Use for simple tasks that can be completed faster": "Agent 将直接执行任务。适用于可以更快完成的简单任务", + "Provide Feedback": "提供反馈", + "Accept": "接受", + "Accept all": "全部接受", + "Skip": "跳过", + "Add": "添加", + "Add Model": "添加模型", + "Add context": "添加上下文", + "Add them to allow future interactions": "将它们添加到允许列表以允许未来的交互", + "Edit": "编辑", + "Edit Model": "编辑模型", + "Editor": "编辑器", + "Editor Settings": "编辑器设置", + "Editor Window": "编辑器窗口", + "Loading...": "加载中...", + "Loading models...": "正在加载模型...", + "Loading Browser recording...": "正在加载浏览器录制...", + "Loading knowledge items...": "正在加载知识项...", + "Loading metrics...": "正在加载指标...", + "Undo": "撤销", + "Discard all changes": "放弃所有更改", + "Discard changes": "放弃更改", + "Run": "运行", + "Running": "运行中", + "Close": "关闭", + "Ran command": "行行命令", + "Close Workspace": "关闭工作区", + "Delete Conversation": "删除对话", + "Start Conversation": "开始对话", + "Open Workspace": "打开工作区", + "Open New Workspace": "打开新工作区", + "Open New Remote Workspace": "打开新远程工作区", + "Start a new conversation": "开始新对话", + "Start conversation": "开始对话", + "Proceed": "继续", + "Artifacts": "产物", + "Model": "模型", + "Expand All": "全部展开", + "Collapse All": "全部折叠", + "Ask anything, @ to mention, / for workflows": "输入任何内容,@ 用于提及,/ 用于调用工作流", + "Collapse all": "全部折叠", + "Thought Process": "思考过程", + "Auto-proceeded by the agent under your review policy.": "已由 Agent 根据您的审查策略自动继续。", + "Manually proceeded under your review policy.": "已根据您的审查策略手动继续。", + "Generating": "生成中", + "Artifacts are files the agent creates during a conversation to help perform longer running tasks and allow the user to provide high-level feedback. Click to open in editor.": "产物是 Agent 在对话中创建的文件,用于帮助执行较长时间运行的任务并允许用户提供高级反馈。点击在编辑器中打开。", + "Artifact Name": "产物名称", + "Last Updated": "最后更新", + "Send": "发送", + "Audio is not supported for this model": "该模型不支持音频", + "No microphone detected": "未检测到麦克风", + "Comment": "评论", + "Reject": "拒绝", + "result": "个结果", + "Always Ask": "始终询问", + "Select one of the": "从", + "Agent security mode": "Agent 安全模式", + "Full access": "完全访问", + "Agents have full access to your machine and external resources.": "Agent 可以完全访问您的计算机和外部资源。", + "Sandboxed": "沙盒化", + "Agents run in a secure sandbox that restricts access to external resources outside of your trusted folders.": "Agent 运行在安全的沙盒中,限制访问信任文件夹以外的外部资源。", + "Strict": "严格", + "Terminal commands always require review and the agent cannot access files outside of its given workspaces.": "终端命令始终需要审查,且 Agent 无法访问指定工作区以外的文件。", + "Enable Shell Integration": "启用 Shell 集成", + "File Access": "文件访问", + "Allows the agent to access files outside of your current workspace.": "允许 Agent 访问当前工作区以外的文件。", + "Planning": "规划", + "Automation": "自动化", + "History": "历史记录", + "General": "常规", + "Explain and Fix in Current Conversation": "在当前对话中解释和修复", + "Advanced": "高级", + "Advanced File Access": "高级文件访问", + "Read Files": "读取文件", + "Write Files": "写入文件", + "Advanced Command Access": "高级命令访问", + "Terminal Commands": "终端命令", + "Commands Outside Sandbox": "沙盒外的命令", + "MCP Tools": "MCP 工具", + "Advanced Web Access": "高级网络访问", + "Read URLs": "读取 URL", + "Execute URLs": "执行 URL", + "Advanced Settings": "高级设置", + "Enable Demo Mode (Beta)": "启用演示模式 (Beta)", + "When toggled on, ${r.product.nameShort} collects usage data to help Google enhance performance and features.": "开启后,${r.product.nameShort} 将收集使用数据,以帮助 Google 提升性能和功能。", + "Marketing Emails": "营销邮件", + "By using this app, you agree to its": "使用此应用即表示您同意其", + "Terms of Service": "服务条款", + "Terms of Service & Data Use": "服务条款与数据使用", + "Configure the browser subagent. It requires": "配置浏览器子 Agent。它需要安装", + "View your available model quota. Quota refreshes periodically based on your plan.": "查看您可用的模型配额。配额会根据您的方案定期刷新。", + "% of the customization budget is available.": "% 的定制预算当前可用。", + "Hide breakdown": "隐藏明细", + "Plugin:": "插件:", + "Plugins are packaged collections of skills and MCPs to help the Agent": "插件是技能和 MCP 的打包集合,用于帮助 Agent", + "Plugins are packaged collections of skills and MCPs to help the Agent in": "插件是技能和 MCP 的打包集合,用于帮助 Agent 在", + "No MCP Servers": "没有 MCP 服务器", + "Account": "账户", + "Notifications": "通知", + "Models": "模型", + "Customizations": "自定义", + "Browser Settings": "浏览器设置", + "Account & Plan": "账户与方案", + "Email": "电子邮件", + "Theme": "主题", + "Chat Settings": "聊天设置", + "Verbose agent chat": "详细 Agent 聊天", + "Model Quota": "模型配额", + "Actuation Permissions": "执行操作权限", + "Browser Actuation Rules": "浏览器执行规则", + "Marketplace": "市场", + "Changes the base URL on each extension page. You must restart Antigravity IDE to use the new marketplace after changing this value.": "更改每个扩展页面的基础 URL。更改此值后,您必须重启 Antigravity IDE 才能使用新的市场。", + "Changes the base URL for marketplace search results. You must restart Antigravity IDE to use the new marketplace after changing this value.": "更改市场搜索结果的基础 URL。更改此值后,您必须重启 Antigravity IDE 才能使用新的市场。", + "Selection Actions": "选中操作", + "MCP Servers": "MCP 服务器", + "Manage MCP Servers": "管理 MCP 服务器", + "Rules": "规则", + "Workflows": "工作流", + "Rules help guide the behavior of Agent.": "规则可以帮助引导 Agent 的行为。", + "Edit rule": "编辑规则", + "Edit workflow": "编辑工作流", + "Refresh rules": "刷新规则", + "Refresh workflows": "刷新工作流", + "Mentions": "提及", + "Screen Recording": "屏幕录制", + "Back to Agent": "返回 Agent", + "Close Agent View": "关闭 Agent 视图", + "Past Conversations": "历史对话", + "Connect to an existing conversation": "连接到现有对话", + "Cancel": "取消", + "Cancel command": "取消命令", + "Cancel step": "取消步骤", + "Confirm": "确认", + "Confirm Undo": "确认撤销", + "Create": "创建", + "Delete": "删除", + "Dismiss": "忽略", + "Expand": "展开", + "Install": "安装", + "Launch": "启动", + "Open": "打开", + "Preview": "预览", + "Refresh": "刷新", + "Retry": "重试", + "Review": "审查", + "Review Changes": "审查更改", + "Save": "保存", + "Send Feedback": "发送反馈", + "See all": "查看全部", + "Show more": "显示更多", + "Continue response": "继续响应", + "Configure": "配置", + "Configure Auto-Continue": "配置自动继续", + "Next": "下一步", + "Previous": "上一步", + "Reload IDE": "重新加载 IDE", + "Clear": "清除", + "Setup": "设置", + "New": "新建", + "Default": "默认", + "Custom": "自定义", + "Copy command": "复制命令", + "Copy diff": "复制差异", + "Copy the trajectory ID": "复制轨迹 ID", + "Open diff": "打开差异", + "Open in New Window": "在新窗口中打开", + "Open allowlist": "打开允许列表", + "Start Screen Recording": "开始屏幕录制", + "Set Browser Config": "设置浏览器配置", + "View Diff": "查看差异", + "View Page": "查看页面", + "View network request": "查看网络请求", + "View network requests": "查看网络请求", + "View plans": "查看计划", + "View Annotation": "查看注释", + "View Created Links": "查看已创建链接", + "View snapshot": "查看快照", + "Thinking": "思考中", + "Analyzed": "已分析", + "Installed": "已安装", + "Error": "错误", + "Something went wrong": "出了点问题", + "An error was thrown.": "发生了一个错误。", + "Failed to send": "发送失败", + "Launching the browser...": "正在启动浏览器...", + "Playback available": "可以回放", + "Preview unavailable": "预览不可用", + "No matching results": "没有匹配的结果", + "No results": "无结果", + "No results found": "未找到结果", + "No results found.": "未找到结果。", + "No browser pages open": "没有打开的浏览器页面", + "Loading MCP servers": "正在加载 MCP 服务器", + "Reconnecting to remote authority.": "正在重新连接到远程服务器。", + "Disabled in strict mode": "在严格模式下已禁用", + "Full output written to": "完整输出已写入", + "Read URL rejected": "读取 URL 被拒绝", + "Rejected MCP tool": "已拒绝 MCP 工具", + "Proceeded with": "已继续执行", + "Unknown edit": "未知编辑", + "Unknown file edit": "未知文件编辑", + "Built-In": "内置", + "Authentication Required": "需要身份验证", + "Confirmation required to execute this step": "执行此步骤需要确认", + "Antigravity would like to use the browser.": "Antigravity 希望使用浏览器。", + "The Agent attempted to interact with some sites that are not allowlisted": "Agent 尝试与一些不在允许列表中的网站交互", + "The agent was prevented from accessing some sites": "Agent 已被阻止访问某些网站", + "The agent will wait for you to install the browser extension.": "Agent 将等待你安装浏览器扩展。", + "This plugin has been built by a verified reference publisher.": "此插件由经过验证的参考发布者构建。", + "This plugin has been built by the official publisher.": "此插件由官方发布者构建。", + "Read URL content?": "读取 URL 内容?", + "Run MCP tool call?": "运行 MCP 工具调用?", + "Modify the config used for browser interactions. Saved automatically.": "修改用于浏览器交互的配置。自动保存。", + "After reporting the issue, reload your window to resume Agent use.": "报告问题后,重新加载窗口以恢复 Agent 使用。", + "Files results show if their associated language extension is installed.": "文件结果会在安装了关联的语言扩展后显示。", + "Select a trajectory": "选择一个轨迹", + "Sources": "来源", + "Details": "详细信息", + "Features": "功能", + "Comments": "评论", + "Images": "图片", + "Files Edited": "已编辑文件", + "Background Steps": "后台步骤", + "Suggested Actions": "建议操作", + "Progress Updates": "进度更新", + "Pending messages": "待处理消息", + "Knowledge Generation": "知识生成", + "Recent actions": "最近操作", + "Report Issue": "报告问题", + "Conversation": "对话", + "Additional options": "其他选项", + "Feedback": "反馈", + "Denied Sites": "被拒绝的网站", + "Global": "全局", + "MCP Store": "MCP 商店", + "Good": "好", + "Bad": "差", + "Good response": "好的响应", + "Bad response": "差的响应", + "Open System Browser": "打开系统浏览器", + "Fetched network request for page.": "已获取页面的网络请求。", + "Fetched network requests for page.": "已获取页面的网络请求。", + "Complete verification": "完成验证", + "Copy": "复制", + "Paste": "粘贴", + "Export": "导出", + "Enable": "启用", + "Try again": "再试一次", + "Deny": "拒绝", + "Allow Once": "允许一次", + "Always Allow": "始终允许", + "Always run": "始终运行", + "Ask every time": "每次询问", + "Ask first": "先询问", + "Download Diagnostics": "下载诊断信息", + "Copy debug info": "复制调试信息", + "Select Model": "选择模型", + "Select another model": "选择其他模型", + "Terminal": "终端命令", + "Media": "媒体", + "Errors": "错误", + "Workspace": "工作区", + "Free": "免费", + "Verification required": "需要验证", + "Share Conversation": "分享对话", + "Enable Notifications": "启用通知", + "Select Model to Send Message": "选择模型以发送消息", + "Model quota limit exceeded": "模型配额已超限", + "Capture screenshot": "截取屏幕", + "Capture console logs": "捕获控制台日志", + "Confirm dismiss?": "确认忽略?", + "Could not send message": "无法发送消息", + "Your modified files:": "你修改的文件:", + "Your recent Browser activity:": "你最近的浏览器活动:", + "Your recent terminal commands:": "你最近的终端命令:", + "Mention Page": "提及页面", + "Full Error": "完整错误", + "First page": "第一页", + "Last page": "最后一页", + "Next page": "下一页", + "Previous page": "上一页", + "Copy full URL to clipboard": "复制完整 URL 到剪贴板", + "Click to copy full command": "点击复制完整命令", + "Copy trajectory ID": "复制轨迹 ID", + "Search MCP servers": "搜索 MCP 服务器", + "Go to Terminal": "前往终端", + "Relocate": "重新定位", + "Allow This Conversation": "本次对话允许", + "Reject all": "全部拒绝", + "Learn more": "了解更多", + "file an issue": "提交问题", + "reload the window": "重新加载窗口", + "troubleshooting guide": "故障排除指南", + "Show items analyzed": "显示已分析项目", + "Added Annotation": "已添加注释", + "Start a New Conversation": "开始新对话", + "Manually set Agent ID": "手动设置 Agent ID", + "Search metrics...": "搜索指标...", + "Find": "查找", + "AI may make mistakes. Double-check all generated code.": "AI 可能会犯错。请仔细检查所有生成的代码。", + "1. Report Issue": "1. 报告问题", + "Get Logs": "获取日志", + "If you are having difficulty using": "如果你在使用", + ", please report the issue using our feedback form.": "时遇到困难,请使用我们的反馈表单报告问题。", + ". As always, you can use the thumbs up or thumbs down feedback mechanism to help improve our metrics.": "。您可以使用点赞或点踩反馈机制来帮助改进我们的指标。", + "(Dev-only) Select a mixin to use in the agent. This will tailor Cascade for different task types by changing things like the system prompt, tools available, etc.": "(仅开发) 选择要在代理中使用的混入。这将通过更改系统提示、可用工具等来为不同的任务类型定制 Cascade。", + "[Today at] LT": "[今天] LT", + "[Tomorrow at] LT": "[明天] LT", + "[Yesterday at] LT": "[昨天] LT", + "%d days": "%d 天", + "%d hours": "%d 小时", + "%d minutes": "%d 分钟", + "%d months": "%d 个月", + "%d seconds": "%d 秒", + "%d weeks": "%d 周", + "%d years": "%d 年", + "%s ago": "%s前", + "2. Resetting Agent": "2. 重置代理", + "A chunk is a section of the page. Long pages are chunked so that only the sections that are relevant to your query are read.": "块是页面的一个部分。长页面会被分块,以便只读取与您的查询相关的部分。", + "a day": "一天", + "a few seconds": "几秒", + "a minute": "一分钟", + "a month": "一个月", + "a week": "一周", + "a year": "一年", + "Aborted": "已中止", + "Absolute uri to pbtxt config": "pbtxt 配置的绝对 URI", + "Accepted": "已接受", + "Accessibility": "辅助功能", + "Active Browser page": "活动浏览器页面", + "Active Browser pages": "活动浏览器页面", + "Active": "活动", + "Activities cannot be viewed": "无法查看活动", + "Activity": "活动", + "Agent Action DOM Diffs:": "代理操作 DOM 差异:", + "Agent can click and drag in the browser.": "代理可以在浏览器中点击和拖动。", + "Agent can click on specific elements in the browser.": "代理可以点击浏览器中的特定元素。", + "Agent can resize browser windows to different dimensions or window states.": "代理可以将浏览器窗口调整为不同的尺寸或窗口状态。", + "Agent execution terminated due to model provider overload. Please try again later.": "代理执行因模型提供商过载而终止。请稍后重试。", + "Agent terminated due to error": "代理因错误而终止", + "Allow once": "允许一次", + "Already exists": "已存在", + "Alt text:": "替代文本:", + "Always allow": "始终允许", + "Always ask for permission": "始终询问权限", + "Always Auto-Run": "始终自动运行", + "Always run terminal commands": "始终运行终端命令", + "An error ID that helps the team investigate the error.": "帮助团队调查错误的错误 ID。", + "an hour": "一小时", + "An unknown error occurred": "发生未知错误", + "Approved": "已批准", + "Argument must be a Buffer": "参数必须是 Buffer", + "Arguments Schema:": "参数模式:", + "Artifact Comments": "工件评论", + "Artifact image": "工件图像", + "Artifacts are created when the agent performs more complex, longer running tasks while in Planning mode.": "工件是代理在规划模式下执行更复杂、耗时更长的任务时创建的。", + "At mention": "@ 引用", + "Attach the trajectory ID to the feedback form": "将轨迹 ID 附加到反馈表单", + "Attempt to write outside buffer bounds": "尝试写入缓冲区边界外", + "Attribute": "属性", + "Authorization": "授权", + "Auto-Run On Model Decision": "根据模型决策自动运行", + "Back to content": "返回内容", + "background terminal command": "后台终端命令", + "Backwards": "向后", + "Baseline": "基线", + "BETA": "测试版", + "Billed at API pricing": "按 API 定价计费", + "Browser Code": "浏览器代码", + "Browser Content": "浏览器内容", + "Browser Mode:": "浏览器模式:", + "Browser Text": "浏览器文本", + "Browser Tool Set Mode:": "浏览器工具集模式:", + "Browser Tools:": "浏览器工具:", + "Bytes": "字节", + "Canceled creation of": "已取消创建", + "Canceled deletion of": "已取消删除", + "Canceled edit to": "已取消编辑", + "Canceled extension code": "已取消扩展代码", + "Canceled": "已取消", + "Cannot revert messages with artifact comments": "无法撤销包含工件评论的消息", + "Cannot revert messages with file comments": "无法撤销包含文件评论的消息", + "Cannot revert messages with file diff comments": "无法撤销包含文件差异评论的消息", + "Cannot revert this message": "无法撤销此消息", + "Caps Lock": "大写锁定", + "Chat Model Metadata": "聊天模型元数据", + "Checked command status": "已检查命令状态", + "Checking command status": "正在检查命令状态", + "Clear NUX state": "清除新用户状态", + "Cleared Count": "已清除计数", + "Click Feedback:": "点击反馈:", + "Clicked in Browser": "在浏览器中点击", + "Clicked": "已点击", + "Clicking in Browser": "正在浏览器中点击", + "Clicking": "点击中", + "Closed": "已关闭", + "Closing": "关闭中", + "Code Context Item Subranges": "代码上下文子范围", + "Code Context Items": "代码上下文项", + "Files": "文件", + "MCP servers": "MCP 服务器", + "Conversations": "聊天列表", + "Code Snippet": "代码片段", + "Combobox": "组合框", + "Configure Auto-Run": "配置自动运行", + "Confirm Browser Interaction": "确认浏览器交互", + "Confirming this undo action will make the following changes:": "确认此撤销操作将进行以下更改:", + "Console Logs": "控制台日志", + "Conversational": "对话式", + "Coordinated Universal Time": "协调世界时", + "Copied": "已复制", + "Copy Link": "复制链接", + "Copy to clipboard": "复制到剪贴板", + "Cost": "成本", + "Created At": "创建时间", + "Created:": "创建于:", + "Creating": "创建中", + "Custom Config": "自定义配置", + "Custom models are only supported on Cloudtop / Linux machines.": "自定义模型仅在 Cloudtop / Linux 机器上支持。", + "Custom Reminder:": "自定义提醒:", + "Custom URI": "自定义 URI", + "Data loss": "数据丢失", + "Dead": "已终止", + "Deadline exceeded": "超时", + "Debug Mode": "调试模式", + "Debug Sidebar": "调试侧边栏", + "Default Config": "默认配置", + "Deleted": "已删除", + "Deleting": "删除中", + "Description:": "描述:", + "Description": "描述", + "Developer Menu": "开发者菜单", + "Dialog": "对话框", + "Diameter": "直径", + "Directories": "目录", + "Disabled in Secure Mode": "在安全模式下已禁用", + "Disclosure": "披露", + "Dismiss suggested actions": "关闭建议操作", + "Document Answers": "文档答案", + "DOM Element": "DOM 元素", + "Dragged in Browser": "在浏览器中拖拽", + "Dragging in Browser": "正在浏览器中拖拽", + "Dynamic Wait Tool:": "动态等待工具:", + "Editing": "编辑中", + "Electron Mode": "Electron 模式", + "Empty": "空", + "Enabled": "已启用", + "End of comment missing": "缺少注释结尾", + "Enlarged image": "放大的图像", + "Enter Agent ID": "输入代理 ID", + "Enter custom reminder text for the planner...": "输入规划器的自定义提醒文本...", + "Ephemeral Options:": "临时选项:", + "Equal": "相等", + "Error checking microphone availability:": "检查麦克风可用性时出错:", + "Error Details:": "错误详情:", + "Error Details": "错误详情", + "Error during tool execution": "工具执行期间出错", + "Error editing file": "编辑文件时出错", + "Error in event listener:": "事件监听器出错:", + "Error occurred": "发生错误", + "Error opening workspace quick pick:": "打开工作区快速选择时出错:", + "Error parsing JSON:": "解析 JSON 时出错:", + "Error rendering CodeBlock": "渲染代码块时出错", + "Error rendering Markdown": "渲染 Markdown 时出错", + "Error rendering playback": "渲染回放时出错", + "Error viewing file": "查看文件时出错", + "Error while analyzing directory": "分析目录时出错", + "Error while editing": "编辑时出错", + "Error while running command": "运行命令时出错", + "Error while running MCP tool": "运行 MCP 工具时出错", + "Error while searching filesystem": "搜索文件系统时出错", + "Error while searching the web": "搜索网页时出错", + "Error while searching": "搜索时出错", + "Error while semantic searching": "语义搜索时出错", + "Error while viewing": "查看时出错", + "Execute Javascript policy": "执行 JavaScript 策略", + "Expected a function": "期望一个函数", + "Expected a string": "期望一个字符串", + "Expected array or object as schema": "期望数组或对象作为架构", + "Expected character": "期望字符", + "Expected substring": "期望子字符串", + "Extension client not available": "扩展客户端不可用", + "Extracted DOM elements": "已提取 DOM 元素", + "Extracting DOM elements": "正在提取 DOM 元素", + "Failed precondition": "前置条件失败", + "Failed to add URL to allowlist: addToBrowserAllowlist is undefined": "添加 URL 到白名单失败: addToBrowserAllowlist 未定义", + "Failed to add URL to allowlist:": "添加 URL 到白名单失败:", + "Failed to copy text using Clipboard API:": "使用剪贴板 API 复制文本失败:", + "Failed to copy text using document.execCommand:": "使用 document.execCommand 复制文本失败:", + "Failed to create workflow:": "创建工作流失败:", + "Failed to delete queued message:": "删除排队消息失败:", + "Failed to enable server, click to see details.": "启用服务器失败,点击查看详情。", + "Failed to extract waveform:": "提取波形失败:", + "Failed to fetch custom agent configs:": "获取自定义代理配置失败:", + "failed to fetch HEAD for": "获取 HEAD 失败:", + "Failed to find the root element": "未能找到根元素", + "Failed to get static experiments": "获取静态实验失败", + "Failed to open plugin page:": "打开插件页面失败:", + "Failed to parse ContextScopeItem from mention node:": "从提及节点解析 ContextScopeItem 失败:", + "Failed to parse quota metadata": "解析配额元数据失败", + "Failed to parse quota reset timestamp": "解析配额重置时间戳失败", + "Failed to parse tool JSON schema:": "解析工具 JSON 模式失败:", + "Failed to parse toolCallArgumentsJson:": "解析 toolCallArgumentsJson 失败:", + "Failed to refresh user memories:": "刷新用户记忆失败:", + "Failed to start screen recording": "启动屏幕录制失败", + "File Comments": "文件评论", + "File Diff Comments": "文件差异评论", + "Files to edit:": "要编辑的文件:", + "First argument must be a string": "第一个参数必须是字符串", + "Focus": "聚焦", + "Focused": "已聚焦", + "Folder": "文件夹", + "Folders": "文件夹", + "Footnotes": "脚注", + "Forward": "前进", + "Forwards": "向前", + "Found references to": "找到引用", + "Fragment": "片段", + "Full Metadata": "完整元数据", + "Gemini Computer Use": "Gemini 计算机使用", + "Generated image preview": "生成的图像预览", + "Generating extension code": "正在生成扩展代码", + "Goal": "目标", + "Greater": "大于", + "Hashing function not available": "哈希函数不可用", + "Heading": "标题", + "Hidden": "已隐藏", + "Hide 0s": "隐藏 0 秒", + "Hours": "小时", + "I did": "已完成", + "If you believe this is a bug, please": "如果您认为这是一个 bug,请", + "Ignore warning and attempt to send messages anyway regardless of network connection status. As a result, messages may get dropped.": "忽略警告并尝试发送消息,无论网络连接状态如何。因此,消息可能会丢失。", + "Image Answers": "图像答案", + "Image Diff Not Supported": "不支持图像差异", + "Image rendering blocked (Secure Mode enabled)": "图像渲染被阻止 (安全模式已启用)", + "Image URL:": "图像 URL:", + "in %s": "%s后", + "In progress": "进行中", + "Index out of range": "索引超出范围", + "Initializing": "初始化中", + "Input": "输入", + "Insert in terminal": "插入到终端", + "Inspected commit": "已检查的提交", + "Internal": "内部", + "Invalid argument": "无效参数", + "Invalid code point": "无效的代码点", + "Invalid date": "无效日期", + "Invalid metadata page": "无效的元数据页面", + "Invalid time value": "无效的时间值", + "Invariant Violation": "不变量违规", + "JavaScript Result": "JavaScript 结果", + "Jumps to the location of the terminal session that ran this command.": "跳转到运行此命令的终端会话位置。", + "Language server client not available": "语言服务器客户端不可用", + "Legacy": "旧版", + "Less": "小于", + "Line Ranges": "行范围", + "List resources:": "列出资源:", + "Listbox": "列表框", + "LLMs can generate incorrect responses that we cannot handle.": "LLM 可能生成我们无法处理的错误响应。", + "Malformed diff information": "差异信息格式错误", + "Manually Captured": "手动捕获", + "Manually Rejected": "手动拒绝", + "Max Context Characters (optional):": "最大上下文字符数 (可选):", + "Max Tokens": "最大 Token 数", + "MCP Tool:": "MCP 工具:", + "Metadata:": "元数据:", + "Metadata": "元数据", + "Metric": "指标", + "Milliseconds": "毫秒", + "Minutes": "分钟", + "Missing chat params context": "缺少聊天参数上下文", + "Mixins": "混入", + "Model Label": "模型标签", + "Model URL": "模型 URL", + "Month": "月", + "Move Mouse in Browser": "在浏览器中移动鼠标", + "Move": "移动", + "Moves this terminal session to the Terminal tab in your IDE. The agent will still be able to use it.": "将此终端会话移动到 IDE 的终端选项卡。代理仍可以使用它。", + "Moving Mouse in Browser": "正在浏览器中移动鼠标", + "Never Auto-Run": "从不自动运行", + "No @-mention results": "无 @ 引用结果", + "No chat model metadata available for this generator": "此生成器无可用的聊天模型元数据", + "No chat model metadata available in latest generator metadata": "最新生成器元数据中无可用的聊天模型元数据", + "No content available for this resource": "此资源无可用内容", + "No credits used": "未使用积分", + "No description": "无描述", + "No generator metadata available": "无可用的生成器元数据", + "No Javascript Result Output": "无 JavaScript 结果输出", + "No message prompts available": "无可用的消息提示", + "No Model Selected": "未选择模型", + "No renderer found for step case": "未找到步骤渲染器", + "No resources available": "无可用资源", + "No response from extension client": "扩展客户端无响应", + "No screenshot returned from captureScreenshot RPC": "captureScreenshot RPC 未返回截图", + "No snapshot taken": "未拍摄快照", + "No step index found for artifact code action step": "未找到工件代码操作步骤的步骤索引", + "No step index found for code action step": "未找到代码操作步骤的步骤索引", + "No trajectories available": "无可用轨迹", + "No trajectory steps available": "无可用轨迹步骤", + "No trajectory": "无轨迹", + "No URL returned from server": "服务器未返回 URL", + "No versions available": "无可用版本", + "None": "无", + "Not a redirect error": "不是重定向错误", + "Not implemented": "未实现", + "Nothing": "无", + "Open extracted DOM tree in editor": "在编辑器中打开提取的 DOM 树", + "Open in Terminal": "在终端中打开", + "Open PLX dashboard for metadata index": "打开元数据索引的 PLX 仪表板", + "Open Trajectory Dashboard": "打开轨迹仪表板", + "Opened URL in Browser": "已在浏览器中打开 URL", + "Opening URL in Browser": "正在浏览器中打开 URL", + "Opening": "打开中", + "Opens the associated terminal session in the Terminal tab in your IDE.": "在 IDE 的终端选项卡中打开关联的终端会话。", + "Out of range index": "索引超出范围", + "Out of range": "超出范围", + "Output": "输出", + "Overflow": "溢出", + "Page contents": "页面内容", + "Parentheses": "圆括号", + "Parser was already resumed": "解析器已恢复", + "Paste or type ID here": "在此粘贴或输入 ID", + "Pending comments": "待处理评论", + "Permission denied": "权限被拒绝", + "Pressed": "已按下", + "Pressing": "按下中", + "Processing": "处理中", + "Profiler": "分析器", + "Radius:": "半径:", + "Ran extension code": "已运行扩展代码", + "Read Browser Page in Browser": "在浏览器中读取页面", + "Read page": "读取页面", + "Read resource:": "读取资源:", + "Reading Browser Page in Browser": "正在浏览器中读取页面", + "Reading page": "正在读取页面", + "Reading": "读取中", + "Ready": "就绪", + "Recommended": "推荐", + "Record voice memo": "录制语音备忘", + "Reference": "引用", + "Refresh Custom Agent Configs": "刷新自定义代理配置", + "Refresh trajectory list": "刷新轨迹列表", + "Rejected extension code": "已拒绝扩展代码", + "Remove audio": "移除音频", + "Rendered Step:": "渲染步骤:", + "Rendering playback": "渲染回放", + "Repositories": "仓库", + "Requested changes": "请求的更改", + "Resized Browser window": "已调整浏览器窗口大小", + "Resizing Browser window": "正在调整浏览器窗口大小", + "Resource exhausted": "资源耗尽", + "Retrieved Browser Pages": "已获取浏览器页面", + "Retrieved Console Logs from Browser": "已从浏览器获取控制台日志", + "Retrieved": "已获取", + "Retrieving Browser Pages": "正在获取浏览器页面", + "Retrieving Console Logs from Browser": "正在从浏览器获取控制台日志", + "Retrieving": "获取中", + "Right": "右", + "Run code?": "运行代码?", + "Run command?": "运行命令?", + "Run extension code": "运行扩展代码", + "Running extension code": "正在运行扩展代码", + "Scroll to bottom": "滚动到底部", + "Scrolled down in Browser": "在浏览器中向下滚动", + "Scrolled in Browser": "在浏览器中滚动", + "Scrolled up in Browser": "在浏览器中向上滚动", + "Scrolled": "已滚动", + "Scrolling down in Browser": "正在浏览器中向下滚动", + "Scrolling in Browser": "正在浏览器中滚动", + "Scrolling up in Browser": "正在浏览器中向上滚动", + "Searched": "已搜索", + "Searching": "搜索中", + "Seconds": "秒", + "Sections": "部分", + "See our": "查看我们的", + "See plans": "查看方案", + "Segment Metrics": "分段指标", + "Select a model using the model selector in the input box": "使用输入框中的模型选择器选择模型", + "Select from known": "从已知中选择", + "Select Model:": "选择模型:", + "Select Option in Browser": "在浏览器中选择选项", + "Select option": "选择选项", + "Selecting Option in Browser": "正在浏览器中选择选项", + "Semantic searched": "已语义搜索", + "Semantic searching": "语义搜索中", + "Send feedback": "发送反馈", + "Shapes": "形状", + "Sheet": "表格", + "Sherlog Links": "Sherlog 链接", + "Show 0s": "显示 0 秒", + "Show all resources": "显示所有资源", + "Show allowlist": "显示允许列表", + "Show fewer resources": "显示较少资源", + "Show less": "显示更少", + "Show page allowlist": "显示页面允许列表", + "Simulated Key Press in Browser": "在浏览器中模拟按键", + "Simulating Key Press in Browser": "正在浏览器中模拟按键", + "Site Allowlist": "网站允许列表", + "Some non-image binary content was truncated.": "部分非图像二进制内容已被截断。", + "Source:": "来源:", + "Step handler not available": "步骤处理程序不可用", + "Step JSON:": "步骤 JSON:", + "Step Type": "步骤类型", + "Step:": "步骤:", + "Stop recording": "停止录制", + "Subagent Context Mode:": "子代理上下文模式:", + "Subagent Reminder Mode:": "子代理提醒模式:", + "System Message": "系统消息", + "Take trajectory snapshot": "拍摄轨迹快照", + "Taking Screenshot": "正在截图", + "Terminal command": "终端命令", + "This operation was aborted": "此操作已中止", + "This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support.": "此浏览器缺少 `buffer` v5.x 所需的类型化数组 (Uint8Array) 支持。如果需要旧浏览器支持,请使用 `buffer` v4.x。", + "To provide feedback": "提供反馈", + "Toggle Debug Mode": "切换调试模式", + "Toggle Debug Sidebar": "切换调试侧边栏", + "Toggle Dev View": "切换开发视图", + "Toggle Ephemeral Messages": "切换临时消息", + "Toggle Incognito Mode": "切换无痕模式", + "Took Screenshot": "已截图", + "Tool Calls": "工具调用", + "Trajectory ID": "轨迹 ID", + "Trajectory Metrics": "轨迹指标", + "Trajectory Snapshot": "轨迹快照", + "Trajectory Stats": "轨迹统计", + "Trigger must be a single character": "触发器必须是单个字符", + "Trigger must be one character long": "触发器长度必须为一个字符", + "Trying to access beyond buffer length": "尝试访问超出缓冲区长度", + "Type into Browser": "在浏览器中输入", + "Typeahead menu": "自动完成菜单", + "Typing into Browser": "正在浏览器中输入", + "Unauthenticated": "未认证", + "Unavailable": "不可用", + "Underflow": "下溢", + "Undo changes up to this point": "撤销到此处的更改", + "Unexpected undefined": "意外的未定义", + "Unidentified": "未识别", + "Unimplemented": "未实现", + "Unknown error fetching browser pages": "获取浏览器页面时发生未知错误", + "Unknown error occurred": "发生未知错误", + "Unknown error": "未知错误", + "Unknown path": "未知路径", + "Unknown quota limit error reason": "未知配额限制错误原因", + "Unknown state": "未知状态", + "Unmount": "卸载", + "Unnamed resource": "未命名资源", + "Unsupported browser target": "不支持的浏览器目标", + "untitled": "未命名", + "Upload to Agent": "上传到代理", + "Upload": "上传", + "User Implicit Trajectories": "用户隐式轨迹", + "User Implicit": "用户隐式", + "User uploaded image": "用户上传的图像", + "Users": "用户", + "Uses your API key": "使用您的 API 密钥", + "Value": "值", + "Visible only": "仅可见", + "Wait for": "等待", + "Waiting": "等待中", + "When debug mode is on, you can see additional information about each steps in the conversation.": "开启调试模式后,您可以查看对话中每个步骤的额外信息。", + "With Markdown Trajectory Summary": "包含 Markdown 轨迹摘要", + "Unleash failed to resolve \\": "Unleash 无法解析 \\", + "Unleash: You must either provide your own \\": "Unleash: 您必须提供自己的 \\", + "Unleash SDK has already started, if you want to restart the SDK you should call client.stop() before starting again.": "Unleash SDK 已启动,如果要重新启动 SDK,应先调用 client.stop()。", + "Unleash: Fetching feature toggles did not have an ok response": "Unleash: 获取功能开关未收到正常响应", + "Unleash: unable to fetch feature toggles": "Unleash: 无法获取功能开关", + "Unleash: unable to send feature metrics": "Unleash: 无法发送功能指标", + "on() must be used within a FlagProvider": "on() 必须在 FlagProvider 中使用", + "off() must be used within a FlagProvider": "off() 必须在 FlagProvider 中使用", + "updateContext() must be used within a FlagProvider": "updateContext() 必须在 FlagProvider 中使用", + "isEnabled() must be used within a FlagProvider": "isEnabled() 必须在 FlagProvider 中使用", + "getVariant() must be used within a FlagProvider": "getVariant() 必须在 FlagProvider 中使用", + "useOnSendMessageContext must be used within an OnSendMessageContextProvider": "useOnSendMessageContext 必须在 OnSendMessageContextProvider 中使用", + "Failed to update conversation annotations:": "更新对话注释失败:", + "Auto Agent not supported at GDM (yet)": "GDM 暂不支持自动代理", + "Failed to send message": "发送消息失败", + "Error fetching model statuses:": "获取模型状态时出错:", + "Exception in backgroundFetchModelStatuses:": "backgroundFetchModelStatuses 中发生异常:", + "Failed to fetch user status:": "获取用户状态失败:", + "[Paste Interceptor] No selection found": "[粘贴拦截器] 未找到选择内容", + "No trigger was found for the editor": "未找到编辑器的触发器", + "Error fetching workflows:": "获取工作流时出错:", + "Error fetching rules:": "获取规则时出错:", + "Error listing MCP resources:": "列出 MCP 资源时出错:", + "Error listing terminals:": "列出终端时出错:", + "Error listing MCP server names:": "列出 MCP 服务器名称时出错:", + "Failed to open Review Changes:": "打开审查更改失败:", + "Failed to get workspace infos:": "获取工作区信息失败:", + "Failed to export conversation:": "导出对话失败:", + "Error fetching MCP servers:": "获取 MCP 服务器时出错:", + "Error: unable to parse context item": "错误: 无法解析上下文项", + "Error in connection error handler:": "连接错误处理程序中出错:", + "Unknown request case:": "未知请求类型:", + "Unexpected error starting chat client server stream:": "启动聊天客户端服务器流时发生意外错误:", + "Chat client server stream canceled by original abort signal": "聊天客户端服务器流被原始中止信号取消", + "Error starting chat client server stream:": "启动聊天客户端服务器流时出错:", + "Failed to update user settings:": "更新用户设置失败:", + "Error sharing trajectory:": "分享轨迹时出错:", + "forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported": "forceFrameRate 接受 0 到 125 之间的正整数,不支持强制帧率高于 125 fps", + "A component is changing from controlled to uncontrolled. This may be caused by the value changing from a defined value to undefined, which should not happen.": "组件正在从受控变为非受控。这可能是由于值从已定义变为 undefined,这不应该发生。", + "A component is changing from uncontrolled to controlled. This may be caused by the value changing from undefined to a defined value, which should not happen.": "组件正在从非受控变为受控。这可能是由于值从 undefined 变为已定义值,这不应该发生。", + "Nonretryable error starting chat client server stream:": "启动聊天客户端服务器流时发生不可重试错误:", + "Error copying to clipboard:": "复制到剪贴板时出错:", + "Failed to capture browser console logs: No console logs found": "捕获浏览器控制台日志失败: 未找到控制台日志", + "Failed to capture browser console logs:": "捕获浏览器控制台日志失败:", + "Failed to capture screenshot:": "捕获截图失败:", + "Failed to fetch revert preview:": "获取还原预览失败:", + "Error opening MCP page:": "打开 MCP 页面时出错:", + "Error opening MCP config modal:": "打开 MCP 配置弹窗时出错:", + "Error opening configure page:": "打开配置页面时出错:", + "Error parsing file diff JSON data:": "解析文件差异 JSON 数据时出错:", + "Failed to close all diff zones:": "关闭所有差异区域失败:", + "Browser is not enabled for this plan": "此计划未启用浏览器功能", + "URL is required": "需要 URL", + "url is required": "需要 url", + "Missing API key. Please make sure you are signed in to Antigravity. If the problem persists, please restart the IDE.": "缺少 API 密钥。请确保您已登录 Antigravity。如果问题仍然存在,请重启 IDE。", + "Function not implemented.": "功能未实现。", + "clientKey is required": "需要 clientKey", + "appName is required.": "需要 appName。", + "Objects are not valid as a React child (found:": "对象不是有效的 React 子元素 (发现:", + "React.Children.only expected to receive a single React element child.": "React.Children.only 期望接收单个 React 元素子节点。", + "Unknown encoding:": "未知编码:", + "out of range index": "索引超出范围", + "BigInt not supported": "不支持 BigInt", + "invalid base64 string.": "无效的 base64 字符串。", + "invalid UTF8": "无效的 UTF8", + "premature EOF": "过早的文件结束", + "useLanguageServerContext must be used within a LanguageServerContextProvider": "useLanguageServerContext 必须在 LanguageServerContextProvider 中使用", + "useContextMenuContext must be used within a ContextMenuProvider": "useContextMenuContext 必须在 ContextMenuProvider 中使用", + "useAgentWorkbenchContext must be used within an AgentWorkbenchContextProvider": "useAgentWorkbenchContext 必须在 AgentWorkbenchContextProvider 中使用", + "useBrowserContext must be used within a BrowserContextProvider": "useBrowserContext 必须在 BrowserContextProvider 中使用", + "useRegisterChatClientRequestHandler must be used within a ChatClientServerContextProvider": "useRegisterChatClientRequestHandler 必须在 ChatClientServerContextProvider 中使用", + "useTrajectorySummariesContext must be used within a TrajectorySummariesProvider": "useTrajectorySummariesContext 必须在 TrajectorySummariesProvider 中使用", + "useMessageHistoryContext must be used within a MessageHistoryContextProvider": "useMessageHistoryContext 必须在 MessageHistoryContextProvider 中使用", + "useTokenThemeContext must be used within a TokenThemeContextProvider": "useTokenThemeContext 必须在 TokenThemeContextProvider 中使用", + "You have to provide an `open` and an `onClose` prop to the `Dialog` component.": "您必须为 `Dialog` 组件提供 `open` 和 `onClose` 属性。", + "You provided an `onClose` prop to the `Dialog`, but forgot an `open` prop.": "您为 `Dialog` 提供了 `onClose` 属性,但忘记了 `open` 属性。", + "You provided an `open` prop to the `Dialog`, but forgot an `onClose` prop.": "您为 `Dialog` 提供了 `open` 属性,但忘记了 `onClose` 属性。", + "Path must be a string. Received": "路径必须是字符串。收到", + "The URL must be of scheme file": "URL 必须是 file 协议", + "Generator is already executing.": "生成器已在执行中。", + "Unknown unit": "未知单位", + "Unexpected object:": "意外的对象:", + "unable to serialize": "无法序列化", + "This undo action will not make any code changes.": "此撤销操作不会进行任何代码更改。", + "Messages can be sent while the agent is still working and your message will be queued and taken into consideration at the next available break in reasoning.": "您可以在代理仍在工作时发送消息,您的消息将被排队,并在下一个可用的推理间歇时被考虑。", + "This tool runs code that can access IDE extension APIs and potentially change the functionality of your IDE the same way that an IDE extension or plugin can.": "此工具运行的代码可以访问 IDE 扩展 API,并可能以与 IDE 扩展或插件相同的方式更改 IDE 的功能。", + "Too many requests, please try again in a bit!": "请求过多,请稍后重试!", + "This error is likely temporary. You can prompt the model to try again after some time.": "此错误可能是暂时的。您可以稍后提示模型重试。", + "Get notified when the agent needs your attention or completes a task.": "当代理需要您注意或完成任务时获得通知。", + "This model is currently experiencing some issues.": "此模型当前遇到一些问题。", + "Failed to load": "加载失败", + "Did you make sure to report this error on Slack?": "您确定已在 Slack 上报告此错误了吗?", + "Standard conversational mode.": "标准对话模式。", + "Uses Google conversational mixin.": "使用 Google 对话混入。", + "Uses custom mixin.": "使用自定义混入。", + "You can prompt the model to try again or start a new conversation if the error persists.": "您可以重试提示模型,或者如果错误持续存在,可以开始新的对话。", + "for more help.": "获取更多帮助。", + "On": "开", + "AI Shortcuts": "AI 快捷键", + "Manage": "管理", + "Snooze": "暂停", + "Manage MCP servers": "管理 MCP 服务器", + "View raw config": "查看原始配置", + "Terminal execution policy": "终端执行策略", + "Review policy": "审查策略", + "JavaScript execution policy": "JavaScript 执行策略", + "Disabled": "已禁用", + "Auto Execution": "自动执行", + "Clipboard Context": "剪贴板上下文", + "Enable Tab Sounds (Beta)": "启用 Tab 声音 (Beta)", + "Set the speed of tab suggestions": "设置 Tab 建议的速度", + "Open files in the background if the agent creates or edits them": "当 Agent 创建或编辑文件时在后台打开它们", + "Open Agent panel on window reload": "窗口重新加载时打开 Agent 面板", + "Predict the location of your next edit and navigates you there with a tab keypress": "预测下一个编辑位置,按 Tab 键即可跳转到该位置", + "Quickly add and update imports with a tab keypress.": "按 Tab 键快速添加和更新导入语句。", + "Highlight newly inserted text after accepting a Tab completion.": "接受 Tab 补全后高亮新插入的文本。", + "Slow": "慢速", + "Fast": "快速", + "View and manage Agent memories, workflows, and rules": "查看和管理 Agent 记忆、工作流和规则", + "Edit your SSH configuration": "编辑你的 SSH 配置", + "Accept hunk": "接受代码块", + "Open Agent": "打开 Agent", + "Reset to default": "重置为默认", + "Submit": "提交", + "Open Agent Manager": "打开 Agent 管理器", + "Settings": "设置", + "Editor-Specific Settings": "编辑器特定设置", + "Accept Changes": "接受更改", + "Hide selection nudge": "隐藏选中操作提示", + "Open Diff": "打开差异", + "Additional Options": "其他选项", + "Try Again": "再试一次", + "Add Context": "添加上下文", + "Open Conversation Picker": "打开对话选择器", + "Open File Search": "打开文件搜索", + "Focus Input": "聚焦输入框", + "New Conversation": "新建对话", + "Open Workspace Selector": "打开工作区选择器", + "Go Back": "后退", + "Go Forward": "前进", + "File Picker": "文件选择器", + "Toggle Editor": "切换编辑器", + "Select Previous Conversation": "选择上一个对话", + "Select Next Conversation": "选择下一个对话", + "Toggle Model Selector": "切换模型选择器", + "Start Voice Recording": "开始语音录制", + "Stop Voice Recording": "停止语音录制", + "Find in Pane": "在窗格中查找", + "Toggle Sidebar": "切换侧边栏", + "Toggle Auxiliary Pane": "切换辅助窗格", + "Toggle Terminal": "切换终端", + "Open Settings": "打开设置", + "Zoom In": "放大", + "Zoom Out": "缩小", + "Reset Zoom": "重置缩放", + "Navigation": "导航", + "Layout Controls": "布局控制", + "Shortcuts": "快捷键", + "Keyboard shortcuts for quick navigation and control.": "用于快速导航和控制的键盘快捷键。", + "Feedback Type": "反馈类型", + "Please describe the issue in detail. The more actionable your feedback, the quicker our team can address your request. Some helpful information includes:": "请详细描述该问题。您的反馈越具可操作性,我们的团队就能越快处理您的请求。一些有帮助的信息包括:", + "Steps to reproduce the issue": "重现问题的步骤", + "Expected behavior": "预期行为", + "Actual behavior": "实际行为", + "Any error messages": "任何错误消息", + "Any relevant information": "任何相关信息", + "Steps to Reproduce": "重现步骤", + "Please list the steps to reproduce the issue": "请列出重现该问题的步骤", + "Attach a screenshot (optional)": "附加屏幕截图 (可选)", + "Attach Antigravity server logs": "附加 Antigravity 服务器日志", + "Send feedback as": "发送反馈,身份为:", + "We recommend attaching logs. Attaching logs will help the Antigravity team act on and prioritize your feedback.": "我们建议附加日志。附加日志将帮助 Antigravity 团队针对您的反馈进行处理并排定优先级。", + "Model quota reached": "已达到模型配额限制", + "Upgrade": "升级", + "Thinking for ": "思考中 ", + "Thought for ": "思考了 ", + "Changes Overview": "更改概览", + "Settings - ": "设置 - " +}; + + function translateTextNode(node) { + if (node.nodeType === Node.TEXT_NODE) { + const originalText = node.nodeValue; + let text = originalText.trim(); + if (!text) return; + + if (dict[text]) { + node.nodeValue = originalText.replace(text, dict[text]); + return; + } + + // 动态前缀匹配 + if (text.startsWith("Thinking for ")) { + node.nodeValue = originalText.replace(text, "思考中 " + text.substring("Thinking for ".length)); + return; + } + if (text.startsWith("Thought for ")) { + node.nodeValue = originalText.replace(text, "思考了 " + text.substring("Thought for ".length)); + return; + } + if (text.startsWith("Changes Overview (")) { + node.nodeValue = originalText.replace(text, text.replace("Changes Overview", "更改概览")); + return; + } + if (text.startsWith("Terminal (") && text.includes(")")) { + node.nodeValue = originalText.replace(text, text.replace("Terminal", "终端")); + return; + } + } + } + + function translateAttributes(node) { + if (node.nodeType === Node.ELEMENT_NODE) { + ['aria-label', 'title', 'placeholder'].forEach(attr => { + if (node.hasAttribute(attr)) { + const val = node.getAttribute(attr); + if (val && dict[val]) { + node.setAttribute(attr, dict[val]); + } + } + }); + } + } + + // 使用 C++ 级的 TreeWalker 进行极速文本遍历,解决界面卡顿问题 + function processTree(root) { + if (root.nodeType === Node.TEXT_NODE) { + translateTextNode(root); + return; + } + + const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false); + let node; + while (node = walker.nextNode()) { + translateTextNode(node); + } + + if (root.nodeType === Node.ELEMENT_NODE) { + translateAttributes(root); + const elements = root.querySelectorAll('*'); + for (let i = 0; i < elements.length; i++) { + translateAttributes(elements[i]); + } + } + } + + let isTranslating = false; + const observer = new MutationObserver((mutations) => { + if (isTranslating) return; + isTranslating = true; + + // 批量处理 mutations 以提升性能 + const targetNodes = new Set(); + mutations.forEach((mutation) => { + if (mutation.type === 'childList') { + mutation.addedNodes.forEach(node => { + if (node.tagName !== 'SCRIPT' && node.tagName !== 'STYLE') { + targetNodes.add(node); + } + }); + } else if (mutation.type === 'characterData') { + translateTextNode(mutation.target); + } else if (mutation.type === 'attributes') { + const node = mutation.target; + const attr = mutation.attributeName; + const val = node.getAttribute(attr); + if (val && dict[val]) { + node.setAttribute(attr, dict[val]); + } + } + }); + + targetNodes.forEach(node => processTree(node)); + + isTranslating = false; + }); + + function init() { + if (document.body) { + processTree(document.body); + observer.observe(document.body, { childList: true, subtree: true, characterData: true, attributes: true, attributeFilter: ['aria-label', 'title', 'placeholder'] }); + } + } + + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } +})();