diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4483bd49f0..ea3f8cdebc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -459,6 +459,25 @@ jobs: - uses: ./.github/actions/npm-ci-retry - run: node scripts/i18n/check-ui-keys-coverage.mjs --threshold=65 + # #8038: cheap single-locale glossary/protected-terms consistency gate — + # complements i18n-ui-coverage (key parity) and the ICU `i18n` job below + # without needing app-boot/Playwright infra. Same gating as i18n-ui-coverage. + i18n-glossary-zhcn: + name: i18n Glossary (zh-CN) + runs-on: ubuntu-latest + needs: changes + if: ${{ github.event_name != 'pull_request' || (github.event.pull_request.draft == false && (needs.changes.outputs.i18n == 'true' || needs.changes.outputs.code == 'true')) }} + steps: + - uses: actions/checkout@v7 + with: + persist-credentials: false + - uses: actions/setup-node@v7 + with: + node-version: ${{ env.CI_NODE_VERSION }} + cache: npm + - uses: ./.github/actions/npm-ci-retry + - run: node scripts/i18n/check-glossary-consistency.mjs --locale=zh-CN + # D4 (plano mestre testes+CI): a matrix de ~40 jobs de <1min por idioma saturava sozinha # a concorrência de jobs da conta (Free = 20 slots, compartilhados entre TODOS os repos) # e pagava spin-up + arredondamento de billing por idioma. Um único job itera os idiomas @@ -1172,6 +1191,7 @@ jobs: - lint - docs-sync-strict - i18n-ui-coverage + - i18n-glossary-zhcn - i18n - pr-test-policy - build @@ -1217,6 +1237,7 @@ jobs: echo "| Lint | $(status '${{ needs.lint.result }}') |" >> "$GITHUB_STEP_SUMMARY" echo "| Docs Sync (Strict) | $(status '${{ needs.docs-sync-strict.result }}') |" >> "$GITHUB_STEP_SUMMARY" echo "| i18n UI Coverage | $(status '${{ needs.i18n-ui-coverage.result }}') |" >> "$GITHUB_STEP_SUMMARY" + echo "| i18n Glossary (zh-CN) | $(status '${{ needs.i18n-glossary-zhcn.result }}') |" >> "$GITHUB_STEP_SUMMARY" echo "| PR Test Policy | $(status '${{ needs.pr-test-policy.result }}') |" >> "$GITHUB_STEP_SUMMARY" echo "| SonarQube | $(status '${{ needs.sonarqube.result }}') |" >> "$GITHUB_STEP_SUMMARY" diff --git a/bin/cli/locales/zh-CN.json b/bin/cli/locales/zh-CN.json index 4f18a1b62d..92a2657191 100644 --- a/bin/cli/locales/zh-CN.json +++ b/bin/cli/locales/zh-CN.json @@ -29,16 +29,16 @@ "setup": { "title": "OmniRoute 设置", "passwordPrompt": "管理员密码", - "providerPrompt": "默认提供商(留空跳过)", + "providerPrompt": "默认提供者(留空跳过)", "done": "设置完成", "passwordSet": "管理员密码已配置", - "providerSet": "提供商已配置:{name}", - "testingProvider": "正在测试提供商连接:{name}", - "testPassed": "提供商测试通过", - "testFailed": "提供商测试失败:{error}", + "providerSet": "提供者已配置:{name}", + "testingProvider": "正在测试提供者连接:{name}", + "testPassed": "提供者测试通过", + "testFailed": "提供者测试失败:{error}", "loginEnabled": "登录:已启用(密码已更新)", "loginDisabled": "登录:已禁用", - "providerInfo": "提供商:{info}" + "providerInfo": "提供者:{info}" }, "doctor": { "title": "OmniRoute 诊断", @@ -52,29 +52,29 @@ "warnings": "{count} 个警告 — 见上文。" }, "providers": { - "title": "提供商", - "noProviders": "未配置提供商。运行:omniroute setup", + "title": "提供者", + "noProviders": "未配置提供者。运行:omniroute setup", "testing": "正在测试 {name}...", - "available": "{count} 个提供商可用", + "available": "{count} 个提供者可用", "connected": "已连接", "disconnected": "未连接", "validationFailed": "验证失败:{error}", "metrics": { - "description": "显示提供商性能指标(延迟、成功率、成本)", - "provider": "按提供商 ID 筛选", + "description": "显示提供者性能指标(延迟、成功率、成本)", + "provider": "按提供者 ID 筛选", "connection_id": "按连接 ID 筛选", "period": "时间范围:1h|6h|24h|7d|30d(默认:24h)", "metric": "关注特定指标字段", "sort": "按字段排序(降序)", "limit": "最大行数(默认:50)", "watch": "每 5 秒刷新(实时模式)", - "compare": "逗号分隔的提供商 ID,并排比较" + "compare": "逗号分隔的提供者 ID,并排比较" }, "metric_single": { "description": "获取特定连接的单个指标值" }, "rotate": { - "description": "轮换提供商连接的上游 API 密钥", + "description": "轮换提供者连接的上游 API 密钥", "newKeyOpt": "新 API 密钥值(避免使用:优先使用 --from-env)", "fromEnvOpt": "从环境变量 VAR 读取新密钥", "oauthOpt": "改为触发 OAuth 重新认证流程", @@ -89,18 +89,18 @@ "testFailed": "轮换后测试失败:{error}" }, "status": { - "description": "显示所有提供商连接的密钥健康状态(期限、过期、冷却)", - "providerOpt": "按提供商名称筛选", - "header": "ID 提供商 名称 过期状态 测试状态 冷却至", - "noData": "没有可用的提供商连接数据。", + "description": "显示所有提供者连接的密钥健康状态(期限、过期、冷却)", + "providerOpt": "按提供者名称筛选", + "header": "ID 提供者 名称 过期状态 测试状态 冷却至", + "noData": "没有可用的提供者连接数据。", "requiresServer": "providers status 需要 OmniRoute 服务器正在运行。" } }, "keys": { "title": "API 密钥", - "addDescription": "为提供商添加或更新 API 密钥", + "addDescription": "为提供者添加或更新 API 密钥", "listDescription": "列出所有已配置的 API 密钥", - "removeDescription": "移除提供商的 API 密钥", + "removeDescription": "移除提供者的 API 密钥", "regenerateDescription": "重新生成 OmniRoute API 密钥", "revokeDescription": "撤销 OmniRoute API 密钥", "revealDescription": "显示未掩码的 API 密钥值", @@ -122,10 +122,10 @@ "revoked": "密钥 {id} 已撤销。", "rotated": "密钥 {id} 已轮换。新密钥 ID:{newId}", "revealWarning": "⚠ 这将显示完整的未掩码密钥。请确保您的屏幕不被人看到。", - "providerRequired": "需要提供商。", + "providerRequired": "需要提供者。", "keyRequired": "需要 API 密钥。", "stdinEmpty": "未通过标准输入提供 API 密钥。", - "unknownProvider": "未知提供商:{provider}", + "unknownProvider": "未知提供者:{provider}", "policy": { "title": "密钥策略", "showDescription": "显示密钥的速率/成本策略", @@ -165,7 +165,7 @@ "analytics": { "description": "显示汇总使用分析", "period": "时间范围:1d|7d|30d|90d|ytd|all(默认:30d)", - "provider": "按提供商 ID 筛选" + "provider": "按提供者 ID 筛选" }, "budget": { "description": "管理成本预算", @@ -175,8 +175,8 @@ } }, "quota": { - "description": "显示提供商配额使用情况", - "provider": "按提供商 ID 筛选", + "description": "显示提供者配额使用情况", + "provider": "按提供者 ID 筛选", "check": "显示新请求是否有可用配额" }, "logs": { @@ -201,7 +201,7 @@ } }, "cost": { - "description": "按提供商、模型、组合或 API 密钥显示成本报告", + "description": "按提供者、模型、组合或 API 密钥显示成本报告", "period": "时间范围:1d|7d|30d|90d|ytd|all(默认:30d)", "since": "开始日期(ISO 格式,例如 2026-01-01)— 覆盖 --period", "until": "结束日期(ISO 格式)", @@ -210,7 +210,7 @@ "limit": "显示的最大行数(默认:100)" }, "simulate": { - "description": "模拟路由(空运行)— 显示将选择哪些提供商而不调用上游", + "description": "模拟路由(空运行)— 显示将选择哪些提供者而不调用上游", "file": "从 JSON 文件加载完整请求体", "model": "模型 ID(默认:auto)", "combo": "强制指定组合名称", @@ -301,7 +301,7 @@ "cost": "成本(24h):" }, "quota": { - "description": "显示提供商配额使用情况", + "description": "显示提供者配额使用情况", "noServer": "服务器未运行。启动:omniroute serve", "noData": "没有可用的配额信息。" }, @@ -315,12 +315,12 @@ "description": "一键启动本地 Redis 容器(Podman 或 Docker),用于 OmniRoute 缓存和配额跟踪" }, "test": { - "description": "测试提供商连接", + "description": "测试提供者连接", "noServer": "服务器未运行。启动:omniroute serve", "testing": "正在测试 {provider} / {model}...", "passed": "连接成功!", "failed": "连接失败:{error}", - "allProvidersOpt": "测试所有已配置的提供商", + "allProvidersOpt": "测试所有已配置的提供者", "latencyOpt": "显示延迟测量值(平均/最小/最大 毫秒)", "repeatOpt": "重复测试 N 次并汇总结果", "compareOpt": "逗号分隔的要比较的模型(例如 gpt-4o,claude-3-5-sonnet)", @@ -328,7 +328,7 @@ "saved": "结果已保存至 {path}", "compareTitle": "模型比较", "compareMinTwo": "--compare 需要至少两个模型(逗号分隔)", - "noProviders": "未配置提供商。添加:omniroute keys add" + "noProviders": "未配置提供者。添加:omniroute keys add" }, "update": { "checking": "正在检查更新...", @@ -509,7 +509,7 @@ }, "models": { "description": "列出可用模型(需要服务器)", - "search": "按 ID、名称、提供商或描述筛选模型", + "search": "按 ID、名称、提供者或描述筛选模型", "noServer": "服务器未运行。启动:omniroute serve", "noModels": "未找到模型。" }, @@ -656,25 +656,25 @@ } }, "oauth": { - "description": "管理 OAuth 提供商连接", + "description": "管理 OAuth 提供者连接", "providers": { - "description": "列出支持 OAuth 的提供商及其流程类型" + "description": "列出支持 OAuth 的提供者及其流程类型" }, "start": { - "description": "为提供商启动 OAuth 授权流程", - "provider": "提供商 ID(gemini, copilot, cursor, ...)", + "description": "为提供者启动 OAuth 授权流程", + "provider": "提供者 ID(gemini, copilot, cursor, ...)", "no_browser": "仅打印 URL — 不打开浏览器", "import_system": "从本地系统配置自动导入凭据", - "social": "社交登录提供商(google|github)— kiro 需要", + "social": "社交登录提供者(google|github)— kiro 需要", "timeout": "等待授权超时时间(毫秒,默认:300000)" }, "status": { "description": "列出活动的 OAuth 连接", - "provider": "按提供商 ID 筛选" + "provider": "按提供者 ID 筛选" }, "revoke": { "description": "撤销 OAuth 连接", - "provider": "要撤销的提供商 ID", + "provider": "要撤销的提供者 ID", "connection_id": "按 ID 撤销特定连接", "yes": "跳过确认提示" } @@ -884,11 +884,11 @@ "description": "管理模型定价数据", "sync": { "description": "从上游同步价格", - "provider": "按提供商筛选", + "provider": "按提供者筛选", "force": "强制重新同步" }, "list": { - "provider": "按提供商筛选", + "provider": "按提供者筛选", "model": "按模型筛选", "limit": "最大结果数" }, @@ -907,25 +907,25 @@ "resilience": { "description": "检查和管理弹性机制", "status": { - "provider": "按提供商筛选" + "provider": "按提供者筛选" }, "breakers": { - "provider": "按提供商筛选" + "provider": "按提供者筛选" }, "cooldowns": { - "provider": "按提供商筛选", + "provider": "按提供者筛选", "connectionId": "按连接 ID 筛选" }, "lockouts": { - "provider": "按提供商筛选", + "provider": "按提供者筛选", "model": "按模型筛选" }, "reset": { "description": "重置断路器/冷却状态", - "provider": "要重置的提供商", + "provider": "要重置的提供者", "connectionId": "要重置的连接 ID", "model": "要重置锁定状态的模型", - "allCooldowns": "重置提供商的所有冷却", + "allCooldowns": "重置提供者的所有冷却", "yes": "跳过确认" }, "profile": { @@ -940,13 +940,13 @@ } }, "nodes": { - "description": "管理提供商节点(端点)", + "description": "管理提供者节点(端点)", "list": { - "provider": "按提供商筛选", + "provider": "按提供者筛选", "enabled": "仅显示已启用的节点" }, "add": { - "provider": "提供商名称", + "provider": "提供者名称", "baseUrl": "节点的基础 URL", "name": "节点名称", "weight": "负载均衡权重", @@ -965,7 +965,7 @@ }, "validate": { "baseUrl": "要验证的 URL", - "provider": "要验证的提供商" + "provider": "要验证的提供者" }, "test": { "description": "向节点发送测试请求" @@ -1091,7 +1091,7 @@ "oneproxy": { "description": "管理 OneProxy 上游代理池", "stats": { - "provider": "按提供商筛选", + "provider": "按提供者筛选", "period": "时间范围(默认:24h)" }, "fetch": { @@ -1101,14 +1101,14 @@ }, "rotate": { "description": "强制轮换代理", - "provider": "要轮换的提供商", + "provider": "要轮换的提供者", "connectionId": "要轮换的特定连接 ID" }, "config": { "description": "显示或更新 OneProxy 配置", "enabled": "启用代理池(true|false)", "poolSize": "池大小", - "providerSource": "代理提供商的 URL", + "providerSource": "代理提供者的 URL", "rotationPolicy": "轮换策略:sticky|per-request|periodic" }, "pool": { @@ -1201,7 +1201,7 @@ "bash": "打印 bash 补全脚本", "fish": "打印 fish 补全脚本", "install": "为检测到的 Shell 全局安装补全脚本", - "refresh": "刷新组合/提供商/模型缓存" + "refresh": "刷新组合/提供者/模型缓存" }, "logs": { "description": "流式传输或导出请求日志", diff --git a/changelog.d/features/8038-zhcn-terminology-visual-qa.md b/changelog.d/features/8038-zhcn-terminology-visual-qa.md new file mode 100644 index 0000000000..287b21dedc --- /dev/null +++ b/changelog.d/features/8038-zhcn-terminology-visual-qa.md @@ -0,0 +1 @@ +- **feat(i18n):** zh-CN terminology glossary + consistency gate + 提供商→提供者 normalization — one-shot pass across `src/i18n/messages/zh-CN.json` (679 substitutions) and `bin/cli/locales/zh-CN.json` (54) mirroring #8024's zh-TW pass, a new versioned glossary (`scripts/i18n/glossary/zh-CN.json`) and protected-terms list (`scripts/i18n/glossary/protected-terms.json`), a pure-function consistency check (`scripts/i18n/check-glossary-consistency.mjs`, `npm run i18n:check-glossary`) wired into CI as `i18n-glossary-zhcn`, and zh-CN added to the visual-QA harness default locales (#8038). diff --git a/docs/guides/I18N.md b/docs/guides/I18N.md index ed684900b9..1cc5a7f088 100644 --- a/docs/guides/I18N.md +++ b/docs/guides/I18N.md @@ -397,7 +397,7 @@ node scripts/i18n/generate-qa-checklist.mjs **Visual QA via Playwright** — takes screenshots of all dashboard routes in multiple locales and viewports, then evaluates page health. ```bash -# Default: es, fr, de, ja, ar on localhost:20128 +# Default: es, fr, de, ja, ar, zh-CN on localhost:20128 node scripts/i18n/run-visual-qa.mjs # Custom base URL and locales @@ -446,6 +446,59 @@ Allowlist of keys that should remain identical to English source. Used by `valid **To add a key:** Edit the `keys` array in `scripts/i18n/untranslatable-keys.json` and re-run validation. +## Terminology Glossary + +Beyond key parity (`check-ui-keys-coverage.mjs`) and ICU validity +(`validate_translation.py`), a maintained per-locale terminology layer +catches semantic drift that those two gates cannot see — e.g. the same +English concept ("provider") rendered with two different, equally-valid +Chinese words (提供商 vs 提供者) across thousands of strings. #8038 added +this layer starting with zh-CN. + +### scripts/i18n/glossary/\.json + +Versioned glossary of recurring concepts (provider, connection, routing, +fallback, quota, context window, reasoning, tool call, cache, circuit +breaker…) for that locale. Each concept has a `canonical` translation and an +optional `synonyms` list — any synonym found in the catalog is flagged as +drift. A concept with an empty `synonyms` array is documented but not yet +enforced (the catalog still has legitimate mixed usage for it; normalizing +it is a follow-up, not this gate's job). + +`scripts/i18n/glossary/zh-CN.json` seeds the ten concepts above; `provider` +is the only one currently enforced, following the one-shot +提供商→提供者 normalization pass (mirroring #8024's zh-TW pass) across +`src/i18n/messages/zh-CN.json` and `bin/cli/locales/zh-CN.json`. + +### scripts/i18n/glossary/protected-terms.json + +Flat list of product/provider/model/protocol/CLI/env/identifier names +(`OmniRoute`, `OAuth`, `MCP`, `A2A`, `DATA_DIR`, …) that must appear verbatim +inside any translated value. This is a different granularity than +`untranslatable-keys.json` (which excludes whole KEYS from the parity/ICU +checks) — protected terms are checked wherever they show up inside any +value, keyed by concept rather than by key path. + +### check-glossary-consistency.mjs + +```bash +# zh-CN by default +npm run i18n:check-glossary + +# explicit locale, JSON report, or non-failing report mode +node scripts/i18n/check-glossary-consistency.mjs --locale=zh-CN +node scripts/i18n/check-glossary-consistency.mjs --locale=zh-CN --json +node scripts/i18n/check-glossary-consistency.mjs --locale=zh-CN --report +``` + +Exports a pure `checkGlossaryConsistency(localeMessages, glossary, +protectedTerms)` function (mirroring `evaluateFileSizes` in +`check-file-size.mjs`) returning `{ violations: [...] }` — a +`glossary-synonym` violation for a non-canonical term, or a +`protected-term-altered` violation for a mistranslated protected name. +Wired into CI as the `i18n-glossary-zhcn` job (same gating as +`i18n-ui-coverage`: skips draft PRs, runs when i18n or code changes). + ## CI Integration ### GitHub Actions (`.github/workflows/ci.yml`) diff --git a/package.json b/package.json index e31d47139a..de8fb48691 100644 --- a/package.json +++ b/package.json @@ -136,6 +136,7 @@ "i18n:sync-ui": "node scripts/i18n/sync-ui-keys.mjs", "i18n:sync-ui:dry": "node scripts/i18n/sync-ui-keys.mjs --dry-run", "i18n:check-ui-coverage": "node scripts/i18n/check-ui-keys-coverage.mjs", + "i18n:check-glossary": "node scripts/i18n/check-glossary-consistency.mjs", "check:node-runtime": "node --import tsx scripts/check/check-supported-node-runtime.ts", "check:pack-artifact": "node --import tsx scripts/build/validate-pack-artifact.ts", "check:pack-boot": "node scripts/check/check-pack-boot.mjs", diff --git a/scripts/i18n/check-glossary-consistency.mjs b/scripts/i18n/check-glossary-consistency.mjs new file mode 100644 index 0000000000..05f275d456 --- /dev/null +++ b/scripts/i18n/check-glossary-consistency.mjs @@ -0,0 +1,199 @@ +#!/usr/bin/env node +/** + * OmniRoute — zh-CN terminology glossary consistency gate. + * + * Complements the existing parity (check-ui-keys-coverage.mjs) and ICU + * (validate_translation.py) checks with a native-quality layer: + * - glossary-synonym: a value uses a non-canonical synonym for a concept + * that has an actively-normalized canonical rendering + * (scripts/i18n/glossary/.json). + * - protected-term-altered: a value renders a protected product/provider/ + * protocol/CLI/env identifier (scripts/i18n/glossary/protected-terms.json) + * using a known incorrect translation instead of leaving it verbatim. + * + * Usage: + * node scripts/i18n/check-glossary-consistency.mjs # zh-CN, exit 1 on drift + * node scripts/i18n/check-glossary-consistency.mjs --locale=zh-CN + * node scripts/i18n/check-glossary-consistency.mjs --json + * node scripts/i18n/check-glossary-consistency.mjs --report # print, always exit 0 + */ + +import { promises as fs } from "node:fs"; +import path from "node:path"; +import process from "node:process"; +import { fileURLToPath, pathToFileURL } from "node:url"; + +const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url)); +const ROOT = path.resolve(SCRIPT_DIR, "..", ".."); +const MESSAGES_DIR = path.join(ROOT, "src", "i18n", "messages"); +const GLOSSARY_DIR = path.join(SCRIPT_DIR, "glossary"); +const LOG_PREFIX = "[i18n-glossary]"; + +// Small, maintained map of known incorrect renderings for protected terms — +// identifiers that must survive translation verbatim. NOT exhaustive by +// design (a full back-translation model is out of scope for a static gate), +// and deliberately conservative: an entry is only added once we've verified +// it doesn't collide with a legitimate, unrelated use of the same Chinese +// phrase elsewhere in the real catalog (e.g. a generic word for +// "authorization" is NOT a safe proxy for "OAuth was translated instead of +// left verbatim" — it fires on every unrelated auth string). Extend as new, +// non-colliding mistranslations are discovered in native review. +const KNOWN_MISTRANSLATIONS = { + DATA_DIR: ["数据目录"], +}; + +function logInfo(...parts) { + console.log(LOG_PREFIX, ...parts); +} + +function isPlainObject(value) { + return value !== null && typeof value === "object" && !Array.isArray(value); +} + +function collectLeaves(obj, prefix = []) { + const leaves = []; + for (const [key, value] of Object.entries(obj)) { + const next = [...prefix, key]; + if (isPlainObject(value)) { + leaves.push(...collectLeaves(value, next)); + } else if (typeof value === "string") { + leaves.push({ path: next.join("."), value }); + } + } + return leaves; +} + +/** + * Pure consistency check — no I/O. Mirrors evaluateFileSizes' split in + * check-file-size.mjs (pure fn + separate CLI wrapper). + * + * @param {object} localeMessages - parsed src/i18n/messages/.json + * @param {object} glossary - parsed scripts/i18n/glossary/.json + * @param {string[]} protectedTerms - flat list from protected-terms.json + * @returns {{violations: Array}} + */ +export function checkGlossaryConsistency(localeMessages, glossary, protectedTerms) { + const violations = []; + const leaves = collectLeaves(localeMessages || {}); + + const terms = glossary && glossary.terms ? glossary.terms : {}; + for (const [concept, def] of Object.entries(terms)) { + const synonyms = Array.isArray(def.synonyms) ? def.synonyms : []; + for (const synonym of synonyms) { + if (!synonym) continue; + for (const leaf of leaves) { + if (leaf.value.includes(synonym)) { + violations.push({ + type: "glossary-synonym", + concept, + path: leaf.path, + found: synonym, + canonical: def.canonical, + }); + } + } + } + } + + const protectedList = Array.isArray(protectedTerms) ? protectedTerms : []; + for (const term of protectedList) { + const badRenderings = KNOWN_MISTRANSLATIONS[term]; + if (!badRenderings || badRenderings.length === 0) continue; + for (const bad of badRenderings) { + for (const leaf of leaves) { + if (leaf.value.includes(bad)) { + violations.push({ + type: "protected-term-altered", + term, + path: leaf.path, + found: bad, + }); + } + } + } + } + + return { violations }; +} + +function parseArgs(argv) { + const opts = { locale: "zh-CN", json: false, report: false }; + for (const arg of argv.slice(2)) { + if (arg.startsWith("--locale=")) { + opts.locale = arg.slice(9); + } else if (arg === "--json") { + opts.json = true; + } else if (arg === "--report") { + opts.report = true; + } else if (arg === "--help" || arg === "-h") { + console.log( + [ + "Usage: node scripts/i18n/check-glossary-consistency.mjs [options]", + "", + " --locale= Locale to check (default zh-CN)", + " --json Emit JSON report to stdout", + " --report Print violations, exit 0 regardless", + ].join("\n") + ); + process.exit(0); + } + } + return opts; +} + +async function loadJson(filePath) { + const raw = await fs.readFile(filePath, "utf8"); + return JSON.parse(raw); +} + +async function main() { + const opts = parseArgs(process.argv); + + const messagesPath = path.join(MESSAGES_DIR, `${opts.locale}.json`); + const glossaryPath = path.join(GLOSSARY_DIR, `${opts.locale}.json`); + const protectedPath = path.join(GLOSSARY_DIR, "protected-terms.json"); + + const [messages, glossary, protectedData] = await Promise.all([ + loadJson(messagesPath), + loadJson(glossaryPath), + loadJson(protectedPath), + ]); + const protectedTerms = Array.isArray(protectedData.terms) ? protectedData.terms : []; + + const { violations } = checkGlossaryConsistency(messages, glossary, protectedTerms); + + if (opts.json) { + process.stdout.write( + JSON.stringify({ locale: opts.locale, ok: violations.length === 0, violations }, null, 2) + + "\n" + ); + if (violations.length && !opts.report) process.exit(1); + return; + } + + if (violations.length === 0) { + logInfo(`PASS — ${opts.locale} has no glossary/protected-term drift.`); + return; + } + + logInfo(`FAIL — ${violations.length} violation(s) in ${opts.locale}.`); + for (const v of violations.slice(0, 50)) { + if (v.type === "glossary-synonym") { + console.log(` - [${v.concept}] ${v.path}: found "${v.found}", canonical is "${v.canonical}"`); + } else { + console.log(` - [protected-term] ${v.path}: "${v.term}" rendered as "${v.found}"`); + } + } + if (violations.length > 50) { + console.log(` ... and ${violations.length - 50} more`); + } + if (!opts.report) process.exit(1); +} + +const isDirectRun = import.meta.url === pathToFileURL(process.argv[1]).href; +if (isDirectRun) { + main().catch((err) => { + console.error(LOG_PREFIX, "ERROR", err?.stack || err?.message || String(err)); + process.exit(1); + }); +} diff --git a/scripts/i18n/glossary/protected-terms.json b/scripts/i18n/glossary/protected-terms.json new file mode 100644 index 0000000000..b99d4aebe0 --- /dev/null +++ b/scripts/i18n/glossary/protected-terms.json @@ -0,0 +1,25 @@ +{ + "description": "Product/provider/model/protocol/header/CLI/env/identifier names that must appear verbatim (untranslated) inside any zh-CN localized string that mentions them. Distinct from untranslatable-keys.json, which excludes whole KEYS from drift checks at key-granularity; this list is consumed by scripts/i18n/check-glossary-consistency.mjs to flag a VALUE that mentions the concept but altered/translated the protected term itself.", + "terms": [ + "OmniRoute", + "OAuth", + "MCP", + "A2A", + "JWT", + "SSE", + "API", + "SQLite", + "GitHub", + "DATA_DIR", + "cf_clearance", + "JSON", + "URL", + "HTTP", + "HTTPS", + "WebSocket", + "CLI", + "Docker", + "Electron", + "Playwright" + ] +} diff --git a/scripts/i18n/glossary/zh-CN.json b/scripts/i18n/glossary/zh-CN.json new file mode 100644 index 0000000000..3af6e67c95 --- /dev/null +++ b/scripts/i18n/glossary/zh-CN.json @@ -0,0 +1,47 @@ +{ + "version": 1, + "locale": "zh-CN", + "description": "Canonical zh-CN terminology for recurring OmniRoute concepts. Consumed by scripts/i18n/check-glossary-consistency.mjs. Each concept lists the canonical translation plus any non-canonical synonym that is actively normalized (drift enforced by the consistency gate). Concepts whose `synonyms` array is empty are seeded for documentation only — the catalog already uses more than one legitimate rendering for them today, so enforcement is deferred to a follow-up normalization pass rather than gating this PR.", + "terms": { + "provider": { + "canonical": "提供者", + "synonyms": ["提供商"] + }, + "connection": { + "canonical": "连接", + "synonyms": [] + }, + "routing": { + "canonical": "路由", + "synonyms": [] + }, + "fallback": { + "canonical": "回退", + "synonyms": [] + }, + "quota": { + "canonical": "配额", + "synonyms": [] + }, + "context window": { + "canonical": "上下文窗口", + "synonyms": [] + }, + "reasoning": { + "canonical": "推理", + "synonyms": [] + }, + "tool call": { + "canonical": "工具调用", + "synonyms": [] + }, + "cache": { + "canonical": "缓存", + "synonyms": [] + }, + "circuit breaker": { + "canonical": "断路器", + "synonyms": [] + } + } +} diff --git a/scripts/i18n/run-visual-qa.mjs b/scripts/i18n/run-visual-qa.mjs index 190ab0be3a..74407d45be 100644 --- a/scripts/i18n/run-visual-qa.mjs +++ b/scripts/i18n/run-visual-qa.mjs @@ -10,7 +10,7 @@ const DATE = new Date().toISOString().slice(0, 10); const BASE_URL = process.env.QA_BASE_URL || "http://localhost:20128"; const REPORT_SUFFIX = process.env.QA_REPORT_SUFFIX ? `-${process.env.QA_REPORT_SUFFIX}` : ""; -const DEFAULT_LOCALES = ["es", "fr", "de", "ja", "ar"]; +const DEFAULT_LOCALES = ["es", "fr", "de", "ja", "ar", "zh-CN"]; const RTL_LOCALES = new Set(["ar", "he"]); const ROUTES = [ diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json index b071a62ddd..575dbe83a7 100644 --- a/src/i18n/messages/zh-CN.json +++ b/src/i18n/messages/zh-CN.json @@ -41,8 +41,8 @@ "type": "类型", "model": "模型", "models": "模型", - "provider": "提供商", - "unknownProvider": "未知提供商", + "provider": "提供者", + "unknownProvider": "未知提供者", "account": "账户", "time": "时间", "details": "详情", @@ -181,7 +181,7 @@ "noLockouts": "无锁定", "webSearchDesc": "Web Search 功能说明", "audioProvidersHeading": "音频 Provider", - "cloudAgentProviders": "云代理提供商", + "cloudAgentProviders": "云代理提供者", "minutesAgo": "分钟前", "a": "A", "liveAutoRefreshing": "实时自动刷新中", @@ -205,19 +205,19 @@ "usageTracking": "使用量跟踪", "disableCloudTitle": "禁用云端", "noConnections": "无连接", - "providerHealth": "提供商健康状态", + "providerHealth": "提供者健康状态", "confirmDbImport": "确认DB导入", "notAvailableSymbol": "—", "backupsAvailable": "可用备份", - "providerAuto": "自动提供商", - "newProviderNamePlaceholder": "新的提供商名称", + "providerAuto": "自动提供者", + "newProviderNamePlaceholder": "新的提供者名称", "a2aQuickStartStep2": "A2A快速开始步骤2", "ok": "确定", "available": "可用", "noBackupYet": "无备份暂无", "more": "更多", "noCompatibleYet": "无兼容暂无", - "multiProvider": "多提供商", + "multiProvider": "多提供者", "repairEnvHint": "修复环境提示", "disablingCloud": "正在禁用 Cloud", "testBench": "测试台", @@ -239,7 +239,7 @@ "formatConverter": "格式转换器", "zedImportNetworkError": "Zed 导入网络错误", "apiKeyLabel": "API key 标签", - "noModelsForProvider": "此提供商没有可用模型", + "noModelsForProvider": "此提供者没有可用模型", "mcpCardDescription": "通过 MCP 工具连接 Agent 和自动化流程。", "apiTypeLabel": "API 类型标签", "configuredProvidersLabel": "已配置 Provider 标签", @@ -267,7 +267,7 @@ "restore": "恢复", "disableWarning": "禁用警告", "moderationsDesc": "审核说明", - "providerHealthStatusAria": "提供商健康状态", + "providerHealthStatusAria": "提供者健康状态", "modelNamePlaceholder": "模型名称", "mcpQuickStartStep2": "MCP 快速开始步骤 2", "quickStart": "快速开始", @@ -275,7 +275,7 @@ "loadingBackups": "正在加载备份", "anthropicBaseUrlPlaceholder": "Anthropic Base URL", "description": "描述", - "noProviderFound": "未找到提供商", + "noProviderFound": "未找到提供者", "auto": "自动", "protocolsDescription": "配置并测试支持的协议端点。", "cloudSessionNote": "Cloud Session 提示", @@ -283,7 +283,7 @@ "defaultStrategy": "默认策略", "purgeExpiredLogs": "清理已过期日志", "justNow": "刚刚现在", - "providerTestFailed": "提供商测试失败", + "providerTestFailed": "提供者测试失败", "openaiBaseUrlPlaceholder": "OpenAI Base URL", "image": "图像", "failedCreateChain": "创建链失败", @@ -303,7 +303,7 @@ "listModelsDesc": "列出可用 Model。", "databaseSize": "数据库大小", "chainCreated": "链已创建", - "providerTestTimeout": "提供商测试超时", + "providerTestTimeout": "提供者测试超时", "routingStrategy": "路由策略", "translateAction": "翻译操作", "exportFailed": "导出失败", @@ -319,12 +319,12 @@ "localProviders": "本地 Provider", "comboNamePlaceholder": "Combo 名称", "memoryRss": "内存 RSS", - "disableProvider": "禁用提供商", + "disableProvider": "禁用提供者", "welcomeDesc": "欢迎使用 OmniRoute。", "nameLabel": "名称标签", "allOperational": "全部运行正常", "backupNow": "备份现在", - "providerMaxRetriesAria": "提供商最大重试次数", + "providerMaxRetriesAria": "提供者最大重试次数", "textToSpeechDesc": "将文本转换为语音音频。", "machineId": "机器 ID", "globalProxy": "全局代理", @@ -336,7 +336,7 @@ "a2aQuickStartStep1": "A2A快速开始步骤1", "importFailed": "导入失败", "inputPlaceholder": "输入内容...", - "providerModelsTitle": "提供商模型", + "providerModelsTitle": "提供者模型", "lastBackup": "最近备份", "yourEndpoint": "你的 Endpoint", "autoDisableThresholdDesc": "触发自动禁用前允许的连续失败次数。", @@ -350,14 +350,14 @@ "paused": "已暂停", "llmProviders": "LLM Provider", "enableCombo": "启用组合", - "removeProviderOverrideAria": "移除提供商覆盖", + "removeProviderOverrideAria": "移除提供者覆盖", "nodeVersion": "Node 版本", "openai": "OpenAI", "exportFailedWithError": "导出失败:{error}", "proxyConfigured": "代理已配置", "concurrencyPerModel": "每个模型并发数", "protocolTasksLabel": "协议任务标签", - "oauthProviders": "OAuth 提供商", + "oauthProviders": "OAuth 提供者", "lockedCount": "已锁定数量", "deleteChainConfirm": "删除此后备链?", "recentTranslations": "最近翻译", @@ -389,8 +389,8 @@ "cloudRequestTimeout": "云端请求超时", "showConfiguredOnly": "显示已配置仅", "showFreeOnly": "仅免费", - "addFirstProvider": "添加您的第一个提供商", - "addFirstProviderDesc": "连接 AI 提供商以开始通过 OmniRoute 路由请求。您可以使用免费提供商、API 密钥或 OAuth 帐户。", + "addFirstProvider": "添加您的第一个提供者", + "addFirstProviderDesc": "连接 AI 提供者以开始通过 OmniRoute 路由请求。您可以使用免费提供者、API 密钥或 OAuth 帐户。", "learnMore": "了解更多", "includeDomains": "包含域名", "promptCache": "提示缓存", @@ -415,7 +415,7 @@ "maxRetries": "最大重试次数", "queueTimeout": "队列超时", "queueDepth": "队列深度", - "addProvider": "添加提供商", + "addProvider": "添加提供者", "realtime": "实时", "totalTranslations": "总计翻译", "protocolActiveStreamsLabel": "协议活跃 Stream", @@ -457,14 +457,14 @@ "openaiPrefixPlaceholder": "OpenAI 前缀", "enterPassword": "输入密码", "openA2aDashboard": "打开 A2A Dashboard", - "enableProvider": "启用提供商", + "enableProvider": "启用提供者", "modeTest": "测试模式", "failedDeleteChain": "删除链失败", - "providerDesc": "提供商描述", + "providerDesc": "提供者描述", "templateLoadHint": "选择模板以快速填充配置。", "lastFailure": "最近失败", "moveDown": "移动下移", - "providerLabel": "提供商标签", + "providerLabel": "提供者标签", "clearCacheFailed": "清除缓存失败", "imagesGenerations": "图像生成", "repairEnvWorking": "修复环境处理中", @@ -484,7 +484,7 @@ "input": "输入", "testingConnection": "正在测试连接", "excludeDomains": "排除域名", - "webCookieProviders": "Web Cookie 提供商", + "webCookieProviders": "Web Cookie 提供者", "allTestsPassed": "全部测试通过", "openaiCompatibleName": "OpenAI 兼容名称", "warningCostOptimizedPartialPricing": "部分模型缺少定价,成本优化结果可能不完整。", @@ -515,7 +515,7 @@ "exampleTemplatesHint": "示例模板提示", "retryDelayLabel": "重试延迟标签", "audioTranscription": "音频转写", - "fallbackChainsDesc": "定义每个模型的提供商后备顺序。", + "fallbackChainsDesc": "定义每个模型的提供者后备顺序。", "exampleTemplates": "示例模板", "connectionsCount": "连接数量", "modelsPathLabel": "Model 路径", @@ -541,7 +541,7 @@ "weighted": "加权", "providers": "Provider", "ccCompatibleLabel": "CC 兼容", - "noFallbackChainsDesc": "创建一条链路,用于定义某个模型的提供商回退顺序。", + "noFallbackChainsDesc": "创建一条链路,用于定义某个模型的提供者回退顺序。", "yesImport": "确认导入", "lockoutsAutoRefreshHint": "锁定自动刷新提示", "tabApis": "API 标签页", @@ -568,7 +568,7 @@ "noModelsYet": "暂无 Model", "signatureFamily": "签名族", "externalApiCalls": "外部 API 调用", - "providerOverridesDesc": "覆盖每个提供商的超时和重试设置。", + "providerOverridesDesc": "覆盖每个提供者的超时和重试设置。", "signatureTool": "签名工具", "connectionFailed": "连接失败", "activeLimitersPlural": "活跃限制器复数", @@ -611,7 +611,7 @@ "errorDuringImport": "错误期间导入", "comboDefaultsGuideHint2": "这些默认值会在新建 Combo 时使用。", "connecting": "正在连接", - "fillModelAndProviders": "请填写模型和提供商", + "fillModelAndProviders": "请填写模型和提供者", "syncing": "正在同步", "resetConfirm": "重置确认", "trackMetrics": "跟踪指标", @@ -622,9 +622,9 @@ "syncingData": "正在同步数据", "cloudBenefitPorts": "通过 Cloud 暴露端口", "compatibleProviders": "兼容 Provider", - "freeTierProviders": "免费层级提供商", + "freeTierProviders": "免费层级提供者", "freeTierLabel": "提供免费套餐", - "freeTierProvidersDesc": "提供免费套餐的提供商 — 有些需要 API 密钥注册,有些则根本不需要凭据。", + "freeTierProvidersDesc": "提供免费套餐的提供者 — 有些需要 API 密钥注册,有些则根本不需要凭据。", "clearCache": "清除缓存", "reqs": "请求数", "addAnthropicCompatible": "添加 Anthropic 兼容 Provider", @@ -634,12 +634,12 @@ "millisecondsAbbr": "毫秒缩写", "backupReasonPreRestore": "恢复前备份", "disableCloud": "禁用云端", - "newProviderNameAria": "新的提供商名称", + "newProviderNameAria": "新的提供者名称", "passwordsMismatch": "密码不匹配", "a2aQuickStartStep3": "A2A快速开始步骤3", "liveMonitorDescriptionSuffix": "或外部 API 调用来生成事件。", - "failedAddProvider": "添加提供商失败", - "addAtLeastOneProvider": "至少添加一个提供商", + "failedAddProvider": "添加提供者失败", + "addAtLeastOneProvider": "至少添加一个提供者", "reasonSeparator": "原因分隔符", "zedImporting": "正在从 Zed 导入", "confirmPasswordPlaceholder": "确认密码占位符", @@ -676,7 +676,7 @@ "modelLockouts": "模型锁定", "usingCloudProxy": "正在使用 Cloud 代理", "loadingHealth": "正在加载健康状态", - "providerOverrides": "提供商覆盖", + "providerOverrides": "提供者覆盖", "audioTranscriptionDesc": "音频转写说明", "learnedFromHeaders": "从响应头学习", "totalRequests": "总计请求", @@ -748,7 +748,7 @@ "batchDetailModel": "型号", "batchDetailWindow": "窗户", "batchDetailCreated": "已创建", - "providerTopologyEmpty": "尚未连接提供商", + "providerTopologyEmpty": "尚未连接提供者", "badgeToastUnlocked": "徽章已解锁!", "batchListSearchPlaceholder": "按 ID、端点、型号搜索...", "batchListDeleteAllCompletedTitle": "删除所有已完成的批次", @@ -806,7 +806,7 @@ "wizardStep2Input": "输入", "wizardStep3Validate": "验证", "wizardStep4Cost": "成本与创建", - "wizardProviderLabel": "提供商", + "wizardProviderLabel": "提供者", "wizardEndpointLabel": "端点", "wizardModelLabel": "模型", "wizardInputKindJsonl": "JSONL", @@ -839,7 +839,7 @@ "wizardCostEstimatedNotice": "估算成本 — 实际计费可能有所不同。", "wizardErrorUpload": "上传文件失败。请重试。", "wizardErrorCreate": "创建批处理失败。请重试。", - "wizardEmptyProviders": "先连接支持批处理的提供商(OpenAI、Anthropic 或 Gemini)以创建批处理。", + "wizardEmptyProviders": "先连接支持批处理的提供者(OpenAI、Anthropic 或 Gemini)以创建批处理。", "uploadModalTitle": "上传批处理文件", "uploadModalDropOrPick": "拖放 .jsonl 文件或点击选择", "uploadModalUpload": "上传", @@ -867,7 +867,7 @@ "filesListUsedByRoleError": "错误", "filesListSizeColumn": "大小", "batchListProgressPartial": "(部分)", - "batchListProviderColumn": "提供商", + "batchListProviderColumn": "提供者", "batchListProviderUnknown": "—", "batchListProviderOther": "其他", "batchListTitle": "批处理", @@ -903,9 +903,9 @@ "wizardCostInputTok": "输入 tok", "wizardCostOutputTok": "输出 tok", "wizardCostWindow": "窗口", - "wizardDestinationSelectProvider": "选择提供商…", + "wizardDestinationSelectProvider": "选择提供者…", "wizardDestinationSelectModel": "选择模型…", - "wizardDestinationConnectProvider": "连接提供商", + "wizardDestinationConnectProvider": "连接提供者", "batchListBatchCreated": "批处理 {id} 已创建 — 刷新列表中…", "batchListBatchCreatedDismiss": "关闭", "batchListRefreshing": "刷新中…", @@ -931,12 +931,12 @@ "batchConceptRetentionNote": "结果和错误文件保留 30 天(Anthropic:29 天)" }, "disabled": "已禁用", - "featureFlagOmnirouteEmergencyFallbackDescription": "将预算耗尽的请求路由到紧急免费备用提供商/模型。", + "featureFlagOmnirouteEmergencyFallbackDescription": "将预算耗尽的请求路由到紧急免费备用提供者/模型。", "featureFlagArenaEloSyncEnabledDescription": "启用定期同步 Arena AI 排行榜 ELO,用于模型智能排名。", "sidebar": { "home": "首页", "dashboard": "仪表板", - "providers": "提供商", + "providers": "提供者", "combos": "组合", "usage": "用量", "analytics": "分析", @@ -1085,8 +1085,8 @@ "costsBudget": "预算", "costsFreeTiers": "免费层预算", "costsFreeTiersSubtitle": "每月免费令牌配额", - "freeProviderRankings": "免费提供商排名", - "freeProviderRankingsSubtitle": "按模型 ELO 分数排名的最佳免费提供商", + "freeProviderRankings": "免费提供者排名", + "freeProviderRankingsSubtitle": "按模型 ELO 分数排名的最佳免费提供者", "costsQuotaShare": "配额共享", "costsPricing": "定价", "logsProxy": "代理日志", @@ -1106,8 +1106,8 @@ "modelLockout": "模型锁定", "settingsAdvanced": "高级", "omniProxySection": "OmniProxy", - "quotaTracker": "提供商配额", - "providerQuota": "提供商配额", + "quotaTracker": "提供者配额", + "providerQuota": "提供者配额", "runtime": "运行时", "consoleLogs": "控制台日志", "globalRouting": "全局路由", @@ -1124,9 +1124,9 @@ "auditGroup": "审计", "batchGroup": "批处理", "homeSubtitle": "仪表盘概览", - "providersSubtitle": "管理 AI 提供商", + "providersSubtitle": "管理 AI 提供者", "quotaTrackerSubtitle": "跟踪使用限制", - "providerQuotaSubtitle": "跟踪提供商使用限制", + "providerQuotaSubtitle": "跟踪提供者使用限制", "runtimeSubtitle": "实时弹性与会话", "contextCombosSubtitle": "组合压缩引擎", "cliToolsSubtitle": "配置 CLI 运行时", @@ -1144,13 +1144,13 @@ "tokensSubtitle": "令牌使用和预算", "usageSubtitle": "流量和使用统计", "analyticsComboHealthSubtitle": "组合目标可靠性", - "analyticsUtilizationSubtitle": "提供商利用率", + "analyticsUtilizationSubtitle": "提供者利用率", "costsSubtitle": "支出明细", "cacheSubtitle": "缓存命中率", "analyticsCompressionSubtitle": "令牌节省统计", "analyticsSearchSubtitle": "搜索工具分析", "analyticsEvalsSubtitle": "评估套件结果", - "providerStats": "提供商统计", + "providerStats": "提供者统计", "providerStatsSubtitle": "延迟和性能指标", "logsSubtitle": "应用日志", "logsProxySubtitle": "代理流量日志", @@ -1159,7 +1159,7 @@ "healthSubtitle": "系统健康检查", "costsPricingSubtitle": "按模型定价规则", "costsBudgetSubtitle": "预算限制", - "costsQuotaShareSubtitle": "跨密钥共享提供商配额", + "costsQuotaShareSubtitle": "跨密钥共享提供者配额", "auditLogSubtitle": "授权审计", "auditMcpSubtitle": "MCP 服务器审计", "auditA2aSubtitle": "A2A 协议审计", @@ -1191,7 +1191,7 @@ "issuesSubtitle": "报告错误", "changelogSubtitle": "发布说明", "costsQuotaPlans": "计划与配额", - "costsQuotaPlansSubtitle": "按提供商配置计划", + "costsQuotaPlansSubtitle": "按提供者配置计划", "activity": "活动", "activitySubtitle": "近期事件的友好动态", "logsGroup": "日志", @@ -1219,7 +1219,7 @@ "alwaysVisible": "始终可见", "groupSeparatorLabel": "隔断", "discovery": "发现", - "discoverySubtitle": "扫描提供商以获取免费访问" + "discoverySubtitle": "扫描提供者以获取免费访问" }, "webhooks": { "title": "Webhook", @@ -1277,7 +1277,7 @@ "step1Desc": "选择此 Webhook 要对接的目标集成系统。" }, "howItWorks": { - "step1": "选择一个集成提供商(如 Slack、Discord、自定义 Webhook)并配置连接详情。", + "step1": "选择一个集成提供者(如 Slack、Discord、自定义 Webhook)并配置连接详情。", "step2": "配置要订阅的系统事件(如补全错误、模型回退或用量限制)。", "step3": "发送测试负载以验证端点是否能正常接收数据。", "step4": "使用 Webhook 密钥对 X-Webhook-Signature HMAC-SHA256 头进行验证,以确保端点安全。", @@ -1360,7 +1360,7 @@ "complianceTab": "合规", "mcpTab": "MCP 审计", "title": "合规审计", - "description": "合规审计日志记录的策略、访问、提供商和安全事件。", + "description": "合规审计日志记录的策略、访问、提供者和安全事件。", "eventType": "事件类型", "eventTypePlaceholder": "按操作或事件类型筛选", "severity": "严重级别", @@ -1479,8 +1479,8 @@ "switchToLightMode": "切换到浅色模式", "switchToDarkMode": "切换到深色模式", "language": "语言", - "providers": "提供商", - "providerDescription": "管理 AI 提供商连接", + "providers": "提供者", + "providerDescription": "管理 AI 提供者连接", "combos": "组合", "comboDescription": "支持故障回退的模型组合", "usage": "用量与分析", @@ -1505,9 +1505,9 @@ "mediaDescription": "生成图像、视频和音乐", "themes": "主题", "themesDescription": "为整个仪表板选择颜色主题", - "costsDescription": "跟踪支出,分析趋势,管理所有 AI 提供商的预算", - "cacheDescription": "监控提供商提示缓存效率和本地语义响应复用。", - "limitsDescription": "为每个 API 密钥和提供商配置速率限制和配额", + "costsDescription": "跟踪支出,分析趋势,管理所有 AI 提供者的预算", + "cacheDescription": "监控提供者提示缓存效率和本地语义响应复用。", + "limitsDescription": "为每个 API 密钥和提供者配置速率限制和配额", "runtimeDescription": "实时运行时可观测性 — 断路器、冷却、模型锁定、会话和配额告警", "apiManagerDescription": "管理 OmniRoute 实例的 API 密钥和访问控制", "batchDescription": "通过批量 API 调用异步处理大量请求", @@ -1521,21 +1521,21 @@ "skillsDescription": "安装和管理沙箱技能,实现自动提示和执行", "agentSkillsDescription": "代理就绪技能目录,一键复制 URL 以集成 AI 客户端", "translatorDescription": "跨 API 格式翻译和测试提示:OpenAI ↔ Claude ↔ Gemini", - "playgroundDescription": "交互式测试提示,实时查看提供商响应和格式检查", - "searchToolsDescription": "搜索分析、提供商细分、缓存命中率和成本跟踪", + "playgroundDescription": "交互式测试提示,实时查看提供者响应和格式检查", + "searchToolsDescription": "搜索分析、提供者细分、缓存命中率和成本跟踪", "logsDescription": "实时请求日志、错误追踪和流式事件检查器", "auditDescription": "API 密钥使用、MCP 工具调用和策略事件的合规审计追踪", "webhooksDescription": "配置 Webhook 端点以接收实时事件通知", - "healthDescription": "系统健康概览:提供商、断路器、速率限制和数据库", - "proxyDescription": "为出站提供商连接配置上游代理设置", + "healthDescription": "系统健康概览:提供者、断路器、速率限制和数据库", + "proxyDescription": "为出站提供者连接配置上游代理设置", "apiEndpointsDescription": "管理自定义 API 端点配置和路由覆盖", "batchFilesDescription": "浏览和管理批处理作业输出文件和结果", "analyticsEvalsDescription": "模型评估结果和性能基准", "analyticsSearchDescription": "搜索查询分析、缓存命中率和成本跟踪", - "analyticsUtilizationDescription": "提供商利用率指标和容量规划", + "analyticsUtilizationDescription": "提供者利用率指标和容量规划", "analyticsComboHealthDescription": "组合路由配置的实时健康与性能", "analyticsCompressionDescription": "上下文压缩分析和令牌节省", - "costsBudgetDescription": "每个 API 密钥和提供商的预算限制和支出告警", + "costsBudgetDescription": "每个 API 密钥和提供者的预算限制和支出告警", "costsPricingDescription": "用于令牌成本计算的自定义定价配置", "logsProxyDescription": "上游代理请求日志和流量检查", "logsConsoleDescription": "应用控制台输出和调试日志", @@ -1591,7 +1591,7 @@ "breadcrumbs": { "ariaLabel": "面包屑", "dashboard": "仪表盘", - "providers": "提供商", + "providers": "提供者", "combos": "组合", "settings": "设置", "general": "通用", @@ -1681,23 +1681,23 @@ }, "home": { "quickStart": "快速入门", - "quickStartDesc": "4 个步骤快速上手:连接提供商、路由模型并监控全局运行情况。", + "quickStartDesc": "4 个步骤快速上手:连接提供者、路由模型并监控全局运行情况。", "fullDocs": "完整文档", "step1Title": "1. 创建 API 密钥", "step1Desc": "前往 端点 -> 已注册密钥。为每个环境生成一个独立密钥。", - "step2Title": "2. 连接提供商", - "step2Desc": "在 提供商 中添加账户。支持 OAuth、API Key 和免费套餐。", + "step2Title": "2. 连接提供者", + "step2Desc": "在 提供者 中添加账户。支持 OAuth、API Key 和免费套餐。", "step3Title": "3. 配置客户端", "step3Desc": "在 IDE 或 API 客户端中将基本 URL 设置为 {url}。", "step4Title": "4. 监控与优化", "step4Desc": "在 请求日志分析 中跟踪 Token、成本与错误。", - "providersOverview": "提供商概览", - "configuredOf": "{total} 个可用提供商中已配置 {configured} 个", - "noModelsAvailable": "该提供商当前没有可用模型。", - "noProvidersConfigured": "尚未配置提供商", - "addProvider": "添加提供商", + "providersOverview": "提供者概览", + "configuredOf": "{total} 个可用提供者中已配置 {configured} 个", + "noModelsAvailable": "该提供者当前没有可用模型。", + "noProvidersConfigured": "尚未配置提供者", + "addProvider": "添加提供者", "configureFirst": "首先在 {providers} 中配置连接", - "configureProvider": "配置提供商", + "configureProvider": "配置提供者", "modelAvailable": "{count} 模型可用", "modelsAvailable": "{count} 个模型可用", "connectionsActive": "{count} 连接处于活动状态", @@ -1718,20 +1718,20 @@ "updateAvailableDesc": "有新版本可用。点击更新。", "updateStarted": "更新已开始...", "reloadingPageAutomatically": "自动重新加载页面...", - "providerTopology": "提供商拓扑" + "providerTopology": "提供者拓扑" }, "analytics": { "title": "分析", "usageAnalyticsTitle": "用量分析", "diversityScoreTitle": "供应商多元化", - "diversityScoreDesc": "近期流量窗口内提供商集中度的快照。", + "diversityScoreDesc": "近期流量窗口内提供者集中度的快照。", "diversityShannonEntropy": "香农熵", "diversityWindow": "窗口:{count} 次请求 · 最近 {mins} 分钟", "diversityHealthy": "分布健康", "diversityRiskHigh": "供应商锁定风险高", "diversityRiskModerate": "分布一般", "diversityScoreLabel": "得分", - "diversityHigherExplanation": "数值越高,表示流量分散到的提供商越多。", + "diversityHigherExplanation": "数值越高,表示流量分散到的提供者越多。", "diversityNoData": "暂无近期用量数据。", "chartRequests": "请求数", "chartInput": "输入", @@ -1744,7 +1744,7 @@ "chartCostPct": "占成本 {pct}%", "chartUsageDetail": "用量明细", "chartCacheRead": "缓存读取", - "chartCostByProvider": "按提供商划分的成本", + "chartCostByProvider": "按提供者划分的成本", "chartNoCostData": "无成本数据", "chartModelUsageOverTime": "模型用量趋势", "chartNoData": "无数据", @@ -1764,8 +1764,8 @@ "unknownApiKey": "未知 API 密钥", "chartModelBreakdown": "按模型拆分", "chartModel": "模型", - "chartProvider": "提供商", - "chartProviderBreakdown": "按提供商拆分", + "chartProvider": "提供者", + "chartProviderBreakdown": "按提供者拆分", "chartDate": "日期", "chartRequestsByProviderDate": "按服务商和日期的请求数", "filterAllKeys": "全部密钥", @@ -1797,7 +1797,7 @@ "estCost": "预估成本", "infraTitle": "基础设施", "infraAccounts": "账号", - "infraProviders": "提供商", + "infraProviders": "提供者", "infraApiKeys": "API 密钥", "infraModels": "模型", "perfTitle": "性能", @@ -1807,12 +1807,12 @@ "perfFastReq": "Fast 请求", "highlightsTitle": "亮点", "highlightsTopModel": "热门模型", - "highlightsTopProvider": "热门提供商", + "highlightsTopProvider": "热门提供者", "highlightsBusiestDay": "最繁忙的一天", "highlightsDiversity": "多样性", "highlightsFallbackRate": "回退率", "customRange": "自定义", - "overviewDescription": "监控所有提供商和模型的 API 使用模式、令牌消耗、成本和活动趋势。", + "overviewDescription": "监控所有提供者和模型的 API 使用模式、令牌消耗、成本和活动趋势。", "evalsDescription": "运行评估套件来测试和验证您的 LLM 端点。比较模型质量、检测回归和基准延迟。", "overview": "概述", "evals": "评测", @@ -1820,7 +1820,7 @@ "utilization": "利用率", "routeTrace": "路由追踪", "sectionsAria": "分析板块", - "utilizationDescription": "提供商配额使用趋势和速率限制跟踪", + "utilizationDescription": "提供者配额使用趋势和速率限制跟踪", "modelStatus": "模型状态", "modelStatusCooldown": "冷却中", "modelStatusUnavailable": "不可用", @@ -1828,13 +1828,13 @@ "comboHealth": "组合健康状况", "comboHealthDescription": "组合级别配额、使用分布和性能指标", "compressionAnalyticsTitle": "压缩分析", - "compressionAnalyticsDescription": "压缩分析 — token 节省、模式分布和提供商统计。", + "compressionAnalyticsDescription": "压缩分析 — token 节省、模式分布和提供者统计。", "autoRoutingTotalAutoRequests": "自动请求总数", "autoRoutingAvgSelectionScore": "平均选择分数", "autoRoutingExplorationRate": "探索率", "autoRoutingLkgpHitRate": "LKGP命中率", "autoRoutingRequestsByVariant": "变体请求", - "autoRoutingTopRoutedProviders": "顶级路由提供商", + "autoRoutingTopRoutedProviders": "顶级路由提供者", "comboHealthWorstQuotaLeft": "剩余最差名额", "comboHealthUsageSkew": "使用偏差", "comboHealthSuccessRate": "成功率", @@ -1865,7 +1865,7 @@ "comboHealthProjectedQuota": "预估配额", "comboHealthPricingCoverage": "定价覆盖范围", "comboHealthAutopilotTitle": "组合健康自动驾驶", - "comboHealthAutopilotDescription": "来自组合健康、预测、配额和提供商健康的优先建议。", + "comboHealthAutopilotDescription": "来自组合健康、预测、配额和提供者健康的优先建议。", "comboHealthIssues": "问题", "comboHealthActionable": "{count} 个可操作项", "comboHealthDown": "宕机", @@ -1899,10 +1899,10 @@ "degraded": "需要关注", "healthy": "健康" }, - "comboHealthModelProviderCount": "跨 {providers} 个提供商的 {models} 个模型", + "comboHealthModelProviderCount": "跨 {providers} 个提供者的 {models} 个模型", "comboHealthGiniCoefficient": "基尼系数", "comboHealthRequestCount": "{count} 次请求", - "comboHealthQuotaHealthDescription": "具有短期趋势信号的提供商中最低的剩余配额。", + "comboHealthQuotaHealthDescription": "具有短期趋势信号的提供者中最低的剩余配额。", "comboHealthRemainingQuota": "Remaining quota {value}", "comboHealthTrend": { "improving": "改善中", @@ -1957,13 +1957,13 @@ "compressionAnalyticsMaxRequests": "每小时最大请求数: {count}", "compressionAnalyticsMaxTokens": "每小时最大 Token 数: {count}", "compressionAnalyticsStartTracking": "使用带有压缩配置的 POST /v1/chat/completions 来开始跟踪压缩分析。", - "compressionAnalyticsInfo": "压缩分析:按模式(off、lite、standard、aggressive、ultra、RTK、stacked)、引擎、压缩组合和提供商跟踪节省的 Token。将鼠标悬停在图表上以查看详情。使用时间选择器查看不同的时间段。", + "compressionAnalyticsInfo": "压缩分析:按模式(off、lite、standard、aggressive、ultra、RTK、stacked)、引擎、压缩组合和提供者跟踪节省的 Token。将鼠标悬停在图表上以查看详情。使用时间选择器查看不同的时间段。", "searchAnalyticsTotalSearches": "总搜索次数", "searchAnalyticsCacheHitRate": "缓存命中率", "searchAnalyticsTotalCost": "总成本", "searchAnalyticsAvgResponse": "平均响应", "searchAnalyticsNoSearchesYet": "还没有搜索", - "providerUtilizationTitle": "提供商利用率", + "providerUtilizationTitle": "提供者利用率", "providerUtilizationFailedToLoad": "无法加载利用率数据", "providerUtilizationNoData": "没有可用的利用率数据", "providerUtilizationGettingStarted": "开始使用", @@ -1980,9 +1980,9 @@ "providerUtilizationLoading": "正在加载使用率数据…", "retrying": "正在重试…", "retry": "重试", - "providerUtilizationNoDataDescription": "收集到使用率数据后,提供商配额快照将显示在此处。", - "providerUtilizationStepConnect": "在提供商中通过 OAuth 或 API 密钥连接提供商", - "providerUtilizationStepEnable": "通过在组合或直接请求中使用该提供商来启用配额跟踪", + "providerUtilizationNoDataDescription": "收集到使用率数据后,提供者配额快照将显示在此处。", + "providerUtilizationStepConnect": "在提供者中通过 OAuth 或 API 密钥连接提供者", + "providerUtilizationStepEnable": "通过在组合或直接请求中使用该提供者来启用配额跟踪", "providerUtilizationStepAutomatic": "收集到配额快照后,数据将自动显示", "statusExhausted": "已耗尽", "statusLow": "较低", @@ -2025,7 +2025,7 @@ "routeRecentSuccess": "近期成功率", "routeAvgTargetLatency": "平均目标延迟", "routeSelectedTarget": "已选目标", - "provider": "提供商", + "provider": "提供者", "model": "模型", "account": "账户", "connection": "连接", @@ -2097,7 +2097,7 @@ "sharedAccountQuotaVisibility": "共享账号配额", "sharedAccountQuotaVisibilityDesc": "当配置了一个明确连接时,允许此密钥查看共享上游账号配额。", "localUsageCommand": "允许本地使用命令", - "localUsageCommandDesc": "允许此 API 密钥使用 @@om-usage 来检索缓存的使用情况和配额信息,而无需调用上游提供商。", + "localUsageCommandDesc": "允许此 API 密钥使用 @@om-usage 来检索缓存的使用情况和配额信息,而无需调用上游提供者。", "localUsageCommandBadge": "使用情况命令", "keyCreated": "API 密钥已创建", "keyCreatedSuccess": "密钥创建成功!", @@ -2108,7 +2108,7 @@ "allEndpointsAllowed": "此密钥可以访问所有 API 端点。", "endpointsRestricted": "仅限 {count} 个端点。", "autoResolve": "自动解析", - "autoResolveDesc": "为这个 API 密钥自动将有歧义的模型名解析到原生提供商。", + "autoResolveDesc": "为这个 API 密钥自动将有歧义的模型名解析到原生提供者。", "streamDefaultMode": "流默认兼容性", "streamDefaultModeDesc": "此键省略了 `stream` 标志。JSON 模式返回非流式响应,除非客户端明确请求 SSE。", "streamDefaultLegacy": "遗留", @@ -2139,7 +2139,7 @@ "selected": "已选择 {count} 个", "all": "全部", "clear": "清空", - "searchModels": "按名称或提供商搜索模型...", + "searchModels": "按名称或提供者搜索模型...", "noModelsFound": "未找到模型", "keyNameRequired": "密钥名称不能为空", "keyNameTooLong": "密钥名称长度不能超过 {max} 个字符", @@ -2252,7 +2252,7 @@ "generate": "生成", "generating": "生成中...", "loadingModels": "正在加载可用模型...", - "noModels": "暂无可用模型。请先配置支持媒体能力的提供商。", + "noModels": "暂无可用模型。请先配置支持媒体能力的提供者。", "error": "生成失败", "result": "结果", "imageDescription": "使用 OpenAI、xAI、Together、Hyperbolic、SD WebUI、ComfyUI 等根据文本提示生成图像。", @@ -2270,11 +2270,11 @@ "music": "音乐", "ocr": "OCR" }, - "noProviders": "尚未为此类型配置任何提供商。", + "noProviders": "尚未为此类型配置任何提供者。", "addConnection": "添加连接", - "backToProviders": "返回提供商列表", + "backToProviders": "返回提供者列表", "connections": "{count} 个连接", - "noConnections": "暂无连接 —— 请从提供商页面添加。", + "noConnections": "暂无连接 —— 请从提供者页面添加。", "loading": "正在加载...", "suggestedModels": "来自服务商的推荐模型", "imageGeneration": "图像生成", @@ -2323,11 +2323,11 @@ "transcribeAudio": "转录音频", "generateModality": "生成 {modality}", "apiKeyRequired": "需要 API 密钥", - "configureApiKeys": "在“提供商”中配置 API 密钥", + "configureApiKeys": "在“提供者”中配置 API 密钥", "downloadFormat": "下载 {format}", "noTextReturned": "未返回文本", "wordTimestamps": "词级时间戳 ({count} 个词)", - "providerCount": "{count} 个提供商" + "providerCount": "{count} 个提供者" }, "search": { "searchQuery": "搜索词", @@ -2335,15 +2335,15 @@ "cachedResult": "已缓存", "searchCost": "成本", "searchTools": "搜索工具", - "searchToolsDesc": "支持提供商对比的高级搜索测试", - "compareProviders": "对比提供商", + "searchToolsDesc": "支持提供者对比的高级搜索测试", + "compareProviders": "对比提供者", "rerankResults": "结果重排", "searchHistory": "搜索历史", "urlOverlap": "URL 重叠度", - "noSearchProviders": "尚未配置搜索提供商。请前往设置添加。", + "noSearchProviders": "尚未配置搜索提供者。请前往设置添加。", "noRerankModels": "没有可用的重排模型", "webSearch": "网页搜索", - "provider": "提供商", + "provider": "提供者", "searchType": "搜索类型", "maxResults": "最大结果数", "filters": "筛选条件", @@ -2390,20 +2390,20 @@ "scrapeConceptTitle": "抓取", "scrapeConceptDesc": "抓取 = 提取 URL 的完整内容(Markdown、文本或 HTML)", "compareConceptTitle": "比较", - "compareConceptDesc": "比较 = 跨 N 个提供商并排运行相同查询,比较延迟、成本和结果重叠", + "compareConceptDesc": "比较 = 跨 N 个提供者并排运行相同查询,比较延迟、成本和结果重叠", "rerankConceptTitle": "重新排序", "rerankConceptDesc": "重新排序 = 通过 LLM 重新排序结果以基于查询提高相关性", "autoConceptTitle": "自动(最便宜)", - "autoConceptDesc": "自动(最便宜)= 自动选择具有已配置凭据的最便宜可用提供商", - "providerCatalogTitle": "提供商目录", + "autoConceptDesc": "自动(最便宜)= 自动选择具有已配置凭据的最便宜可用提供者", + "providerCatalogTitle": "提供者目录", "kindSearch": "搜索", "kindFetch": "获取/抓取", "statusConfigured": "已配置", "statusMissing": "无凭据", "statusRateLimited": "速率受限", - "configureProvider": "在提供商中配置", - "loadingProviders": "加载提供商…", - "failedToLoadProviders": "加载提供商失败", + "configureProvider": "在提供者中配置", + "loadingProviders": "加载提供者…", + "failedToLoadProviders": "加载提供者失败", "costPerQuery": "成本/查询", "freeQuota": "免费配额/月", "scrapeUrl": "要抓取的 URL", @@ -2421,10 +2421,10 @@ "scrapeRaw": "原始", "scrapeContentTruncated": "(已截断,查看原始)", "scrapeMetadata": "元数据", - "scrapeProvider": "提供商", + "scrapeProvider": "提供者", "scrapeSize": "大小", "scrapeEmptyState": "输入 URL 以提取其内容", - "scrapeProvidersAvailable": "可用提供商: Firecrawl, Jina Reader, Tavily, TinyFish。", + "scrapeProvidersAvailable": "可用提供者: Firecrawl, Jina Reader, Tavily, TinyFish。", "compareRun": "比较", "compareRunning": "比较中…", "autoProvider": "自动(最便宜)", @@ -2438,11 +2438,11 @@ "configurationPane": "配置窗格", "configuration": "配置", "status": "状态", - "compareProviderHint": "在“比较”标签页中最多选择 4 个提供商以进行并排比较。", + "compareProviderHint": "在“比较”标签页中最多选择 4 个提供者以进行并排比较。", "history": "历史记录", "historyHint": "历史记录可在“搜索”标签页中查看。", - "noActiveProvider": "无活动的搜索提供商", - "configureMoreProviders": "配置更多提供商", + "noActiveProvider": "无活动的搜索提供者", + "configureMoreProviders": "配置更多提供者", "links": "链接", "contentTruncated": "内容已截断至 256 KB (原始大小: {size})", "viewFullRaw": "查看完整原始内容", @@ -2471,21 +2471,21 @@ "videoSample": "山脉上空云层的延时摄影", "webFetch": "网页抓取", "webSearchSample": "什么是 OmniRoute AI 网关?", - "noActiveProviderDescription": "无活动搜索提供商。请在“提供商”中配置。", - "configureProviders": "配置提供商", + "noActiveProviderDescription": "无活动搜索提供者。请在“提供者”中配置。", + "configureProviders": "配置提供者", "compareQuery": "要比较的查询", "compareQueryPlaceholder": "2026 年人工智能趋势", - "selectedProviders": "提供商(已选 {count} 个):", + "selectedProviders": "提供者(已选 {count} 个):", "selectAll": "全选", "clear": "清除", - "maxCompareProviders": "一次最多可比较 {count} 个提供商。", + "maxCompareProviders": "一次最多可比较 {count} 个提供者。", "compareResults": "结果 — “{query}”", "resultCount": "{count} 条结果", "noResults": "无结果", - "sharedResultTitle": "与其他提供商共有", + "sharedResultTitle": "与其他提供者共有", "sharedResult": "共有", "overlapSummary": "{first} vs {second}:{overlap} 共有", - "compareEmptyTitle": "选择提供商并输入查询以进行比较", + "compareEmptyTitle": "选择提供者并输入查询以进行比较", "compareEmptyDescription": "结果将并排显示,包含延迟、成本和 URL 重合度" }, "cliTools": { @@ -2501,14 +2501,14 @@ }, "failedSave": "保存失败", "profileSyncTitle": "CLI 配置文件自动同步", - "profileSyncDescription": "在提供商模型同步后,自动从实时目录重新生成 CLI 工具配置文件。默认关闭 — 仅写入配置文件;绝不会更改活动/默认配置。", + "profileSyncDescription": "在提供者模型同步后,自动从实时目录重新生成 CLI 工具配置文件。默认关闭 — 仅写入配置文件;绝不会更改活动/默认配置。", "profileSyncLoadFailed": "加载设置失败", "codexProfiles": "Codex 配置文件", "codexProfilesDescription": "在模型发现后重新生成 ~/.codex/*.config.toml。", "claudeProfiles": "Claude Code 配置文件", "claudeProfilesDescription": "在模型发现后重新生成每个 ~/.claude/profiles/…/settings.json。", - "noActiveProviders": "当前没有活跃的提供商", - "noActiveProvidersDesc": "请先添加并连接提供商以配置 CLI 工具。", + "noActiveProviders": "当前没有活跃的提供者", + "noActiveProvidersDesc": "请先添加并连接提供者以配置 CLI 工具。", "mapModels": "映射模型", "testConnection": "测试连接", "connectionStatus": "连接状态", @@ -2598,7 +2598,7 @@ "antigravityStep2Prefix": "2. 添加", "antigravityStep2Suffix": "添加到您的主机文件中作为 127.0.0.1。", "antigravityStep3": "3. 打开 Antigravity,请求就会被代理。", - "mitmHowWorksDesc": "{toolName} 会先向原始提供商端点发起请求,随后由 MITM 拦截并重定向到 OmniRoute。", + "mitmHowWorksDesc": "{toolName} 会先向原始提供者端点发起请求,随后由 MITM 拦截并重定向到 OmniRoute。", "mitmStep1": "1. 启动 MITM,让请求经由 OmniRoute 路由。", "mitmStep2Prefix": "2. 将", "mitmStep2Suffix": "添加到你的 hosts 文件,并指向 127.0.0.1。", @@ -2632,7 +2632,7 @@ "current": "当前", "baseUrlPlaceholder": "https://.../v1", "resetToDefault": "重置为默认值", - "providerModelPlaceholder": "提供商/模型 ID", + "providerModelPlaceholder": "提供者/模型 ID", "apply": "应用", "reset": "重置", "manualConfig": "手动配置", @@ -2645,10 +2645,10 @@ "applied": "已应用!", "failed": "失败", "resetDone": "重置!", - "omnirouteConfiguredOpenAiCompatible": "OmniRoute 已配置为 OpenAI 兼容提供商", - "provider": "提供商", + "omnirouteConfiguredOpenAiCompatible": "OmniRoute 已配置为 OpenAI 兼容提供者", + "provider": "提供者", "model": "模型", - "providers": "提供商", + "providers": "提供者", "auth": "授权", "noApiKeysAvailable": "没有可用的 API 密钥", "usingDefaultOmniroute": "使用默认值:sk_omniroute", @@ -2700,7 +2700,7 @@ "antigravity": "带 MITM 的 Google Antigravity IDE", "claude": "Claude Code CLI", "codex": "OpenAI Codex CLI", - "grok-build": "支持自定义提供商的 xAI Grok Build TUI 编码智能体", + "grok-build": "支持自定义提供者的 xAI Grok Build TUI 编码智能体", "droid": "Factory Droid AI 助手", "openclaw": "OpenClaw AI 助手", "cline": "Cline AI 编码助手 CLI", @@ -2717,7 +2717,7 @@ "hermes-agent": "Hermes Agent (by Nousresearch) — 支持多模型(委派、视觉、压缩等)的高级终端 AI。", "custom": "通用 OpenAI 兼容 CLI 或 SDK 配置生成器", "aider": "具有 OpenAI 兼容 Base URL 的 Aider AI 结对编程 CLI", - "forge": "支持自定义提供商的 ForgeCode 编码智能体 CLI", + "forge": "支持自定义提供者的 ForgeCode 编码智能体 CLI", "cursor-cli": "无头智能体模式下的 Cursor Agent CLI", "roo": "适用于 VS Code 的 Roo Code AI 助手", "jcode": "jcode 终端编码智能体", @@ -2730,7 +2730,7 @@ "interpreter": "Open Interpreter 自主编程智能体 CLI", "omp": "Oh My Pi 终端编程智能体", "letta": "具备持久记忆和工具使用能力的 Letta CLI 智能体", - "warp": "支持自定义提供商的 Warp AI 终端", + "warp": "支持自定义提供者的 Warp AI 终端", "agent-deck": "Agent Deck 多智能体编排器" }, "guides": { @@ -2838,7 +2838,7 @@ "desc": "点击 Windsurf 中的 AI Settings 图标,或前往 Settings" }, "2": { - "title": "添加自定义提供商", + "title": "添加自定义提供者", "desc": "选择 \"Add custom provider\" (OpenAI 兼容)" }, "3": { @@ -2940,7 +2940,7 @@ "description": "创建支持权重路由与故障回退的模型组合", "autoCatalogTitle": "自动路由目录", "autoCatalogTemplateCount": "{count} 个模板", - "autoCatalogDescription": "内置 auto/* 组合,从已连接的提供商动态解析。直接将这些 ID 作为 model 字段使用——无需设置。", + "autoCatalogDescription": "内置 auto/* 组合,从已连接的提供者动态解析。直接将这些 ID 作为 model 字段使用——无需设置。", "autoCatalogExpand": "展开自动路由目录", "autoCatalogCollapse": "收起自动路由目录", "createCombo": "创建组合", @@ -3024,8 +3024,8 @@ "contextRelayMaxMessagesHelp": "限制压缩进接力摘要中的最近历史消息数量。", "contextRelaySummaryModel": "摘要模型", "contextRelaySummaryModelHelp": "仅用于生成交接摘要的可选覆盖模型。留空则复用当前活跃的 combo 模型。", - "contextRelayProviderNote": "Context Relay 当前主要为 Codex 账户轮换生成交接摘要。与同一提供商的多个账户配合使用时,连续性效果最佳。", - "advancedHint": "留空则使用全局默认值。这些设置会覆盖每个提供商的配置。", + "contextRelayProviderNote": "Context Relay 当前主要为 Codex 账户轮换生成交接摘要。与同一提供者的多个账户配合使用时,连续性效果最佳。", + "advancedHint": "留空则使用全局默认值。这些设置会覆盖每个提供者的配置。", "failoverBeforeRetry": "重试之前进行故障转移", "maxSetRetries": "最大设置重试次数", "setRetryDelayMs": "设置重试延迟(毫秒)", @@ -3033,7 +3033,7 @@ "moveDown": "下移", "removeModel": "移除", "saving": "保存中...", - "liveNoProviders": "尚未检测到任何提供商。", + "liveNoProviders": "尚未检测到任何提供者。", "liveFleetDataHint": "集群数据通过实时组合事件传入。", "liveActiveCount": "活跃 ({count})", "liveErrorCount": "错误 ({count})", @@ -3131,8 +3131,8 @@ "example": "示例:在接近配额耗尽时轮换多个账户的 Codex 会话。" }, "fill-first": { - "when": "当您希望在转移到下一个提供商之前完全耗尽一个提供商的配额时使用。", - "avoid": "当您需要在提供商之间进行请求级负载均衡时避免使用。", + "when": "当您希望在转移到下一个提供者之前完全耗尽一个提供者的配额时使用。", + "avoid": "当您需要在提供者之间进行请求级负载均衡时避免使用。", "example": "示例:在使用完所有 200 美元的 Deepgram 额度后再回退到 Groq。" }, "auto": { @@ -3155,7 +3155,7 @@ "maxRetries": "请求失败前最多会尝试多少次重试。", "retryDelay": "两次重试之间的初始等待时间。值越大越能降低突发压力。", "timeout": "请求被中止前允许的最长持续时间。", - "healthcheck": "路由决策时跳过不健康的模型或提供商。", + "healthcheck": "路由决策时跳过不健康的模型或提供者。", "concurrencyPerModel": "轮询模式下每个模型允许的最大并发请求数。", "queueTimeout": "请求在队列中等待超时前允许停留的最长时间。", "failoverBeforeRetry": "启用后,任何上游错误都会触发立即故障转移到下一个组合目标,跳过所有重试和回退 URL。", @@ -3217,10 +3217,10 @@ "routingInputs": "路由输入", "routingInputsHint": "模式包与权重保留在此处;熔断器运行状态保留在健康页面。", "emailVisibilityHint": "此处账号邮箱遵循全局隐私开关。", - "emailVisibilityTooltip": "使用眼睛图标可在组合、提供商与配额页面间全局切换账号邮箱的显示与隐藏。", + "emailVisibilityTooltip": "使用眼睛图标可在组合、提供者与配额页面间全局切换账号邮箱的显示与隐藏。", "manualModel": "手动模型", "manualModelInvalid": "请按 provider/model 格式填写。", - "manualModelUnknownProvider": "未知的提供商前缀。", + "manualModelUnknownProvider": "未知的提供者前缀。", "builderDynamicAccountShort": "动态账号", "builderNeedValidName": "请先填写有效的组合名称再继续。", "statusOverview": "状态概览", @@ -3268,7 +3268,7 @@ "description": "使用一个主模型,并保持回退链路简短且可靠。", "tip1": "把最可靠的模型放在第一位。", "tip2": "保留 1 到 2 个质量相近的备用模型。", - "tip3": "开启安全重试,吸收临时性的提供商故障。" + "tip3": "开启安全重试,吸收临时性的提供者故障。" }, "weighted": { "title": "可控流量分配", @@ -3307,8 +3307,8 @@ }, "reset-aware": { "title": "重置感知账户轮换", - "description": "根据重置时间平衡剩余的提供商配额。", - "tip1": "对具有配额遥测的提供商使用显式帐户步骤或帐户标签路由。", + "description": "根据重置时间平衡剩余的提供者配额。", + "tip1": "对具有配额遥测的提供者使用显式帐户步骤或帐户标签路由。", "tip2": "当短期疲劳风险更大时,调整训练次数与每周重量。", "tip3": "保持领带较小,这样等值账户仍然可以公平地轮换。" }, @@ -3320,9 +3320,9 @@ "tip3": "非常适合在多个 API 账户之间做负载均衡。" }, "fill-first": { - "description": "在切换到链中的下一个提供商之前,先耗尽一个提供商的配额。", + "description": "在切换到链中的下一个提供者之前,先耗尽一个提供者的配额。", "tip1": "按免费配额大小排列模型 — 最大的放在第一位。", - "tip2": "启用健康检查以跳过已耗尽的提供商。", + "tip2": "启用健康检查以跳过已耗尽的提供者。", "tip3": "非常适合免费层级堆叠(Deepgram → Groq → NIM)。", "title": "配额耗尽策略" }, @@ -3349,7 +3349,7 @@ }, "context-relay": { "description": "当预期账户轮换且下一个账户必须继承简化的任务摘要时效果最佳。", - "tip1": "与为同一模型系列轮换账户的提供商配合使用。", + "tip1": "与为同一模型系列轮换账户的提供者配合使用。", "tip2": "将交接阈值设置在硬配额截止值以下,以便有时间生成摘要。", "tip3": "仅在主模型太贵或不稳定时,才设置专用摘要模型。", "title": "会话连续性优先" @@ -3363,11 +3363,11 @@ } }, "templateFreeStack": "免费栈($0)", - "templateFreeStackDesc": "在所有免费提供商之间进行轮询:Kiro(Claude)、Qoder(5 个模型)、Qwen(4 个模型)。零成本,编码不中断。", + "templateFreeStackDesc": "在所有免费提供者之间进行轮询:Kiro(Claude)、Qoder(5 个模型)、Qwen(4 个模型)。零成本,编码不中断。", "auto": "自动组合", "autoDesc": "自愈型智能路由池(性能优化)", "lkgp": "LKGP 模式", - "lkgpDesc": "最后已知良好提供商(可预测的弹性)", + "lkgpDesc": "最后已知良好提供者(可预测的弹性)", "wizardGuideTitle": "组合入门指南", "wizardGuideDesc": "创建模型组合以智能路由 AI 流量", "wizardGuideHint": "或点击上方「+ 创建组合」", @@ -3392,7 +3392,7 @@ }, "steps": { "label": "步骤", - "description": "提供商、模型和账户选择" + "description": "提供者、模型和账户选择" }, "strategy": { "label": "策略", @@ -3413,16 +3413,16 @@ "builderStageLocked": "已锁定 — 请先完成上一步", "builderTitle": "构建组合", "builderBrowseCatalog": "浏览目录", - "builderProvider": "提供商", - "builderLoadingProviders": "加载提供商中...", - "builderSelectProvider": "选择提供商", + "builderProvider": "提供者", + "builderLoadingProviders": "加载提供者中...", + "builderSelectProvider": "选择提供者", "builderModel": "模型", "builderSelectModel": "选择模型", - "builderProviderFirst": "请先选择提供商", + "builderProviderFirst": "请先选择提供者", "builderAccount": "账户", "builderPreview": "预览", "builderAddStep": "添加步骤", - "builderDuplicateExact": "该提供商/模型/账户步骤已存在于组合中。", + "builderDuplicateExact": "该提供者/模型/账户步骤已存在于组合中。", "builderComboRef": "组合引用", "builderAddComboRef": "添加组合引用", "builderComboRefStep": "添加组合引用步骤", @@ -3432,24 +3432,24 @@ "reviewStrategy": "策略", "reviewSteps": "步骤", "reviewAccounts": "账户", - "reviewProviders": "提供商", + "reviewProviders": "提供者", "reviewComboRefs": "组合引用", "reviewAdvanced": "高级设置", "reviewAgentFlags": "Agent 标志", "reviewSequence": "模型序列", "reviewNoSteps": "未配置任何步骤", "builderStagesDescription": "按顺序完成各个阶段以定义组合、构建步骤、选择路由策略并审查结果。", - "builderStepsDescription": "按顺序构建每个组合步骤:提供商、模型,然后是账户。这允许在不同账户上重复使用相同的提供商和模型。", - "selectProvider": "选择提供商", - "selectProviderPlaceholder": "选择提供商", + "builderStepsDescription": "按顺序构建每个组合步骤:提供者、模型,然后是账户。这允许在不同账户上重复使用相同的提供者和模型。", + "selectProvider": "选择提供者", + "selectProviderPlaceholder": "选择提供者", "selectModel": "选择模型", - "selectModelPlaceholder": "请先选择提供商", + "selectModelPlaceholder": "请先选择提供者", "selectAccount": "选择账户", "selectComboToReference": "选择要引用的现有组合", "comboReference": "组合引用", "addComboReference": "添加组合引用", "addStepBeforeContinue": "在继续到下一阶段之前,请至少添加一个步骤。", - "previewNextStep": "选择提供商和模型以预览下一步。", + "previewNextStep": "选择提供者和模型以预览下一步。", "autoSelectAccount": "运行时自动选择账户", "modePackBalanced": "均衡", "modePackBudget": "预算优先", @@ -3490,14 +3490,14 @@ }, "costs": { "title": "成本", - "pageDescription": "跟踪支出、分析趋势,并管理所有提供商的 AI 预算", + "pageDescription": "跟踪支出、分析趋势,并管理所有提供者的 AI 预算", "overview": "概览", "budget": "预算", "totalCost": "总成本", "breakdown": "成本明细", "noData": "无成本数据", "byModel": "按模型", - "byProvider": "按提供商", + "byProvider": "按提供者", "range7d": "7 天", "range30d": "30 天", "range90d": "90 天", @@ -3514,8 +3514,8 @@ "noCostDataDescription": "发起请求后,成本数据会显示在这里。", "spendToday": "今日支出", "overviewLoadFailed": "加载成本概览失败", - "overviewDescription": "按提供商、模型和时间段汇总成本。", - "providerShare": "提供商占比", + "overviewDescription": "按提供者、模型和时间段汇总成本。", + "providerShare": "提供者占比", "topProviders": "热门 Provider", "costTrend": "成本趋势", "noCostDataTitle": "暂无成本数据", @@ -3555,8 +3555,8 @@ "exportJSON": "导出为 JSON", "legacyFreeLabel": "旧版 / 免费", "costExplorerTitle": "成本探索器", - "costExplorerDescription": "按提供商、模型、API 密钥、账户或服务层级探索支出。", - "groupProvider": "提供商", + "costExplorerDescription": "按提供者、模型、API 密钥、账户或服务层级探索支出。", + "groupProvider": "提供者", "groupModel": "模型", "groupApiKey": "API 密钥", "groupAccount": "账户", @@ -3597,7 +3597,7 @@ "enableCloud": "启用云端", "modelsAcrossEndpoints": "{endpoints} 个端点共提供 {models} 个模型", "loadingModels": "正在加载可用模型...", - "chatDesc": "支持所有提供商的流式与非流式聊天", + "chatDesc": "支持所有提供者的流式与非流式聊天", "embeddings": "嵌入", "embeddingsDesc": "用于搜索和 RAG 流程的文本向量", "imageGeneration": "图像生成", @@ -3613,7 +3613,7 @@ "moderations": "内容审核", "moderationsDesc": "内容安全审核与分类", "responsesDesc": "适用于 Codex 和高级智能体工作流的 OpenAI Responses API", - "listModelsDesc": "列出所有已连接提供商下的可用模型", + "listModelsDesc": "列出所有已连接提供者下的可用模型", "settingsApiDesc": "通过 API 读取和修改 OmniRoute 配置", "settingsApi": "设置 API", "categoryCore": "核心 API", @@ -3621,9 +3621,9 @@ "categorySearch": "搜索与发现", "categoryUtility": "工具与管理", "webSearch": "网页搜索", - "webSearchDesc": "统一接入多个提供商的网页搜索,支持自动故障转移与缓存", - "searchProvider": "搜索提供商", - "searchProviderDesc": "该提供商会用于 `POST /v1/search` 的网页搜索。无需配置模型,只要连接 API 密钥即可使用。", + "webSearchDesc": "统一接入多个提供者的网页搜索,支持自动故障转移与缓存", + "searchProvider": "搜索提供者", + "searchProviderDesc": "该提供者会用于 `POST /v1/search` 的网页搜索。无需配置模型,只要连接 API 密钥即可使用。", "enableCloudTitle": "启用云代理", "whatYouGet": "启用后可获得", "cloudBenefitAccess": "从世界任何地方访问你的 API", @@ -3676,7 +3676,7 @@ "cloudflaredIdleNote": "为当前端点创建一个临时的 Cloudflare Quick Tunnel。", "cloudflaredLastError": "最近错误:{error}", "providerModelsTitle": "{provider} — 模型", - "noModelsForProvider": "该提供商当前没有可用模型。", + "noModelsForProvider": "该提供者当前没有可用模型。", "chat": "聊天", "embedding": "向量", "image": "图像", @@ -3947,7 +3947,7 @@ "profileConservative": "保守", "applyProfile": "应用配置", "resetCircuitBreakers": "重置断路器", - "resetCircuitBreakersHelp": "清除当前断路器状态及提供商失败计数。", + "resetCircuitBreakersHelp": "清除当前断路器状态及提供者失败计数。", "resetAllBreakers": "重置全部断路器", "toolsAndScopes": "工具与作用域", "tableTool": "工具", @@ -4284,7 +4284,7 @@ "successRate": "成功率", "marketplaceTab": "市场", "applyFilters": "应用筛选", - "popularDefaultsLabel": "所选提供商的默认热门技能:", + "popularDefaultsLabel": "所选提供者的默认热门技能:", "onMode": "开", "offMode": "关", "autoMode": "自动", @@ -4306,7 +4306,7 @@ "pageInfo": "第 {page} / {totalPages} 页(共 {total} 条)", "previous": "上一页", "next": "下一页", - "activeProvider": "当前提供商:", + "activeProvider": "当前提供者:", "changeInSettings": "可在 设置 → 记忆与技能 中修改。", "installs": "安装", "marketplaceSkillsMpHint": "请在设置中配置 SkillsMP API 密钥以浏览市场。", @@ -4330,7 +4330,7 @@ "database": "数据库", "version": "版本", "lastCheck": "最后检查", - "providerHealth": "提供商健康", + "providerHealth": "提供者健康", "systemMetrics": "系统指标", "tokenHealth": "令牌健康", "refreshAll": "全部刷新", @@ -4360,16 +4360,16 @@ "signatureSession": "会话", "recovering": "正在恢复中", "noCBData": "当前没有可用的断路器数据,请先发起一些请求。", - "providerHealthStatusAria": "提供商健康状况", + "providerHealthStatusAria": "提供者健康状况", "issuesLabel": "检测到的问题", "operational": "运行中", - "providers": "提供商", + "providers": "提供者", "configuredProvidersLabel": "在仪表板中配置", - "configuredProvidersHint": "指已在 /dashboard/providers 中配置凭证的提供商,无论当前运行时状态如何。", + "configuredProvidersHint": "指已在 /dashboard/providers 中配置凭证的提供者,无论当前运行时状态如何。", "activeProviders": "{count} 个活跃", - "activeProvidersHint": "指当前已启用并可参与请求路由的已配置提供商。", + "activeProvidersHint": "指当前已启用并可参与请求路由的已配置提供者。", "monitoredProviders": "{count} 个监控中", - "monitoredProvidersHint": "指当前由断路器健康监控器持续跟踪的提供商。", + "monitoredProvidersHint": "指当前由断路器健康监控器持续跟踪的提供者。", "healthyCount": "{count} 健康", "nodeVersion": "节点 {version}", "failures": "{count} 失败", @@ -4384,7 +4384,7 @@ "runningCount": "{count} 正在运行", "ok": "正常", "activeLockouts": "主动锁定", - "resetConfirm": "将所有断路器重置为正常状态?这将清除所有故障计数并将所有提供商恢复到运行状态。", + "resetConfirm": "将所有断路器重置为正常状态?这将清除所有故障计数并将所有提供者恢复到运行状态。", "resetAllTitle": "将所有断路器重置为正常状态", "resetting": "正在重置...", "resetAll": "全部重置", @@ -4422,18 +4422,18 @@ "noSessionQuotaMonitorsActive": "没有活动的会话配额监视器。", "gracefulDegradationStatus": "优雅降级状态", "additionalModels": "+{count} 更多型号", - "providerHealthMatrixTitle": "提供商健康矩阵", - "providerHealthMatrixDescription": "来自熔断器、冷却、锁定和日志的提供商 × 账户 × 模型状态。", + "providerHealthMatrixTitle": "提供者健康矩阵", + "providerHealthMatrixDescription": "来自熔断器、冷却、锁定和日志的提供者 × 账户 × 模型状态。", "healthMatrixRange": "健康矩阵时间范围", - "providerFilter": "提供商筛选", + "providerFilter": "提供者筛选", "onlyIssues": "仅显示问题", "refresh": "刷新", "accounts": "账户", "models": "模型", "issues": "问题", - "loadingProviderHealthMatrix": "正在加载提供商健康矩阵...", - "failedProviderHealthMatrix": "加载提供商健康矩阵失败:{error}", - "noProvidersMatchedFilters": "没有提供商匹配当前筛选条件。", + "loadingProviderHealthMatrix": "正在加载提供者健康矩阵...", + "failedProviderHealthMatrix": "加载提供者健康矩阵失败:{error}", + "noProvidersMatchedFilters": "没有提供者匹配当前筛选条件。", "modelPillSummary": "{requests} 请求 · {successRate} 成功率 · {latency} 平均延迟", "modelLockoutSummary": "{reason} · 剩余 {duration}", "locked": "已锁定", @@ -4555,12 +4555,12 @@ "noEntries": "未找到审核日志条目", "previous": "上一页", "next": "下一页", - "providerWarningTitle": "提供商警告", + "providerWarningTitle": "提供者警告", "viewDetails": "查看详情", "eventMetadata": "事件元数据", "eventPayload": "事件负载", "requestId": "请求 ID", - "providerWarningDesc": "上游提供商返回了警告。请查看详情以了解更多信息。", + "providerWarningDesc": "上游提供者返回了警告。请查看详情以了解更多信息。", "a": "A", "offset": "偏移量", "limit": "限制", @@ -4575,7 +4575,7 @@ "clearAll": "全部清除", "confirmClearActiveRequests": "清除所有活跃请求?", "model": "模型", - "provider": "提供商", + "provider": "提供者", "account": "账户", "elapsed": "已耗时", "activeStage": "阶段", @@ -4592,7 +4592,7 @@ "viewPayloads": "查看", "activeCount": "{count} 个活跃", "clientPayload": "客户端请求载荷", - "upstreamPayload": "上游提供商载荷", + "upstreamPayload": "上游提供者载荷", "upstreamNotSentYet": "尚未发送到上游", "runningRequestDetailMeta": "Account:{account} — 已耗时:{elapsed}", "export": "导出", @@ -4638,7 +4638,7 @@ "test": "测试", "ready": "准备好了!", "setPassword": "设置密码", - "addProvider": "添加您的第一个提供商", + "addProvider": "添加您的第一个提供者", "getStarted": "开始使用", "skip": "跳过", "skipWizard": "完全跳过向导", @@ -4651,18 +4651,18 @@ "passwordsMismatch": "密码不匹配", "setupComplete": "设置完成!", "goToDashboard": "转到仪表板→", - "welcomeDesc": "OmniRoute 是您的本地 AI API 代理。它通过负载均衡、故障转移和使用情况跟踪将请求路由到多个 AI 提供商。", - "multiProvider": "多提供商", + "welcomeDesc": "OmniRoute 是您的本地 AI API 代理。它通过负载均衡、故障转移和使用情况跟踪将请求路由到多个 AI 提供者。", + "multiProvider": "多提供者", "usageTracking": "使用情况追踪", "securityDesc": "设置密码以保护您的仪表板,或暂时跳过。", - "providerDesc": "连接你的第一个 AI 提供商。你之后还可以继续添加。", + "providerDesc": "连接你的第一个 AI 提供者。你之后还可以继续添加。", "apiKeyRequired": "API 密钥(必填)", "customUrlOptional": "自定义 URL(可选)", - "testDesc": "让我们验证您的提供商连接是否有效。", + "testDesc": "让我们验证您的提供者连接是否有效。", "runTest": "运行连接测试", "testingConnection": "测试连接...", - "connectionSuccessful": "连接成功!您的提供商已准备就绪。", - "noProviderFound": "未找到提供商。您可以稍后从仪表板添加一个。", + "connectionSuccessful": "连接成功!您的提供者已准备就绪。", + "noProviderFound": "未找到提供者。您可以稍后从仪表板添加一个。", "testFailed": "测试失败,但您可以稍后配置。", "couldNotTest": "现在无法测试。您可以从仪表板进行测试。", "doneDesc": "你都准备好了!您的 OmniRoute 实例已配置并准备好代理 AI 请求。", @@ -4670,12 +4670,12 @@ "continue": "继续", "retry": "重试", "failedSetPassword": "设置密码失败。再试一次。", - "failedAddProvider": "添加提供商失败。再试一次。", + "failedAddProvider": "添加提供者失败。再试一次。", "connectionError": "连接错误。请再试一次。", - "provider": "提供商", - "apiKeyHelp": "API密钥是AI服务的密码。从提供商的网站(例如 platform.openai.com、console.anthropic.com)获取一个。", + "provider": "提供者", + "apiKeyHelp": "API密钥是AI服务的密码。从提供者的网站(例如 platform.openai.com、console.anthropic.com)获取一个。", "tier": { - "subtitle": "OmniRoute 将提供商组织为三层,因此路由首先优先选择最可靠、成本最低的路径。", + "subtitle": "OmniRoute 将提供者组织为三层,因此路由首先优先选择最可靠、成本最低的路径。", "flowCaption": "请求会先流经您的订阅配额,然后是按 token 付费的廉价服务商,最后是免费层级服务商 —— 自动运行,零配置。", "afterSetup": "设置后。", "tier1": { @@ -4684,26 +4684,26 @@ }, "tier2": { "label": "成本优化", - "description": "用于日常流量的廉价、高吞吐量提供商。" + "description": "用于日常流量的廉价、高吞吐量提供者。" }, "tier3": { "label": "后备和专业", "description": "本地托管或专用端点用作后备。" }, - "configure": "配置提供商" + "configure": "配置提供者" }, "tierFlowDiagramAlt": "OmniRoute 3 层回退图", "apiKeyMgmt": "API密钥管理" }, "providers": { - "title": "提供商", + "title": "提供者", "Account Deactivated": "账户已停用", - "allProviders": "所有提供商", - "audioProviders": "音频提供商", + "allProviders": "所有提供者", + "audioProviders": "音频提供者", "showFreeOnly": "仅显示免费", - "addProvider": "添加提供商", - "addFirstProvider": "添加您的第一个提供商", - "addFirstProviderDesc": "连接 AI 提供商以开始通过 OmniRoute 路由请求。您可以使用免费提供商、API 密钥或 OAuth 帐户。", + "addProvider": "添加提供者", + "addFirstProvider": "添加您的第一个提供者", + "addFirstProviderDesc": "连接 AI 提供者以开始通过 OmniRoute 路由请求。您可以使用免费提供者、API 密钥或 OAuth 帐户。", "learnMore": "了解更多", "importFromFile": "从文件导入", "importFromFileTitle": "从文件导入服务商", @@ -4750,13 +4750,13 @@ "tipPrefix": "该", "tipSuffix": "cookie 是长期有效的,通常可持续数月。您只需在退出登录或 Adapta 使会话失效时更新它。" }, - "editProvider": "编辑提供商", - "deleteProvider": "删除提供商", - "noProviders": "没有配置提供商", + "editProvider": "编辑提供者", + "deleteProvider": "删除提供者", + "noProviders": "没有配置提供者", "modelAvailability": "模型可用性", "accounts": "账户", "newAccount": "新账户", - "deleteConfirm": "您确定要删除该提供商吗?", + "deleteConfirm": "您确定要删除该提供者吗?", "testing": "测试...", "testConnection": "测试连接", "testSuccess": "连接成功", @@ -4770,10 +4770,10 @@ "chat": "聊天", "responses": "回应", "messages": "留言", - "oauthProviders": "OAuth 提供商", - "freeProviders": "免费提供商", - "apiKeyProviders": "API 密钥提供商", - "compatibleProviders": "API 密钥兼容提供商", + "oauthProviders": "OAuth 提供者", + "freeProviders": "免费提供者", + "apiKeyProviders": "API 密钥提供者", + "compatibleProviders": "API 密钥兼容提供者", "testAll": "测试全部", "reorderByAvailability": "重新排序", "reorderByAvailabilityTitle": "按可用性重新排序连接", @@ -4818,39 +4818,39 @@ "freeTierAvailable": "有免费额度", "hasFreeTooltip": "提供免费层", "noAuthLabel": "免鉴权", - "noAuthProviders": "免鉴权提供商", + "noAuthProviders": "免鉴权提供者", "upstreamProxyLabel": "上游代理", - "freeAggregated": "所有提供免费层的提供商(同时也会显示在各自的原生分类中)", + "freeAggregated": "所有提供免费层的提供者(同时也会显示在各自的原生分类中)", "deprecated": "已弃用", - "deprecatedProvider": "此提供商已弃用", + "deprecatedProvider": "此提供者已弃用", "riskNotice": { "title": "继续之前", - "tooltip": "该提供商有使用注意事项 —— 点击查看详情", - "oauth": "此提供商使用你官方产品的会话 / OAuth,这并未被授权用于代理或路由用途。 不建议进行高强度的自主代理使用(OpenCloud 风格、长链路多步流程、大批量请求)—— 上游可能因此限制甚至封禁账号。 使用风险自负。", - "webCookie": "此提供商通过你的网页会话 Cookie 进行鉴权。上游服务可能随时让会话失效,届时你需要重新登录。不建议用于长时间无人值守的操作。 使用风险自负。", - "deprecated": "此提供商已被上游下线,可能随时停止工作。已存在的连接可能在上游完全关闭访问前继续可用。建议考虑替代方案。", - "dontShowAgain": "对此提供商不再显示此提示", + "tooltip": "该提供者有使用注意事项 —— 点击查看详情", + "oauth": "此提供者使用你官方产品的会话 / OAuth,这并未被授权用于代理或路由用途。 不建议进行高强度的自主代理使用(OpenCloud 风格、长链路多步流程、大批量请求)—— 上游可能因此限制甚至封禁账号。 使用风险自负。", + "webCookie": "此提供者通过你的网页会话 Cookie 进行鉴权。上游服务可能随时让会话失效,届时你需要重新登录。不建议用于长时间无人值守的操作。 使用风险自负。", + "deprecated": "此提供者已被上游下线,可能随时停止工作。已存在的连接可能在上游完全关闭访问前继续可用。建议考虑替代方案。", + "dontShowAgain": "对此提供者不再显示此提示", "understand": "我已了解,继续", "cancel": "取消" }, "disabled": "已禁用", - "enableProvider": "启用提供商", - "disableProvider": "禁用提供商", + "enableProvider": "启用提供者", + "disableProvider": "禁用提供者", "testResults": "测试结果", - "noCompatibleYet": "尚未添加兼容的提供商", + "noCompatibleYet": "尚未添加兼容的提供者", "compatibleHint": "使用上面的按钮添加 OpenAI 或 Anthropic 兼容端点", "addOpenAICompatible": "添加 OpenAI 兼容", "addAnthropicCompatible": "添加 Anthropic 兼容端点", - "addNewProvider": "添加新提供商", - "backToProviders": "返回提供商", - "configureNewProvider": "配置新的 AI 提供商以与您的应用程序一起使用。", - "providerLabel": "提供商", - "selectProvider": "选择提供商", - "selectedProvider": "选定的提供商", + "addNewProvider": "添加新提供者", + "backToProviders": "返回提供者", + "configureNewProvider": "配置新的 AI 提供者以与您的应用程序一起使用。", + "providerLabel": "提供者", + "selectProvider": "选择提供者", + "selectedProvider": "选定的提供者", "authMethod": "认证方式", "apiKeyLabel": "API key", "apiKeyRequired": "需要 API 密钥", - "selectProviderRequired": "请选择提供商", + "selectProviderRequired": "请选择提供者", "enterApiKey": "输入您的 API 密钥", "apiKeySecure": "您的 API 密钥将被加密并安全存储。", "oauth2Connect": "使用 OAuth2 连接", @@ -4860,10 +4860,10 @@ "displayNamePlaceholder": "例如,生产 API、开发环境", "displayNameHint": "可选。用于标识此配置的友好名称。", "active": "活跃", - "activeDescription": "启用此提供商以在您的应用程序中使用", + "activeDescription": "启用此提供者以在您的应用程序中使用", "cancel": "取消", - "createProvider": "创建提供商", - "failedCreate": "创建提供商失败", + "createProvider": "创建提供者", + "failedCreate": "创建提供者失败", "errorOccurred": "发生错误。请再试一次。", "modelStatus": "模型状态", "showConfiguredOnly": "仅显示已配置", @@ -4876,8 +4876,8 @@ "clearCooldown": "清除", "clearing": "清算...", "until": "直到 {time}", - "providerTestFailed": "提供商测试失败", - "providerTestTimeout": "提供商测试超时,可能是同时测试的连接过多", + "providerTestFailed": "提供者测试失败", + "providerTestTimeout": "提供者测试超时,可能是同时测试的连接过多", "modeTest": "{mode} 测试", "passedCount": "{count} 通过", "failedCount": "{count} 失败", @@ -4894,7 +4894,7 @@ "apiTypeLabel": "API 类型", "prefixHint": "必填。模型名称使用的唯一前缀。", "nameHint": "必填。该节点的友好标签。", - "baseUrlHint": "必填。 提供商 API 基本 URL。", + "baseUrlHint": "必填。 提供者 API 基本 URL。", "iconUrlLabel": "图标 URL", "iconUrlHint": "可选。显示为此服务商图标的图片 URL。", "anthropicPrefixPlaceholder": "ac-prod", @@ -4907,7 +4907,7 @@ "connectionFailed": "连接失败。检查 URL 和密钥。", "testKeyLabel": "测试 API 密钥", "testKeyPlaceholder": "sk-...(仅用于验证)", - "providerNotFound": "未找到提供商", + "providerNotFound": "未找到提供者", "deleteConnectionConfirm": "删除这个连接吗?", "deleteConnectionConfirmNamed": "确定要删除{name}吗?此操作无法撤销。", "batchDeleteSelected": "删除选中({count})", @@ -4957,7 +4957,7 @@ "autoSyncDisabled": "自动同步已禁用", "autoSyncToggleFailed": "切换自动同步失败", "clearAllModels": "清除所有模型", - "clearAllModelsConfirm": "您确定要删除此提供商的所有模型吗?", + "clearAllModelsConfirm": "您确定要删除此提供者的所有模型吗?", "clearAllModelsSuccess": "所有模型已清除", "clearAllModelsFailed": "清除模型失败", "addConnectionToImport": "添加连接以启用导入。", @@ -5035,10 +5035,10 @@ "openai": "OpenAI", "singleConnectionPerCompatible": "每个兼容节点仅允许一个连接。如果需要更多连接,请添加另一个节点。", "connections": "连接", - "providerProxyTitleConfigured": "提供商代理:{host}", + "providerProxyTitleConfigured": "提供者代理:{host}", "configured": "已配置", - "providerProxyConfigureHint": "为该提供商的所有连接配置代理", - "providerProxy": "提供商代理", + "providerProxyConfigureHint": "为该提供者的所有连接配置代理", + "providerProxy": "提供者代理", "repairEnv": "修复 .env", "repairEnvWorking": "修复中...", "repairEnvHint": "将缺失的 OAuth 默认值补充到 .env 中,不会覆盖现有值。", @@ -5049,7 +5049,7 @@ "addConnection": "添加连接", "availableModels": "可用模型", "builtInModels": "内置模型", - "builtInModelsHint": "该提供商的注册表模型。点击铅笔可设置兼容选项。", + "builtInModelsHint": "该提供者的注册表模型。点击铅笔可设置兼容选项。", "pageAutoRefresh": "页面会自动刷新...", "statusDisabled": "已禁用", "statusConnected": "已连接", @@ -5075,7 +5075,7 @@ "errorTypeCreditsExhausted": "额度已用完", "errorTypeBanned": "403 禁止访问", "proxySourceGlobal": "全局", - "proxySourceProvider": "提供商", + "proxySourceProvider": "提供者", "proxySourceKey": "密钥", "proxyConfiguredBySource": "代理 ({source}):{host}", "proxyOn": "代理开启", @@ -5084,8 +5084,8 @@ "proxyDisabledTitle": "此连接已禁用代理", "perKeyProxyOn": "按密钥", "perKeyProxyOff": "连接", - "perKeyProxyEnabledTitle": "已为此提供商启用按密钥代理分配", - "perKeyProxyDisabledTitle": "已为此提供商禁用按密钥代理分配", + "perKeyProxyEnabledTitle": "已为此提供者启用按密钥代理分配", + "perKeyProxyDisabledTitle": "已为此提供者禁用按密钥代理分配", "autoPriority": "自动:{priority}", "proxy": "代理", "retestAuthentication": "重新验证身份", @@ -5123,15 +5123,15 @@ "targetFormatAntigravity": "Antigravity", "contextWindowOverrideLabel": "上下文窗口覆盖", "contextWindowOverridePlaceholder": "例如 131072", - "contextWindowOverrideHint": "当提供商误报时,手动设置此模型的实际上下文窗口(token)。此设置优先于自动检测/目录值,并防止组合路由丢弃该模型。", + "contextWindowOverrideHint": "当提供者误报时,手动设置此模型的实际上下文窗口(token)。此设置优先于自动检测/目录值,并防止组合路由丢弃该模型。", "contextWindowOverrideInvalid": "上下文窗口覆盖值必须是正整数 token 数", "visionCapableLabel": "支持视觉", - "visionCapableHint": "当提供商的发现元数据未报告图像输入模态时(常见于自托管/本地后端),手动将此模型标记为支持视觉。", + "visionCapableHint": "当提供者的发现元数据未报告图像输入模态时(常见于自托管/本地后端),手动将此模型标记为支持视觉。", "compatParamFiltersLabel": "参数过滤器", "compatBlockedParamsHint": "已屏蔽的参数(从请求中移除)", "compatAllowedParamsHint": "允许的参数(在拒绝后重新添加)", "paramFiltersSectionTitle": "参数过滤器", - "paramFiltersSectionHint": "在发送给此提供商之前剥离或重新添加请求参数。用于避免因提供商拒绝某些参数而导致的 400 错误(例如 NVIDIA NIM 拒绝 thinking)。", + "paramFiltersSectionHint": "在发送给此提供者之前剥离或重新添加请求参数。用于避免因提供者拒绝某些参数而导致的 400 错误(例如 NVIDIA NIM 拒绝 thinking)。", "paramFiltersBlockedLabel": "已屏蔽的参数", "paramFiltersBlockedHint": "这些参数将从发送的请求中剥离(黑名单)。", "paramFiltersAllowedLabel": "允许的参数", @@ -5147,7 +5147,7 @@ "paramFiltersResetSuccess": "参数过滤器配置已重置为默认值", "paramFiltersResetError": "重置参数过滤器配置失败:{error}", "interceptionSectionTitle": "网页工具拦截", - "interceptionSectionHint": "将此提供商的原生 web_search / web_fetch 工具调用路由到 OmniRoute 自身的搜索和获取端点,而不是让提供商原生运行它们。默认关闭 — 现有行为保持不变。", + "interceptionSectionHint": "将此提供者的原生 web_search / web_fetch 工具调用路由到 OmniRoute 自身的搜索和获取端点,而不是让提供者原生运行它们。默认关闭 — 现有行为保持不变。", "interceptSearchLabel": "拦截 web_search", "interceptSearchHint": "将原生的 web_search 工具调用重写为 OmniRoute 的 /v1/search。", "interceptFetchLabel": "拦截 web_fetch", @@ -5164,7 +5164,7 @@ "perModelQuotaLabel": "按模型配额", "perModelQuotaDescription": "启用后,429/404 错误只会锁定特定 Model,而不是整个连接。适用于具有按 Model 速率限制的 Provider(例如 ModelScope)。", "importFreeModelsOnlyLabel": "仅导入免费模型", - "importFreeModelsOnlyHint": "启用后,仅导入此提供商的免费模型。付费模型将被跳过。", + "importFreeModelsOnlyHint": "启用后,仅导入此提供者的免费模型。付费模型将被跳过。", "perModelQuotaToggle": "按模型配额开关", "modelId": "模型 ID", "customModelPlaceholder": "例如:gpt-4.5-turbo", @@ -5213,7 +5213,7 @@ "apiKeyForCheck": "API 密钥(用于检查)", "testModelIdLabel": "模型 ID(可选)", "testModelIdPlaceholder": "例如 my-model-id", - "testModelIdHint": "如果提供商缺少 /models 端点,请输入模型 ID 以改用 /chat/completions 进行验证。", + "testModelIdHint": "如果提供者缺少 /models 端点,请输入模型 ID 以改用 /chat/completions 进行验证。", "compatibleProdPlaceholder": "{type} 兼容(产品)", "tokenRefreshed": "Token 刷新成功", "tokenRefreshFailed": "Token 刷新失败", @@ -5346,7 +5346,7 @@ "advancedSettings": "高级设置", "chatPathLabel": "聊天端点路径", "chatPathPlaceholder": "/chat/completions", - "chatPathHint": "为非标准 API 的提供商自定义聊天路径(例如:/v4/chat/completions)", + "chatPathHint": "为非标准 API 的提供者自定义聊天路径(例如:/v4/chat/completions)", "modelsPathLabel": "模型端点路径", "modelsPathPlaceholder": "/models", "modelsPathHint": "为验证流程自定义模型路径(例如:/v4/models)", @@ -5377,7 +5377,7 @@ "apikey": "API key", "audio": "音频", "audioProvidersHeading": "音频 Provider", - "cloudAgentProviders": "云代理提供商", + "cloudAgentProviders": "云代理提供者", "audioShortLabel": "音频", "azureOpenAiBaseUrlHint": "Azure OpenAI 资源的 Base URL。", "bailianBaseUrlHint": "阿里云百炼服务的 Base URL。", @@ -5444,7 +5444,7 @@ "expirationBannerExpiringSoon": "凭据即将过期", "expirationBannerExpiringSoonDesc": "此 Provider 的凭据即将过期,请提前更新。", "extraApiKeyMasked": "密钥 {index}:{prefix}••••{suffix}", - "extraApiKeysHint": "为同一提供商添加额外 API 密钥,以便轮换和回退使用。", + "extraApiKeysHint": "为同一提供者添加额外 API 密钥,以便轮换和回退使用。", "extraApiKeysLabel": "额外 API 密钥", "apiKeyHealthLabel": "API 密钥健康状态", "apiKeyStatusActive": "正常", @@ -5473,8 +5473,8 @@ "embeddingRerankProviders": "嵌入与重排序", "imagesShortLabel": "图像", "llmProviders": "LLM Provider", - "localProviderApiKeyOptionalHint": "本地提供商的 API 密钥通常是可选的。", - "localProviderBaseUrlHint": "输入本地提供商的 Base URL。", + "localProviderApiKeyOptionalHint": "本地提供者的 API 密钥通常是可选的。", + "localProviderBaseUrlHint": "输入本地提供者的 Base URL。", "localProviders": "本地 Provider", "maxConcurrentWholeNumberError": "最大并发必须是整数", "m365TierLabel": "Copilot 层级", @@ -5487,7 +5487,7 @@ "tierOverrideFree": "免费", "tierOverrideCheap": "低成本", "tierOverridePremium": "高级", - "tierOverrideHelpText": "将此提供商固定到特定的路由层级,而不是让 OmniRoute 根据模型定价进行推断。", + "tierOverrideHelpText": "将此提供者固定到特定的路由层级,而不是让 OmniRoute 根据模型定价进行推断。", "museSparkWebCookieHint": "从 Muse Spark Web 会话复制 Cookie。", "museSparkWebCookiePlaceholder": "Muse Spark Web Cookie", "oauth": "OAuth", @@ -5506,11 +5506,11 @@ "rateLimitOverridesMaxConcurrentLabel": "最大并发(速率限制)", "rateLimitOverridesMinTimeHint": "请求之间的最小时间(毫秒)。覆盖默认速率限制器延迟。", "rateLimitOverridesMinTimeLabel": "最小间隔(毫秒)", - "rateLimitOverridesRpmHint": "此连接的每分钟最大请求数。覆盖提供商默认值。", + "rateLimitOverridesRpmHint": "此连接的每分钟最大请求数。覆盖提供者默认值。", "rateLimitOverridesRpmLabel": "RPM(请求/分钟)", - "rateLimitOverridesTpdHint": "此连接的每日最大令牌数。覆盖提供商默认值。", + "rateLimitOverridesTpdHint": "此连接的每日最大令牌数。覆盖提供者默认值。", "rateLimitOverridesTpdLabel": "TPD(令牌/天)", - "rateLimitOverridesTpmHint": "此连接的每分钟最大令牌数。覆盖提供商默认值。", + "rateLimitOverridesTpmHint": "此连接的每分钟最大令牌数。覆盖提供者默认值。", "rateLimitOverridesTpmLabel": "TPM(令牌/分钟)", "refreshOauthTokenTitle": "刷新 OAuth Token", "regionHint": "选择此 Provider 使用的区域。", @@ -5523,8 +5523,8 @@ "searchEngineIdHint": "Google Programmable Search Engine 的 ID。", "searchEngineIdLabel": "Search Engine ID", "searchEngineIdRequired": "Search Engine ID 为必填项", - "searchProvider": "搜索提供商", - "searchProviderDesc": "按名称、能力或类别查找提供商。", + "searchProvider": "搜索提供者", + "searchProviderDesc": "按名称、能力或类别查找提供者。", "searchProviders": "搜索 Provider", "searchByModel": "按模型搜索…", "searchProvidersHeading": "搜索 Provider", @@ -5552,7 +5552,7 @@ "totalKeysRotating": "{count, plural, one {1 个 key 正在轮换} other {# 个 key 正在轮换}}", "unhideModel": "取消隐藏模型", "upstreamProxyProviders": "上游代理 Provider", - "validationModelIdHint": "用于验证此提供商连接的模型 ID。", + "validationModelIdHint": "用于验证此提供者连接的模型 ID。", "validationModelIdLabel": "验证模型 ID", "validationModelIdPlaceholder": "输入用于测试的模型 ID", "vertexServiceAccountPlaceholder": "粘贴 Service Account JSON({\"type\":\"service_account\"...})或 OAuth access_token", @@ -5567,7 +5567,7 @@ "importAuth": "导入身份验证", "importGrokAuth": "导入 Grok Build 身份验证", "zedImportTitle": "从 Zed 钥匙串导入", - "zedImportDescription": "发现 Zed IDE 存储在操作系统钥匙串中的 AI 提供商凭据(OpenAI、Anthropic、Google、Mistral、xAI)并将其导入为连接。此机器上必须安装 Zed IDE。", + "zedImportDescription": "发现 Zed IDE 存储在操作系统钥匙串中的 AI 提供者凭据(OpenAI、Anthropic、Google、Mistral、xAI)并将其导入为连接。此机器上必须安装 Zed IDE。", "zedImportButton": "从 Zed 导入", "zedImportFailed": "Zed 导入失败", "zedImportHint": "从 Zed 配置中导入 Provider。", @@ -5576,7 +5576,7 @@ "zedImportSuccess": "Zed 导入成功", "zedImporting": "正在从 Zed 导入", "zedNoCredentials": "在钥匙串中未找到 Zed 凭据", - "zedUnsupportedCredentials": "找到 {count} 个钥匙串凭据,但没有与支持的提供商匹配的凭据", + "zedUnsupportedCredentials": "找到 {count} 个钥匙串凭据,但没有与支持的提供者匹配的凭据", "zedManualTitle": "手动导入令牌", "zedManualDescription": "当 OmniRoute 在 Docker 中运行或密钥链不可用时使用此选项。粘贴 Zed 存储在 ~/.config/zed/settings.json 下的 API 密钥,或从 Zed AI 设置面板中复制它。", "zedPasteApiKey": "粘贴 API 密钥…", @@ -5598,13 +5598,13 @@ "grokConnectionName": "连接名称(可选)", "grokSaving": "正在保存…", "grokSaveConnection": "保存连接", - "freeTierProviders": "免费层提供商", + "freeTierProviders": "免费层提供者", "freeTierLabel": "有免费额度", - "freeTierProvidersDesc": "提供免费层的提供商——有些需要注册 API 密钥,有些无需任何凭证。", + "freeTierProvidersDesc": "提供免费层的提供者——有些需要注册 API 密钥,有些无需任何凭证。", "providerSummaryAll": "全部", - "ideProviders": "IDE 提供商", - "ideProvidersDesc": "内置 AI 订阅的编辑器。使用提供商页面直接从 IDE 密钥链导入凭据。", - "noIdeProviders": "没有符合当前筛选条件的 IDE 提供商。", + "ideProviders": "IDE 提供者", + "ideProvidersDesc": "内置 AI 订阅的编辑器。使用提供者页面直接从 IDE 密钥链导入凭据。", + "noIdeProviders": "没有符合当前筛选条件的 IDE 提供者。", "providerDetailFastTierTooltip": "默认对所有 Codex 连接应用 Codex Fast 层级", "providerDetailFastDefaultLabel": "快速默认", "providerDetailBrowserManualConnect": "浏览器/手动连接", @@ -5625,61 +5625,61 @@ "claudeImportParseError": "解析错误", "claudeImportNoValidEntries": "没有可导入的有效条目", "webFetch": "网页抓取", - "webFetchTooltip": "从网页 URL 抽取内容的提供商(HTML → Markdown、抓取、截图)", - "webFetchProvidersHeading": "网页抓取提供商", + "webFetchTooltip": "从网页 URL 抽取内容的提供者(HTML → Markdown、抓取、截图)", + "webFetchProvidersHeading": "网页抓取提供者", "compatibleProvidersDesc": "您托管或配置的 OpenAI 兼容和 Anthropic 兼容端点。将任意 OpenAI SDK 指向您的 URL 并在此处路由请求。", - "oauthProvidersDesc": "通过 OAuth 认证的提供商——登录一次,OmniRoute 自动处理令牌轮换。", - "webCookieProvidersDesc": "这些提供商使用浏览器网络会话、cookie 或网络令牌而不是 API 密钥。打开提供程序以添加所需的会话凭据。", - "apiKeyProvidersDesc": "标准 API 密钥提供商。添加密钥后,OmniRoute 代为路由、重试和限流。", + "oauthProvidersDesc": "通过 OAuth 认证的提供者——登录一次,OmniRoute 自动处理令牌轮换。", + "webCookieProvidersDesc": "这些提供者使用浏览器网络会话、cookie 或网络令牌而不是 API 密钥。打开提供程序以添加所需的会话凭据。", + "apiKeyProvidersDesc": "标准 API 密钥提供者。添加密钥后,OmniRoute 代为路由、重试和限流。", "noAuthProvidersDesc": "无需凭证的开放端点——无需注册即可立即使用。", "upstreamProxyProvidersDesc": "通过上游代理路由出站流量。适用于企业网络或流量审计场景。", - "webFetchProvidersDesc": "从网页 URL 抓取和提取内容的提供商。用于将实时网页数据注入提示词。", - "aggregatorsGatewaysDesc": "多提供商聚合器和 AI 网关,通过单一统一 API 对接数十个底层模型。", + "webFetchProvidersDesc": "从网页 URL 抓取和提取内容的提供者。用于将实时网页数据注入提示词。", + "aggregatorsGatewaysDesc": "多提供者聚合器和 AI 网关,通过单一统一 API 对接数十个底层模型。", "enterpriseCloudDesc": "企业级和云托管模型,提供增强 SLA、合规认证和专用容量。", "cloudAgentProvidersDesc": "自主云代理,可执行长时间运行的任务,支持计划审批和实时状态跟踪。", "localProvidersDesc": "在您自己的硬件上运行的自托管模型。数据不会离开您的基础设施。", - "searchProvidersDesc": "网页和文档搜索提供商。可附加到 LLM 调用以实现检索增强生成(RAG)。", - "audioProvidersDesc": "文本转语音和语音转文本提供商,用于语音输入输出和音频转录管道。", - "embeddingRerankProvidersDesc": "向量嵌入和重排序提供商,用于语义搜索、RAG 管道和相似度评分。", - "imageProvidersDesc": "图像生成和视觉提供商——从文本创建图像或分析现有图像。", - "videoProvidersDesc": "视频生成提供商。从文本提示或图像创建短视频片段。", - "onboardingWizard": "提供商入职向导", + "searchProvidersDesc": "网页和文档搜索提供者。可附加到 LLM 调用以实现检索增强生成(RAG)。", + "audioProvidersDesc": "文本转语音和语音转文本提供者,用于语音输入输出和音频转录管道。", + "embeddingRerankProvidersDesc": "向量嵌入和重排序提供者,用于语义搜索、RAG 管道和相似度评分。", + "imageProvidersDesc": "图像生成和视觉提供者——从文本创建图像或分析现有图像。", + "videoProvidersDesc": "视频生成提供者。从文本提示或图像创建短视频片段。", + "onboardingWizard": "提供者入职向导", "onboardingWizardShort": "入职向导", - "onboardingWizardDescription": "通过验证、持久性和即时连接测试连接 API 密钥、自定义兼容和 OAuth 提供商。", + "onboardingWizardDescription": "通过验证、持久性和即时连接测试连接 API 密钥、自定义兼容和 OAuth 提供者。", "onboardingStepType": "类型", - "onboardingStepProvider": "提供商", + "onboardingStepProvider": "提供者", "onboardingStepCredentials": "凭证", "onboardingStepResult": "结果", - "onboardingTypeApiKeyTitle": "API 密钥提供商", + "onboardingTypeApiKeyTitle": "API 密钥提供者", "onboardingTypeApiKeyText": "使用内置提供程序,例如 OpenAI、Anthropic、Gemini、Groq、Azure 等。", - "onboardingTypeCustomTitle": "自定义兼容提供商", + "onboardingTypeCustomTitle": "自定义兼容提供者", "onboardingTypeCustomText": "创建与 OpenAI、Anthropic 或 Claude Code 兼容的端点并添加其密钥。", - "onboardingTypeOAuthTitle": "OAuth 提供商", - "onboardingTypeOAuthText": "为编码提供商重用现有的 OAuth、设备代码或本地导入流程。", - "onboardingChooseOAuthProvider": "选择 OAuth 提供商", - "onboardingChooseApiKeyProvider": "选择 API 密钥提供商", - "onboardingChooseProviderDescription": "选择一个提供商,然后向导将指导您完成凭据和测试。", + "onboardingTypeOAuthTitle": "OAuth 提供者", + "onboardingTypeOAuthText": "为编码提供者重用现有的 OAuth、设备代码或本地导入流程。", + "onboardingChooseOAuthProvider": "选择 OAuth 提供者", + "onboardingChooseApiKeyProvider": "选择 API 密钥提供者", + "onboardingChooseProviderDescription": "选择一个提供者,然后向导将指导您完成凭据和测试。", "onboardingChangeType": "变更类型", - "onboardingChangeProvider": "更换提供商", - "onboardingSearchProviders": "搜索提供商...", + "onboardingChangeProvider": "更换提供者", + "onboardingSearchProviders": "搜索提供者...", "onboardingApiKeyOptional": "API 密钥可选", - "onboardingProviderConnected": "提供商已连接", + "onboardingProviderConnected": "提供者已连接", "onboardingProviderSavedWithWarnings": "提供者保存时带有警告", - "onboardingProviderFinished": "提供商入职完成", - "onboardingYourProviderConnection": "您的提供商连接", + "onboardingProviderFinished": "提供者入职完成", + "onboardingYourProviderConnection": "您的提供者连接", "onboardingTestPassed": "测试通过", "onboardingTestFailed": "测试失败", - "onboardingOpenProviderDetails": "开放提供商详细信息", + "onboardingOpenProviderDetails": "开放提供者详细信息", "onboardingTryInPlayground": "去游乐场试试", "onboardingDefaultConnectionName": "{provider} 主要", - "onboardingTestingConnection": "测试提供商连接...", + "onboardingTestingConnection": "测试提供者连接...", "onboardingValidatingCredentials": "正在验证凭据...", - "onboardingSavingConnection": "正在保存提供商连接...", - "onboardingProviderFailed": "提供商加入失败", + "onboardingSavingConnection": "正在保存提供者连接...", + "onboardingProviderFailed": "提供者加入失败", "onboardingCreatingCompatibleProvider": "创建兼容的提供者...", - "onboardingSavingCompatibleConnection": "正在保存兼容的提供商连接...", - "onboardingCustomProviderFallbackName": "定制提供商", - "onboardingCustomProviderFailed": "自定义提供商加入失败", + "onboardingSavingCompatibleConnection": "正在保存兼容的提供者连接...", + "onboardingCustomProviderFallbackName": "定制提供者", + "onboardingCustomProviderFailed": "自定义提供者加入失败", "onboardingLoadingOAuthConnection": "正在加载 OAuth 连接...", "onboardingOAuthNoConnectionFound": "OAuth 已完成,但未找到提供者连接。", "onboardingOAuthFailed": "OAuth 登录失败", @@ -5690,24 +5690,24 @@ "onboardingBaseUrlOverrideHint": "可选。存储为providerSpecificData.baseUrl。", "onboardingRegion": "地区", "onboardingSearchCx": "搜索 CX/引擎 ID", - "onboardingProviderSpecificIdPlaceholder": "可选的提供商特定 ID", + "onboardingProviderSpecificIdPlaceholder": "可选的提供者特定 ID", "onboardingCustomUserAgent": "自定义用户代理", "onboardingWorking": "工作…", "onboardingValidateSaveTest": "验证、保存和测试", "onboardingBack": "返回", - "onboardingCreateCustomCompatibleProvider": "创建自定义兼容提供商", + "onboardingCreateCustomCompatibleProvider": "创建自定义兼容提供者", "onboardingCreateCustomCompatibleDescription": "该向导首先创建一个提供程序节点,然后存储并测试其 API 密钥连接。", "onboardingProtocol": "协议", "onboardingOpenAiCompatible": "兼容 OpenAI", "onboardingAnthropicCompatible": "人类兼容", "onboardingClaudeCodeCompatible": "克劳德代码兼容", - "onboardingProviderPrefix": "提供商前缀", - "onboardingProviderPrefixHint": "用于生成托管提供商 ID。", + "onboardingProviderPrefix": "提供者前缀", + "onboardingProviderPrefixHint": "用于生成托管提供者 ID。", "onboardingChatPath": "聊天路径", "onboardingModelsPath": "模型路径", "onboardingCreateSaveTest": "创建、保存和测试", "onboardingConnectProvider": "连接 {provider}", - "onboardingOAuthFlowDescription": "OmniRoute 将打开该提供商的现有 OAuth 流程。登录后,向导将重新加载已保存的连接并运行与提供程序页面相同的连接测试。", + "onboardingOAuthFlowDescription": "OmniRoute 将打开该提供者的现有 OAuth 流程。登录后,向导将重新加载已保存的连接并运行与提供程序页面相同的连接测试。", "onboardingStartOAuthFlow": "启动 OAuth 流程", "onboardingProviderDescriptions": { "360ai": "在 ai.360.cn 获取 API 密钥", @@ -5912,7 +5912,7 @@ "webTokenCredentialLabel": "网络会话令牌", "webNoAuthCredentialLabel": "无需任何凭证", "webCookieCredentialHint": "所需 cookie:{credential}。粘贴您自己登录的 {provider} Web 会话中的 Cookie 标头值。请勿包含 Cookie: 前缀。", - "webTokenCredentialHint": "凭证:{credential}。粘贴您自己登录的 {provider} Web 会话中的令牌值,或者粘贴 DevTools HAR 导出(如果提供商支持)的令牌值。", + "webTokenCredentialHint": "凭证:{credential}。粘贴您自己登录的 {provider} Web 会话中的令牌值,或者粘贴 DevTools HAR 导出(如果提供者支持)的令牌值。", "webCookieEditHint": "留空以保留当前会话 cookie。所需 cookie:{credential}。", "webTokenEditHint": "留空以保留当前的 ​​Web 会话令牌。凭证:{credential}。", "webSessionGuideTitle": "如何获取会话凭证", @@ -5921,7 +5921,7 @@ "webTokenRequiredCredential": "所需令牌:{credential}", "webSessionGuideStep1": "在浏览器中登录 {provider}。", "webSessionGuideStep2": "打开浏览器开发人员工具并检查 Web 应用程序发出的请求。", - "webSessionGuideStep3": "从提供商自己的域复制所需的凭据。对于 cookie,仅复制 Cookie 标头值并省略 Cookie:。", + "webSessionGuideStep3": "从提供者自己的域复制所需的凭据。对于 cookie,仅复制 Cookie 标头值并省略 Cookie:。", "webSessionGuideStep4": "将其粘贴到此处并检查连接。如果它停止工作,请重新登录并将其替换为新值。", "webSessionSecurityHint": "将其视为密码:它可以访问您登录的网络帐户,直到其过期或被撤销。", "webNoAuthGuideTitle": "无需任何凭证", @@ -5942,7 +5942,7 @@ "doubaoWebLabel": "Dola Web", "doubaoWebDesc": "通过 dola.com 访问字节跳动 AI 聊天", "overrideBaseUrlAdvanced": "高级:覆盖基础 URL", - "overrideBaseUrlHint": "高级:将此内置提供商指向自定义端点。留空以使用默认值。", + "overrideBaseUrlHint": "高级:将此内置提供者指向自定义端点。留空以使用默认值。", "bulkAddFormatHintCloudflare": "每行一个密钥。格式:name|accountId|apiKey(Cloudflare 账户 ID + API 令牌)。", "lmarenaWebCookieHint": "打开 arena.ai,登录,然后从网络请求中复制完整的 Cookie 请求头。包含 arena-auth-prod-v1.0 和 arena-auth-prod-v1.1(如果存在更多分块也一并包含),最好附带 cf_clearance。请勿仅粘贴空的 arena-auth-prod-v1 cookie。可选:如果 create-evaluation 仍返回 403,可提供 providerSpecificData.recaptchaV3Token。", "kimiOfficialSupporterBadge": "创始好友", @@ -5962,7 +5962,7 @@ "enable": "启用", "disable": "禁用", "update": "更新", - "routingSettingsIntro": "控制您的请求如何路由、转换和发送给 AI 提供商。", + "routingSettingsIntro": "控制您的请求如何路由、转换和发送给 AI 提供者。", "routingOpDropParagraphContainsLabel": "丢弃段落(包含)", "routingOpDropParagraphStartsWithLabel": "丢弃段落(开头匹配)", "routingOpReplaceTextLabel": "替换文本", @@ -5979,7 +5979,7 @@ "routingOpDropBlockContainsDesc": "移除整个系统块(而非仅段落),只要其文本包含任一指定子串。当一整块带指纹时使用,例如注入的 MCP 服务器描述。", "routingOpPrependSystemBlockDesc": "在系统数组的开头插入一个新的文本块。用于添加 Anthropic 分类器期望的 SDK 身份声明 'You are a Claude agent, built on Anthropic's Claude Agent SDK.'。", "routingOpAppendSystemBlockDesc": "在系统数组末尾追加一个新文本块。用于不必置于 [0] 位置的修饰性内容。", - "routingOpInjectBillingHeaderDesc": "在前置位置插入特殊的 'x-anthropic-billing-header: cc_version=...; cc_entrypoint=...; cch=...;' 文本块,用于通过 Anthropic 分类器校验。CC 桥接转发端点必须使用;原生 claude 提供商已自带计费行,在那里通常无需此操作。", + "routingOpInjectBillingHeaderDesc": "在前置位置插入特殊的 'x-anthropic-billing-header: cc_version=...; cc_entrypoint=...; cch=...;' 文本块,用于通过 Anthropic 分类器校验。CC 桥接转发端点必须使用;原生 claude 提供者已自带计费行,在那里通常无需此操作。", "routingOpObfuscateWordsDesc": "在每个指定词的首字母后插入零宽连字符,例如 'opencode' 变为 'o‍pencode'。视觉上对人类完全相同,但能绕过分类器的词匹配。作用于系统块、用户/助手消息以及工具描述。", "routingNeedlesHint": "子串列表。段落只要包含其中任一项即匹配。通过「添加条目」逐行添加。", "routingPrefixesHint": "字符串列表。段落以其中任一项开头即匹配(匹配前会去除前导空白)。", @@ -6006,8 +6006,8 @@ "routingSummarizeAppendSystemBlock": "追加块:\"{text}\"", "routingSummarizeInjectBillingHeader": "注入计费头(entrypoint={entrypoint},version={versionFormat},cch={cchAlgo})", "routingSummarizeObfuscateWords": "通过 ZWJ 在 {targets} 中混淆 {count} 个词", - "routingDefaultAutoVariantLKGP": "上次正常的提供商", - "routingDefaultAutoVariantLKGPDesc": "上次正常的提供商", + "routingDefaultAutoVariantLKGP": "上次正常的提供者", + "routingDefaultAutoVariantLKGPDesc": "上次正常的提供者", "routingDefaultAutoVariantCoding": "代码场景质量优先", "routingDefaultAutoVariantCodingDesc": "代码场景质量优先", "routingDefaultAutoVariantFast": "低延迟路由", @@ -6086,13 +6086,13 @@ "justNow": "刚才", "modelsDevStats": "同步统计", "modelsDevStatsDesc": "当前 models.dev 数据覆盖情况", - "providers": "提供商", + "providers": "提供者", "modelsWithPricing": "已有定价的模型", "capabilities": "能力", "lastSyncCount": "上次同步数量", "lastSyncFull": "上次完整同步", "modelsDevInfo": "工作原理", - "modelsDevInfoDesc": "models.dev 是由 SST/OpenCode 团队维护的开源 AI 模型规格数据库,提供 100+ 提供商、4,000+ 模型的定价、能力、上下文限制和模态信息。", + "modelsDevInfoDesc": "models.dev 是由 SST/OpenCode 团队维护的开源 AI 模型规格数据库,提供 100+ 提供者、4,000+ 模型的定价、能力、上下文限制和模态信息。", "modelsDevInfoResolution": "定价解析顺序(优先级从高到低):", "modelsDevInfoOrder": "用户覆盖 → models.dev → LiteLLM → 硬编码默认值", "systemTheme": "系统主题", @@ -6101,22 +6101,22 @@ "logToolSourcesDescription": "每个请求输出一行诊断日志,汇总工具数量以及 MCP/托管/客户端来源明细。", "homePinProviderQuotaToHome": "将信息固定到首页", "homePinnedSectionsDesc": "选择要固定到主页顶部的板块。", - "homeProviderQuotaLimits": "提供商配额限制", - "homeProviderQuotaLimitsDesc": "将提供商配额状态容器(含全部刷新按钮)固定到首页顶部。", + "homeProviderQuotaLimits": "提供者配额限制", + "homeProviderQuotaLimitsDesc": "将提供者配额状态容器(含全部刷新按钮)固定到首页顶部。", "homeQuickStart": "快速入门", "homeQuickStartDesc": "在首页上显示快速入门面板。", - "homeProviderTopology": "提供商拓扑", - "homeProviderTopologyDesc": "在首页上显示提供商拓扑。", + "homeProviderTopology": "提供者拓扑", + "homeProviderTopologyDesc": "在首页上显示提供者拓扑。", "accountEmailVisibility": "账号邮箱可见性", - "accountEmailVisibilityDesc": "在提供商、组合、日志、配额和 Playground 页面显示完整账号邮箱。关闭后默认打码显示。", + "accountEmailVisibilityDesc": "在提供者、组合、日志、配额和 Playground 页面显示完整账号邮箱。关闭后默认打码显示。", "comboConfigMode": "组合配置模式", "comboConfigModeDesc": "选择组合创建和编辑对话框的组织方式。", "comboConfigModeGuided": "引导", "comboConfigModeGuidedDesc": "使用当前的分步组合构建器。", "comboConfigModeExpert": "专家", "comboConfigModeExpertDesc": "在单页上显示所有组合选项,并支持直接输入模型。", - "providerQuotaAutoRefresh": "提供商配额自动刷新", - "providerQuotaAutoRefreshDesc": "在保持打开状态时自动刷新提供商限制视图。", + "providerQuotaAutoRefresh": "提供者配额自动刷新", + "providerQuotaAutoRefreshDesc": "在保持打开状态时自动刷新提供者限制视图。", "providerQuotaAutoRefreshToggle": "自动刷新", "providerQuotaAutoRefreshToggleDesc": "在页面可见时每隔几分钟刷新一次配额视图。", "providerQuotaAutoRefreshInterval": "刷新间隔", @@ -6152,7 +6152,7 @@ "enableSystemPrompt": "启用系统提示", "systemPromptText": "系统提示文字", "autoDisableBannedAccounts": "自动禁用被封禁账户", - "autoDisableDescription": "若提供商连接返回特定的永久封禁信号(如 HTTP 403\"请验证您的账户\"),则将其永久标记为停用。这会将其从组合轮换中移除。", + "autoDisableDescription": "若提供者连接返回特定的永久封禁信号(如 HTTP 403\"请验证您的账户\"),则将其永久标记为停用。这会将其从组合轮换中移除。", "autoDisableThreshold": "封禁阈值", "autoDisableThresholdDesc": "触发永久停用所需的连续封禁信号次数。", "customBannedSignals": "封禁关键词", @@ -6165,7 +6165,7 @@ "maxThinkingTokens": "最大思考令牌", "enableProxy": "启用代理", "perKeyProxyEnabled": "启用按密钥代理分配", - "perKeyProxyEnabledDesc": "启用后,每个提供商连接可以使用自己的代理分配", + "perKeyProxyEnabledDesc": "启用后,每个提供者连接可以使用自己的代理分配", "proxyUrl": "代理网址", "pricingRates": "定价费率格式", "currentPricing": "当前定价概述", @@ -6250,7 +6250,7 @@ "evictions": "驱逐", "loadingCacheStats": "正在加载缓存统计信息...", "globalProxy": "全局代理", - "globalProxyDesc": "为所有 API 调用配置全局出站代理。单独的提供商、组合和键可以覆盖此设置。", + "globalProxyDesc": "为所有 API 调用配置全局出站代理。单独的提供者、组合和键可以覆盖此设置。", "noGlobalProxy": "没有配置全局代理", "proxyPool": "代理池", "freePool": "免费池", @@ -6281,7 +6281,7 @@ "healthcheckLatency": "延迟", "proxyDocumentationScopeTitle": "代理作用域解析", "proxyDocumentationScopeDescBefore": "OmniRoute 按优先级顺序解析出站代理:", - "proxyDocumentationScopeOrder": "组合 → 账户 → 提供商 → 全局", + "proxyDocumentationScopeOrder": "组合 → 账户 → 提供者 → 全局", "proxyDocumentationScopeDescAfter": "。最具体的作用域优先。", "proxyDocumentationAddTitle": "添加自定义代理", "proxyDocumentationAddDescBefore": "转到", @@ -6342,18 +6342,18 @@ "globalSystemPrompt": "全局系统提示", "saved": "已保存", "beforePromptLabel": "提示词前置", - "beforePromptDesc": "注入到代理/提供商系统指令之前", - "beforePromptPlaceholder": "插入到代理/提供商提示词之前的指令...", + "beforePromptDesc": "注入到代理/提供者系统指令之前", + "beforePromptPlaceholder": "插入到代理/提供者提示词之前的指令...", "afterPromptLabel": "提示词后置", - "afterPromptDesc": "注入到代理/提供商系统指令之后", - "afterPromptPlaceholder": "插入到代理/提供商提示词之后的指令...", + "afterPromptDesc": "注入到代理/提供者系统指令之后", + "afterPromptPlaceholder": "插入到代理/提供者提示词之后的指令...", "chars": "{count} 字符", "thinkingBudgetTitle": "思考预算", "thinkingBudgetDesc": "控制所有请求中 AI 推理令牌的使用", "passthrough": "直通", "passthroughDesc": "没有变化——客户控制思维预算", "auto": "自动", - "autoDesc": "丢弃所有思考配置,由提供商自行决定", + "autoDesc": "丢弃所有思考配置,由提供者自行决定", "custom": "定制", "customDesc": "为所有请求设置固定的 Token 预算", "adaptive": "自适应", @@ -6391,30 +6391,30 @@ "bruteForceProtectionDesc": "在同一 IP 多次失败后,对 /api/auth/login 进行限流和锁定。", "corsAllowedOrigins": "CORS 允许的源", "corsAllowedOriginsDesc": "允许调用此服务器的浏览器来源列表,以逗号分隔。空列表 = 不允许浏览器 CORS 访问(服务器到服务器仍可用)。仅在开发环境使用 CORS_ALLOW_ALL=true 环境变量。", - "blockedProviders": "被阻止的提供商", - "blockedProvidersDesc": "在 `/v1/models` 响应中隐藏指定提供商。被隐藏的提供商不会出现在模型列表中。", - "providersBlocked": "{count} 个提供商/模型已屏蔽", + "blockedProviders": "被阻止的提供者", + "blockedProvidersDesc": "在 `/v1/models` 响应中隐藏指定提供者。被隐藏的提供者不会出现在模型列表中。", + "providersBlocked": "{count} 个提供者/模型已屏蔽", "blockProviderTitle": "屏蔽 {provider}", "unblockProviderTitle": "取消屏蔽 {provider}", "cliFingerprint": "CLI 指纹匹配", "cliFingerprintDesc": "在代理请求时模拟原生 CLI 二进制的请求特征。会重新排列请求头和请求体字段,使其与官方 CLI 工具更一致,同时保留你的代理 IP。", - "cliFingerprintEnabled": "已有 {count} 个提供商启用了 CLI 指纹", + "cliFingerprintEnabled": "已有 {count} 个提供者启用了 CLI 指纹", "enableFingerprintTitle": "为 {provider} 启用指纹", "disableFingerprintTitle": "为 {provider} 禁用指纹", "systemTransforms": "系统块转换管道", - "systemTransformsDesc": "在转发之前,每个提供者订购的转换管道应用于请求正文。支持任何提供商 ID。", - "systemTransformsAddProvider": "添加提供商", - "systemTransformsAddProviderPlaceholder": "选择提供商...", - "systemTransformsAddProviderAllConfigured": "所有提供商均已配置", - "systemTransformsRemoveProvider": "删除提供商", - "systemTransformsNoProviders": "没有配置提供者。添加提供商即可开始。", + "systemTransformsDesc": "在转发之前,每个提供者订购的转换管道应用于请求正文。支持任何提供者 ID。", + "systemTransformsAddProvider": "添加提供者", + "systemTransformsAddProviderPlaceholder": "选择提供者...", + "systemTransformsAddProviderAllConfigured": "所有提供者均已配置", + "systemTransformsRemoveProvider": "删除提供者", + "systemTransformsNoProviders": "没有配置提供者。添加提供者即可开始。", "systemTransformsOpMoveUp": "向上移动", "systemTransformsOpMoveDown": "下移", "systemTransformsOpDelete": "删除操作", "routingStrategy": "路由策略", "routingAdvancedGuideTitle": "高级路由指南", "routingAdvancedGuideHint1": "需要可预测优先级时使用 Fill First,需要公平分配时使用 Round Robin,需要延迟弹性时使用 P2C。", - "routingAdvancedGuideHint2": "如果各提供商在质量或成本上差异明显,后台任务可优先考虑“成本优化”,需要均衡消耗时可从“最少使用”开始。", + "routingAdvancedGuideHint2": "如果各提供者在质量或成本上差异明显,后台任务可优先考虑“成本优化”,需要均衡消耗时可从“最少使用”开始。", "fillFirst": "优先填满", "fillFirstDesc": "按优先级顺序使用账户", "roundRobin": "轮询", @@ -6446,7 +6446,7 @@ "routingStrategyComboSummary": " 每个目标调用 {limit} 次后轮换组合。", "routingStrategyComboFallbackSummary": " 组合使用每个组合配置的策略(默认优先级/备用)。", "providerAccountRoutingTitle": "多账户路由", - "providerAccountRoutingDesc": "覆盖此提供商的全局账户策略(与 9router 保持一致)。", + "providerAccountRoutingDesc": "覆盖此提供者的全局账户策略(与 9router 保持一致)。", "providerRoutingStrategy": "账户策略", "providerRoutingInheritGlobal": "继承全局默认值", "modelAliases": "模型别名", @@ -6508,15 +6508,15 @@ "details": "详情", "time": "时间", "fallbackChainsTitle": "后备链", - "fallbackChainsDesc": "定义每个模型的提供商后备顺序", + "fallbackChainsDesc": "定义每个模型的提供者后备顺序", "addChain": "+ 添加链", "modelName": "模型名称", "modelNamePlaceholder": "claude-sonnet-4-20250514", - "providersCommaSeparated": "提供商(用逗号分隔,按优先级排序)", + "providersCommaSeparated": "提供者(用逗号分隔,按优先级排序)", "providersCommaSeparatedPlaceholder": "anthropic, openai, gemini", "createChain": "创建链", "noFallbackChains": "无后备链", - "noFallbackChainsDesc": "创建一条链路,用于定义某个模型的提供商回退顺序。", + "noFallbackChainsDesc": "创建一条链路,用于定义某个模型的提供者回退顺序。", "loadingFallbackChains": "正在加载后备链...", "deleteChainConfirm": "删除“{model}”的后备链?", "chainCreated": "为 {model} 创建的链", @@ -6524,8 +6524,8 @@ "failedCreateChain": "创建链失败", "failedDeleteChain": "删除链失败", "deleteChain": "删除链", - "fillModelAndProviders": "请填写模型名称和提供商", - "addAtLeastOneProvider": "添加至少一个提供商", + "fillModelAndProviders": "请填写模型名称和提供者", + "addAtLeastOneProvider": "添加至少一个提供者", "comboDefaultsTitle": "组合默认值", "comboDefaultsGuideTitle": "如何调整组合默认值", "comboDefaultsGuideHint1": "在低延迟流中保持较低的重试次数;仅增加长生成任务的超时。", @@ -6533,8 +6533,8 @@ "globalComboConfig": "全局组合配置", "moveUp": "上移", "moveDown": "下移", - "allProvidersAdded": "已添加所有提供商", - "noProvidersFound": "未找到提供商", + "allProvidersAdded": "已添加所有提供者", + "noProvidersFound": "未找到提供者", "defaultStrategy": "默认策略", "defaultStrategyDesc": "应用于没有明确策略的新组合", "comboStrategyAria": "组合策略", @@ -6546,19 +6546,19 @@ "retryDelayLabel": "重试延迟(毫秒)", "timeoutLabel": "超时(毫秒)", "healthCheck": "健康检查", - "healthCheckDesc": "预先检查提供商的可用性", + "healthCheckDesc": "预先检查提供者的可用性", "trackMetrics": "跟踪指标", "trackMetricsDesc": "记录每个组合请求指标", - "providerOverrides": "提供商覆盖", - "providerOverridesDesc": "覆盖每个提供商的超时和重试。提供商设置会覆盖全局默认设置。", + "providerOverrides": "提供者覆盖", + "providerOverridesDesc": "覆盖每个提供者的超时和重试。提供者设置会覆盖全局默认设置。", "providerMaxRetriesAria": "{provider} 最大重试次数", "providerTimeoutAria": "{provider} 超时毫秒", "removeProviderOverrideAria": "删除 {provider} 覆盖", - "selectProviderPlaceholder": "选择提供商...", - "searchProviderPlaceholder": "搜索提供商...", - "searchProviderAria": "搜索提供商", + "selectProviderPlaceholder": "选择提供者...", + "searchProviderPlaceholder": "搜索提供者...", + "searchProviderAria": "搜索提供者", "newProviderNamePlaceholder": "例如 google、openai...", - "newProviderNameAria": "新的提供商名称", + "newProviderNameAria": "新的提供者名称", "retries": "重试", "ms": "毫秒", "saveComboDefaults": "保存组合默认值", @@ -6570,17 +6570,17 @@ "contextRelayMaxMessages": "摘要最大消息数", "contextRelaySummaryModel": "摘要模型", "contextRelayProviderNote": "Context Relay 当前会为 Codex 账户生成交接摘要,并将这些值作为新的或未配置 combo 的全局默认值。", - "providerProfiles": "提供商策略配置", - "providerProfilesDesc": "为 OAuth(基于会话)和 API Key(计费型)提供商分别设置弹性策略。由于速率限制更低,OAuth 提供商通常采用更严格的阈值。", - "oauthProviders": "OAuth 提供商", - "apiKeyProviders": "API 密钥提供商", + "providerProfiles": "提供者策略配置", + "providerProfilesDesc": "为 OAuth(基于会话)和 API Key(计费型)提供者分别设置弹性策略。由于速率限制更低,OAuth 提供者通常采用更严格的阈值。", + "oauthProviders": "OAuth 提供者", + "apiKeyProviders": "API 密钥提供者", "transientCooldown": "瞬时故障冷却", "rateLimitCooldown": "限流冷却", "maxBackoffLevel": "最大退避级别", "cbThreshold": "熔断阈值", "cbResetTime": "熔断重置时间", "rateLimiting": "速率限制", - "rateLimitingDesc": "API 密钥提供商会自动受到安全默认值的速率限制。限制是从响应标头中学习的,并随着时间的推移进行调整。", + "rateLimitingDesc": "API 密钥提供者会自动受到安全默认值的速率限制。限制是从响应标头中学习的,并随着时间的推移进行调整。", "defaultSafetyNet": "默认安全网", "rpm": "RPM", "minGap": "最小间隔", @@ -6690,17 +6690,17 @@ "modelOverrideRemoveFailed": "移除模型覆盖失败", "registry": "登记处", "priced": "定价", - "searchProvidersModels": "搜索提供商或模型...", + "searchProvidersModels": "搜索提供者或模型...", "showAll": "显示全部", - "noProvidersMatch": "没有与您的搜索匹配的提供商。", + "noProvidersMatch": "没有与您的搜索匹配的提供者。", "howPricingWorks": "定价如何运作", "cacheWrite": "缓存写入", "unsaved": "未保存", "resetDefaults": "重置默认值", - "saveProvider": "保存提供商", + "saveProvider": "保存提供者", "model": "模型", "models": "模型", - "moreProviders": "{count} 更多提供商", + "moreProviders": "{count} 更多提供者", "withPricing": "已配置定价", "policiesCircuitBreakers": "策略与断路器", "activeIssuesDetected": "检测到活跃问题", @@ -6730,13 +6730,13 @@ "viewFullDetails": "查看完整详情", "themeCoral": "珊瑚色", "adaptiveVolumeRouting": "自适应流量路由", - "adaptiveVolumeRoutingDesc": "根据实时负载量和吞吐压力,动态调整各提供商连接承载的流量。", - "lkgpToggleTitle": "最后已知良好提供商(LKGP)", - "lkgpToggleDesc": "启用后,路由器会记住上一次成功返回响应的提供商,并在后续请求中优先尝试它。", + "adaptiveVolumeRoutingDesc": "根据实时负载量和吞吐压力,动态调整各提供者连接承载的流量。", + "lkgpToggleTitle": "最后已知良好提供者(LKGP)", + "lkgpToggleDesc": "启用后,路由器会记住上一次成功返回响应的提供者,并在后续请求中优先尝试它。", "echoRequestedModelTitle": "在响应中回显请求的模型名称", "echoRequestedModelDesc": "启用后,响应的 `model` 字段将回显客户端请求的别名或组合名称,而不是上游模型名称。这可以解决严格的客户端(例如 Claude Desktop)因响应中的模型与请求不匹配而拒绝响应的问题。", "webSearchRouteTitle": "网页搜索路由", - "webSearchRouteDesc": "当请求包含原生 web_search 工具时,将整个请求路由到此模型而不是默认模型 —— 这对于未实现 Anthropic 的 web_search 服务端工具的提供商非常有用。留空以禁用。", + "webSearchRouteDesc": "当请求包含原生 web_search 工具时,将整个请求路由到此模型而不是默认模型 —— 这对于未实现 Anthropic 的 web_search 服务端工具的提供者非常有用。留空以禁用。", "webSearchRoutePlaceholder": "搜索或选择模型…", "paidModelPatternWarning": "此模式仅匹配付费模型 — 请启用付费模型或调整该模式。", "clearLkgpCache": "清除 LKGP 缓存", @@ -6744,7 +6744,7 @@ "lkgpCacheClearFailed": "清除 LKGP 缓存失败", "days": "天", "lkgp": "LKGP 模式", - "lkgpDesc": "最后已知良好提供商(可预测的弹性)", + "lkgpDesc": "最后已知良好提供者(可预测的弹性)", "maintenance": "维护", "purgeExpiredLogs": "清理过期日志", "purgeLogsFailed": "清理日志失败", @@ -6766,8 +6766,8 @@ "resetting": "正在重置...", "contextOpt": "上下文优化", "contextOptDesc": "根据上下文窗口需求和对话长度进行路由", - "priorityDesc": "顺序回退——先尝试提供商 1,再尝试提供商 2,依此类推", - "weightedDesc": "按百分比权重在各提供商之间分配流量", + "priorityDesc": "顺序回退——先尝试提供者 1,再尝试提供者 2,依此类推", + "weightedDesc": "按百分比权重在各提供者之间分配流量", "modelRoutingTitle": "模型路由规则", "modelRoutingDesc": "使用 glob 模式自动将模型路由到指定组合", "addRule": "添加规则", @@ -6818,7 +6818,7 @@ "pricingSyncFailedWithReason": "价格同步失败:{reason}", "clearSyncedPricing": "清除同步定价", "compressionTitle": "提示词压缩", - "compressionDesc": "在发送给提供商之前压缩提示词,以减少 token 使用量", + "compressionDesc": "在发送给提供者之前压缩提示词,以减少 token 使用量", "compressionGuidanceFullGuideLink": "完整压缩指南", "compressionGuidanceShow": "详情", "compressionGuidanceHide": "隐藏详情", @@ -6827,9 +6827,9 @@ "tokenSaverTitle": "Token Saver", "tokenSaverSubtitle": "让每次请求消耗更少 token。", "tokenSaverToolOutput": "工具输出", - "tokenSaverToolOutputDesc": "在发送给提供商前清理 git、grep、ls、tree 和日志输出。", + "tokenSaverToolOutputDesc": "在发送给提供者前清理 git、grep、ls、tree 和日志输出。", "tokenSaverLlmOutput": "LLM 输出", - "tokenSaverLlmOutputDesc": "注入简洁回复指令,不改写提供商输出。", + "tokenSaverLlmOutputDesc": "注入简洁回复指令,不改写提供者输出。", "tokenSaverInputCompression": "输入压缩", "tokenSaverInputCompressionDesc": "在保留代码、URL 和意图的前提下改写可压缩的对话历史。", "tokenSaverFineTunePrefix": "可在以下页面微调各引擎:", @@ -6917,7 +6917,7 @@ "qdrantHelpStep4": "4. 保存,测试连接,然后测试搜索。", "qdrantEmbeddingQuickSelect": "从发现的模型中快速选择...", "qdrantEmbeddingInputPlaceholder": "openai/text-embedding-3-small", - "qdrantEmbeddingHint": "格式:提供商/模型。必须配置提供者凭证。", + "qdrantEmbeddingHint": "格式:提供者/模型。必须配置提供者凭证。", "qdrantApiKeyPlaceholderKeep": "(留空以保留当前密钥)", "qdrantApiKeyPlaceholderOptional": "(如不用则留空)", "qdrantSaveHint": "提示:编辑主机/端口/集合/模型,然后单击“保存”。 API 密钥是可选的。", @@ -6941,14 +6941,14 @@ "resilienceTrigger": "触发:", "resilienceEffect": "效果:", "resilienceRequestQueueTitle": "请求队列与速率", - "resilienceAutoEnableApiKeyProviders": "为 API 密钥提供商自动启用", + "resilienceAutoEnableApiKeyProviders": "为 API 密钥提供者自动启用", "resilienceRequestsPerMinute": "每分钟请求数", "resilienceMinTimeBetweenRequests": "请求之间的最小时间", "resilienceConcurrentRequests": "并发请求数", "resilienceMaxQueueWaitTime": "最大队列等待时间", "resilienceBaseCooldown": "基础冷却时间", "resilienceUseUpstreamRetryHints": "使用上游重试提示", - "resilienceDefaultPerProvider": "默认(按提供商)", + "resilienceDefaultPerProvider": "默认(按提供者)", "resilienceAlwaysOn": "始终开启", "resilienceAlwaysOff": "始终关闭", "routingRemoveEntry": "删除条目", @@ -7011,18 +7011,18 @@ "routingAntigravitySignatureBypassDesc": "经过轻量校验后接受客户端提交的签名,无效时回退到已存储的签名。", "routingAntigravitySignatureBypassStrictLabel": "严格绕过", "routingAntigravitySignatureBypassStrictDesc": "在接受客户端提交的签名前要求完整的 protobuf 校验。", - "routingHeaderFingerprintTitle": "标头指纹(每个提供商)", + "routingHeaderFingerprintTitle": "标头指纹(每个提供者)", "routingServerRejectedSave": "⚠ 服务器拒绝保存:", "routingAddTransformOp": "添加变换操作", "routingClientCacheControlTitle": "客户端缓存控制", "routingClientCacheControlDesc": "配置 OmniRoute 是否保留客户端提交的 cache_control 标记", "routingClientCacheControlAutoDesc": "对于确定性的 Claude 兼容流程,按原样保留客户端提交的 cache_control。如果请求未携带 cache_control,OmniRoute 不会注入任何由桥接器拥有的标记,以兼容 CC 兼容的第三方代理。", "routingClientCacheControlAlwaysLabel": "始终保留", - "routingClientCacheControlAlwaysDesc": "始终按原样将客户端提交的 cache_control 请求头转发给上游提供商。", + "routingClientCacheControlAlwaysDesc": "始终按原样将客户端提交的 cache_control 请求头转发给上游提供者。", "routingClientCacheControlNeverLabel": "从不保留", - "routingClientCacheControlNeverDesc": "始终移除客户端的 cache_control 请求头,在原生提供商流程支持时由 OmniRoute 管理缓存。", + "routingClientCacheControlNeverDesc": "始终移除客户端的 cache_control 请求头,在原生提供者流程支持时由 OmniRoute 管理缓存。", "routingZeroConfigTitle": "零配置自动路由", - "routingZeroConfigDesc": "启用使用 auto/ 前缀的自动提供商选择。启用后,发往 auto、auto/coding、auto/fast 等的请求将在所有已连接提供商之间动态路由。", + "routingZeroConfigDesc": "启用使用 auto/ 前缀的自动提供者选择。启用后,发往 auto、auto/coding、auto/fast 等的请求将在所有已连接提供者之间动态路由。", "routingDefaultAutoVariant": "默认自动变体", "visionBridge": "愿景桥", "visionBridgeDesc": "在将图像请求路由到纯文本模型之前,自动执行一次视觉到文本的回退。", @@ -7037,7 +7037,7 @@ "visionBridgeTimeoutMs": "超时(毫秒)", "visionBridgeMaxImagesPerRequest": "每个请求的最大图像数", "resilienceMaxBackoffSteps": "最大退避步数", - "resilienceProviderBreakerTitle": "按提供商的断路器", + "resilienceProviderBreakerTitle": "按提供者的断路器", "resilienceFailureThreshold": "失败阈值", "resilienceDegradationThreshold": "Degradation threshold", "resilienceResetTimeout": "重置超时", @@ -7404,14 +7404,14 @@ "resilienceConnectionCooldownTrigger": "当连接返回暂时性上游故障时", "resilienceConnectionCooldownEffect": "暂时跳过该连接并增加重复失败的退避时间", "resilienceConnectionCooldownDesc": "基础冷却时间涵盖短暂的连接故障。当启用上游重试提示时,提供程序的显式窗口将覆盖本地冷却时间。", - "resilienceUseUpstreamRetryHintsDesc": "使用来自上游提供商的重试/重置值(如果可用)。", + "resilienceUseUpstreamRetryHintsDesc": "使用来自上游提供者的重试/重置值(如果可用)。", "resilienceUseUpstream429BreakerHints": "使用上游 429 提示进行断路器冷却", "resilienceUseUpstream429BreakerHintsShort": "使用上游 429 提示", - "resilienceUseUpstream429BreakerHintsDesc": "将 429 响应中的重试/配额耗尽信号应用于断路器冷却持续时间。默认使用每个提供商的策略:直接云提供商默认开启;反向代理、自托管和 CLI 支持的提供商默认关闭。独立于“使用上游重试提示”。", - "resilienceProviderBreakerScope": "整个提供商", + "resilienceUseUpstream429BreakerHintsDesc": "将 429 响应中的重试/配额耗尽信号应用于断路器冷却持续时间。默认使用每个提供者的策略:直接云提供者默认开启;反向代理、自托管和 CLI 支持的提供者默认关闭。独立于“使用上游重试提示”。", + "resilienceProviderBreakerScope": "整个提供者", "resilienceProviderBreakerTrigger": "连接回退耗尽后最终传输/服务器失败", - "resilienceProviderBreakerEffect": "暂时阻止该提供商,直到重置时间到期", - "resilienceProviderBreakerDesc": "实时断路器状态仅显示在运行状况页面上。连接范围的 429 速率限制保留在连接冷却中,并且不会触发提供商断路器。", + "resilienceProviderBreakerEffect": "暂时阻止该提供者,直到重置时间到期", + "resilienceProviderBreakerDesc": "实时断路器状态仅显示在运行状况页面上。连接范围的 429 速率限制保留在连接冷却中,并且不会触发提供者断路器。", "resilienceResetTime": "复位时间", "resilienceWaitForCooldownTitle": "等待冷却", "resilienceWaitForCooldownScope": "当前客户请求", @@ -7513,7 +7513,7 @@ "disableSessionStickiness": "禁用会话粘性", "disableSessionStickinessDesc": "轮询和随机组合在每次请求时都会轮换到不同的连接,而不是通过首条消息的哈希将整个对话固定在单个连接上。保持关闭以保留多轮对话的提示词缓存命中率。每个组合的覆盖设置优先。", "credentialRedaction": "凭据脱敏", - "credentialRedactionDesc": "对发送给提供商的上下文以及响应中的 API 密钥、令牌和机密信息进行脱敏。", + "credentialRedactionDesc": "对发送给提供者的上下文以及响应中的 API 密钥、令牌和机密信息进行脱敏。", "enableCredentialRedaction": "启用凭据脱敏", "enableCredentialRedactionDesc": "清除消息、工具调用和响应中的 API 密钥、令牌、私钥和 JWT。", "pricingAutoSyncDisabled": "Automatic Sync Disabled", @@ -7781,7 +7781,7 @@ "hideExplanation": "隐藏说明", "howItWorks": "工作原理", "saveSettingsFailed": "保存设置失败。", - "explanationIntro": "压缩通过在将历史记录发送给提供商之前对其进行重写来减少 Token 和成本,同时保留其语义。", + "explanationIntro": "压缩通过在将历史记录发送给提供者之前对其进行重写来减少 Token 和成本,同时保留其语义。", "explanationActiveProfile": "活动配置文件:选择全局运行的压缩配置文件 — 面板派生的默认配置或您保存的命名组合之一。", "explanationDefault": "默认(来自面板):派生自您在“压缩设置”中配置的总开关和各引擎开关。", "explanationNamedCombos": "命名组合:您在命名组合编辑器中构建的已保存流水线。选择其中一个会将其设为每个请求的活动配置文件。", @@ -7792,11 +7792,11 @@ "runs": "运行:", "defaultConfiguredPrefix": "默认 — 配置于", "compressionSettings": "压缩设置", - "providerDelegated": "提供商委托压缩", + "providerDelegated": "提供者委托压缩", "contextEditingClaude": "上下文编辑 (Claude)", - "contextEditingDescription": "允许提供商在服务端清除旧的工具使用块,而无需重写消息。", + "contextEditingDescription": "允许提供者在服务端清除旧的工具使用块,而无需重写消息。", "contextEditingAria": "上下文编辑", - "contextEditingNote": "目前仅适用于 Claude (Anthropic)。这是一种委托模式:提供商在服务端清除旧的工具使用块 — 我们不会重写消息。这不会影响其他提供商。", + "contextEditingNote": "目前仅适用于 Claude (Anthropic)。这是一种委托模式:提供者在服务端清除旧的工具使用块 — 我们不会重写消息。这不会影响其他提供者。", "namedCombos": "命名组合", "namedCombosDescription": "保存不同的流水线并将其分配给特定的路由组合。", "comboNamePlaceholder": "组合名称", @@ -7850,7 +7850,7 @@ "output": "输出", "tokenCount": "{count, number} 个 token", "tokenShort": "tok", - "provider": "提供商", + "provider": "提供者", "judgeModel": "裁判模型", "judgeModelPlaceholder": "例如 claude-haiku", "maxCostUsd": "美元上限", @@ -8065,18 +8065,18 @@ "translator": { "title": "翻译器", "metaTitle": "翻译器游乐场 | OmniRoute", - "metaDescription": "调试、测试和可视化提供商之间的 API 格式转换", + "metaDescription": "调试、测试和可视化提供者之间的 API 格式转换", "playgroundTitle": "翻译器游乐场", "playground": "游乐场", "realtime": "实时翻译活动", "chatTester": "聊天测试仪", "testBench": "测试台", "liveMonitor": "实时监控", - "modeDescriptionPlayground": "粘贴任意 API 请求体,查看 OmniRoute 如何在不同提供商格式之间进行转换(OpenAI ↔ Claude ↔ Gemini ↔ Responses API)。", - "modeDescriptionChatTester": "通过 OmniRoute 发送真实聊天请求,并检查完整往返流程:输入、转换后的请求、提供商响应以及转换后的输出。", - "modeDescriptionTestBench": "运行预定义的场景并比较提供商和模型之间的兼容性。", + "modeDescriptionPlayground": "粘贴任意 API 请求体,查看 OmniRoute 如何在不同提供者格式之间进行转换(OpenAI ↔ Claude ↔ Gemini ↔ Responses API)。", + "modeDescriptionChatTester": "通过 OmniRoute 发送真实聊天请求,并检查完整往返流程:输入、转换后的请求、提供者响应以及转换后的输出。", + "modeDescriptionTestBench": "运行预定义的场景并比较提供者和模型之间的兼容性。", "modeDescriptionLiveMonitor": "实时查看请求流经 OmniRoute 时产生的翻译事件。", - "modeDescriptionFallback": "调试、测试并可视化 OmniRoute 如何在提供商之间转换 API 请求。", + "modeDescriptionFallback": "调试、测试并可视化 OmniRoute 如何在提供者之间转换 API 请求。", "recentTranslations": "最近的翻译", "noTranslations": "还没有翻译", "source": "来源", @@ -8116,7 +8116,7 @@ "featureRoleNormalization": "角色规范化", "featureRoleNormalizationDesc": "针对非 OpenAI 目标将 developer→system。针对不支持 system 角色的模型将 system→user。", "featureToolCallIds": "工具调用 ID 规范化", - "featureToolCallIdsDesc": "在缺失时生成唯一的 tool_call ID。针对 Mistral 等提供商规范化为 9 字符格式。", + "featureToolCallIdsDesc": "在缺失时生成唯一的 tool_call ID。针对 Mistral 等提供者规范化为 9 字符格式。", "featureMissingToolResponse": "工具响应注入", "featureMissingToolResponseDesc": "当客户端发送 tool_calls 但没有对应响应时,注入空的 tool_result 消息。", "featureThinkingBudget": "思考预算", @@ -8137,8 +8137,8 @@ "templateLoadHint": "模板以 {format} 格式加载请求。更改源格式以以不同的格式加载。", "compatibilityTester": "兼容性测试仪", "compatibilityReport": "兼容性报告", - "testBenchDescription": "运行预定义的场景(简单聊天、工具调用等)以验证翻译和提供商兼容性。选择源格式和目标提供商,然后运行所有测试以查看兼容性百分比。使用它来查找哪些功能可以跨提供商使用。", - "targetProvider": "目标提供商", + "testBenchDescription": "运行预定义的场景(简单聊天、工具调用等)以验证翻译和提供者兼容性。选择源格式和目标提供者,然后运行所有测试以查看兼容性百分比。使用它来查找哪些功能可以跨提供者使用。", + "targetProvider": "目标提供者", "runAllTests": "运行所有测试", "runTest": "运行测试", "reRun": "重新运行", @@ -8225,16 +8225,16 @@ "copyIntermediateJson": "复制中间 JSON", "copyOutputJson": "复制输出 JSON", "pipelineVisualization": "管道可视化", - "pipelineVisualizationHint": "发送消息以查看您的请求如何经过检测 → 翻译 → 提供商调用。", + "pipelineVisualizationHint": "发送消息以查看您的请求如何经过检测 → 翻译 → 提供者调用。", "chatTesterDescription": "以特定客户端格式发送消息并检查翻译管道的每个步骤。", - "chatTesterFlow": "客户端请求 → 格式检测 → OpenAI 中间格式 → 提供商格式 → 响应", + "chatTesterFlow": "客户端请求 → 格式检测 → OpenAI 中间格式 → 提供者格式 → 响应", "clickStepToInspect": "单击任意步骤即可检查该阶段的数据。", "clientFormat": "客户端格式", - "provider": "提供商", + "provider": "提供者", "modelPlaceholder": "选择或输入模型名称...", "sendMessageToSeePipeline": "发送消息查看翻译管道", "chatMessageHintPrefix": "您的消息将被格式化为", - "chatMessageHintSuffix": "请求,通过管道进行翻译,然后发送给选定的提供商。", + "chatMessageHintSuffix": "请求,通过管道进行翻译,然后发送给选定的提供者。", "youWithFormat": "您 ({format})", "assistant": "助理", "typeMessage": "输入消息...", @@ -8245,11 +8245,11 @@ "formatDetectedDescription": "OmniRoute 会根据请求结构自动识别 API 格式", "openaiIntermediate": "OpenAI 中间格式", "openaiIntermediateDescription": "所有格式都会先归一化为 OpenAI 格式(通用桥接层)", - "providerFormat": "提供商格式", - "providerFormatDescription": "随后再把 OpenAI 格式转换为提供商原生格式", - "providerResponse": "提供商回应", - "providerResponseRawDescription": "来自提供商 API 的原始响应", - "providerResponseSseDescription": "来自提供商 API 的原始 SSE 流", + "providerFormat": "提供者格式", + "providerFormatDescription": "随后再把 OpenAI 格式转换为提供者原生格式", + "providerResponse": "提供者回应", + "providerResponseRawDescription": "来自提供者 API 的原始响应", + "providerResponseSseDescription": "来自提供者 API 的原始 SSE 流", "unexpectedError": "发生意外错误", "error": "错误", "errorMessage": "错误:{message}", @@ -8290,7 +8290,7 @@ "scenarioSchemaCoercion": "模式强制(结构化输出)", "techniques": "技巧:", "friendlyTitle": "翻译器", - "friendlySubtitle": "使用您现有的应用程序与任何提供商 — 无需重写代码。", + "friendlySubtitle": "使用您现有的应用程序与任何提供者 — 无需重写代码。", "conceptHeadline": "您的应用程序使用一个 API 的“语言”。翻译器将其转换为使用另一个提供者。", "conceptDiagramAppLabel": "您的应用程序", "conceptDiagramSourceLabel": "源格式", @@ -8300,7 +8300,7 @@ "conceptDiagramExampleSource": "Claude", "conceptDiagramExampleTarget": "双子座", "conceptHowItWorksToggle": "它是如何工作的", - "conceptHowItWorksBody": "您的应用以其自己的格式发送请求。翻译器检测该格式,通过 OpenAI 作为中介中心进行转换(或在可用的情况下直接进行转换),将其发送到所选提供商,并将响应转换回您应用的格式。", + "conceptHowItWorksBody": "您的应用以其自己的格式发送请求。翻译器检测该格式,通过 OpenAI 作为中介中心进行转换(或在可用的情况下直接进行转换),将其发送到所选提供者,并将响应转换回您应用的格式。", "tabTranslate": "翻译", "tabMonitor": "监视器", "tabTranslateAriaLabel": "前往翻译选项卡", @@ -8485,7 +8485,7 @@ "notifyEvalRunFailed": "评估运行失败", "notifyEvalTitle": "评估:{name}", "modelEvals": "模型评估", - "evalsHeroDescription": "通过运行预定义评测套件来测试和验证你的 LLM 端点。每个套件都包含多个测试用例,会经由 OmniRoute 发送真实提示,并将响应与预期标准进行比较,帮助你发现回归、比较模型,并确保跨提供商的响应质量。", + "evalsHeroDescription": "通过运行预定义评测套件来测试和验证你的 LLM 端点。每个套件都包含多个测试用例,会经由 OmniRoute 发送真实提示,并将响应与预期标准进行比较,帮助你发现回归、比较模型,并确保跨提供者的响应质量。", "qualityValidation": "质量验证", "modelComparison": "模型对比", "regressionDetection": "回归检测", @@ -8506,9 +8506,9 @@ "durationHoursShort": "{value} 时", "reasonSeparator": "-", "notAvailableSymbol": "-", - "providerLimits": "提供商限制", - "noProviders": "没有连接提供商", - "connectProvidersForQuota": "通过 OAuth 连接提供商,以跟踪 API 配额限制和使用情况。", + "providerLimits": "提供者限制", + "noProviders": "没有连接提供者", + "connectProvidersForQuota": "通过 OAuth 连接提供者,以跟踪 API 配额限制和使用情况。", "accountsCount": "{count, plural, one {# 个账户} other {# 个账户}}", "filteredFromCount": "(从 {count} 过滤)", "autoRefresh": "自动刷新", @@ -8531,7 +8531,7 @@ "inDuration": "在 {duration} 中", "notApplicable": "不适用", "rawPlanWithValue": "原始计划:{plan}", - "noPlanFromProvider": "提供商没有计划", + "noPlanFromProvider": "提供者没有计划", "tokenExpiresIn": "令牌在 {time} 后过期", "tokenExpired": "令牌已过期", "noQuotaData": "无配额数据", @@ -8766,7 +8766,7 @@ "budgetLinearExtrapolation": "线性外推法", "budgetThisMonthSoFar": "这个月到目前为止", "budgetProjectedEndOfMonth": "预计月底", - "budgetByProvider": "按提供商", + "budgetByProvider": "按提供者", "budgetProjection": "预测", "budgetAboveMonthlyLimit": "⚠ 超过 {limit}/月", "budgetCostBreakdown30d": "费用明细 (30 天)", @@ -8776,7 +8776,7 @@ "budgetResetMonthly": "每月", "budgetNextReset": "下次重置", "budgetHardCapComingSoon": "硬限制策略和邮件告警即将推出", - "unknownProvider": "未知提供商", + "unknownProvider": "未知提供者", "budgetDailyDollar": "每日 $", "budgetWeeklyDollar": "每周 $", "budgetMonthlyDollar": "每月 $", @@ -8786,7 +8786,7 @@ "noSpendLast30Days": "过去 30 天内没有消费", "updatedShort": "更新于", "lastRefreshed": "上次刷新", - "providerQuota": "提供商配额", + "providerQuota": "提供者配额", "providerQuotaHomeHint": "已连接账户的实时状态" }, "modals": { @@ -8815,7 +8815,7 @@ "noModelsFound": "没有找到模型" }, "loggers": { - "allProviders": "所有提供商", + "allProviders": "所有提供者", "allModels": "所有模型", "allAccounts": "所有账户", "allApiKeys": "所有 API 密钥", @@ -8862,13 +8862,13 @@ "password": "密码", "unifiedProxy": "统一 AI API 代理", "unifiedAiApiProxy": "统一 AI API 代理", - "unifiedAiApiProxyDesc": "通过单个端点将请求路由到多个 AI 提供商。内置负载均衡、故障转移和使用情况跟踪。", + "unifiedAiApiProxyDesc": "通过单个端点将请求路由到多个 AI 提供者。内置负载均衡、故障转移和使用情况跟踪。", "passwordNotEnabled": "未启用密码保护", "loading": "正在加载...", "invalidPassword": "密码无效", "errorOccurredRetry": "发生错误。请再试一次。", "configureInstance": "开始配置你的 OmniRoute 实例", - "runOnboardingWizard": "运行入门向导来设置您的密码并连接您的第一个 AI 提供商。", + "runOnboardingWizard": "运行入门向导来设置您的密码并连接您的第一个 AI 提供者。", "startOnboarding": "开始引导", "secureYourInstance": "保护您的实例", "setPasswordDescription": "设置密码以保护您的仪表板并保护您的 API 端点免遭未经授权的访问。", @@ -8879,7 +8879,7 @@ "copyUrlManual": "请复制地址栏中的 URL 并将其粘贴到应用程序中。", "accessDeniedDescription": "您无权访问此资源。检查您的 API 密钥或联系管理员。", "goToDashboard": "转到仪表板", - "featureMultiProviderTitle": "多提供商", + "featureMultiProviderTitle": "多提供者", "featureMultiProviderDesc": "OpenAI、Anthropic、Google 等", "featureLoadBalancingTitle": "负载均衡", "featureLoadBalancingDesc": "智能分配请求", @@ -8930,18 +8930,18 @@ "github": "GitHub", "versionLive": "v1.0 现已上线", "oneEndpoint": "一个端点", - "allProviders": "所有 AI 提供商", + "allProviders": "所有 AI 提供者", "heroDescription": "带 Web 仪表板的 AI 端点代理,是 CLIProxyAPI 的 JavaScript 版本。可与 Claude Code、OpenAI Codex、Cline、RooCode 等 CLI 工具无缝配合。", "getStarted": "开始使用", "viewOnGithub": "在 GitHub 上查看", "powerfulFeatures": "强大的功能", "featuresSubtitle": "在一个地方管理 AI 基础设施所需的一切,专为规模化而构建。", "featureUnifiedEndpointTitle": "统一端点", - "featureUnifiedEndpointDesc": "通过单一标准 API URL 访问所有提供商。", + "featureUnifiedEndpointDesc": "通过单一标准 API URL 访问所有提供者。", "featureEasySetupTitle": "轻松设置", "featureEasySetupDesc": "使用 npx 命令在几分钟内启动并运行。", "featureModelFallbackTitle": "模型回退", - "featureModelFallbackDesc": "发生故障或高延迟时自动切换提供商。", + "featureModelFallbackDesc": "发生故障或高延迟时自动切换提供者。", "featureUsageTrackingTitle": "使用情况追踪", "featureUsageTrackingDesc": "所有模型的详细分析和成本监控。", "featureOAuthApiKeysTitle": "OAuth 与 API 密钥", @@ -8953,19 +8953,19 @@ "featureDashboardTitle": "仪表板", "featureDashboardDesc": "用于实时流量分析的可视化仪表板。", "howItWorks": "OmniRoute 工作原理", - "howItWorksDescription": "数据从您的应用程序通过我们的智能路由层无缝流向最适合该工作的提供商。", + "howItWorksDescription": "数据从您的应用程序通过我们的智能路由层无缝流向最适合该工作的提供者。", "howItWorksStep1Title": "1. CLI 和 SDK", "howItWorksStep1Description": "您的请求从您最喜欢的工具或我们的统一 SDK 开始。只需更改基本 URL 即可。", "howItWorksStep2Title": "2. OmniRoute 中枢", - "howItWorksStep2Description": "我们的引擎分析提示、检查提供商的运行状况以及最低延迟或成本的路线。", - "howItWorksStep3Title": "3. AI 提供商", - "howItWorksStep3Description": "请求会被立即转发给 OpenAI、Anthropic、Gemini 或其他提供商完成处理。", + "howItWorksStep2Description": "我们的引擎分析提示、检查提供者的运行状况以及最低延迟或成本的路线。", + "howItWorksStep3Title": "3. AI 提供者", + "howItWorksStep3Description": "请求会被立即转发给 OpenAI、Anthropic、Gemini 或其他提供者完成处理。", "getStartedIn30Seconds": "30 秒内开始", - "getStartedDescription": "安装 OmniRoute,通过 Web 仪表板配置你的提供商,然后开始路由 AI 请求。", + "getStartedDescription": "安装 OmniRoute,通过 Web 仪表板配置你的提供者,然后开始路由 AI 请求。", "installOmniRoute": "安装 OmniRoute", "installStepDescription": "运行 npx 命令立即启动服务器", "openDashboard": "打开仪表板", - "openDashboardStepDescription": "通过 Web 界面配置提供商和 API 密钥", + "openDashboardStepDescription": "通过 Web 界面配置提供者和 API 密钥", "routeRequests": "路由请求", "routeRequestsStepDescription": "将您的 CLI 工具指向 {endpoint}", "terminal": "终端", @@ -8975,7 +8975,7 @@ "serverRunningOnLabel": "服务器运行于", "dashboardLabel": "仪表板", "readyToRoute": "已准备好开始路由! ✓", - "configureProvidersNote": "📝 在仪表板中配置提供商或使用环境变量", + "configureProvidersNote": "📝 在仪表板中配置提供者或使用环境变量", "dataLocation": "数据位置:", "dataLocationMacLinux": "macOS/Linux:", "dataLocationWindows": "Windows:", @@ -8987,7 +8987,7 @@ "npm": "npm", "legal": "法律", "mitLicense": "MIT 许可证", - "footerTagline": "AI 生成的统一端点。轻松连接、路由和管理您的 AI 提供商。", + "footerTagline": "AI 生成的统一端点。轻松连接、路由和管理您的 AI 提供者。", "copyright": "© {year} OmniRoute。保留所有权利。", "flowToolClaudeCode": "Claude Code", "flowToolOpenAICodex": "OpenAI Codex", @@ -9008,8 +9008,8 @@ "quickStart": "快速入门", "deploymentGuides": "部署指南", "features": "特点", - "supportedProviders": "支持的提供商", - "supportedProvidersToc": "提供商", + "supportedProviders": "支持的提供者", + "supportedProvidersToc": "提供者", "commonUseCases": "常见用例", "clientCompatibility": "客户端兼容性", "protocolsToc": "协议", @@ -9026,7 +9026,7 @@ "oauthAutoRefresh": "支持自动刷新 Token 的 OAuth 连接。", "fullStreaming": "所有模型都支持完整流式输出。", "docsLabel": "文档", - "docsHeroDescription": "面向多提供商 LLM 的 AI 网关。一个端点即可统一接入 OpenAI、Anthropic、Gemini、GitHub Copilot、Claude Code、Cursor 等 20+ 提供商。", + "docsHeroDescription": "面向多提供者 LLM 的 AI 网关。一个端点即可统一接入 OpenAI、Anthropic、Gemini、GitHub Copilot、Claude Code、Cursor 等 20+ 提供者。", "openDashboard": "打开仪表板", "endpointPage": "端点页面", "github": "GitHub", @@ -9038,11 +9038,11 @@ "quickStartStep1Middle": "或者从 GitHub 克隆并运行", "quickStartStep2Title": "2. 创建API密钥", "quickStartStep2Text": "转至端点 -> 注册密钥。每个环境生成一个密钥。", - "quickStartStep3Title": "3. 连接提供商", - "quickStartStep3Text": "通过 OAuth 登录、API 密钥或免费套餐自动接入来添加提供商账户。", + "quickStartStep3Title": "3. 连接提供者", + "quickStartStep3Text": "通过 OAuth 登录、API 密钥或免费套餐自动接入来添加提供者账户。", "quickStartStep4Title": "4. 设置客户端基本 URL", "quickStartStep4Prefix": "将您的 IDE 或 API 客户端指向", - "quickStartStep4Suffix": "例如使用提供商前缀", + "quickStartStep4Suffix": "例如使用提供者前缀", "deploySetupTitle": "设置指南", "deploySetupText": "OmniRoute 的分步安装、环境配置和首次运行演练。", "deployElectronTitle": "电子桌面", @@ -9057,34 +9057,34 @@ "deployPwaText": "在 Android、iOS 和桌面浏览器上将 OmniRoute 作为渐进式 Web 应用程序安装。", "deployTermuxTitle": "Termux(Android)", "deployTermuxText": "通过 Termux 在 Android 上以无界面模式运行 OmniRoute,并从移动浏览器访问仪表盘。", - "featureRoutingTitle": "多提供商路由", - "featureRoutingText": "通过单一 OpenAI 兼容端点将请求路由到 30+ AI 提供商,支持聊天、Responses、音频和图像 API。", + "featureRoutingTitle": "多提供者路由", + "featureRoutingText": "通过单一 OpenAI 兼容端点将请求路由到 30+ AI 提供者,支持聊天、Responses、音频和图像 API。", "featureCombosTitle": "组合和平衡", "featureCombosText": "使用后备链和平衡策略创建模型组合:循环、优先级、随机、最少使用和成本优化。", "featureUsageTitle": "使用情况和成本跟踪", - "featureUsageText": "实时令牌计数、每个提供商/模型的成本计算以及按 API 密钥和帐户划分的详细使用情况细分。", + "featureUsageText": "实时令牌计数、每个提供者/模型的成本计算以及按 API 密钥和帐户划分的详细使用情况细分。", "featureAnalyticsTitle": "分析仪表板", "featureAnalyticsText": "可视化分析,包含随时间变化的请求、令牌、错误、延迟、成本和模型受欢迎程度的图表。", "featureHealthTitle": "健康监测", - "featureHealthText": "实时健康检查、提供商状态、断路器状态以及具有指数退避功能的自动速率限制检测。", + "featureHealthText": "实时健康检查、提供者状态、断路器状态以及具有指数退避功能的自动速率限制检测。", "featureCliTitle": "CLI工具", "featureCliText": "可在仪表板中管理 IDE 配置、导出/导入备份、发现 Codex 配置文件并修改设置。", "featureSecurityTitle": "安全与策略", "featureSecurityText": "API 密钥身份验证、IP 过滤、提示注入防护、域策略、会话管理和审核日志记录。", "featureCloudSyncTitle": "云同步", "featureCloudSyncText": "将配置同步到 Cloudflare Workers,以便通过加密凭据和自动故障转移实现远程访问。", - "providersAcrossConnectionTypes": "跨三种连接类型的 {count} 提供商。", - "manageProviders": "管理提供商", - "providersCount": "{count} 提供商", + "providersAcrossConnectionTypes": "跨三种连接类型的 {count} 提供者。", + "manageProviders": "管理提供者", + "providersCount": "{count} 提供者", "providerTypeFree": "免费套餐", "providerTypeOAuth": "OAuth", "providerTypeApiKey": "API密钥", - "useCaseSingleEndpointTitle": "许多提供商的单一端点", + "useCaseSingleEndpointTitle": "许多提供者的单一端点", "useCaseSingleEndpointText": "将客户端统一指向一个 Base URL,再通过模型前缀进行路由(例如:gh/、cc/、kr/、openai/)。", "useCaseFallbackTitle": "使用组合进行回退和模型切换", - "useCaseFallbackText": "在仪表板中创建组合模型,并在提供商内部轮换时保持客户端配置稳定。", + "useCaseFallbackText": "在仪表板中创建组合模型,并在提供者内部轮换时保持客户端配置稳定。", "useCaseUsageVisibilityTitle": "使用情况、成本和调试可见性", - "useCaseUsageVisibilityText": "在“使用情况”和“分析”选项卡中按提供商、帐户和 API 密钥跟踪令牌和成本。", + "useCaseUsageVisibilityText": "在“使用情况”和“分析”选项卡中按提供者、帐户和 API 密钥跟踪令牌和成本。", "clientCherryStudioTitle": "樱桃工作室", "baseUrlLabel": "基础 URL", "chatEndpointLabel": "聊天端点", @@ -9102,15 +9102,15 @@ "clientClaudeBullet1Middle": "(Claude)或", "clientClaudeBullet1Suffix": "(Antigravity)前缀。", "clientWindsurfTitle": "Windsurf", - "clientWindsurfBullet1": "将 OmniRoute 用作 OpenAI 兼容的 base URL,并保留显式提供商前缀,以实现确定性路由。", + "clientWindsurfBullet1": "将 OmniRoute 用作 OpenAI 兼容的 base URL,并保留显式提供者前缀,以实现确定性路由。", "clientWindsurfBullet2": "常规流量将模型指向 `/v1/chat/completions`,并为 Codex 风格流程保留 `/v1/responses`。", "clientWindsurfBullet3": "使用仪表盘 -> CLI 工具获取现成的 Windsurf 配置指南。", "clientClineTitle": "Cline", - "clientClineBullet1": "Cline 最适合使用显式的提供商/模型前缀,这样路由器无需猜测后端。", + "clientClineBullet1": "Cline 最适合使用显式的提供者/模型前缀,这样路由器无需猜测后端。", "clientClineBullet2": "常规模型使用 `/v1/chat/completions`,并在不同账户间复用同一个 OmniRoute base URL。", - "clientClineBullet3": "调试 Cline 运行时问题前,请使用提供商仪表盘验证 OAuth/API 密钥。", + "clientClineBullet3": "调试 Cline 运行时问题前,请使用提供者仪表盘验证 OAuth/API 密钥。", "clientKimiTitle": "Kimi Coding", - "clientKimiBullet1": "轮换底层账户或提供商组合时,将 OmniRoute 用作稳定的 base URL。", + "clientKimiBullet1": "轮换底层账户或提供者组合时,将 OmniRoute 用作稳定的 base URL。", "clientKimiBullet2": "在编码流程中优先使用带前缀的模型,让回退和审计轨迹保持明确。", "clientKimiBullet3": "当你希望为使用工具的客户端启用原生 Responses 风格路由时,请使用 `/v1/responses`。", "protocolsTitle": "协议:MCP 与 A2A", @@ -9131,7 +9131,7 @@ "protocolTroubleshooting3": "可使用 `/dashboard/mcp` 和 `/dashboard/a2a` 进行运行控制并查看审计信息。", "endpointChatNote": "OpenAI 兼容聊天端点(默认)。", "endpointResponsesNote": "Responses API 端点(Codex、o 系列)。", - "endpointModelsNote": "所有连接的提供商的模型目录。", + "endpointModelsNote": "所有连接的提供者的模型目录。", "endpointAudioNote": "音频转录(Deepgram、AssemblyAI)。", "endpointSpeechNote": "语音生成(ElevenLabs、OpenAI TTS)。", "endpointEmbeddingsNote": "文本嵌入生成(OpenAI、Cohere、Voyage)。", @@ -9146,20 +9146,20 @@ "mgmtAssignmentsListNote": "按 scope、scope_id 或 proxy_id 列出代理绑定关系。", "mgmtAssignmentsUpdateNote": "为 global/provider/account/combo 作用域分配或清除代理。", "mgmtLegacyMigrationNote": "将旧版 proxyConfig 映射导入为注册表绑定关系。", - "modelPrefixesDescriptionStart": "在模型名称之前使用提供商前缀可路由到特定提供商。示例:", + "modelPrefixesDescriptionStart": "在模型名称之前使用提供者前缀可路由到特定提供者。示例:", "modelPrefixesDescriptionEnd": "会被路由到 GitHub Copilot。", - "provider": "提供商", + "provider": "提供者", "type": "类型", "troubleshootingModelRouting": "如果客户端在模型路由上失败,请使用显式 provider/model(例如:gh/gpt-5.1-codex)。", - "troubleshootingAmbiguousModels": "如果您收到不明确的模型错误,请选择提供商前缀而不是裸模型 ID。", + "troubleshootingAmbiguousModels": "如果您收到不明确的模型错误,请选择提供者前缀而不是裸模型 ID。", "troubleshootingCodexFamily": "对于 GitHub Codex 系列模型,请保持模型名为 `gh/codex-model`;路由器会自动选择 `/responses`。", - "troubleshootingTestConnection": "在从 IDE 或外部客户端进行测试之前,请使用仪表板 > 提供商 > 测试连接。", - "troubleshootingCircuitBreaker": "如果提供商显示断路器已打开,请等待冷却或查看运行状况页面以了解详细信息。", - "troubleshootingOAuth": "对于 OAuth 提供商,如果 Token 过期,请重新认证,并检查提供商卡片上的状态指示器。", + "troubleshootingTestConnection": "在从 IDE 或外部客户端进行测试之前,请使用仪表板 > 提供者 > 测试连接。", + "troubleshootingCircuitBreaker": "如果提供者显示断路器已打开,请等待冷却或查看运行状况页面以了解详细信息。", + "troubleshootingOAuth": "对于 OAuth 提供者,如果 Token 过期,请重新认证,并检查提供者卡片上的状态指示器。", "endpointCompletionsNote": "用于文本生成的旧版 completions 端点。", "endpointModerationsNote": "内容审核和安全分类。", "endpointRerankNote": "用于检索增强生成的文档重排序(Cohere、Jina)。", - "endpointSearchNote": "通过 5 个提供商进行网页搜索(Serper、Brave、Exa、Tavily、Perplexity)。", + "endpointSearchNote": "通过 5 个提供者进行网页搜索(Serper、Brave、Exa、Tavily、Perplexity)。", "endpointSearchAnalyticsNote": "搜索请求的分析和指标。", "endpointVideoNote": "视频生成(ComfyUI、SD WebUI 工作流)。", "endpointMusicNote": "通过 ComfyUI 工作流生成音乐。", @@ -9168,12 +9168,12 @@ "endpointFilesNote": "用于多模态输入的文件上传。", "endpointBatchesNote": "用于批量 API 请求的 Batch 处理。", "endpointWsNote": "用于实时流式传输的 WebSocket 端点。", - "mgmtProvidersListNote": "列出所有已注册的提供商连接。", - "mgmtProvidersCreateNote": "创建新的提供商连接。", - "mgmtProvidersUpdateNote": "更新现有提供商连接。", - "mgmtProvidersDeleteNote": "删除提供商连接。", - "mgmtProvidersTestNote": "测试提供商的连接和认证。", - "mgmtProvidersModelsNote": "列出特定提供商的可用模型。", + "mgmtProvidersListNote": "列出所有已注册的提供者连接。", + "mgmtProvidersCreateNote": "创建新的提供者连接。", + "mgmtProvidersUpdateNote": "更新现有提供者连接。", + "mgmtProvidersDeleteNote": "删除提供者连接。", + "mgmtProvidersTestNote": "测试提供者的连接和认证。", + "mgmtProvidersModelsNote": "列出特定提供者的可用模型。", "mgmtSettingsGetNote": "获取当前应用设置。", "mgmtSettingsUpdateNote": "更新应用设置。", "mgmtPayloadRulesGetNote": "获取载荷转换规则。", @@ -9185,7 +9185,7 @@ "mcpToolsRoutingTitle": "路由与发现", "mcpToolsRoutingDesc": "健康检查、组合管理、配额监控、成本报告和模型目录访问。", "mcpToolsOperationsTitle": "运维与策略", - "mcpToolsOperationsDesc": "路由模拟、预算保护、策略切换、韧性配置和提供商指标。", + "mcpToolsOperationsDesc": "路由模拟、预算保护、策略切换、韧性配置和提供者指标。", "mcpToolsCacheTitle": "缓存管理", "mcpToolsCacheDesc": "查看缓存统计,并清空语义缓存或签名缓存。", "mcpToolsCompressionTitle": "压缩发动机", @@ -9197,9 +9197,9 @@ "mcpToolsSkillsTitle": "技能", "mcpToolsSkillsDesc": "列出、启用、执行和监控自定义技能执行。", "featureAutoComboTitle": "Auto-Combo", - "featureAutoComboText": "根据你连接的提供商、使用模式和模型能力,自动创建优化组合。", + "featureAutoComboText": "根据你连接的提供者、使用模式和模型能力,自动创建优化组合。", "featureSearchTitle": "网页搜索", - "featureSearchText": "集成 5 个提供商的网页搜索(Serper、Brave、Exa、Tavily、Perplexity),并包含分析和成本跟踪。", + "featureSearchText": "集成 5 个提供者的网页搜索(Serper、Brave、Exa、Tavily、Perplexity),并包含分析和成本跟踪。", "featureMemoryTitle": "记忆系统", "featureMemoryText": "跨会话提供提取、注入、检索和摘要能力的持久化对话记忆。", "featureSkillsTitle": "技能框架", @@ -9215,7 +9215,7 @@ "legal": { "privacyPolicy": "隐私政策", "termsOfService": "服务条款", - "providerConfigurations": "提供商配置", + "providerConfigurations": "提供者配置", "apiKeys": "API 密钥", "usageLogs": "使用日志", "applicationSettings": "应用程序设置", @@ -9237,32 +9237,32 @@ "privacySection1Text": "OmniRoute 是一款本地优先的应用。所有数据处理和存储都只发生在你的设备上,不存在集中式服务器收集你的信息。", "privacySection2Title": "2. 我们存储的数据", "privacyDataStoredIn": "以下数据存储在本地", - "privacyDataProviderConfigurationsDesc": "连接 URL、提供商类型和优先级设置", - "privacyDataApiKeysDesc": "已加密并存储在本地,用于与 AI 提供商进行身份验证", + "privacyDataProviderConfigurationsDesc": "连接 URL、提供者类型和优先级设置", + "privacyDataApiKeysDesc": "已加密并存储在本地,用于与 AI 提供者进行身份验证", "privacyDataUsageLogsDesc": "请求计数、令牌使用情况、模型名称、时间戳和响应时间", "privacyDataApplicationSettingsDesc": "主题偏好、路由策略和组合配置", "privacySection3Title": "3. 无遥测", "privacySection3Text": "OmniRoute 不收集遥测、分析或崩溃报告。不会向我们或任何第三方发送数据。你的使用模式、API 调用和配置都会保持私密。", - "privacySection4Title": "4. 第三方 AI 提供商", - "privacySection4Text": "当你通过 OmniRoute 发起 API 调用时,请求会被转发到你配置的 AI 提供商(例如:OpenAI、Anthropic、Google)。这些提供商有各自的隐私政策,请查阅:", + "privacySection4Title": "4. 第三方 AI 提供者", + "privacySection4Text": "当你通过 OmniRoute 发起 API 调用时,请求会被转发到你配置的 AI 提供者(例如:OpenAI、Anthropic、Google)。这些提供者有各自的隐私政策,请查阅:", "privacyOpenAiPolicy": "OpenAI 隐私政策", "privacyAnthropicPolicy": "Anthropic 隐私政策", "privacyGooglePolicy": "Google 隐私政策", "privacySection5Title": "5. 云同步(可选)", - "privacySection5Text": "如果您启用可选的云同步功能,提供商配置和 API 密钥可能会传输到配置的云端点。此功能默认处于禁用状态,需要明确选择加入。", + "privacySection5Text": "如果您启用可选的云同步功能,提供者配置和 API 密钥可能会传输到配置的云端点。此功能默认处于禁用状态,需要明确选择加入。", "privacySection6Title": "6. 日志记录", "privacyLoggingIntro": "可以通过仪表板设置配置请求日志。您可以:", "privacySection7Title": "7. 您的权利", "privacySection7TextStart": "由于所有数据都存储在本地,因此您拥有完全的控制权。您可以随时删除您的数据,方法是删除", "privacySection7TextEnd": "目录或使用仪表板中的数据库备份和恢复功能。", "termsSection1Title": "1. 概述", - "termsSection1Text": "OmniRoute 是一款本地优先的 AI API 代理路由器,完全运行在你的设备上。它通过负载均衡、故障回退和用量跟踪,将请求路由到多个 AI 提供商。", + "termsSection1Text": "OmniRoute 是一款本地优先的 AI API 代理路由器,完全运行在你的设备上。它通过负载均衡、故障回退和用量跟踪,将请求路由到多个 AI 提供者。", "termsSection2Title": "2. 用户的责任", - "termsResponsibilityApiKeys": "你需要自行负责管理自己的 API 密钥,以及第三方 AI 提供商(OpenAI、Anthropic、Google 等)的凭证。", - "termsResponsibilityCompliance": "你必须遵守通过 OmniRoute 访问的每个 AI 提供商的服务条款。", + "termsResponsibilityApiKeys": "你需要自行负责管理自己的 API 密钥,以及第三方 AI 提供者(OpenAI、Anthropic、Google 等)的凭证。", + "termsResponsibilityCompliance": "你必须遵守通过 OmniRoute 访问的每个 AI 提供者的服务条款。", "termsResponsibilitySecurity": "你需要负责本地 OmniRoute 安装的安全,包括设置密码和限制网络访问。", "termsSection3Title": "3. 工作原理", - "termsSection3Text": "OmniRoute 充当中间代理。发送到 OmniRoute 的 API 调用会被转换后转发到你配置的 AI 提供商。除必要的协议转换外,OmniRoute 不会修改你的请求或响应内容。", + "termsSection3Text": "OmniRoute 充当中间代理。发送到 OmniRoute 的 API 调用会被转换后转发到你配置的 AI 提供者。除必要的协议转换外,OmniRoute 不会修改你的请求或响应内容。", "termsSection4Title": "4. 数据处理", "termsDataStoredLocally": "所有数据都保存在你本机上的 SQLite 数据库中。", "termsNoTransmission": "除非你明确启用云同步功能,否则 OmniRoute 不会将任何数据传输到外部服务器。", @@ -9318,7 +9318,7 @@ "comparisonTitle": "CLI 工具与 Agent 目标有什么区别?", "comparisonCliToolsLabel": "CLI 工具页面", "comparisonCliToolsTitle": "你的 IDE 通过 OmniRoute 发送请求", - "comparisonCliToolsDesc": "配置 Claude Code、Codex、Cursor 和其他 IDE,将 OmniRoute 用作它们的 API base URL。OmniRoute 作为代理,将请求路由到你配置的提供商。", + "comparisonCliToolsDesc": "配置 Claude Code、Codex、Cursor 和其他 IDE,将 OmniRoute 用作它们的 API base URL。OmniRoute 作为代理,将请求路由到你配置的提供者。", "comparisonAgentsLabel": "当前页面(Agent 目标)", "comparisonAgentsTitle": "OmniRoute 将请求发送到本地 CLI 工具", "comparisonAgentsDesc": "OmniRoute 可以启动本地 CLI 二进制文件(claude、codex、goose)作为执行后端。CLI 工具使用自己的认证处理请求并返回结果。", @@ -9376,7 +9376,7 @@ "settingsTab": "设置", "agentsEnabled": "已启用", "agentsDisabled": "已禁用", - "filterAllProviders": "所有提供商", + "filterAllProviders": "所有提供者", "filterAll": "全部", "autoRefreshing": "自动刷新中", "viewPR": "查看 Pull Request", @@ -9476,7 +9476,7 @@ }, "cache": { "title": "缓存管理", - "description": "监控提供商侧 Prompt Cache 的效率,以及本地 Semantic Cache 的响应复用情况。", + "description": "监控提供者侧 Prompt Cache 的效率,以及本地 Semantic Cache 的响应复用情况。", "refresh": "刷新", "clearAll": "清空语义缓存", "memoryEntries": "内存条目", @@ -9506,9 +9506,9 @@ "unavailable": "缓存不可用", "unavailableDesc": "无法获取缓存统计信息。请确保服务器正在运行。", "loadingCacheAria": "正在加载缓存", - "promptCache": "Prompt 缓存(提供商侧)", + "promptCache": "Prompt 缓存(提供者侧)", "semanticCache": "语义缓存", - "promptCacheSectionDesc": "基于 usage history 展示提供商侧 prompt cache 的活跃度,让你区分哪些请求真的启用了 cache control,以及实际复用了多少输入。", + "promptCacheSectionDesc": "基于 usage history 展示提供者侧 prompt cache 的活跃度,让你区分哪些请求真的启用了 cache control,以及实际复用了多少输入。", "promptTrendDesc": "按小时展示最近 24 小时的请求量、缓存覆盖率,以及 cache read token 的变化。", "cachedRequests": "缓存请求数", "cachedRequests24h": "24 小时缓存请求数", @@ -9536,9 +9536,9 @@ "writeShort": "写入", "resetting": "正在重置...", "resetMetrics": "重置指标", - "byProvider": "按提供商分类", - "providerCacheRateDesc": "每个提供商都会直接展示总输入 token、cache read token 和 cache write token,方便你对照原始数据判断比率是否可靠。", - "provider": "提供商", + "byProvider": "按提供者分类", + "providerCacheRateDesc": "每个提供者都会直接展示总输入 token、cache read token 和 cache write token,方便你对照原始数据判断比率是否可靠。", + "provider": "提供者", "requests": "请求数", "inputTokens": "输入 Tokens 总计", "cachedTokensCol": "缓存读取", @@ -9547,7 +9547,7 @@ "peakCached": "峰值缓存量", "cached": "已缓存", "overview": "概览", - "tableProvider": "提供商", + "tableProvider": "提供者", "tableModel": "模型", "performanceTitle": "性能", "semanticCacheSectionDesc": "OmniRoute 自己维护的确定性响应缓存。开启后,重复的非流式、temperature=0 请求可以直接在本地命中,不再访问上游 provider。", @@ -9558,7 +9558,7 @@ "loading": "加载中...", "entriesLoadError": "加载语义缓存条目失败。", "noEntries": "未找到缓存条目", - "noPromptCacheData": "暂时还没有记录到提供商侧 prompt cache 活动。", + "noPromptCacheData": "暂时还没有记录到提供者侧 prompt cache 活动。", "noTrendData": "最近 24 小时还没有记录到 prompt cache 活动。", "signature": "签名", "model": "模型", @@ -9577,7 +9577,7 @@ "reasoningReplays": "总回放次数", "reasoningCharsCached": "已缓存字符数", "reasoningMisses": "缓存未命中", - "reasoningByProvider": "按提供商", + "reasoningByProvider": "按提供者", "reasoningByModel": "按模型", "reasoningRecentEntries": "最近条目", "reasoningToolCallId": "工具调用 ID", @@ -9761,7 +9761,7 @@ "labelScope": "作用域", "labelProxy": "代理", "scopeGlobal": "全局", - "scopeProvider": "按提供商", + "scopeProvider": "按提供者", "scopeAccount": "按账号", "scopeCombo": "按组合", "bulkImportErrorMissingName": "缺少 NAME", @@ -9820,8 +9820,8 @@ "poolTitle": "代理池与轮换", "poolDescription": "将多个代理附加到一个作用域,并在它们之间轮换出口 IP。仅包含单个代理的作用域的行为与普通分配完全相同。", "poolScopeIdLabel": "作用域 ID", - "poolScopeIdPlaceholder": "提供商 ID / 连接 ID / 组合 ID", - "poolScopeIdRequired": "提供商、账户或组合作用域需要作用域 ID。", + "poolScopeIdPlaceholder": "提供者 ID / 连接 ID / 组合 ID", + "poolScopeIdRequired": "提供者、账户或组合作用域需要作用域 ID。", "poolLoad": "加载池", "poolLoadFailed": "加载代理池失败", "poolStrategyLabel": "轮换策略", @@ -9843,9 +9843,9 @@ }, "playground": { "title": "模型演练场", - "description": "直接从仪表板测试任何模型。选择提供商、模型和端点类型,然后发送请求以查看原始响应。", + "description": "直接从仪表板测试任何模型。选择提供者、模型和端点类型,然后发送请求以查看原始响应。", "endpoint": "端点", - "provider": "提供商", + "provider": "提供者", "model": "模型", "accountKey": "账户 / 密钥", "autoAccounts": "自动({count} 个账户)", @@ -10124,8 +10124,8 @@ "updatingPipelineLogs": "正在更新管道日志...", "updatePipelineFailed": "更新流水线日志失败", "capturePipeline": "为新请求捕获流水线载荷", - "searchPlaceholder": "搜索模型、提供商、账户、API密钥、组合...", - "allProviders": "所有提供商", + "searchPlaceholder": "搜索模型、提供者、账户、API密钥、组合...", + "allProviders": "所有提供者", "allModels": "所有模型", "allAccounts": "所有账户", "allApiKeys": "所有API密钥", @@ -10153,7 +10153,7 @@ "semantic": "Semantic Cache", "upstream": "上游", "semanticCacheHit": "语义缓存命中(由 OmniRoute 提供)", - "upstreamResponse": "上游提供商响应", + "upstreamResponse": "上游提供者响应", "noApiKey": "无 API key", "requestedRoutedTitle": "请求 {requested},路由为 {routed}", "statusFilters": { @@ -10167,7 +10167,7 @@ "cacheSource": "缓存来源", "model": "模型", "requested": "请求", - "provider": "提供商", + "provider": "提供者", "protocol": "请求协议", "account": "账户", "apiKey": "API密钥", @@ -10195,14 +10195,14 @@ "colTls": "TLS", "colType": "类型", "colLevel": "级别", - "colProvider": "提供商", + "colProvider": "提供者", "colTarget": "目标", "colLatency": "延迟", "colClientIp": "客户端 IP", "colTime": "时间", "recording": "记录中", "paused": "已暂停", - "searchPlaceholder": "搜索主机、提供商、目标或 IP...", + "searchPlaceholder": "搜索主机、提供者、目标或 IP...", "allTypes": "全部类型", "allLevels": "全部级别", "allProviders": "全部 Provider", @@ -10261,10 +10261,10 @@ "hintModelsBlocked": "模型已阻止", "resilienceTitle": "3 层弹性", "resilienceSubtitle": "反映记录的弹性模型", - "providersHealthy": "{percent}% 提供商健康", + "providersHealthy": "{percent}% 提供者健康", "layer": "第 {n} 层", - "layer1Title": "提供商断路器", - "layer1Desc": "阻止到上游级失败的提供商的流量", + "layer1Title": "提供者断路器", + "layer1Desc": "阻止到上游级失败的提供者的流量", "layer2Title": "连接冷却", "layer2Desc": "跳过一个坏账户/密钥;其他连接继续服务", "layer3Title": "模型锁定", @@ -10311,16 +10311,16 @@ "quotaShare": { "weightPercent": "权重 %", "title": "配额共享", - "description": "通过百分比限制跨 API 密钥共享提供商配额", + "description": "通过百分比限制跨 API 密钥共享提供者配额", "newPool": "新建池", "betaTitle": "Beta — UI preview.", "betaDescription": "配置保存在 localStorage 中(尚未持久化到服务器)。每次请求的上限执行将在未来更新中实现。", "kpiActivePools": "活跃池", "kpiKeysAllocated": "已分配密钥", "kpiAvgUnallocated": "平均未分配", - "kpiProvidersWithQuota": "有配额的提供商", + "kpiProvidersWithQuota": "有配额的提供者", "emptyTitle": "未配置池", - "emptyDescription": "创建池以分配 API 密钥,通过百分比分配共享提供商的配额窗口。", + "emptyDescription": "创建池以分配 API 密钥,通过百分比分配共享提供者的配额窗口。", "loading": "加载中…", "removePool": "移除池", "removeConfirm": "移除此池?", @@ -10343,7 +10343,7 @@ "policyBurstHint": "允许突发进入空闲池", "editAllocations": "编辑分配", "newPoolTitle": "新建配额池", - "providerConnection": "提供商连接(账户)", + "providerConnection": "提供者连接(账户)", "selectConnection": "选择连接…", "noEligibleConnections": "没有带配额数据的连接。首先从 /dashboard/quota 刷新。", "quotaWindow": "配额窗口", @@ -10396,7 +10396,7 @@ "wizardStep1Label": "账户", "wizardStep2Label": "限制", "wizardStep3Label": "密钥", - "wizardStep1Title": "选择提供商连接", + "wizardStep1Title": "选择提供者连接", "wizardStep1Subtitle": "选择此池将共享配额的提供者帐户,设置名称和默认策略。", "wizardStep2Title": "配置配额维度", "wizardStep2Subtitle": "为所选连接定义配额计划维度(单位、窗口、限制)。保持不变以保持当前设置。", @@ -10495,7 +10495,7 @@ }, "quotaPlans": { "title": "计划与配额", - "description": "为每个提供商配置配额计划 — 维度(%、请求、令牌、$)和时间窗口", + "description": "为每个提供者配置配额计划 — 维度(%、请求、令牌、$)和时间窗口", "providerLabel": "提供者 / 连接", "detectedPlanLabel": "检测到的计划", "manualPlanLabel": "手动覆盖", @@ -10520,9 +10520,9 @@ "useCatalogButton": "使用目录", "saveOverrideButton": "保存覆盖", "revertToCatalogButton": "恢复到目录", - "unknownProviderNotice": "在左侧选择一个提供商以配置其配额计划。", + "unknownProviderNotice": "在左侧选择一个提供者以配置其配额计划。", "catalogTitle": "已知目录", - "catalogDescription": "自动检测到以下提供商的计划:" + "catalogDescription": "自动检测到以下提供者的计划:" }, "activity": { "title": "活动", @@ -10733,18 +10733,18 @@ }, "providerStats": { "unknownError": "未知错误", - "loading": "正在加载提供商统计信息...", - "loadFailed": "加载提供商统计信息失败:{error}", + "loading": "正在加载提供者统计信息...", + "loadFailed": "加载提供者统计信息失败:{error}", "retry": "重试", "updated": "更新于 {time}", "refresh": "刷新", "totalRequests": "总请求数", "avgLatency": "平均延迟", "successRate": "成功率", - "activeProviders": "活跃提供商", - "providerBreakdown": "提供商明细", - "providerCount": "{count} 个提供商", - "provider": "提供商", + "activeProviders": "活跃提供者", + "providerBreakdown": "提供者明细", + "providerCount": "{count} 个提供者", + "provider": "提供者", "requests": "请求数", "success": "成功", "rate": "速率", @@ -10753,7 +10753,7 @@ "ttftAfterTool": "工具后 TTFT", "gapAfterTool": "工具后间隔", "model": "模型", - "noProviderData": "尚未记录提供商数据。", + "noProviderData": "尚未记录提供者数据。", "comboMetrics": "组合指标", "comboMetricsDescription": "来自流式传输的每个组合的延迟和吞吐量", "avgTtft": "平均 TTFT", @@ -10981,7 +10981,7 @@ "baseUrlPartial": "部分基础 URL", "refreshDetection": "刷新检测", "alsoAcp": "也 ACP", - "connectProviderHint": "在“提供商”中连接提供商" + "connectProviderHint": "在“提供者”中连接提供者" }, "detail": { "back": "返回", @@ -11065,12 +11065,12 @@ "description": "管理 API 密钥身份验证和会话令牌。从此处开始通过 Bearer 令牌验证请求、获取会话 Cookie,并配置 OmniRoute API 的登录要求。" }, "omni-providers": { - "name": "提供商", - "description": "通过 REST API 管理提供商连接、API 密钥、OAuth 流程和连接测试。列出、添加、更新、删除和测试 AI 提供商集成(OpenAI、Anthropic、Gemini 以及 160+ 种)。" + "name": "提供者", + "description": "通过 REST API 管理提供者连接、API 密钥、OAuth 流程和连接测试。列出、添加、更新、删除和测试 AI 提供者集成(OpenAI、Anthropic、Gemini 以及 160+ 种)。" }, "omni-models": { "name": "模型", - "description": "查询所有已配置提供商的可用 AI 模型。列出模型、解析模型别名,并浏览包含特定提供商变体的完整模型目录。" + "description": "查询所有已配置提供者的可用 AI 模型。列出模型、解析模型别名,并浏览包含特定提供者变体的完整模型目录。" }, "omni-combos-routing": { "name": "组合与路由", @@ -11082,11 +11082,11 @@ }, "omni-usage-logs": { "name": "用量与日志", - "description": "访问详细的调用日志和用量分析。按提供商、模型、时间范围、状态和费用进行筛选。导出日志并汇总所有连接的 Token 用量。" + "description": "访问详细的调用日志和用量分析。按提供者、模型、时间范围、状态和费用进行筛选。导出日志并汇总所有连接的 Token 用量。" }, "omni-budget": { "name": "预算与速率限制", - "description": "按 API 密钥或全局配置支出限额、Token 配额和速率限制策略。检查当前消耗并在各提供商之间实施成本控制。" + "description": "按 API 密钥或全局配置支出限额、Token 配额和速率限制策略。检查当前消耗并在各提供者之间实施成本控制。" }, "omni-settings": { "name": "设置", @@ -11094,7 +11094,7 @@ }, "omni-proxies": { "name": "代理配置", - "description": "为上游提供商请求配置 HTTP/HTTPS/SOCKS 代理。设置按提供商或全局代理规则、测试连通性并管理代理轮换。" + "description": "为上游提供者请求配置 HTTP/HTTPS/SOCKS 代理。设置按提供者或全局代理规则、测试连通性并管理代理轮换。" }, "omni-cache": { "name": "缓存", @@ -11110,7 +11110,7 @@ }, "omni-resilience": { "name": "弹性与监控", - "description": "监控提供商健康状况、熔断器状态、p50/p95/p99 延迟指标和预算防护警报。实时检查连接冷却时间和模型锁定状态。" + "description": "监控提供者健康状况、熔断器状态、p50/p95/p99 延迟指标和预算防护警报。实时检查连接冷却时间和模型锁定状态。" }, "omni-cli-tools": { "name": "CLI 工具", @@ -11122,7 +11122,7 @@ }, "omni-sync-cloud": { "name": "云同步", - "description": "在云存储之间同步 OmniRoute 配置、提供商连接和设置。管理云 Worker 身份验证和远程备份目标。" + "description": "在云存储之间同步 OmniRoute 配置、提供者连接和设置。管理云 Worker 身份验证和远程备份目标。" }, "omni-db-backups": { "name": "数据库与备份", @@ -11134,7 +11134,7 @@ }, "omni-mcp": { "name": "MCP 服务器", - "description": "连接到 OmniRoute MCP 服务器(37 个工具,3 种传输方式:SSE/stdio/HTTP)。涵盖 16 个权限范围内的路由、缓存、压缩、内存、技能、提供商和审计工具。" + "description": "连接到 OmniRoute MCP 服务器(37 个工具,3 种传输方式:SSE/stdio/HTTP)。涵盖 16 个权限范围内的路由、缓存、压缩、内存、技能、提供者和审计工具。" }, "omni-agents-a2a": { "name": "智能体与 A2A 协议", @@ -11154,23 +11154,23 @@ }, "cli-health": { "name": "CLI: 健康检查", - "description": "从 CLI 检查服务器健康状况、组件状态和实时指标。运行 `health`、`health components` 和 `health watch` 以获取熔断器和提供商状态的实时仪表板。" + "description": "从 CLI 检查服务器健康状况、组件状态和实时指标。运行 `health`、`health components` 和 `health watch` 以获取熔断器和提供者状态的实时仪表板。" }, "cli-providers": { - "name": "CLI: 提供商", - "description": "从 CLI 管理提供商连接:列出可用/已配置的提供商、添加、测试、test-all、验证、轮换 API 密钥,并查看每个提供商的指标。" + "name": "CLI: 提供者", + "description": "从 CLI 管理提供者连接:列出可用/已配置的提供者、添加、测试、test-all、验证、轮换 API 密钥,并查看每个提供者的指标。" }, "cli-keys": { "name": "CLI: API 密钥", - "description": "从 CLI 创建、列出、轮换和撤销 OmniRoute API 密钥。管理用于提供商身份验证的 OAuth 流程,并检查密钥范围和过期时间。" + "description": "从 CLI 创建、列出、轮换和撤销 OmniRoute API 密钥。管理用于提供者身份验证的 OAuth 流程,并检查密钥范围和过期时间。" }, "cli-models": { "name": "CLI: 模型", - "description": "从 CLI 查询可用的 AI 模型、列出模型别名并浏览完整的模型目录。按提供商筛选、按功能搜索并解析模型名称变体。" + "description": "从 CLI 查询可用的 AI 模型、列出模型别名并浏览完整的模型目录。按提供者筛选、按功能搜索并解析模型名称变体。" }, "cli-chat": { "name": "CLI: 对话", - "description": "从 CLI 发送对话补全、流式传输响应并启动交互式 REPL 会话。支持所有 OmniRoute 提供商、组合路由和系统提示词配置。" + "description": "从 CLI 发送对话补全、流式传输响应并启动交互式 REPL 会话。支持所有 OmniRoute 提供者、组合路由和系统提示词配置。" }, "cli-routing": { "name": "CLI: 路由与组合", @@ -11178,7 +11178,7 @@ }, "cli-resilience": { "name": "CLI: 弹性与配额", - "description": "从 CLI 检查和管理熔断器状态、连接冷却时间、配额限制和退避级别。重置卡住的提供商并配置弹性阈值。" + "description": "从 CLI 检查和管理熔断器状态、连接冷却时间、配额限制和退避级别。重置卡住的提供者并配置弹性阈值。" }, "cli-compression": { "name": "CLI: 压缩", @@ -11190,7 +11190,7 @@ }, "cli-cost-usage": { "name": "CLI: 成本与用量", - "description": "从 CLI 查看成本明细、Token 用量和调用日志。按提供商、模型或日期范围筛选。导出用量报告并检查每个连接的支出。" + "description": "从 CLI 查看成本明细、Token 用量和调用日志。按提供者、模型或日期范围筛选。导出用量报告并检查每个连接的支出。" }, "cli-mcp": { "name": "CLI: MCP", @@ -11238,7 +11238,7 @@ }, "omni-github-skills": { "name": "GitHub 技能发现", - "description": "从包含 SKILL.md、CLAUDE.md、.cursorrules 及类似 agent 技能文件的 GitHub 仓库中搜索、评分、扫描和导入 agent 技能。发现跨 160 多个提供商类别的社区技能,通过启发式评分评估相关性,检查恶意软件或硬编码机密,并安装到 Hermes、Claude Code、Gemini CLI 或 OpenCode agent 目录中。" + "description": "从包含 SKILL.md、CLAUDE.md、.cursorrules 及类似 agent 技能文件的 GitHub 仓库中搜索、评分、扫描和导入 agent 技能。发现跨 160 多个提供者类别的社区技能,通过启发式评分评估相关性,检查恶意软件或硬编码机密,并安装到 Hermes、Claude Code、Gemini CLI 或 OpenCode agent 目录中。" } }, "pageTitle": "特工技能", @@ -11316,8 +11316,8 @@ "regenerateError": "无法重新生成技能。" }, "freeProviderRankingsPage": { - "title": "免费提供商排名", - "subtitle": "根据 Arena AI 排行榜的模型 ELO 得分排名的最佳免费提供商", + "title": "免费提供者排名", + "subtitle": "根据 Arena AI 排行榜的模型 ELO 得分排名的最佳免费提供者", "loading": "正在加载排名...", "errorLoading": "加载排名失败", "emptyState": "暂无可用排名。Arena ELO 数据在启动时同步(每天)— 请稍后查看,或触发手动同步。在 Feature Flags 中禁用 Arena ELO Sync 或设置 ARENA_ELO_SYNC_ENABLED=false 以选择退出。", @@ -11329,7 +11329,7 @@ "categoryDocumentation": "文档", "categoryDebugging": "调试", "colRank": "排名", - "colProvider": "提供商", + "colProvider": "提供者", "colTopModel": "顶级模型", "colScore": "得分", "colAvgScore": "平均得分", @@ -11403,7 +11403,7 @@ "updateConnectionFailed": "更新连接失败", "fetchProxiesFailed": "获取代理失败", "noSavedProxiesError": "未找到已保存的代理。请先在“设置 → 代理”中添加代理。", - "updateProviderFailed": "更新提供商失败", + "updateProviderFailed": "更新提供者失败", "providerEnabled": "{provider} 已启用", "providerDisabled": "{provider} 已禁用" }, @@ -11505,8 +11505,8 @@ }, "explorer": { "name": "探索者", - "description": "使用了 5 个不同的提供商", - "criteria": "使用至少 5 个不同的 AI 提供商。" + "description": "使用了 5 个不同的提供者", + "criteria": "使用至少 5 个不同的 AI 提供者。" }, "polyglot": { "name": "多语通", @@ -11711,7 +11711,7 @@ "description": "允许 Codex 通过 WebSocket 使用 Responses。禁用时,Codex 将回退到 HTTP Responses。" }, "OMNIROUTE_EMERGENCY_FALLBACK": { - "description": "将预算耗尽的请求路由到紧急免费备用提供商和模型。" + "description": "将预算耗尽的请求路由到紧急免费备用提供者和模型。" }, "STREAM_RECOVERY_ENABLED": { "description": "在任何响应字节到达客户端之前,透明地重试被截断的上游 SSE 流。" @@ -11723,7 +11723,7 @@ "description": "在 /v1/models 响应中包含易于显示的名称字段。对于仅接受模型 ID 的客户端,请禁用此项。" }, "MODELS_CATALOG_PREFIX_MODE": { - "description": "控制 /v1/models 中的模型 ID 前缀:dual 发送别名和规范前缀,alias 仅发送短前缀,canonical 仅发送完整提供商 ID。" + "description": "控制 /v1/models 中的模型 ID 前缀:dual 发送别名和规范前缀,alias 仅发送短前缀,canonical 仅发送完整提供者 ID。" }, "ARENA_ELO_SYNC_ENABLED": { "description": "定期同步 Arena AI 排行榜 ELO 数据以进行模型智能排名。" @@ -11738,10 +11738,10 @@ "description": "自动同步定价数据。PRICING_SYNC_ENABLED 环境变量也必须为 true。" }, "OMNIROUTE_AUTO_SYNC_CODEX_PROFILES": { - "description": "提供商-模型同步后,从实时目录重新生成 ~/.codex/*.config.toml 配置文件。这绝不会更改活动或默认的 Codex 配置,并且默认关闭。" + "description": "提供者-模型同步后,从实时目录重新生成 ~/.codex/*.config.toml 配置文件。这绝不会更改活动或默认的 Codex 配置,并且默认关闭。" }, "OMNIROUTE_AUTO_SYNC_CLAUDE_PROFILES": { - "description": "提供商-模型同步后,从实时目录重新生成 ~/.claude/profiles//settings.json 配置文件。这绝不会更改活动或默认的 Claude 配置,并且默认关闭。" + "description": "提供者-模型同步后,从实时目录重新生成 ~/.claude/profiles//settings.json 配置文件。这绝不会更改活动或默认的 Claude 配置,并且默认关闭。" }, "OMNIROUTE_DISABLE_LOCAL_HEALTHCHECK": { "description": "禁用本地实例健康检查端点。" @@ -11778,12 +11778,12 @@ "runtimeHealthBlend": "运行时/健康度融合", "averageResponseTime": "平均响应时间", "worstQuota": "最差配额", - "providerAccountTelemetry": "提供商/账户遥测", + "providerAccountTelemetry": "提供者/账户遥测", "overview": "概览", "overviewDescription": "此组合的策略、运行时状态和控制链接。", "strategy": "策略", "targets": "目标", - "providers": "提供商", + "providers": "提供者", "targetCounts": "{configured} 已配置 · {resolved} 已解析", "healthReasons": "健康状况原因", "healthReason": { @@ -11827,7 +11827,7 @@ "stepShort": "步骤 {id}", "dynamic": "动态", "unknown": "未知", - "unknownProvider": "未知提供商", + "unknownProvider": "未知提供者", "unknownModel": "未知模型", "resolvedTargetMetrics": "{requests} 请求 · {success} 成功 · {latency} · 配额 {quota}" }, @@ -11867,7 +11867,7 @@ "fromObservedReset": "自观察到的 {quota} 重置起", "fromReset": "自 {quota} 重置起", "quotaEstimator": "配额估算器", - "noApiKeyUsage": "在此提供商窗口期内无 API 密钥使用记录。", + "noApiKeyUsage": "在此提供者窗口期内无 API 密钥使用记录。", "requestTokenCounts": "{requests} 次请求 · {tokens} 个 token", "noUsdLimit": "无 USD 限制" }, @@ -11881,7 +11881,7 @@ "boost": "一次性充值 $10 OpenRouter 即可每月多解锁约 ~{tokens}(50 → 1000 次请求/天)", "uncapped": "永久免费,无公开上限(受速率限制)— 实际可用,未计入总览:", "tosRestricted": "{count, plural, one {# 个模型} other {# 个模型}}被标记为受 ToS 限制 — 由您决定", - "provider": "提供商", + "provider": "提供者", "model": "模型", "modelName": "模型名称", "type": "类型", @@ -11905,8 +11905,8 @@ } }, "providerHealthAutopilot": { - "title": "提供商健康自动巡航", - "description": "查找不稳定的提供商、账户冷却、陈旧错误以及安全的手动修复方案。", + "title": "提供者健康自动巡航", + "description": "查找不稳定的提供者、账户冷却、陈旧错误以及安全的手动修复方案。", "loadFailed": "加载自动巡航报告失败", "actionApplied": "已应用 {action}。", "actionFailed": "自动巡航操作失败", @@ -11921,8 +11921,8 @@ "critical": "严重", "loading": "加载中" }, - "loadingRecommendations": "正在加载提供商建议...", - "noRecommendations": "目前没有提供商健康建议。", + "loadingRecommendations": "正在加载提供者建议...", + "noRecommendations": "目前没有提供者健康建议。", "providerMetrics": "评分 {score}% · 活跃 {active}/{total} · 冷却 {cooldown} · 模型锁定 {lockouts}", "providerState": { "healthy": "健康", @@ -11938,9 +11938,9 @@ "errorCode": "代码 {code}", "applying": "正在应用...", "issue": { - "circuitOpenTitle": "提供商熔断器已开启", - "circuitOpenRecommendation": "验证上游恢复情况,然后重置提供商熔断器或等待重试窗口。", - "circuitRecoveryTitle": "提供商正在探测恢复情况", + "circuitOpenTitle": "提供者熔断器已开启", + "circuitOpenRecommendation": "验证上游恢复情况,然后重置提供者熔断器或等待重试窗口。", + "circuitRecoveryTitle": "提供者正在探测恢复情况", "circuitRecoveryRecommendation": "等待下一次探测完成,或在手动验证后重置熔断器。", "terminalTitle": "{label} 处于终止账户状态", "terminalRecommendation": "在重新激活之前,请检查账单、重新进行身份验证或更换凭据。", @@ -11956,7 +11956,7 @@ "quotaRecommendation": "检查配额使用情况,并在需要时将流量轮换到另一个正常的连接。" }, "action": { - "resetProviderBreaker": "重置提供商熔断器", + "resetProviderBreaker": "重置提供者熔断器", "clearConnectionCooldown": "清除连接冷却时间", "disableConnection": "禁用此连接", "clearStaleError": "清除过期的错误状态", @@ -12066,11 +12066,11 @@ "timeoutDesc": "每次模型调用的最长时间 (5000-600000ms)", "systemPrompt": "系统提示词 (可选)", "systemPromptDesc": "适用于所有混沌模式模型实例的自定义指令", - "providerOverrides": "提供商覆盖", - "providerOverridesDesc": "为混沌模式按提供商选择特定模型", - "providerId": "提供商", + "providerOverrides": "提供者覆盖", + "providerOverridesDesc": "为混沌模式按提供者选择特定模型", + "providerId": "提供者", "modelId": "模型", - "addProvider": "添加提供商", + "addProvider": "添加提供者", "removeProvider": "移除", "saveConfig": "保存配置", "configSaved": "混沌配置保存成功", @@ -12080,18 +12080,18 @@ "keyPermissionDesc": "允许此 API 密钥使用混沌模式(多模型并行执行)", "testButton": "测试混沌模式", "testTask": "写一首关于人工智能的短诗", - "loadingProviderModels": "正在加载提供商...", + "loadingProviderModels": "正在加载提供者...", "systemPromptPlaceholder": "可选:覆盖默认的混沌模式系统提示词...", "enabled": "已启用", "disabled": "已禁用", "maxTokens": "最大 Token 数", "maxTokensDesc": "每个模型响应的最大 Token 数。数值越高,成本越高且耗时越长。", - "providerIdPlaceholder": "提供商 ID(输入或选择)", + "providerIdPlaceholder": "提供者 ID(输入或选择)", "modelIdPlaceholder": "模型 ID(可选)", "on": "开启", "off": "关闭", - "availableProviders": "可用提供商 ({count})", - "noProviderOverrides": "无覆盖 — 所有活跃提供商都将使用其默认模型参与" + "availableProviders": "可用提供者 ({count})", + "noProviderOverrides": "无覆盖 — 所有活跃提供者都将使用其默认模型参与" }, "kimiSponsorBanner": { "title": "Kimi(Moonshot AI)是 OmniRoute 的创始开源好友", diff --git a/tests/unit/i18n-glossary-consistency-check.test.ts b/tests/unit/i18n-glossary-consistency-check.test.ts new file mode 100644 index 0000000000..af3a46fa0e --- /dev/null +++ b/tests/unit/i18n-glossary-consistency-check.test.ts @@ -0,0 +1,112 @@ +import { test } from "node:test"; +import assert from "node:assert"; +import { readFileSync } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { checkGlossaryConsistency } from "../../scripts/i18n/check-glossary-consistency.mjs"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const ROOT = path.resolve(__dirname, "..", ".."); + +const glossary = { + version: 1, + locale: "zh-CN", + terms: { + provider: { canonical: "提供者", synonyms: ["提供商"] }, + }, +}; + +const protectedTerms = ["DATA_DIR"]; + +test("catalog mixing canonical and synonym for a concept is flagged", () => { + const messages = { + common: { + provider: "提供者", + unknownProvider: "未知提供商", + }, + }; + const { violations } = checkGlossaryConsistency(messages, glossary, protectedTerms); + assert.equal(violations.length, 1); + assert.equal(violations[0].type, "glossary-synonym"); + assert.equal(violations[0].concept, "provider"); + assert.equal(violations[0].found, "提供商"); + assert.equal(violations[0].canonical, "提供者"); +}); + +test("clean catalog using only the canonical rendering has no violations", () => { + const messages = { + common: { + provider: "提供者", + providerHealth: "提供者健康状态", + }, + }; + const { violations } = checkGlossaryConsistency(messages, glossary, protectedTerms); + assert.deepEqual(violations, []); +}); + +test("protected term altered inside a value is flagged", () => { + const messages = { + settings: { + dataDirHint: "存储在 数据目录 中", + }, + }; + const { violations } = checkGlossaryConsistency(messages, glossary, protectedTerms); + assert.equal(violations.length, 1); + assert.equal(violations[0].type, "protected-term-altered"); + assert.equal(violations[0].term, "DATA_DIR"); + assert.equal(violations[0].found, "数据目录"); +}); + +test("protected term left verbatim is not flagged", () => { + const messages = { + settings: { + dataDirHint: "存储在 DATA_DIR 中", + }, + }; + const { violations } = checkGlossaryConsistency(messages, glossary, protectedTerms); + assert.deepEqual(violations, []); +}); + +test("empty synonyms list for a concept never produces violations", () => { + const permissiveGlossary = { + version: 1, + locale: "zh-CN", + terms: { + cache: { canonical: "缓存", synonyms: [] }, + }, + }; + const messages = { common: { cache: "高速缓存" } }; + const { violations } = checkGlossaryConsistency(messages, permissiveGlossary, protectedTerms); + assert.deepEqual(violations, []); +}); + +// Regression guard: the one-shot 提供商→提供者 normalization pass (#8038) must +// not silently regress. Load the REAL zh-CN catalogs and assert the retired +// synonym is gone. +test("regression: src/i18n/messages/zh-CN.json no longer contains 提供商", () => { + const raw = readFileSync(path.join(ROOT, "src/i18n/messages/zh-CN.json"), "utf8"); + assert.equal(raw.includes("提供商"), false); +}); + +test("regression: bin/cli/locales/zh-CN.json no longer contains 提供商", () => { + const raw = readFileSync(path.join(ROOT, "bin/cli/locales/zh-CN.json"), "utf8"); + assert.equal(raw.includes("提供商"), false); +}); + +test("real zh-CN.json + real glossary + real protected terms pass the gate", () => { + const realMessages = JSON.parse( + readFileSync(path.join(ROOT, "src/i18n/messages/zh-CN.json"), "utf8") + ); + const realGlossary = JSON.parse( + readFileSync(path.join(ROOT, "scripts/i18n/glossary/zh-CN.json"), "utf8") + ); + const realProtected = JSON.parse( + readFileSync(path.join(ROOT, "scripts/i18n/glossary/protected-terms.json"), "utf8") + ); + const { violations } = checkGlossaryConsistency( + realMessages, + realGlossary, + realProtected.terms + ); + assert.deepEqual(violations, []); +});