diff --git a/CITATION.cff b/CITATION.cff
new file mode 100644
index 0000000..c83812b
--- /dev/null
+++ b/CITATION.cff
@@ -0,0 +1,18 @@
+cff-version: 1.2.0
+message: "If Agent Switch supports your work, please cite the software using these metadata."
+title: "Agent Switch"
+type: software
+authors:
+ - name: "JNHFlow21"
+repository-code: "https://github.com/JNHFlow21/agent-switch"
+url: "https://github.com/JNHFlow21/agent-switch"
+license: MIT
+version: 0.2.0
+date-released: 2026-07-26
+keywords:
+ - MCP
+ - macOS
+ - AI agents
+ - secret management
+ - Codex
+ - Claude Code
diff --git a/README.md b/README.md
index a9816cb..804acd9 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,15 @@
-
+
+
+
+
+
+
+
+
+
@@ -40,6 +48,21 @@ credential store, and deterministic per-agent projections.
> and [release checksums](https://github.com/JNHFlow21/agent-switch/releases/tag/v0.2.0)
> before installing.
+
+## Project activity
+
+| Public signal | Live or latest owner-visible value |
+| --- | ---: |
+| Stars / forks / commits / release downloads | Live badges above |
+| README visits | Public counter above; may include bots and repeat visits |
+| Unique repository visitors | **0** in the rolling 14-day GitHub Traffic window |
+| Unique Git cloners | **11** (**12** total clones) in the rolling 14-day window |
+
+Traffic snapshot: 2026-08-10. GitHub exposes clone and unique-visitor analytics only to maintainers, so those values are a dated, transparent snapshot rather than a token-backed public badge.
+
+The native app follows the macOS language preference and ships complete
+**English** and **Simplified Chinese** interface catalogs.
+
## Quick start
### Prerequisites
diff --git a/README.zh-CN.md b/README.zh-CN.md
index e4a97b4..94a4794 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -19,7 +19,15 @@
-
+
+
+
+
+
+
+
+
+
@@ -38,6 +46,20 @@ Agent Switch 用一个本地 MCP 注册表、一个私密凭据存储和可重
> quarantine。安装前请先检查[公开源码](https://github.com/JNHFlow21/agent-switch)
> 和[发行校验和](https://github.com/JNHFlow21/agent-switch/releases/tag/v0.2.0)。
+
+## 项目数据
+
+| 公开指标 | 实时数据或最近一次维护者可见数据 |
+| --- | ---: |
+| Star / Fork / Commit / 发行下载量 | 见上方实时徽章 |
+| README 访问量 | 见上方公开计数器;可能包含机器人和重复访问 |
+| 仓库独立访客 | GitHub Traffic 最近 14 天滚动窗口内为 **0** |
+| 独立克隆者 | 最近 14 天滚动窗口内为 **11**(共 **12** 次克隆) |
+
+数据快照日期:2026-08-10。GitHub 只向仓库维护者提供克隆与独立访客数据,因此这里采用注明日期的透明快照,而不是需要私密 Token 的公开徽章。
+
+原生应用会跟随 macOS 的语言偏好,并完整提供**英文**与**简体中文**界面。
+
## 快速开始
### 前置条件
diff --git a/docs/assets/agent-switch-dashboard-en.png b/docs/assets/agent-switch-dashboard-en.png
new file mode 100644
index 0000000..f4cbbb2
Binary files /dev/null and b/docs/assets/agent-switch-dashboard-en.png differ
diff --git a/docs/assets/agent-switch-dashboard.jpg b/docs/assets/agent-switch-dashboard.jpg
deleted file mode 100644
index 1c95dd2..0000000
Binary files a/docs/assets/agent-switch-dashboard.jpg and /dev/null differ
diff --git a/llms.txt b/llms.txt
index 3870709..c49a301 100644
--- a/llms.txt
+++ b/llms.txt
@@ -5,6 +5,7 @@
Canonical repository: https://github.com/JNHFlow21/agent-switch
License: MIT
Platform: macOS 14+ for the native app; Python 3.11+ for the CLI
+Interface languages: English and Simplified Chinese
## Primary purpose
@@ -21,6 +22,7 @@ Agent Switch prevents configuration drift across local AI coding agents. It cent
- Diagnostics list secret names only.
- Downloaded Skills are dormant until explicitly activated for a project or the global profile.
- Skill source updates never activate Skills.
+- The native interface is localized in English and Simplified Chinese and follows the macOS language preference.
- `doctor` previews and validates; `reconcile` writes atomically and creates backups.
## Supported integrations
diff --git a/macos-app/AgentSwitch/AgentSwitch.xcodeproj/project.pbxproj b/macos-app/AgentSwitch/AgentSwitch.xcodeproj/project.pbxproj
index 50ac0a5..4d281d5 100644
--- a/macos-app/AgentSwitch/AgentSwitch.xcodeproj/project.pbxproj
+++ b/macos-app/AgentSwitch/AgentSwitch.xcodeproj/project.pbxproj
@@ -24,6 +24,7 @@
A1000001000000000000000F /* AgentsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2000001000000000000000F; };
A10000010000000000000010 /* CLIsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A20000010000000000000010; };
A10000010000000000000011 /* SkillsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A20000010000000000000011; };
+ A10000010000000000000012 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = A20000010000000000000012; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@@ -44,6 +45,7 @@
A2000001000000000000000F /* AgentsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AgentsView.swift; sourceTree = ""; };
A20000010000000000000010 /* CLIsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CLIsView.swift; sourceTree = ""; };
A20000010000000000000011 /* SkillsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SkillsView.swift; sourceTree = ""; };
+ A20000010000000000000012 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = ""; };
A30000010000000000000001 /* Agent Switch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Agent Switch.app"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
@@ -179,6 +181,7 @@
isa = PBXGroup;
children = (
A2000001000000000000000D /* L10n.swift */,
+ A20000010000000000000012 /* Localizable.xcstrings */,
A2000001000000000000000E /* Assets.xcassets */,
);
path = Resources;
@@ -243,6 +246,7 @@
hasScannedForEncodings = 0;
knownRegions = (
en,
+ "zh-Hans",
Base,
);
mainGroup = A40000010000000000000001;
@@ -261,6 +265,7 @@
buildActionMask = 2147483647;
files = (
A1000001000000000000000E /* Assets.xcassets in Resources */,
+ A10000010000000000000012 /* Localizable.xcstrings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/macos-app/AgentSwitch/AgentSwitch/AgentSwitchApp.swift b/macos-app/AgentSwitch/AgentSwitch/AgentSwitchApp.swift
index b3585f3..9ef2c93 100644
--- a/macos-app/AgentSwitch/AgentSwitch/AgentSwitchApp.swift
+++ b/macos-app/AgentSwitch/AgentSwitch/AgentSwitchApp.swift
@@ -80,9 +80,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
let appMenuItem = NSMenuItem()
let appMenu = NSMenu(title: L10n.appName)
- appMenu.addItem(NSMenuItem(title: "About \(L10n.appName)", action: #selector(NSApplication.orderFrontStandardAboutPanel(_:)), keyEquivalent: ""))
+ appMenu.addItem(NSMenuItem(title: L10n.aboutAgentSwitch, action: #selector(NSApplication.orderFrontStandardAboutPanel(_:)), keyEquivalent: ""))
appMenu.addItem(NSMenuItem.separator())
- appMenu.addItem(NSMenuItem(title: "Quit \(L10n.appName)", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q"))
+ appMenu.addItem(NSMenuItem(title: L10n.quitAgentSwitch, action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q"))
appMenuItem.submenu = appMenu
mainMenu.addItem(appMenuItem)
@@ -93,9 +93,9 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
mainMenu.addItem(actionsMenuItem)
let windowMenuItem = NSMenuItem()
- let windowMenu = NSMenu(title: "Window")
- windowMenu.addItem(menuItem(title: "Show \(L10n.appName)", action: #selector(showMainWindowFromMenu), key: "0"))
- windowMenu.addItem(NSMenuItem(title: "Minimize", action: #selector(NSWindow.miniaturize(_:)), keyEquivalent: "m"))
+ let windowMenu = NSMenu(title: L10n.window)
+ windowMenu.addItem(menuItem(title: L10n.showAgentSwitch, action: #selector(showMainWindowFromMenu), key: "0"))
+ windowMenu.addItem(NSMenuItem(title: L10n.minimize, action: #selector(NSWindow.miniaturize(_:)), keyEquivalent: "m"))
windowMenuItem.submenu = windowMenu
mainMenu.addItem(windowMenuItem)
NSApp.windowsMenu = windowMenu
diff --git a/macos-app/AgentSwitch/AgentSwitch/Features/Dashboard/DashboardView.swift b/macos-app/AgentSwitch/AgentSwitch/Features/Dashboard/DashboardView.swift
index 4954d13..2c97409 100644
--- a/macos-app/AgentSwitch/AgentSwitch/Features/Dashboard/DashboardView.swift
+++ b/macos-app/AgentSwitch/AgentSwitch/Features/Dashboard/DashboardView.swift
@@ -55,7 +55,7 @@ struct DashboardView: View {
DSMetricCard(
label: L10n.runtimeState,
value: report.map { $0.blocked ? L10n.blocked : L10n.ready } ?? "—",
- note: report.map { $0.driftCount == 0 ? L10n.noDriftDetected : L10n.reviewPlannedChanges } ?? "加载中..."
+ note: report.map { $0.driftCount == 0 ? L10n.noDriftDetected : L10n.reviewPlannedChanges } ?? L10n.loadingTools
)
DSMetricCard(
label: L10n.driftChanges,
diff --git a/macos-app/AgentSwitch/AgentSwitch/Features/Skills/SkillsView.swift b/macos-app/AgentSwitch/AgentSwitch/Features/Skills/SkillsView.swift
index afc51a1..3ad553a 100644
--- a/macos-app/AgentSwitch/AgentSwitch/Features/Skills/SkillsView.swift
+++ b/macos-app/AgentSwitch/AgentSwitch/Features/Skills/SkillsView.swift
@@ -154,7 +154,7 @@ private enum SkillFilter: String, CaseIterable, Identifiable {
var id: String { rawValue }
var label: String {
switch self {
- case .all: return "全部"
+ case .all: return L10n.allSkills
case .dormant: return L10n.dormant
case .project: return L10n.projectActive
case .global: return L10n.globalActive
diff --git a/macos-app/AgentSwitch/AgentSwitch/Resources/L10n.swift b/macos-app/AgentSwitch/AgentSwitch/Resources/L10n.swift
index df18410..119a30e 100644
--- a/macos-app/AgentSwitch/AgentSwitch/Resources/L10n.swift
+++ b/macos-app/AgentSwitch/AgentSwitch/Resources/L10n.swift
@@ -10,186 +10,200 @@ enum AppVersion {
}
enum L10n {
+ private static func localized(_ key: String.LocalizationValue) -> String {
+#if SWIFT_PACKAGE
+ String(localized: key, bundle: .module)
+#else
+ String(localized: key, bundle: .main)
+#endif
+ }
+
// MARK: - Sidebar
- static let appName = String(localized: "Agent Switch", comment: "App name")
- static let dashboard = String(localized: "仪表板", comment: "Sidebar: Dashboard")
- static let agents = String(localized: "Agent 托管", comment: "Sidebar: Agents")
- static let clis = String(localized: "CLI 管理", comment: "Sidebar: CLI")
- static let skills = String(localized: "Skill 仓库", comment: "Sidebar: Skills")
- static let mcpTools = String(localized: "MCP 工具", comment: "Sidebar: MCP Tools")
- static let secrets = String(localized: "密钥管理", comment: "Sidebar: Secrets")
- static let settings = String(localized: "设置", comment: "Sidebar: Settings")
- static let healthy = String(localized: "运行正常", comment: "Status: healthy")
- static let needsAttention = String(localized: "需要关注", comment: "Status: needs attention")
- static let checking = String(localized: "检查中", comment: "Status: checking")
+ static let appName = localized("appName")
+ static let dashboard = localized("dashboard")
+ static let agents = localized("agents")
+ static let clis = localized("clis")
+ static let skills = localized("skills")
+ static let mcpTools = localized("mcpTools")
+ static let secrets = localized("secrets")
+ static let settings = localized("settings")
+ static let healthy = localized("healthy")
+ static let needsAttention = localized("needsAttention")
+ static let checking = localized("checking")
// MARK: - Dashboard
- static let lastRefreshed = String(localized: "上次刷新:", comment: "Dashboard header")
- static let blocked = String(localized: "已阻塞", comment: "State: blocked")
- static let ready = String(localized: "就绪", comment: "State: ready")
- static let drift = String(localized: "漂移", comment: "Drift suffix")
- static let runtimeState = String(localized: "运行状态", comment: "Metric: runtime state")
- static let driftChanges = String(localized: "漂移变更", comment: "Metric: drift changes")
- static let findingsLabel = String(localized: "检查结果", comment: "Metric: findings")
- static let secretsLabel = String(localized: "密钥状态", comment: "Metric: secrets")
- static let noDriftDetected = String(localized: "无漂移", comment: "Metric note")
- static let reviewPlannedChanges = String(localized: "请检查计划变更", comment: "Metric note")
- static let allTargetsInSync = String(localized: "所有目标已同步", comment: "Metric note")
- static let runReconcileToFix = String(localized: "运行修复以解决", comment: "Metric note")
- static let noIssuesFound = String(localized: "无问题", comment: "Metric note")
- static let errors = String(localized: "个错误", comment: "Error count suffix")
- static let allPresent = String(localized: "全部就位", comment: "Metric note")
- static let missing = String(localized: "缺失", comment: "Missing suffix")
- static let loadFailed = String(localized: "加载失败", comment: "Dashboard error")
+ static let lastRefreshed = localized("lastRefreshed")
+ static let blocked = localized("blocked")
+ static let ready = localized("ready")
+ static let drift = localized("drift")
+ static let runtimeState = localized("runtimeState")
+ static let driftChanges = localized("driftChanges")
+ static let findingsLabel = localized("findingsLabel")
+ static let secretsLabel = localized("secretsLabel")
+ static let noDriftDetected = localized("noDriftDetected")
+ static let reviewPlannedChanges = localized("reviewPlannedChanges")
+ static let allTargetsInSync = localized("allTargetsInSync")
+ static let runReconcileToFix = localized("runReconcileToFix")
+ static let noIssuesFound = localized("noIssuesFound")
+ static let errors = localized("errors")
+ static let allPresent = localized("allPresent")
+ static let missing = localized("missing")
+ static let loadFailed = localized("loadFailed")
// MARK: - Routes
- static let accessRoutes = String(localized: "访问路由", comment: "Section: Access Routes")
- static let searchDefault = String(localized: "搜索默认", comment: "Route: search default")
- static let xReader = String(localized: "X 阅读器", comment: "Route: X reader")
- static let xFallback = String(localized: "X 备用", comment: "Route: X fallback")
+ static let accessRoutes = localized("accessRoutes")
+ static let searchDefault = localized("searchDefault")
+ static let xReader = localized("xReader")
+ static let xFallback = localized("xFallback")
// MARK: - Findings
- static let findings = String(localized: "检查发现", comment: "Section: Findings")
- static let noFindingsHealthy = String(localized: "无异常发现,所有托管资源运行正常。", comment: "Empty findings")
- static let plannedChanges = String(localized: "计划变更", comment: "Section: Planned Changes")
- static let noPlannedChanges = String(localized: "无计划变更,修复同步当前为空操作。", comment: "Empty changes")
+ static let findings = localized("findings")
+ static let noFindingsHealthy = localized("noFindingsHealthy")
+ static let plannedChanges = localized("plannedChanges")
+ static let noPlannedChanges = localized("noPlannedChanges")
// MARK: - Tools
- static let managedMCPTools = String(localized: "托管 MCP 工具", comment: "Page: Tools")
- static let loadingTools = String(localized: "加载工具中…", comment: "Loading state")
- static let targets = String(localized: "目标应用", comment: "Tool row: targets")
- static let secretsSection = String(localized: "所需密钥", comment: "Tool row: secrets")
- static let command = String(localized: "命令", comment: "Tool row: command")
- static let readyState = String(localized: "就绪", comment: "Tool badge")
- static let missingSecrets = String(localized: "缺少密钥", comment: "Tool badge")
- static let driftState = String(localized: "漂移", comment: "Tool badge: drift")
- static let addMCP = String(localized: "添加 MCP", comment: "Add MCP")
- static let editMCP = String(localized: "编辑 MCP", comment: "Edit MCP")
- static let removeMCP = String(localized: "删除 MCP", comment: "Remove MCP")
- static let removeMCPConfirmation = String(localized: "确认从统一注册表删除:", comment: "Remove MCP confirmation")
- static let enableMCP = String(localized: "启用 MCP", comment: "Enable MCP")
- static let disableMCP = String(localized: "停用 MCP", comment: "Disable MCP")
- static let disabledMCP = String(localized: "已停用", comment: "Disabled MCP")
- static let importMCPs = String(localized: "导入已有 MCP", comment: "Import MCPs")
- static let importAndAdoptMCPs = String(localized: "备份并统一接管", comment: "Import and adopt MCPs")
- static let importMCPConfirmation = String(localized: "Agent Switch 会扫描已安装 Agent 的 MCP,迁移内嵌密钥,备份原配置,再用统一注册表生成托管项。", comment: "Import MCP confirmation")
- static let discoveredMCPs = String(localized: "发现 MCP", comment: "Import preview discovered count")
- static let supportedMCPs = String(localized: "可接管 MCP", comment: "Import preview supported count")
- static let skippedMCPs = String(localized: "保留未接管", comment: "Import preview skipped MCPs")
- static let secretNamesOnly = String(localized: "密钥名称(不含值)", comment: "Import preview secret names")
- static let none = String(localized: "无", comment: "Empty value")
- static let saveMCP = String(localized: "保存 MCP", comment: "Save MCP")
- static let mcpID = String(localized: "MCP ID,例如 filesystem", comment: "MCP id")
- static let mcpName = String(localized: "显示名称", comment: "MCP name")
- static let mcpCommand = String(localized: "启动命令", comment: "MCP command")
- static let mcpDescription = String(localized: "说明(可选)", comment: "MCP description")
- static let mcpArguments = String(localized: "参数(每行一个)", comment: "MCP arguments")
- static let mcpRequiredSecrets = String(localized: "所需密钥名称(每行一个)", comment: "MCP secrets")
- static let mcpEnvironment = String(localized: "普通环境变量(每行 NAME=VALUE;密钥不要填这里)", comment: "MCP environment")
- static let mcpEditorNote = String(localized: "密钥值只在密钥页面保存;每个 MCP 运行时只能获得这里声明的密钥。", comment: "MCP editor note")
+ static let managedMCPTools = localized("managedMCPTools")
+ static let loadingTools = localized("loadingTools")
+ static let targets = localized("targets")
+ static let secretsSection = localized("secretsSection")
+ static let command = localized("command")
+ static let readyState = localized("readyState")
+ static let missingSecrets = localized("missingSecrets")
+ static let driftState = localized("driftState")
+ static let addMCP = localized("addMCP")
+ static let editMCP = localized("editMCP")
+ static let removeMCP = localized("removeMCP")
+ static let removeMCPConfirmation = localized("removeMCPConfirmation")
+ static let enableMCP = localized("enableMCP")
+ static let disableMCP = localized("disableMCP")
+ static let disabledMCP = localized("disabledMCP")
+ static let importMCPs = localized("importMCPs")
+ static let importAndAdoptMCPs = localized("importAndAdoptMCPs")
+ static let importMCPConfirmation = localized("importMCPConfirmation")
+ static let discoveredMCPs = localized("discoveredMCPs")
+ static let supportedMCPs = localized("supportedMCPs")
+ static let skippedMCPs = localized("skippedMCPs")
+ static let secretNamesOnly = localized("secretNamesOnly")
+ static let none = localized("none")
+ static let saveMCP = localized("saveMCP")
+ static let mcpID = localized("mcpID")
+ static let mcpName = localized("mcpName")
+ static let mcpCommand = localized("mcpCommand")
+ static let mcpDescription = localized("mcpDescription")
+ static let mcpArguments = localized("mcpArguments")
+ static let mcpRequiredSecrets = localized("mcpRequiredSecrets")
+ static let mcpEnvironment = localized("mcpEnvironment")
+ static let mcpEditorNote = localized("mcpEditorNote")
// MARK: - Secrets
- static let secretsInventory = String(localized: "密钥清单", comment: "Page: Secrets")
- static let secretManagementSubtitle = String(localized: "安全地添加、查看和维护本机密钥", comment: "Page: Secrets subtitle")
- static let secretFile = String(localized: "密钥文件", comment: "Metric: secret file")
- static let found = String(localized: "已找到", comment: "Secret file found")
- static let missingFile = String(localized: "文件缺失", comment: "Secret file missing")
- static let present = String(localized: "已配置", comment: "Metric: present")
- static let ofRequired = String(localized: "共需", comment: "of N required prefix")
- static let requiredSuffix = String(localized: "项", comment: "required suffix")
- static let allSecretsConfigured = String(localized: "所有密钥已配置", comment: "Metric note")
- static let requiredSecrets = String(localized: "所需密钥列表", comment: "Section: Required Secrets")
- static let presentBadge = String(localized: "已配置", comment: "Badge: present")
- static let missingBadge = String(localized: "缺失", comment: "Badge: missing")
- static let secretFileLocation = String(localized: "密钥文件位置", comment: "Section: Secret File Location")
- static let revealInFinder = String(localized: "在访达中显示", comment: "Button: Reveal in Finder")
- static let secretsRuntimeNote = String(localized: "密钥由 wrapper 脚本在运行时加载,不会嵌入应用配置文件中。", comment: "Note")
- static let noSecretInfo = String(localized: "无密钥信息", comment: "Empty state title")
- static let runDoctorForSecrets = String(localized: "运行 Doctor 以检查密钥状态", comment: "Empty state subtitle")
- static let stored = String(localized: "已保存", comment: "Secret stored count")
- static let storedSecrets = String(localized: "已保存密钥", comment: "Metric: stored secrets")
- static let storedSecretsNote = String(localized: "包括暂未被 MCP 引用的密钥", comment: "Stored secrets note")
- static let requiredSecretsNote = String(localized: "当前 MCP 配置声明需要", comment: "Required secrets note")
- static let allSecrets = String(localized: "全部密钥", comment: "Section: all secrets")
- static let noStoredSecrets = String(localized: "尚未保存任何密钥。", comment: "Empty secret list")
- static let addSecret = String(localized: "添加密钥", comment: "Add secret")
- static let updateSecret = String(localized: "更新密钥", comment: "Update secret")
- static let deleteSecret = String(localized: "删除密钥", comment: "Delete secret")
- static let deleteSecretConfirmation = String(localized: "确认删除本机密钥:", comment: "Delete secret confirmation")
- static let revealSecret = String(localized: "查看密钥", comment: "Reveal secret")
- static let hideSecret = String(localized: "隐藏密钥", comment: "Hide secret")
- static let copySecret = String(localized: "复制密钥", comment: "Copy secret")
- static let configureSecret = String(localized: "配置密钥", comment: "Configure missing secret")
- static let notConfigured = String(localized: "尚未配置", comment: "Secret missing")
- static let requiredBadge = String(localized: "必需", comment: "Required badge")
- static let secretEditorNote = String(localized: "密钥值通过安全管道写入,不会进入命令参数或日志。", comment: "Secret editor note")
- static let usedByMCP = String(localized: "授权给", comment: "Secret consumers")
- static let secretName = String(localized: "密钥名称,例如 FIRECRAWL_API_KEY", comment: "Secret name field")
- static let secretNameLabel = String(localized: "密钥名称", comment: "Existing secret name label")
- static let secretValue = String(localized: "密钥值", comment: "Secret value field")
- static let cancel = String(localized: "取消", comment: "Cancel")
+ static let secretsInventory = localized("secretsInventory")
+ static let secretManagementSubtitle = localized("secretManagementSubtitle")
+ static let secretFile = localized("secretFile")
+ static let found = localized("found")
+ static let missingFile = localized("missingFile")
+ static let present = localized("present")
+ static let ofRequired = localized("ofRequired")
+ static let requiredSuffix = localized("requiredSuffix")
+ static let allSecretsConfigured = localized("allSecretsConfigured")
+ static let requiredSecrets = localized("requiredSecrets")
+ static let presentBadge = localized("presentBadge")
+ static let missingBadge = localized("missingBadge")
+ static let secretFileLocation = localized("secretFileLocation")
+ static let revealInFinder = localized("revealInFinder")
+ static let secretsRuntimeNote = localized("secretsRuntimeNote")
+ static let noSecretInfo = localized("noSecretInfo")
+ static let runDoctorForSecrets = localized("runDoctorForSecrets")
+ static let stored = localized("stored")
+ static let storedSecrets = localized("storedSecrets")
+ static let storedSecretsNote = localized("storedSecretsNote")
+ static let requiredSecretsNote = localized("requiredSecretsNote")
+ static let allSecrets = localized("allSecrets")
+ static let noStoredSecrets = localized("noStoredSecrets")
+ static let addSecret = localized("addSecret")
+ static let updateSecret = localized("updateSecret")
+ static let deleteSecret = localized("deleteSecret")
+ static let deleteSecretConfirmation = localized("deleteSecretConfirmation")
+ static let revealSecret = localized("revealSecret")
+ static let hideSecret = localized("hideSecret")
+ static let copySecret = localized("copySecret")
+ static let configureSecret = localized("configureSecret")
+ static let notConfigured = localized("notConfigured")
+ static let requiredBadge = localized("requiredBadge")
+ static let secretEditorNote = localized("secretEditorNote")
+ static let usedByMCP = localized("usedByMCP")
+ static let secretName = localized("secretName")
+ static let secretNameLabel = localized("secretNameLabel")
+ static let secretValue = localized("secretValue")
+ static let cancel = localized("cancel")
// MARK: - CLI management
- static let cliManagement = String(localized: "CLI 管理", comment: "Page: CLI management")
- static let cliManagementSubtitle = String(localized: "查看本机 Agent 与工具链的安装路径和版本", comment: "CLI page subtitle")
- static let installed = String(localized: "已安装", comment: "Installed status")
- static let notInstalled = String(localized: "未安装", comment: "Not installed status")
- static let packageManager = String(localized: "安装方式", comment: "CLI package manager")
- static let installedCLIs = String(localized: "已安装 CLI", comment: "Installed CLI metric")
- static let cliInventory = String(localized: "CLI 清单", comment: "CLI list")
- static let cliUpdateNote = String(localized: "当前先统一盘点版本与路径;自动更新将按各 CLI 的安装方式执行。", comment: "CLI update note")
+ static let cliManagement = localized("cliManagement")
+ static let cliManagementSubtitle = localized("cliManagementSubtitle")
+ static let installed = localized("installed")
+ static let notInstalled = localized("notInstalled")
+ static let packageManager = localized("packageManager")
+ static let installedCLIs = localized("installedCLIs")
+ static let cliInventory = localized("cliInventory")
+ static let cliUpdateNote = localized("cliUpdateNote")
// MARK: - Skill management
- static let skillWarehouse = String(localized: "Skill 仓库", comment: "Page: Skill warehouse")
- static let skillWarehouseSubtitle = String(localized: "下载只入库;明确加载后才进入项目或全局", comment: "Skill page subtitle")
- static let skillSources = String(localized: "来源", comment: "Skill sources")
- static let skillProfiles = String(localized: "项目配置", comment: "Skill profiles")
- static let skillInventory = String(localized: "Skill 清单", comment: "Skill list")
- static let dormant = String(localized: "沉默", comment: "Dormant skill")
- static let projectActive = String(localized: "项目", comment: "Project active skill")
- static let globalActive = String(localized: "全局", comment: "Global active skill")
- static let missingSkill = String(localized: "缺失", comment: "Missing skill")
- static let searchSkills = String(localized: "搜索 Skill、来源或项目", comment: "Search skills")
- static let updateGitSources = String(localized: "更新 Git 来源", comment: "Update git skill sources")
- static let updateGitSourcesNote = String(localized: "只更新 Skill Hub 中的 Git 仓库和版本锁,不会自动启用任何 Skill。", comment: "Skill update note")
- static let noMatchingSkills = String(localized: "没有匹配的 Skill", comment: "No matching skills")
+ static let skillWarehouse = localized("skillWarehouse")
+ static let skillWarehouseSubtitle = localized("skillWarehouseSubtitle")
+ static let skillSources = localized("skillSources")
+ static let skillProfiles = localized("skillProfiles")
+ static let skillInventory = localized("skillInventory")
+ static let allSkills = localized("allSkills")
+ static let dormant = localized("dormant")
+ static let projectActive = localized("projectActive")
+ static let globalActive = localized("globalActive")
+ static let missingSkill = localized("missingSkill")
+ static let searchSkills = localized("searchSkills")
+ static let updateGitSources = localized("updateGitSources")
+ static let updateGitSourcesNote = localized("updateGitSourcesNote")
+ static let noMatchingSkills = localized("noMatchingSkills")
// MARK: - File actions
- static let openFile = String(localized: "直接打开", comment: "Open file action")
- static let syncAndCheck = String(localized: "同步并检查", comment: "Single toolbar synchronization action")
+ static let openFile = localized("openFile")
+ static let syncAndCheck = localized("syncAndCheck")
// MARK: - Agent management
- static let agentManagement = String(localized: "Agent 托管", comment: "Page: agent management")
- static let agentManagementSubtitle = String(localized: "一套规则,同步到所有受支持的 Agent", comment: "Agent page subtitle")
- static let managed = String(localized: "已托管", comment: "Managed status")
- static let detected = String(localized: "已发现", comment: "Detected status")
- static let notDetected = String(localized: "未发现", comment: "Not detected status")
- static let notManaged = String(localized: "未托管", comment: "Not managed status")
- static let synchronized = String(localized: "已同步", comment: "Synchronized status")
- static let needsSync = String(localized: "需要同步", comment: "Needs sync status")
- static let manageDetectedAgents = String(localized: "托管并同步所有支持的 Agent", comment: "Manage supported agents")
- static let manageDetectedAgentsNote = String(localized: "只写入 Agent Switch 管理区域;其他配置保持不变并自动备份。", comment: "Manage agents note")
- static let howManagementWorks = String(localized: "规则如何生效", comment: "How management works heading")
- static let howManagementWorksBody = String(localized: "Agent Switch 维护一份统一规则,再分别写入 Codex 的 AGENTS.md 入口、Claude Code 的 CLAUDE.md 管理区和 Hermes 的 SOUL.md 管理区。", comment: "How management works body")
- static let welcomeHeading = String(localized: "让 Agent Switch 接管这套环境", comment: "Onboarding heading")
- static let welcomeBody = String(localized: "已发现以下 Agent。开始托管后,Agent Switch 将同步统一指令和 MCP,并保留、备份现有配置。", comment: "Onboarding body")
- static let startManagement = String(localized: "开始托管", comment: "Start management")
- static let notNow = String(localized: "暂不处理", comment: "Not now")
+ static let agentManagement = localized("agentManagement")
+ static let agentManagementSubtitle = localized("agentManagementSubtitle")
+ static let managed = localized("managed")
+ static let detected = localized("detected")
+ static let notDetected = localized("notDetected")
+ static let notManaged = localized("notManaged")
+ static let synchronized = localized("synchronized")
+ static let needsSync = localized("needsSync")
+ static let manageDetectedAgents = localized("manageDetectedAgents")
+ static let manageDetectedAgentsNote = localized("manageDetectedAgentsNote")
+ static let howManagementWorks = localized("howManagementWorks")
+ static let howManagementWorksBody = localized("howManagementWorksBody")
+ static let welcomeHeading = localized("welcomeHeading")
+ static let welcomeBody = localized("welcomeBody")
+ static let startManagement = localized("startManagement")
+ static let notNow = localized("notNow")
// MARK: - Settings
- static let general = String(localized: "通用", comment: "Settings: General")
- static let autoRefreshOnLaunch = String(localized: "启动时自动刷新", comment: "Settings toggle")
- static let includeCCSwitch = String(localized: "Doctor 检查时包含 CC Switch 数据库", comment: "Settings toggle")
- static let runtimePaths = String(localized: "运行时路径", comment: "Settings: Runtime Paths")
- static let config = String(localized: "配置文件", comment: "Settings label")
- static let secretsPath = String(localized: "密钥文件", comment: "Settings label")
- static let wrappers = String(localized: "Wrapper 脚本", comment: "Settings label")
- static let backups = String(localized: "备份目录", comment: "Settings label")
- static let targetConfigs = String(localized: "目标配置文件", comment: "Settings: Target Configs")
- static let about = String(localized: "关于", comment: "Settings: About")
- static let version = String(localized: "版本", comment: "Settings label")
- static let repository = String(localized: "仓库地址", comment: "Settings label")
+ static let general = localized("general")
+ static let autoRefreshOnLaunch = localized("autoRefreshOnLaunch")
+ static let includeCCSwitch = localized("includeCCSwitch")
+ static let runtimePaths = localized("runtimePaths")
+ static let config = localized("config")
+ static let secretsPath = localized("secretsPath")
+ static let wrappers = localized("wrappers")
+ static let backups = localized("backups")
+ static let targetConfigs = localized("targetConfigs")
+ static let about = localized("about")
+ static let version = localized("version")
+ static let repository = localized("repository")
// MARK: - Actions (menu)
- static let actions = String(localized: "操作", comment: "Menu: Actions")
+ static let actions = localized("actions")
+ static let aboutAgentSwitch = localized("aboutAgentSwitch")
+ static let quitAgentSwitch = localized("quitAgentSwitch")
+ static let window = localized("window")
+ static let showAgentSwitch = localized("showAgentSwitch")
+ static let minimize = localized("minimize")
}
diff --git a/macos-app/AgentSwitch/AgentSwitch/Resources/Localizable.xcstrings b/macos-app/AgentSwitch/AgentSwitch/Resources/Localizable.xcstrings
new file mode 100644
index 0000000..5b71721
--- /dev/null
+++ b/macos-app/AgentSwitch/AgentSwitch/Resources/Localizable.xcstrings
@@ -0,0 +1,2811 @@
+{
+ "sourceLanguage": "en",
+ "strings": {
+ "appName": {
+ "comment": "App name",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Agent Switch"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Agent Switch"
+ }
+ }
+ }
+ },
+ "dashboard": {
+ "comment": "Sidebar: Dashboard",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Dashboard"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "仪表板"
+ }
+ }
+ }
+ },
+ "agents": {
+ "comment": "Sidebar: Agents",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Agents"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Agent 托管"
+ }
+ }
+ }
+ },
+ "clis": {
+ "comment": "Sidebar: CLI",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "CLI Inventory"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "CLI 管理"
+ }
+ }
+ }
+ },
+ "skills": {
+ "comment": "Sidebar: Skills",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Skill Library"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Skill 仓库"
+ }
+ }
+ }
+ },
+ "mcpTools": {
+ "comment": "Sidebar: MCP Tools",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "MCP Tools"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "MCP 工具"
+ }
+ }
+ }
+ },
+ "secrets": {
+ "comment": "Sidebar: Secrets",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Secrets"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "密钥管理"
+ }
+ }
+ }
+ },
+ "settings": {
+ "comment": "Sidebar: Settings",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Settings"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "设置"
+ }
+ }
+ }
+ },
+ "healthy": {
+ "comment": "Status: healthy",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Healthy"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "运行正常"
+ }
+ }
+ }
+ },
+ "needsAttention": {
+ "comment": "Status: needs attention",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Needs attention"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "需要关注"
+ }
+ }
+ }
+ },
+ "checking": {
+ "comment": "Status: checking",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Checking"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "检查中"
+ }
+ }
+ }
+ },
+ "lastRefreshed": {
+ "comment": "Dashboard header",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Last refreshed: "
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "上次刷新:"
+ }
+ }
+ }
+ },
+ "blocked": {
+ "comment": "State: blocked",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Blocked"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "已阻塞"
+ }
+ }
+ }
+ },
+ "ready": {
+ "comment": "State: ready",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Ready"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "就绪"
+ }
+ }
+ }
+ },
+ "drift": {
+ "comment": "Drift suffix",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "drift"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "漂移"
+ }
+ }
+ }
+ },
+ "runtimeState": {
+ "comment": "Metric: runtime state",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Runtime status"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "运行状态"
+ }
+ }
+ }
+ },
+ "driftChanges": {
+ "comment": "Metric: drift changes",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Drift changes"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "漂移变更"
+ }
+ }
+ }
+ },
+ "findingsLabel": {
+ "comment": "Metric: findings",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Findings"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "检查结果"
+ }
+ }
+ }
+ },
+ "secretsLabel": {
+ "comment": "Metric: secrets",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Secret status"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "密钥状态"
+ }
+ }
+ }
+ },
+ "noDriftDetected": {
+ "comment": "Metric note",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "No drift"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "无漂移"
+ }
+ }
+ }
+ },
+ "reviewPlannedChanges": {
+ "comment": "Metric note",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Review planned changes"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "请检查计划变更"
+ }
+ }
+ }
+ },
+ "allTargetsInSync": {
+ "comment": "Metric note",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "All targets in sync"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "所有目标已同步"
+ }
+ }
+ }
+ },
+ "runReconcileToFix": {
+ "comment": "Metric note",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Run reconcile to fix"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "运行修复以解决"
+ }
+ }
+ }
+ },
+ "noIssuesFound": {
+ "comment": "Metric note",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "No issues"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "无问题"
+ }
+ }
+ }
+ },
+ "errors": {
+ "comment": "Error count suffix",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "errors"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "个错误"
+ }
+ }
+ }
+ },
+ "allPresent": {
+ "comment": "Metric note",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "All present"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "全部就位"
+ }
+ }
+ }
+ },
+ "missing": {
+ "comment": "Missing suffix",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "missing"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "缺失"
+ }
+ }
+ }
+ },
+ "loadFailed": {
+ "comment": "Dashboard error",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Load failed"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "加载失败"
+ }
+ }
+ }
+ },
+ "accessRoutes": {
+ "comment": "Section: Access Routes",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Access routes"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "访问路由"
+ }
+ }
+ }
+ },
+ "searchDefault": {
+ "comment": "Route: search default",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Default search"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "搜索默认"
+ }
+ }
+ }
+ },
+ "xReader": {
+ "comment": "Route: X reader",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "X reader"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "X 阅读器"
+ }
+ }
+ }
+ },
+ "xFallback": {
+ "comment": "Route: X fallback",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "X fallback"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "X 备用"
+ }
+ }
+ }
+ },
+ "findings": {
+ "comment": "Section: Findings",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Findings"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "检查发现"
+ }
+ }
+ }
+ },
+ "noFindingsHealthy": {
+ "comment": "Empty findings",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "No findings. All managed resources are healthy."
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "无异常发现,所有托管资源运行正常。"
+ }
+ }
+ }
+ },
+ "plannedChanges": {
+ "comment": "Section: Planned Changes",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Planned changes"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "计划变更"
+ }
+ }
+ }
+ },
+ "noPlannedChanges": {
+ "comment": "Empty changes",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "No planned changes. Reconcile is currently a no-op."
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "无计划变更,修复同步当前为空操作。"
+ }
+ }
+ }
+ },
+ "managedMCPTools": {
+ "comment": "Page: Tools",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Managed MCP tools"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "托管 MCP 工具"
+ }
+ }
+ }
+ },
+ "loadingTools": {
+ "comment": "Loading state",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Loading tools…"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "加载工具中…"
+ }
+ }
+ }
+ },
+ "targets": {
+ "comment": "Tool row: targets",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Target apps"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "目标应用"
+ }
+ }
+ }
+ },
+ "secretsSection": {
+ "comment": "Tool row: secrets",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Required secrets"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "所需密钥"
+ }
+ }
+ }
+ },
+ "command": {
+ "comment": "Tool row: command",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Command"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "命令"
+ }
+ }
+ }
+ },
+ "readyState": {
+ "comment": "Tool badge",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Ready"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "就绪"
+ }
+ }
+ }
+ },
+ "missingSecrets": {
+ "comment": "Tool badge",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Missing secrets"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "缺少密钥"
+ }
+ }
+ }
+ },
+ "driftState": {
+ "comment": "Tool badge: drift",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Drift"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "漂移"
+ }
+ }
+ }
+ },
+ "addMCP": {
+ "comment": "Add MCP",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Add MCP"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "添加 MCP"
+ }
+ }
+ }
+ },
+ "editMCP": {
+ "comment": "Edit MCP",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Edit MCP"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "编辑 MCP"
+ }
+ }
+ }
+ },
+ "removeMCP": {
+ "comment": "Remove MCP",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Remove MCP"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "删除 MCP"
+ }
+ }
+ }
+ },
+ "removeMCPConfirmation": {
+ "comment": "Remove MCP confirmation",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Remove from the central registry:"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "确认从统一注册表删除:"
+ }
+ }
+ }
+ },
+ "enableMCP": {
+ "comment": "Enable MCP",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Enable MCP"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "启用 MCP"
+ }
+ }
+ }
+ },
+ "disableMCP": {
+ "comment": "Disable MCP",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Disable MCP"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "停用 MCP"
+ }
+ }
+ }
+ },
+ "disabledMCP": {
+ "comment": "Disabled MCP",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Disabled"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "已停用"
+ }
+ }
+ }
+ },
+ "importMCPs": {
+ "comment": "Import MCPs",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Import existing MCPs"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "导入已有 MCP"
+ }
+ }
+ }
+ },
+ "importAndAdoptMCPs": {
+ "comment": "Import and adopt MCPs",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Back up and adopt"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "备份并统一接管"
+ }
+ }
+ }
+ },
+ "importMCPConfirmation": {
+ "comment": "Import MCP confirmation",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Agent Switch will scan installed agents for MCPs, migrate embedded secrets, back up native configs, and generate managed entries from the central registry."
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Agent Switch 会扫描已安装 Agent 的 MCP,迁移内嵌密钥,备份原配置,再用统一注册表生成托管项。"
+ }
+ }
+ }
+ },
+ "discoveredMCPs": {
+ "comment": "Import preview discovered count",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Discovered MCPs"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "发现 MCP"
+ }
+ }
+ }
+ },
+ "supportedMCPs": {
+ "comment": "Import preview supported count",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Supported MCPs"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "可接管 MCP"
+ }
+ }
+ }
+ },
+ "skippedMCPs": {
+ "comment": "Import preview skipped MCPs",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Skipped and preserved"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "保留未接管"
+ }
+ }
+ }
+ },
+ "secretNamesOnly": {
+ "comment": "Import preview secret names",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Secret names (values excluded)"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "密钥名称(不含值)"
+ }
+ }
+ }
+ },
+ "none": {
+ "comment": "Empty value",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "None"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "无"
+ }
+ }
+ }
+ },
+ "saveMCP": {
+ "comment": "Save MCP",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Save MCP"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "保存 MCP"
+ }
+ }
+ }
+ },
+ "mcpID": {
+ "comment": "MCP id",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "MCP ID, for example filesystem"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "MCP ID,例如 filesystem"
+ }
+ }
+ }
+ },
+ "mcpName": {
+ "comment": "MCP name",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Display name"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "显示名称"
+ }
+ }
+ }
+ },
+ "mcpCommand": {
+ "comment": "MCP command",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Launch command"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "启动命令"
+ }
+ }
+ }
+ },
+ "mcpDescription": {
+ "comment": "MCP description",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Description (optional)"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "说明(可选)"
+ }
+ }
+ }
+ },
+ "mcpArguments": {
+ "comment": "MCP arguments",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Arguments (one per line)"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "参数(每行一个)"
+ }
+ }
+ }
+ },
+ "mcpRequiredSecrets": {
+ "comment": "MCP secrets",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Required secret names (one per line)"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "所需密钥名称(每行一个)"
+ }
+ }
+ }
+ },
+ "mcpEnvironment": {
+ "comment": "MCP environment",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Regular environment variables (one NAME=VALUE per line; never put secrets here)"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "普通环境变量(每行 NAME=VALUE;密钥不要填这里)"
+ }
+ }
+ }
+ },
+ "mcpEditorNote": {
+ "comment": "MCP editor note",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Store secret values only on the Secrets page. Each MCP receives only the secret names declared here."
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "密钥值只在密钥页面保存;每个 MCP 运行时只能获得这里声明的密钥。"
+ }
+ }
+ }
+ },
+ "secretsInventory": {
+ "comment": "Page: Secrets",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Secret inventory"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "密钥清单"
+ }
+ }
+ }
+ },
+ "secretManagementSubtitle": {
+ "comment": "Page: Secrets subtitle",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Safely add, inspect, and maintain local credentials"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "安全地添加、查看和维护本机密钥"
+ }
+ }
+ }
+ },
+ "secretFile": {
+ "comment": "Metric: secret file",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Secret file"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "密钥文件"
+ }
+ }
+ }
+ },
+ "found": {
+ "comment": "Secret file found",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Found"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "已找到"
+ }
+ }
+ }
+ },
+ "missingFile": {
+ "comment": "Secret file missing",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "File missing"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "文件缺失"
+ }
+ }
+ }
+ },
+ "present": {
+ "comment": "Metric: present",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Configured"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "已配置"
+ }
+ }
+ }
+ },
+ "ofRequired": {
+ "comment": "of N required prefix",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "of"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "共需"
+ }
+ }
+ }
+ },
+ "requiredSuffix": {
+ "comment": "required suffix",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "required"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "项"
+ }
+ }
+ }
+ },
+ "allSecretsConfigured": {
+ "comment": "Metric note",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "All secrets configured"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "所有密钥已配置"
+ }
+ }
+ }
+ },
+ "requiredSecrets": {
+ "comment": "Section: Required Secrets",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Required secrets"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "所需密钥列表"
+ }
+ }
+ }
+ },
+ "presentBadge": {
+ "comment": "Badge: present",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Configured"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "已配置"
+ }
+ }
+ }
+ },
+ "missingBadge": {
+ "comment": "Badge: missing",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Missing"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "缺失"
+ }
+ }
+ }
+ },
+ "secretFileLocation": {
+ "comment": "Section: Secret File Location",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Secret file location"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "密钥文件位置"
+ }
+ }
+ }
+ },
+ "revealInFinder": {
+ "comment": "Button: Reveal in Finder",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Reveal in Finder"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "在访达中显示"
+ }
+ }
+ }
+ },
+ "secretsRuntimeNote": {
+ "comment": "Note",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Wrapper scripts load secrets at runtime; values are never embedded in app configuration files."
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "密钥由 wrapper 脚本在运行时加载,不会嵌入应用配置文件中。"
+ }
+ }
+ }
+ },
+ "noSecretInfo": {
+ "comment": "Empty state title",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "No secret information"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "无密钥信息"
+ }
+ }
+ }
+ },
+ "runDoctorForSecrets": {
+ "comment": "Empty state subtitle",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Run Doctor to inspect secret status"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "运行 Doctor 以检查密钥状态"
+ }
+ }
+ }
+ },
+ "stored": {
+ "comment": "Secret stored count",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "stored"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "已保存"
+ }
+ }
+ }
+ },
+ "storedSecrets": {
+ "comment": "Metric: stored secrets",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Stored secrets"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "已保存密钥"
+ }
+ }
+ }
+ },
+ "storedSecretsNote": {
+ "comment": "Stored secrets note",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Includes secrets not currently referenced by an MCP"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "包括暂未被 MCP 引用的密钥"
+ }
+ }
+ }
+ },
+ "requiredSecretsNote": {
+ "comment": "Required secrets note",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Declared by the current MCP configuration"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "当前 MCP 配置声明需要"
+ }
+ }
+ }
+ },
+ "allSecrets": {
+ "comment": "Section: all secrets",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "All secrets"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "全部密钥"
+ }
+ }
+ }
+ },
+ "noStoredSecrets": {
+ "comment": "Empty secret list",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "No secrets have been stored."
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "尚未保存任何密钥。"
+ }
+ }
+ }
+ },
+ "addSecret": {
+ "comment": "Add secret",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Add secret"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "添加密钥"
+ }
+ }
+ }
+ },
+ "updateSecret": {
+ "comment": "Update secret",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Update secret"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "更新密钥"
+ }
+ }
+ }
+ },
+ "deleteSecret": {
+ "comment": "Delete secret",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Delete secret"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "删除密钥"
+ }
+ }
+ }
+ },
+ "deleteSecretConfirmation": {
+ "comment": "Delete secret confirmation",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Delete local secret:"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "确认删除本机密钥:"
+ }
+ }
+ }
+ },
+ "revealSecret": {
+ "comment": "Reveal secret",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Reveal secret"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "查看密钥"
+ }
+ }
+ }
+ },
+ "hideSecret": {
+ "comment": "Hide secret",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Hide secret"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "隐藏密钥"
+ }
+ }
+ }
+ },
+ "copySecret": {
+ "comment": "Copy secret",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Copy secret"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "复制密钥"
+ }
+ }
+ }
+ },
+ "configureSecret": {
+ "comment": "Configure missing secret",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Configure secret"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "配置密钥"
+ }
+ }
+ }
+ },
+ "notConfigured": {
+ "comment": "Secret missing",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Not configured"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "尚未配置"
+ }
+ }
+ }
+ },
+ "requiredBadge": {
+ "comment": "Required badge",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Required"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "必需"
+ }
+ }
+ }
+ },
+ "secretEditorNote": {
+ "comment": "Secret editor note",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Secret values are written through a protected pipe and never enter command arguments or logs."
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "密钥值通过安全管道写入,不会进入命令参数或日志。"
+ }
+ }
+ }
+ },
+ "usedByMCP": {
+ "comment": "Secret consumers",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Granted to"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "授权给"
+ }
+ }
+ }
+ },
+ "secretName": {
+ "comment": "Secret name field",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Secret name, for example FIRECRAWL_API_KEY"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "密钥名称,例如 FIRECRAWL_API_KEY"
+ }
+ }
+ }
+ },
+ "secretNameLabel": {
+ "comment": "Existing secret name label",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Secret name"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "密钥名称"
+ }
+ }
+ }
+ },
+ "secretValue": {
+ "comment": "Secret value field",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Secret value"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "密钥值"
+ }
+ }
+ }
+ },
+ "cancel": {
+ "comment": "Cancel",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Cancel"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "取消"
+ }
+ }
+ }
+ },
+ "cliManagement": {
+ "comment": "Page: CLI management",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "CLI inventory"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "CLI 管理"
+ }
+ }
+ }
+ },
+ "cliManagementSubtitle": {
+ "comment": "CLI page subtitle",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Inspect installed agents and toolchain paths and versions"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "查看本机 Agent 与工具链的安装路径和版本"
+ }
+ }
+ }
+ },
+ "installed": {
+ "comment": "Installed status",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Installed"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "已安装"
+ }
+ }
+ }
+ },
+ "notInstalled": {
+ "comment": "Not installed status",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Not installed"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "未安装"
+ }
+ }
+ }
+ },
+ "packageManager": {
+ "comment": "CLI package manager",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Installed via"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "安装方式"
+ }
+ }
+ }
+ },
+ "installedCLIs": {
+ "comment": "Installed CLI metric",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Installed CLIs"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "已安装 CLI"
+ }
+ }
+ }
+ },
+ "cliInventory": {
+ "comment": "CLI list",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "CLI inventory"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "CLI 清单"
+ }
+ }
+ }
+ },
+ "cliUpdateNote": {
+ "comment": "CLI update note",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Agent Switch currently inventories versions and paths. Future updates will follow each CLI installation method."
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "当前先统一盘点版本与路径;自动更新将按各 CLI 的安装方式执行。"
+ }
+ }
+ }
+ },
+ "skillWarehouse": {
+ "comment": "Page: Skill warehouse",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Skill library"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Skill 仓库"
+ }
+ }
+ }
+ },
+ "skillWarehouseSubtitle": {
+ "comment": "Skill page subtitle",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Downloads stay dormant until explicitly enabled for a project or globally"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "下载只入库;明确加载后才进入项目或全局"
+ }
+ }
+ }
+ },
+ "skillSources": {
+ "comment": "Skill sources",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Sources"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "来源"
+ }
+ }
+ }
+ },
+ "skillProfiles": {
+ "comment": "Skill profiles",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Project profiles"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "项目配置"
+ }
+ }
+ }
+ },
+ "skillInventory": {
+ "comment": "Skill list",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Skill inventory"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Skill 清单"
+ }
+ }
+ }
+ },
+ "dormant": {
+ "comment": "Dormant skill",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Dormant"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "沉默"
+ }
+ }
+ }
+ },
+ "projectActive": {
+ "comment": "Project active skill",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Project"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "项目"
+ }
+ }
+ }
+ },
+ "globalActive": {
+ "comment": "Global active skill",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Global"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "全局"
+ }
+ }
+ }
+ },
+ "missingSkill": {
+ "comment": "Missing skill",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Missing"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "缺失"
+ }
+ }
+ }
+ },
+ "searchSkills": {
+ "comment": "Search skills",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Search skills, sources, or projects"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "搜索 Skill、来源或项目"
+ }
+ }
+ }
+ },
+ "updateGitSources": {
+ "comment": "Update git skill sources",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Update Git sources"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "更新 Git 来源"
+ }
+ }
+ }
+ },
+ "updateGitSourcesNote": {
+ "comment": "Skill update note",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Updates Git checkouts and version locks in Skill Hub without enabling any Skill."
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "只更新 Skill Hub 中的 Git 仓库和版本锁,不会自动启用任何 Skill。"
+ }
+ }
+ }
+ },
+ "noMatchingSkills": {
+ "comment": "No matching skills",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "No matching Skills"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "没有匹配的 Skill"
+ }
+ }
+ }
+ },
+ "openFile": {
+ "comment": "Open file action",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Open directly"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "直接打开"
+ }
+ }
+ }
+ },
+ "syncAndCheck": {
+ "comment": "Single toolbar synchronization action",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Sync and check"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "同步并检查"
+ }
+ }
+ }
+ },
+ "agentManagement": {
+ "comment": "Page: agent management",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Agent management"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Agent 托管"
+ }
+ }
+ }
+ },
+ "agentManagementSubtitle": {
+ "comment": "Agent page subtitle",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "One policy, synchronized across every supported agent"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "一套规则,同步到所有受支持的 Agent"
+ }
+ }
+ }
+ },
+ "managed": {
+ "comment": "Managed status",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "managed"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "已托管"
+ }
+ }
+ }
+ },
+ "detected": {
+ "comment": "Detected status",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "detected"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "已发现"
+ }
+ }
+ }
+ },
+ "notDetected": {
+ "comment": "Not detected status",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Not detected"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "未发现"
+ }
+ }
+ }
+ },
+ "notManaged": {
+ "comment": "Not managed status",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Not managed"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "未托管"
+ }
+ }
+ }
+ },
+ "synchronized": {
+ "comment": "Synchronized status",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "In sync"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "已同步"
+ }
+ }
+ }
+ },
+ "needsSync": {
+ "comment": "Needs sync status",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Needs sync"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "需要同步"
+ }
+ }
+ }
+ },
+ "manageDetectedAgents": {
+ "comment": "Manage supported agents",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Manage and sync all supported agents"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "托管并同步所有支持的 Agent"
+ }
+ }
+ }
+ },
+ "manageDetectedAgentsNote": {
+ "comment": "Manage agents note",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Writes only to Agent Switch managed sections. Other settings are preserved and backed up."
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "只写入 Agent Switch 管理区域;其他配置保持不变并自动备份。"
+ }
+ }
+ }
+ },
+ "howManagementWorks": {
+ "comment": "How management works heading",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "How management works"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "规则如何生效"
+ }
+ }
+ }
+ },
+ "howManagementWorksBody": {
+ "comment": "How management works body",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Agent Switch maintains one shared policy and projects it into Codex AGENTS.md, Claude Code CLAUDE.md managed blocks, and Hermes SOUL.md managed blocks."
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Agent Switch 维护一份统一规则,再分别写入 Codex 的 AGENTS.md 入口、Claude Code 的 CLAUDE.md 管理区和 Hermes 的 SOUL.md 管理区。"
+ }
+ }
+ }
+ },
+ "welcomeHeading": {
+ "comment": "Onboarding heading",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Let Agent Switch manage this environment"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "让 Agent Switch 接管这套环境"
+ }
+ }
+ }
+ },
+ "welcomeBody": {
+ "comment": "Onboarding body",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "The following agents were detected. Agent Switch will synchronize shared instructions and MCPs while preserving and backing up existing configuration."
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "已发现以下 Agent。开始托管后,Agent Switch 将同步统一指令和 MCP,并保留、备份现有配置。"
+ }
+ }
+ }
+ },
+ "startManagement": {
+ "comment": "Start management",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Start management"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "开始托管"
+ }
+ }
+ }
+ },
+ "notNow": {
+ "comment": "Not now",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Not now"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "暂不处理"
+ }
+ }
+ }
+ },
+ "general": {
+ "comment": "Settings: General",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "General"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "通用"
+ }
+ }
+ }
+ },
+ "autoRefreshOnLaunch": {
+ "comment": "Settings toggle",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Refresh automatically at launch"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "启动时自动刷新"
+ }
+ }
+ }
+ },
+ "includeCCSwitch": {
+ "comment": "Settings toggle",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Include the CC Switch database in Doctor checks"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Doctor 检查时包含 CC Switch 数据库"
+ }
+ }
+ }
+ },
+ "runtimePaths": {
+ "comment": "Settings: Runtime Paths",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Runtime paths"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "运行时路径"
+ }
+ }
+ }
+ },
+ "config": {
+ "comment": "Settings label",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Configuration"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "配置文件"
+ }
+ }
+ }
+ },
+ "secretsPath": {
+ "comment": "Settings label",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Secret file"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "密钥文件"
+ }
+ }
+ }
+ },
+ "wrappers": {
+ "comment": "Settings label",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Wrapper scripts"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Wrapper 脚本"
+ }
+ }
+ }
+ },
+ "backups": {
+ "comment": "Settings label",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Backup directory"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "备份目录"
+ }
+ }
+ }
+ },
+ "targetConfigs": {
+ "comment": "Settings: Target Configs",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Target configuration files"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "目标配置文件"
+ }
+ }
+ }
+ },
+ "about": {
+ "comment": "Settings: About",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "About"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "关于"
+ }
+ }
+ }
+ },
+ "version": {
+ "comment": "Settings label",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Version"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "版本"
+ }
+ }
+ }
+ },
+ "repository": {
+ "comment": "Settings label",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Repository"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "仓库地址"
+ }
+ }
+ }
+ },
+ "actions": {
+ "comment": "Menu: Actions",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Actions"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "操作"
+ }
+ }
+ }
+ },
+ "aboutAgentSwitch": {
+ "comment": "App menu: About Agent Switch",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "About Agent Switch"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "关于 Agent Switch"
+ }
+ }
+ }
+ },
+ "quitAgentSwitch": {
+ "comment": "App menu: Quit Agent Switch",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Quit Agent Switch"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "退出 Agent Switch"
+ }
+ }
+ }
+ },
+ "window": {
+ "comment": "Window menu title",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Window"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "窗口"
+ }
+ }
+ }
+ },
+ "showAgentSwitch": {
+ "comment": "Window menu: Show Agent Switch",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Show Agent Switch"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "显示 Agent Switch"
+ }
+ }
+ }
+ },
+ "minimize": {
+ "comment": "Window menu: Minimize",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Minimize"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "最小化"
+ }
+ }
+ }
+ },
+ "allSkills": {
+ "comment": "Skill filter: All",
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "All"
+ }
+ },
+ "zh-Hans": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "全部"
+ }
+ }
+ }
+ }
+ },
+ "version": "1.0"
+}
diff --git a/macos-app/AgentSwitch/Package.swift b/macos-app/AgentSwitch/Package.swift
index 46c0567..23a91cb 100644
--- a/macos-app/AgentSwitch/Package.swift
+++ b/macos-app/AgentSwitch/Package.swift
@@ -8,7 +8,8 @@ let package = Package(
.executableTarget(
name: "AgentSwitch",
path: "AgentSwitch",
- exclude: ["Resources/Assets.xcassets"]
+ exclude: ["Resources/Assets.xcassets"],
+ resources: [.process("Resources/Localizable.xcstrings")]
),
]
)
diff --git a/tests/test_localization_catalog.py b/tests/test_localization_catalog.py
new file mode 100644
index 0000000..1a3131b
--- /dev/null
+++ b/tests/test_localization_catalog.py
@@ -0,0 +1,43 @@
+import json
+import re
+import unittest
+from pathlib import Path
+
+
+ROOT = Path(__file__).resolve().parents[1]
+APP = ROOT / "macos-app" / "AgentSwitch"
+L10N = APP / "AgentSwitch" / "Resources" / "L10n.swift"
+CATALOG = APP / "AgentSwitch" / "Resources" / "Localizable.xcstrings"
+
+
+class LocalizationCatalogTests(unittest.TestCase):
+ def test_every_declared_key_has_complete_english_and_chinese_text(self) -> None:
+ declared = set(re.findall(r'localized\("([^"]+)"\)', L10N.read_text()))
+ strings = json.loads(CATALOG.read_text())["strings"]
+
+ self.assertEqual(declared, set(strings), "L10n.swift and the string catalog must stay in sync")
+ self.assertGreaterEqual(len(strings), 165)
+
+ for key, entry in strings.items():
+ localizations = entry.get("localizations", {})
+ for language in ("en", "zh-Hans"):
+ value = localizations.get(language, {}).get("stringUnit", {}).get("value", "")
+ self.assertTrue(value.strip(), f"{key} is missing a {language} translation")
+
+ def test_build_systems_package_the_string_catalog(self) -> None:
+ package = (APP / "Package.swift").read_text()
+ project = (APP / "AgentSwitch.xcodeproj" / "project.pbxproj").read_text()
+
+ self.assertIn('Resources/Localizable.xcstrings', package)
+ self.assertIn('Localizable.xcstrings', project)
+ self.assertIn('zh-Hans', project)
+
+ def test_readmes_use_the_sanitized_english_dashboard(self) -> None:
+ image = "docs/assets/agent-switch-dashboard-en.png"
+ self.assertTrue((ROOT / image).is_file())
+ for readme in ("README.md", "README.zh-CN.md"):
+ self.assertIn(image, (ROOT / readme).read_text())
+
+
+if __name__ == "__main__":
+ unittest.main()