feat(frontend): add reactive localization and refine admin layouts (#501)

* feat(frontend): add English and Traditional Chinese locales

* fix(frontend): capitalize the English login key label

* fix(frontend): capitalize standalone English labels

* feat(frontend): add reactive localization and refine admin layouts

Replace DOM text translation with domain-based Vue I18n resources for English, Simplified Chinese, and Traditional Chinese. Localize shared controls, notifications, charts, and key usage while refining table alignment, menus, and compact labels.

Expose semantic usage-window and trend-metric identifiers from the API. Pin the UI and workbench dependencies to published feature commits and preserve the original font defaults.

Co-authored-by: Codex <noreply@openai.com>

---------

Co-authored-by: Jimbb <14995924+jimbb@users.noreply.github.com>
Co-authored-by: Zyy <zyycn@users.noreply.github.com>
Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Jimbb
2026-10-23 11:40:38 +08:00
committed by GitHub
co-authored by Codex Jimbb Zyy
parent 8fc8c6228d
commit 39b35d46a0
363 changed files with 15479 additions and 3795 deletions
@@ -84,7 +84,7 @@ pub(super) fn account_view(
let usage_period = quota.usage_window().map(|(_, period)| period);
let mut usage = account_usage_view(usage, usage_period, now, time);
if account.authentication_kind == "api_key" {
usage.window_label_display = "通用额度".to_owned();
usage.window_kind = AccountUsageWindowKind::General;
}
let (quota, refresh_token_expires_at) = account_quota_view(quota, cooldown, now, time);
AccountView {
@@ -344,12 +344,11 @@ pub(super) fn account_usage_view(
"known"
};
AccountUsageView {
window_label_display: match period {
Some(AccountUsagePeriod::Weekly) => "周额度窗口",
Some(AccountUsagePeriod::Monthly) => "月额度窗口",
None => "周/月额度窗口",
}
.to_owned(),
window_kind: match period {
Some(AccountUsagePeriod::Weekly) => AccountUsageWindowKind::Weekly,
Some(AccountUsagePeriod::Monthly) => AccountUsageWindowKind::Monthly,
None => AccountUsageWindowKind::Quota,
},
request_count: Some(usage.request_count),
request_count_display: format_number(usage.request_count),
input_tokens: usage.input_tokens,
@@ -470,7 +469,7 @@ pub(super) fn display_optional_tokens(value: Option<u64>) -> String {
pub(super) fn empty_account_usage() -> AccountUsageView {
AccountUsageView {
window_label_display: "周/月额度窗口".to_owned(),
window_kind: AccountUsageWindowKind::Quota,
request_count: None,
request_count_display: "—".to_owned(),
input_tokens: None,
@@ -425,11 +425,21 @@ pub struct AccountQuotaWindowView {
pub reset_at_display: String,
}
/// 账号用量窗口的语义标识,展示名称由管理端本地化
#[derive(Debug, Clone, Copy, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum AccountUsageWindowKind {
General,
Weekly,
Monthly,
Quota,
}
/// 账号观测用量
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct AccountUsageView {
pub window_label_display: String,
pub window_kind: AccountUsageWindowKind,
pub request_count: Option<u64>,
pub request_count_display: String,
pub input_tokens: Option<u64>,
@@ -735,34 +735,34 @@ pub(crate) fn trend_summary_view(
match kind {
TrendKind::Usage => vec![
TrendSummaryView {
label: "输入".to_owned(),
metric: TrendMetric::InputTokens,
value: format_compact_number(summary.input_tokens),
ratio: None,
},
TrendSummaryView {
label: "输出".to_owned(),
metric: TrendMetric::OutputTokens,
value: format_compact_number(summary.output_tokens),
ratio: None,
},
TrendSummaryView {
label: "缓存".to_owned(),
metric: TrendMetric::CachedInputTokens,
value: format_compact_number(summary.cached_input_tokens),
ratio: None,
},
],
TrendKind::Latency => vec![
TrendSummaryView {
label: "首字 P95".to_owned(),
metric: TrendMetric::FirstTokenP95Ms,
value: display_duration_f64(summary.peak_first_token_p95_ms),
ratio: None,
},
TrendSummaryView {
label: "总耗时 P95".to_owned(),
metric: TrendMetric::LatencyP95Ms,
value: display_duration_f64(summary.peak_latency_p95_ms),
ratio: None,
},
TrendSummaryView {
label: "速率 P50".to_owned(),
metric: TrendMetric::OutputThroughputP50,
value: summary
.minimum_output_throughput_p50
.map_or_else(|| "—".to_owned(), |value| format!("{value} tok/s")),
@@ -771,19 +771,19 @@ pub(crate) fn trend_summary_view(
],
TrendKind::Errors => vec![
TrendSummaryView {
label: "错误数".to_owned(),
metric: TrendMetric::Errors,
value: format_compact_number(summary.service_failure_count),
ratio: None,
},
TrendSummaryView {
label: "成功率".to_owned(),
metric: TrendMetric::SuccessRate,
value: "—".to_owned(),
ratio: summary
.success_rate
.map(|value| format!("{:.1}%", value * 100.0)),
},
TrendSummaryView {
label: "总请求".to_owned(),
metric: TrendMetric::Requests,
value: format_compact_number(summary.request_count),
ratio: None,
},
@@ -323,10 +323,25 @@ pub struct TrendPointView {
pub capacity_utilization: Option<f64>,
}
/// 趋势指标的稳定身份,展示名称由管理端本地化
#[derive(Debug, Clone, Copy, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum TrendMetric {
InputTokens,
OutputTokens,
CachedInputTokens,
FirstTokenP95Ms,
LatencyP95Ms,
OutputThroughputP50,
Errors,
SuccessRate,
Requests,
}
/// Dashboard 趋势摘要
#[derive(Debug, Serialize)]
pub struct TrendSummaryView {
pub label: String,
pub metric: TrendMetric,
pub value: String,
pub ratio: Option<String>,
}
@@ -476,13 +476,13 @@ fn single_update_should_reject_oversized_notes_and_control_characters() {
}
mod response {
use gateway_api::admin::accounts::AccountUsageView;
use gateway_api::admin::accounts::{AccountUsageView, AccountUsageWindowKind};
use gateway_api::admin::presenter::format_decimal_currency;
#[test]
fn account_usage_view_should_keep_unobserved_numbers_null() {
let view = AccountUsageView {
window_label_display: "周/月额度窗口".to_owned(),
window_kind: AccountUsageWindowKind::Quota,
request_count: None,
request_count_display: "-".to_owned(),
input_tokens: None,
@@ -516,7 +516,7 @@ mod response {
models: Vec::new(),
};
let value = serde_json::to_value(view).expect("serialize account usage");
assert_eq!(value["windowLabelDisplay"], "周/月额度窗口");
assert_eq!(value["windowKind"], "quota");
assert!(value["inputTokens"].is_null());
assert!(value["totalTokens"].is_null());
assert!(value["reasoningOutputTokens"].is_null());
@@ -1464,3 +1464,69 @@ async fn usage_status_query_accepts_three_modes_and_rejects_unknown_values() {
}
}
}
#[tokio::test]
async fn dashboard_summary_should_identify_metrics_without_localized_labels() {
use axum::{
body::{Body, to_bytes},
http::{Request, StatusCode, header},
};
use chrono::Duration;
use gateway_admin::model::observability::{DashboardObservation, TimeRange};
use gateway_api::admin::observability;
use tower::ServiceExt as _;
use crate::admin::{AdminTestFixture, AdminTestState};
let fixture = AdminTestFixture::new().await;
fixture.auth.insert_session("valid-session");
let now = Utc::now();
*fixture.dashboard_observation.lock().unwrap() = Some(DashboardObservation {
yesterday: Default::default(),
analytics: Default::default(),
runtime_slots: None,
range: TimeRange::new(now - Duration::hours(1), now).unwrap(),
totals: Default::default(),
provider_accounts: Default::default(),
trend: Vec::new(),
account_usage: Vec::new(),
recent_requests: Vec::new(),
});
for (kind, metrics) in [
(
"usage",
["inputTokens", "outputTokens", "cachedInputTokens"],
),
(
"latency",
["firstTokenP95Ms", "latencyP95Ms", "outputThroughputP50"],
),
("errors", ["errors", "successRate", "requests"]),
] {
let response = observability::router::<AdminTestState>()
.with_state(fixture.state())
.oneshot(
Request::builder()
.uri(format!("/api/admin/dashboard/summary?kind={kind}"))
.header(header::COOKIE, "cpr_session=valid-session")
.header(header::ACCEPT_LANGUAGE, "en")
.header("x-request-id", format!("req_trend_metrics_{kind}"))
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
let status = response.status();
let body = to_bytes(response.into_body(), 1024 * 1024).await.unwrap();
let value: serde_json::Value = serde_json::from_slice(&body).unwrap();
assert_eq!(status, StatusCode::OK, "{kind}: {value}");
let summary = value["data"]["trend"]["summary"].as_array().unwrap();
assert_eq!(summary.len(), metrics.len());
for (item, metric) in summary.iter().zip(metrics) {
assert_eq!(item["metric"], metric);
assert!(item.get("label").is_none());
assert!(item["value"].is_string());
}
}
}
+18 -4
View File
@@ -158,6 +158,8 @@ Codex PAT 验证服务不可用和身份响应无效分别返回 `50301`、`5020
`YYYY-MM-DD HH:mm:ss`,短时间、相对时间和图表标签按对应视图返回;缺失时间的展示字段为 `null` 或占位文本。
调用者直接显示文本,使用原始时间点进行排序、比较和输入,不把展示文本转回请求时间
账号、模型用量和 Key 列表的最近使用时间由前端根据原始 RFC3339 时间点,通过 VueUse `useTimeAgoIntl` 按界面语言显示短相对时间,并随时间更新;悬停的完整日期仍使用后端 `lastUsedAtFullDisplay`,不使用浏览器本地时区重算
账号冷却返回 RFC3339 `rateLimitedUntil` 和 `rateLimitRecoveryDisplay`,后者包含剩余时长、
到期时间或等待恢复探测的提示,随账号数据刷新;前端不解析展示文本或自行计算恢复提示
@@ -1034,7 +1036,7 @@ API Key 账号与 OAuth 共用现有 Responses、Images 和 standalone Search
包括 Responses Lite 和原生压缩协议的透传,实际支持情况由上游决定;不提供独立 compact 路由。
模型目录、连接测试和本地用量统计可用;OAuth 刷新/重新授权、ChatGPT 额度、个人资料、订阅和重置卡不适用。
客户端的 `image_generation` 和 `X-OpenAI-Actor-Authorization` 声明不改变账号的实际能力。
账号列表和详情的 API Key `usage` 汇总该账号创建后仍保留的本地请求记录,`windowLabelDisplay` 为 `通用额度`;
账号列表和详情的 API Key `usage` 汇总该账号创建后仍保留的本地请求记录,`usage.windowKind` 为 `general`,管理端按当前语言显示通用额度;
日志清理会影响累计范围,不代表上游余额。OAuth 账号仍按实际周/月额度窗口统计
批量导入 AT / RT 使用 `accounts` JSON 数组,最多 200 项,不接受纯文本 token 列表。例如:
@@ -1165,10 +1167,10 @@ OAuth start 使用:
- 正常 Responses 请求会解析上游响应的 rate-limit headers,合并进同一 quota 快照并同步状态。Free、
K12 等套餐共用该状态机;套餐只参与账号展示和按套餐隔离的模型目录 cache,不存在 K12 专属额度路径
- 账号详情的 Token 统计、模型排行和列表 Token 汇总优先使用账号级周额度窗口,无可统计的周窗口时
使用月额度窗口;`usage.windowLabelDisplay` 随选中的窗口返回“周额度窗口”或“月额度窗口”。查询边界
使用月额度窗口;`usage.windowKind` 随选中的窗口返回 `weekly` 或 `monthly`。查询边界
严格为 `[resetAt - windowSeconds, resetAt)`,不是自然周/月或最近 7/30 天;额度刷新若返回了更早的
重置时间,会按新边界重新聚合。没有边界完整、可归属到账号的周/月窗口时显示无数据,标签为
“周/月额度窗口”,不回退到 5 小时、日窗口或历史累计。
重置时间,会按新边界重新聚合。没有边界完整、可归属到账号的周/月窗口时显示无数据,`usage.windowKind` 为 `quota`
(周/月额度窗口),不回退到 5 小时、日窗口或历史累计。
金额原值保持完整精度,USD 展示值
小于 1 美元时最多保留四位小数,其余保留两位
@@ -1989,6 +1991,18 @@ errorCode, errorMessage, startedAt, completedAt, expiresAt, createdAt, updatedAt
| `GET` | `/api/admin/operations/errors` | 运维错误分页列表 |
| `GET` | `/api/admin/diagnostics/export` | 按 `requestId` 或 `errorId` 下载诊断 ZIP 附件 |
### Dashboard 趋势指标
趋势摘要 `summary[]` 返回稳定的 `metric`、展示数值 `value` 和可空的 `ratio`,指标名称由前端本地化
| kind | metric |
| --- | --- |
| `usage` | `inputTokens`、`outputTokens`、`cachedInputTokens` |
| `latency` | `firstTokenP95Ms`、`latencyP95Ms`、`outputThroughputP50` |
| `errors` | `errors`、`successRate`、`requests` |
图表颜色、系列身份和选中状态使用 `metric`,不根据译文或数组位置推断指标
### Dashboard 容量与账号用量
Dashboard 的 `capacityInfo` 统计普通容量,不含独立审批池;`maxConcurrentPerAccount` 为默认账号并发上限,`0` 表示不限制。
+2 -1
View File
@@ -91,7 +91,7 @@ Pinia 持久化、登录、路由和业务请求由各应用持有
部署时区由 Host 配置拥有,组合根把不可变的 `DeploymentTimeZone` 传给各模块。
Core 的 `time` 只提供时区与日历边界换算;Admin/Provider 拥有查询范围与调度规则,Store 绑定显式 UTC 边界并维护事务。
API 的时间 presenter 负责页面及事件展示文本,前端消费投影,不解释时区或格式化日期。
API 的时间 presenter 负责部署时区下的日期及事件展示文本,前端不重新解释时区或格式化绝对日期;最近使用的相对时间本地化边界见 [API 页面时间](api.md#页面时间合同)。
持久化、协议传输、排序与 TTL 使用 UTC 时间点或持续时长,不依赖进程、浏览器及数据库会话的本地时区。
请求位置中的时区属于 Provider 请求身份,与部署日历规则独立。配置操作见[部署时区](../deploy/README.md#部署时区)
@@ -342,6 +342,7 @@ Client Key 费用账本独立累计各次 attempt 的实际费用,不能因请
| `presenter.ts`、页面 `utils/` | 纯展示投影或该页面拥有的业务转换,不启动请求 |
| `components/usage/`、`components/account/` | 跨页面复用的用量、健康时间线、套餐和额度窗口展示 |
| `composables/` | 请求取消与过期结果隔离、分页、选择、异步动作、目录加载等共享机制 |
| `i18n/` | Vue I18n 实例、三语资源和应用语言策略;从全局 Composer 派生 UI 库语言,不翻译用户数据或远端自由文本 |
| `utils/` | 按用途分开的数据解析、数字与时长格式化、位置校验、客户端配置、插件导航及颜色工具 |
JSON、原始字节与流式请求共用会话恢复和身份代际校验,身份变化后的迟到结果按取消处理。
+17 -1
View File
@@ -45,7 +45,7 @@
- **文案不使用句号和分号**:自行编写的标题、标签、按钮、表单帮助、空状态、提示和错误文案不使用 `。`、句末 `.`、`;` 或 `;`,优先写成短语或简短分句
需要表达多个要点时,按内容关系拆成字段、短行或列表,不把长段落机械替换成逗号串
这项约定针对界面文案,URL、版本号、小数、代码、原始日志和用户输入保留原样
- **说明只补必要信息**:标题、字段值和操作已能表达的内容不再重复,不同时用帮助文字、状态行和说明卡解释同一事实
- **页面直显以简洁为主**:标题、标签、按钮使用简短明确的名称或动作,说明只补必要信息,不重复标题、字段值和操作已能表达的内容,不同时用多种说明形式解释同一事实
页面保留当前决策必需的短提示,详细规则、背景原因、示例和低频帮助优先收进已有 Popover 或就近的帮助入口,不把实现细节写成用户教程
重要说明可以在 Popover 中展开,但影响当前选择的关键限制、错误原因和不可逆后果需在操作处保留简明提示,不能全部藏起来
- **按内容选择提示方式**:Tooltip 用于短名称或单句补充,Popover 用于需要阅读、多段说明或含链接的内容,复用项目现有组件
@@ -62,10 +62,26 @@
| 页面头部 | `@codex-proxy/ui` 的 `ZPageHeader`、[系统概览](../frontend/src/views/dashboard/components/DashboardContent.vue) | 简短标题、必要的统计范围或状态、就近操作 |
| 内容与指标 | `@codex-proxy/ui` 的 `ZCard`、[用量概览卡片](../frontend/src/views/usage/components/UsageSummaryCards.vue) | 可选说明、紧凑摘要、数值与辅助信息的主次 |
| 表单帮助 | [API Key 账号字段](../frontend/src/views/accounts/components/AccountApiKeyFields.vue) | 直接命名字段,在对应位置提供短提示和示例 |
| 详细规则 | [自动审批并发帮助](../frontend/src/views/settings/components/ConcurrencyPolicyCard.vue) | 标签旁帮助图标打开 Popover,页面保留短提示,浮层补充规则和示例 |
| 账号与用量展示 | [账号额度窗口](../frontend/src/components/account/account-usage-window/index.vue)、[共用用量表格](../frontend/src/components/usage/UsageRecordsTable.vue) | 复用后端展示字段和共享 presenter,管理端与 Key 页保持同一展示口径 |
页面查询、表单状态与纯展示逻辑的归属见 [前端模块职责](architecture.md#34-前端模块职责)
## 语言与字体
应用使用 Vue I18n Composition API,语言标识为 `en`、`zh-Hans`、`zh-Hant`。资源按领域存放在 `frontend/src/i18n/locales/`,使用 `领域.功能.用途` 的语义 key,例如 `accounts.connectionTest.description`,三种语言保持相同 key 和具名参数
- 标签、帮助、ARIA、通知和图表显式取消息;列定义、选项和展示投影使用响应式计算,不把翻译结果存进业务数据
- 完整句子使用具名参数,含组件的消息使用 `I18nT`;数量使用 Vue I18n 复数规则,不拆词拼接
- 专业缩写在三种语言中保留原样及规范大小写,例如 `TTFT`、`RPM`、`TPM`、`API`、`HTTP`、`WS`、`RC`,直接显示时不翻译或展开,必要的全称和解释放入帮助提示
- 英文使用句首大写和美式拼写,统一 Account、Proxy、Usage、Rate limit、API key、TTFT 等术语,协议标识和用户值保留原样
- 繁体中文只转换简体原文的字形,保持措辞与语序,不替换地区用词,例如 `数据 → 數據`、`设置 → 設置`
- 只翻译应用拥有的文本,具体后端错误、上游诊断、日志和独立插件内容保留原文;固定错误码在请求层映射,业务分类码优先保留后端公开的具体原因,无原因时使用本地兜底文案
- 侧边栏语言图标展开就地选项,选择后切换并收起;品牌区固定显示 `Codex Proxy`、`Rust build` 和版本号
- UI 库默认文案由 `ZConfigProvider` 提供,命令式通知通过 `utils/notification.ts` 绑定同一个语言来源,组件约定见 [UI 国际化](../modules/ui/playground/guide/i18n.md)
正文默认使用 Inter Variable,中文及缺失字形按系统无衬线字体栈回退。代码使用 JetBrains Mono Variable,中文由系统字体补齐,不随语言切换额外修改字重。默认值由 UI 库持有,应用负责加载字体包,图表读取同一字体 Token
## 架构概览
```mermaid
+22
View File
@@ -1,6 +1,7 @@
// @env node
import type { ESLint, Rule } from 'eslint'
import antfu from '@antfu/eslint-config'
import vueI18n from '@intlify/eslint-plugin-vue-i18n'
type LocatedRuleNode = Rule.Node & {
loc: NonNullable<Rule.Node['loc']>
@@ -99,4 +100,25 @@ export default antfu(
'vue/mustache-interpolation-spacing': ['error', 'always'],
},
},
...vueI18n.configs.base,
{
settings: {
'vue-i18n': {
localeDir: {
pattern: './src/i18n/locales/*/*.json',
localeKey: 'path',
localePattern: /\/locales\/(?<locale>[^/]+)\//,
},
messageSyntaxVersion: '^11.0.0',
},
},
rules: {
'@intlify/vue-i18n/no-missing-keys': 'error',
'@intlify/vue-i18n/no-missing-keys-in-other-locales': 'error',
'@intlify/vue-i18n/no-duplicate-keys-in-locale': 'error',
'@intlify/vue-i18n/valid-message-syntax': 'error',
'@intlify/vue-i18n/valid-plural-forms': 'error',
'@intlify/vue-i18n/no-unused-keys': ['error', { extensions: ['.ts', '.vue'] }],
},
},
)
+4 -1
View File
@@ -17,7 +17,7 @@
},
"dependencies": {
"@boxicons/vue": "1.0.1",
"@codex-proxy/ui": "github:zyycn/codex-proxy-ui#v0.5.0",
"@codex-proxy/ui": "github:zyycn/codex-proxy-ui#acd8578f82a91dc5d6da70b68c3bd354a1dde061",
"@fontsource-variable/inter": "^5.3.0",
"@fontsource-variable/jetbrains-mono": "^5.3.0",
"@lucide/vue": "^1.59.0",
@@ -34,10 +34,13 @@
"semver": "^7.8.5",
"sortablejs": "^1.15.7",
"vue": "^3.5.44",
"vue-i18n": "11.4.16",
"vue-router": "^5.4.0"
},
"devDependencies": {
"@antfu/eslint-config": "^9.5.1",
"@intlify/eslint-plugin-vue-i18n": "4.5.1",
"@intlify/unplugin-vue-i18n": "11.2.7",
"@tailwindcss/vite": "^4.3.3",
"@types/css-tree": "^3.2.0",
"@types/node": "^26.6.5",
+874 -5
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -3,3 +3,4 @@ autoInstallPeers: false
# Git 依赖通过 prepack 生成产物;信任自有 UI 仓库,实际提交仍由锁文件固定。
allowBuilds:
'@codex-proxy/ui@git+https://github.com/zyycn/codex-proxy-ui.git': true
esbuild@0.25.12: true
+11 -1
View File
@@ -1,7 +1,17 @@
<script setup lang="ts">
import { ZConfigProvider } from '@codex-proxy/ui'
import { watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { RouterView } from 'vue-router'
import { applyLocale } from '@/i18n/locale'
import { uiLocale } from '@/i18n/ui'
const { locale } = useI18n({ useScope: 'global' })
watch(locale, applyLocale, { immediate: true })
</script>
<template>
<RouterView />
<ZConfigProvider :locale="uiLocale">
<RouterView />
</ZConfigProvider>
</template>
+1 -1
View File
@@ -87,7 +87,7 @@ export interface AccountModelUsage {
}
export interface AccountUsage {
windowLabelDisplay: string
windowKind: 'general' | 'weekly' | 'monthly' | 'quota'
requestCount: number | null
requestCountDisplay: string
inputTokens: number | null
+6 -1
View File
@@ -42,8 +42,13 @@ export interface DashboardTrendPoint {
capacityUtilization: number | null
}
export type DashboardTrendMetric
= 'inputTokens' | 'outputTokens' | 'cachedInputTokens'
| 'firstTokenP95Ms' | 'latencyP95Ms' | 'outputThroughputP50'
| 'errors' | 'successRate' | 'requests'
export interface DashboardTrendSummaryItem {
label: string
metric: DashboardTrendMetric
value: string
ratio: string | null
}
-13
View File
@@ -9,11 +9,6 @@ export interface KeyUsageConfig {
plaintextKey: string
}
export interface KeyUsageVersion {
version: string
gitSha: string
}
export interface KeyUsageMetrics {
requests: number
inputTokens: number
@@ -109,14 +104,6 @@ export function getKeyUsageOverview(data: KeyUsageQuery, options: RequestOptions
})
}
export function getKeyUsageVersion(options: RequestOptions = {}) {
return request<KeyUsageVersion>({
url: '/api/key-usage/version',
method: 'GET',
...options,
})
}
export function getKeyUsageConfig(options: RequestOptions = {}) {
return request<KeyUsageConfig>({
url: '/api/key-usage/config',
+40 -19
View File
@@ -1,6 +1,7 @@
import type { AxiosError, AxiosResponse, AxiosResponseHeaders, RawAxiosResponseHeaders } from 'axios'
import type { RequestContext, RequestNext } from './index'
import { isAxiosError } from 'axios'
import { t } from '@/i18n'
export type ApiErrorKind = 'api' | 'timeout' | 'network' | 'http' | 'cancelled'
@@ -45,16 +46,16 @@ export function normalizeApiError(error: AxiosError<unknown>) {
const requestId = responseHeader(error.response?.headers, 'x-request-id')
if (error.code === 'ERR_CANCELED') {
return new ApiError('请求已取消', status, undefined, requestId, 'cancelled')
return new ApiError(t('common.errors.canceled'), status, undefined, requestId, 'cancelled')
}
const apiError = error.response && normalizeApiResponseError(error.response)
if (apiError)
return apiError
if (error.code === 'ECONNABORTED' || error.code === 'ETIMEDOUT' || error.code === 'ERR_TIMEOUT') {
return new ApiError('请求超时,请稍后重试', status, undefined, requestId, 'timeout')
return new ApiError(t('common.errors.timeout'), status, undefined, requestId, 'timeout')
}
if (!error.response) {
return new ApiError('网络连接失败,请检查网络后重试', 0, undefined, requestId, 'network')
return new ApiError(t('common.errors.network'), 0, undefined, requestId, 'network')
}
return new ApiError(httpFallback(status), status, undefined, requestId, 'http')
}
@@ -63,8 +64,9 @@ export function normalizeApiResponseError(response: AxiosResponse<unknown>) {
const envelope = adminErrorEnvelope(response.data)
if (!envelope || envelope.code === 200)
return undefined
const message = adminErrorMessage(envelope) || httpFallback(response.status >= 400 ? response.status : 0)
return new ApiError(
envelope.message || httpFallback(response.status >= 400 ? response.status : 0),
message,
response.status,
envelope.code,
responseHeader(response.headers, 'x-request-id'),
@@ -82,6 +84,25 @@ function adminErrorEnvelope(value: unknown): AdminErrorEnvelope | null {
return { code: record.code, message }
}
// 固定错误码使用本地文案,业务分类码保留后端已公开的具体原因
function adminErrorMessage(error: AdminErrorEnvelope): string {
switch (error.code) {
case 40000: return t('common.errors.malformedJson')
case 40002: return t('common.errors.invalidTimeRange')
case 40101: return t('common.errors.signInRequired')
case 40102: return t('common.errors.invalidCredentials')
case 40103: return t('common.errors.invalidAdminApiKey')
case 40301: return t('common.errors.forbidden')
case 42901: return t('common.errors.tooManyLoginAttempts')
case 42902: return error.message || t('common.errors.rateLimited')
case 50001: return t('common.errors.internal')
case 50201: return error.message || t('common.errors.upstreamFailure')
case 50202: return error.message || t('common.errors.upstreamResultUnknown')
case 50301: return error.message || t('common.errors.unavailable')
default: return error.message
}
}
function responseHeader(
headers: RawAxiosResponseHeaders | AxiosResponseHeaders | undefined,
name: string,
@@ -95,35 +116,35 @@ function responseHeader(
function httpFallback(status: number) {
switch (status) {
case 400:
return '请求参数不合法'
return t('common.errors.invalidParameters')
case 401:
return '需要登录'
return t('common.errors.signInRequired')
case 403:
return '没有权限执行此操作'
return t('common.errors.forbidden')
case 404:
return '请求的接口不存在'
return t('common.errors.notFound')
case 408:
return '请求超时,请稍后重试'
return t('common.errors.timeout')
case 409:
return '资源状态冲突,请刷新后重试'
return t('common.errors.conflict')
case 413:
return '请求内容过大'
return t('common.errors.payloadTooLarge')
case 415:
return '请求格式不受支持'
return t('common.errors.unsupportedFormat')
case 422:
return '请求内容不合法'
return t('common.errors.invalidContent')
case 429:
return '请求过于频繁,请稍后重试'
return t('common.errors.rateLimited')
case 500:
return '服务内部错误'
return t('common.errors.internal')
case 502:
return '上游服务请求失败'
return t('common.errors.upstreamFailure')
case 503:
return '服务暂不可用,请稍后重试'
return t('common.errors.unavailable')
case 504:
return '上游服务响应超时'
return t('common.errors.upstreamTimeout')
default:
return status > 0 ? `请求失败(HTTP ${status})` : '请求失败'
return status > 0 ? t('common.errors.http', { status }) : t('common.errors.request')
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
import type { RequestContext, RequestNext } from './index'
import { ZNotification } from '@codex-proxy/ui'
import { notification as ZNotification } from '@/utils/notification'
import { ApiError, isSessionRequired } from './error'
// 共享刷新 Promise 的同一个失败只提示一次,弱引用不保留已结束请求
+4 -3
View File
@@ -1,4 +1,5 @@
import type { RequestContext, RequestNext } from './index'
import { t } from '@/i18n'
import { ApiError, normalizeApiResponseError } from './error'
export interface RawResponseMeta {
@@ -50,7 +51,7 @@ export async function rawPlugin(context: RequestContext, next: RequestNext) {
}
const body = response.data as ArrayBuffer
if (body.byteLength > options.maximumBytes)
throw new ApiError('响应内容超过大小限制', 502, undefined, rawHeader(response.headers, 'x-request-id'), 'http')
throw new ApiError(t('common.errors.responseTooLarge'), 502, undefined, rawHeader(response.headers, 'x-request-id'), 'http')
return {
...response,
data: {
@@ -69,7 +70,7 @@ export async function rawPlugin(context: RequestContext, next: RequestNext) {
if (normalized)
throw normalized
throw new ApiError(
response.status >= 400 ? `请求失败(HTTP ${response.status})` : '服务返回了不受支持的响应',
response.status >= 400 ? t('common.errors.http', { status: response.status }) : t('common.errors.unsupportedResponse'),
response.status,
undefined,
rawHeader(response.headers, 'x-request-id'),
@@ -90,7 +91,7 @@ async function readErrorBody(body: ReadableStream<Uint8Array> | null, maximumByt
break
length += value.byteLength
if (length > maximumBytes)
throw new ApiError('响应内容超过大小限制', 502, undefined, undefined, 'http')
throw new ApiError(t('common.errors.responseTooLarge'), 502, undefined, undefined, 'http')
chunks.push(value)
}
}
+2 -1
View File
@@ -1,4 +1,5 @@
import type { RequestContext, RequestNext } from './index'
import { t } from '@/i18n'
import { ApiError, isTransientApiError } from './error'
export async function retryPlugin(context: RequestContext, next: RequestNext) {
@@ -6,7 +7,7 @@ export async function retryPlugin(context: RequestContext, next: RequestNext) {
const retry = config.retry ?? ['GET', 'HEAD'].includes((config.method ?? 'GET').toUpperCase())
for (let attempt = 0; ; attempt += 1) {
if (!context.isCurrent())
throw new ApiError('请求已取消', 0, undefined, undefined, 'cancelled')
throw new ApiError(t('common.errors.canceled'), 0, undefined, undefined, 'cancelled')
try {
return await next()
}
+5 -4
View File
@@ -1,6 +1,7 @@
import type { RequestConfig } from '../index'
import type { RequestContext, RequestNext } from './index'
import { ZNotification } from '@codex-proxy/ui'
import { t } from '@/i18n'
import { notification as ZNotification } from '@/utils/notification'
import { ApiError, isSessionRequired } from './error'
// 会话失效是后端业务事实,登录凭据错误和 403 不清除已有会话
@@ -65,15 +66,15 @@ export async function sessionPlugin(context: RequestContext, send: RequestNext)
const isCurrent = context.isCurrent
context.isCurrent = () => isCurrent() && generation === sessionGeneration
if (!config.skipSessionRecovery && sessionRecovery && !await sessionRecovery)
return expireSession(new ApiError('登录已失效,请重新登录', 401, SESSION_REQUIRED), config, generation)
return expireSession(new ApiError(t('common.errors.sessionExpired'), 401, SESSION_REQUIRED), config, generation)
if (config.signal?.aborted || generation !== sessionGeneration)
throw new ApiError('请求已取消', 0, undefined, undefined, 'cancelled')
throw new ApiError(t('common.errors.canceled'), 0, undefined, undefined, 'cancelled')
const sendCurrent: RequestNext = async () => {
const response = await send()
if (context.isCurrent())
return response
// 身份已切换时丢弃迟到结果,流式传输由请求层终止
throw new ApiError('请求已取消', 0, undefined, undefined, 'cancelled')
throw new ApiError(t('common.errors.canceled'), 0, undefined, undefined, 'cancelled')
}
const recovered = successfulRecoveries
try {
@@ -3,6 +3,8 @@ import type { AccountGroupRef } from '@/api'
import { ZCheckbox } from '@codex-proxy/ui'
import { useI18n } from 'vue-i18n'
withDefaults(
defineProps<{
groups: AccountGroupRef[]
@@ -15,6 +17,8 @@ withDefaults(
},
)
const { t } = useI18n({ useScope: 'global' })
const selectedGroupIds = defineModel<string[]>({ required: true })
function updateGroup(groupId: string, selected: boolean) {
@@ -42,10 +46,10 @@ function updateGroup(groupId: string, selected: boolean) {
@update:model-value="updateGroup(group.id, $event)"
/>
</span>
<span v-if="!group.enabled" class="shrink-0 text-cp-xs font-emphasis text-cp-text-quaternary"> 已禁用 </span>
<span v-if="!group.enabled" class="shrink-0 text-cp-xs font-emphasis text-cp-text-quaternary"> {{ t('common.status.disabled') }} </span>
</div>
</div>
<p v-else class="m-0 rounded-cp bg-cp-fill-quaternary px-3.5 py-3 text-cp-sm font-emphasis text-cp-text-secondary">
{{ loading ? '正在加载分组...' : '暂无分组,请先在分组管理中创建' }}
{{ loading ? t('groups.selector.loading') : t('groups.selector.empty') }}
</p>
</template>
@@ -1,13 +1,17 @@
<script setup lang="ts">
import type { AccountGroupRef } from '@/api'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
const props = defineProps<{
groups: AccountGroupRef[]
}>()
const { t } = useI18n({ useScope: 'global' })
const fullNames = computed(() =>
props.groups.map(group => (group.enabled ? group.name : `${group.name}(已禁用)`)).join('、'),
props.groups.map(group => (group.enabled ? group.name : t('common.status.disabledName', { name: group.name }))).join('、'),
)
</script>
+13 -9
View File
@@ -2,22 +2,26 @@
import { ZButton, ZDialog, ZIconButton, ZScrollbar, ZSegmented, ZSwitch } from '@codex-proxy/ui'
import { Apple, Copy, Monitor, Upload } from '@lucide/vue'
import { computed, shallowRef } from 'vue'
import { useI18n } from 'vue-i18n'
import { buildCodexCcSwitchImportDeeplink, buildCodexConfig, CODEX_WEBSOCKET_ENABLED_BY_DEFAULT } from '@/utils/client'
const props = withDefaults(defineProps<{
const props = defineProps<{
title?: string
apiKey: {
name?: string
key?: string
} | null
apiBaseUrl: string
}>(), { title: '使用密钥' })
}>()
const emit = defineEmits<{
copy: [text: string]
}>()
const { t } = useI18n({ useScope: 'global' })
const open = defineModel<boolean>({ default: false })
const activePlatform = shallowRef('unix')
@@ -54,16 +58,16 @@ function importToCcs() {
<template>
<ZDialog
v-model="open"
:title="title"
description="保存或合并下方配置后重启 Codex"
:title="title ?? t('keys.configuration.title')"
:description="t('keys.configuration.description')"
width="48rem"
>
<div class="flex flex-col gap-5">
<div class="flex flex-wrap items-center justify-between gap-3">
<ZSegmented v-model="activePlatform" aria-label="配置平台" :options="platformOptions" />
<ZSegmented v-model="activePlatform" :aria-label="t('keys.configuration.platform')" :options="platformOptions" />
<ZSwitch
v-model="websocketEnabled"
aria-label="切换 WebSocket 配置"
:aria-label="t('keys.configuration.toggleWebSocket')"
active-text="WS"
inactive-text="WS"
inline-prompt
@@ -81,7 +85,7 @@ function importToCcs() {
<ZIconButton
variant="solid"
size="small"
aria-label="复制"
:aria-label="t('common.actions.copy')"
@click="emit('copy', codexConfig)"
>
<Copy class="size-3.5" />
@@ -101,10 +105,10 @@ function importToCcs() {
<template #footer>
<ZButton :disabled="!keyValue" @click="importToCcs">
<Upload class="size-4" />
导入 CCSwitch
{{ t('keys.configuration.importCcSwitch') }}
</ZButton>
<ZButton type="primary" @click="open = false">
关闭
{{ t('common.actions.close') }}
</ZButton>
</template>
</ZDialog>
-112
View File
@@ -1,112 +0,0 @@
<script setup lang="ts">
import { Github } from '@boxicons/vue'
import { ZDialog } from '@codex-proxy/ui'
import { ExternalLink } from '@lucide/vue'
import { computed } from 'vue'
const props = defineProps<{
version: { version: string, gitSha: string } | null
}>()
const open = defineModel<boolean>({ default: false })
const author = 'Zyy'
const githubUrl = 'https://github.com/zyycn/codex-proxy-rs'
function normalizeBuildValue(value: string | undefined) {
const normalized = value?.trim()
if (!normalized) {
return ''
}
return ['unknown', 'null'].includes(normalized.toLowerCase()) ? '' : normalized
}
const versionDisplay = computed(() => {
const versionText = normalizeBuildValue(props.version?.version).replace(/^v/i, '')
return versionText ? `v${versionText}` : ''
})
const gitShaDisplay = computed(() => {
const gitSha = normalizeBuildValue(props.version?.gitSha)
return gitSha ? gitSha.slice(0, 8) : ''
})
const versionLine = computed(() => {
const parts = [versionDisplay.value, gitShaDisplay.value].filter(Boolean)
return parts.length ? `版本 ${parts.join(' · ')}` : '版本信息不可用'
})
const linkItems = [
{
label: 'GitHub',
value: 'codex-proxy-rs',
href: githubUrl,
icon: Github,
},
]
</script>
<template>
<ZDialog v-model="open" title="关于" width="28rem">
<div class="grid gap-5">
<section class="flex min-w-0 items-center gap-3">
<span
class="inline-flex size-9 shrink-0 items-center justify-center rounded-cp bg-cp-fill-quaternary font-mono text-cp-xl leading-none font-extrabold text-cp-text"
>
Z
</span>
<div class="min-w-0">
<p class="m-0 truncate text-cp-xl leading-none font-heavy text-cp-text">
{{ author }}
</p>
<p class="mt-1.5 mb-0 text-cp-sm leading-none font-emphasis text-cp-text-secondary">
Built by Zyy · Codex Proxy RS
</p>
</div>
</section>
<section class="grid gap-1">
<div
v-for="item in linkItems"
:key="item.label"
class="group flex min-w-0 items-center justify-between gap-3 rounded-cp px-1 py-2.5 transition-colors hover:bg-cp-fill-quaternary"
>
<div class="flex min-w-0 items-center gap-3">
<span
class="inline-flex size-8 shrink-0 items-center justify-center rounded-cp bg-cp-fill-tertiary text-cp-text"
>
<component :is="item.icon" class="size-5" />
</span>
<div class="min-w-0">
<p class="m-0 text-cp-xs leading-none font-heavy text-cp-text-quaternary">
{{ item.label }}
</p>
<p
class="mt-2 mb-0 truncate font-mono text-cp-sm leading-none font-bold text-cp-text"
:title="item.value"
>
{{ item.value }}
</p>
</div>
</div>
<a
:href="item.href"
target="_blank"
rel="noreferrer"
class="inline-flex size-7 shrink-0 items-center justify-center rounded-cp text-cp-text-quaternary transition-colors hover:bg-cp-fill-tertiary hover:text-cp-link"
:aria-label="`打开 ${item.label}`"
>
<ExternalLink class="size-3.5" />
</a>
</div>
</section>
<p class="m-0 font-mono text-cp-xs leading-none font-emphasis text-cp-text-quaternary">
{{ versionLine }}
</p>
</div>
</ZDialog>
</template>
@@ -0,0 +1,66 @@
<script setup lang="ts">
import type { IconButtonProps } from '@codex-proxy/ui'
import type { Locale } from '@/i18n/locale'
import { ZIconButton, ZMenuItem, ZPopover } from '@codex-proxy/ui'
import { Check, Languages } from '@lucide/vue'
import chineseFlag from 'circle-flags/flags/cn.svg?url&no-inline'
import englishFlag from 'circle-flags/flags/us.svg?url&no-inline'
import { computed, useTemplateRef } from 'vue'
import { useI18n } from 'vue-i18n'
import { useLocale } from '@/composables/useLocale'
withDefaults(defineProps<{ size?: IconButtonProps['size'], variant?: IconButtonProps['variant'] }>(), {
size: 'small',
variant: 'text',
})
const { t } = useI18n({ useScope: 'global' })
const { locale, localeOptions, setLocale } = useLocale()
const localeFlags: Record<Locale, string> = {
'zh-Hans': chineseFlag,
'zh-Hant': chineseFlag,
'en': englishFlag,
}
const choices = useTemplateRef<HTMLElement>('choices')
const label = computed(() => t('navigation.switchLanguage', {
value: localeOptions.find(option => option.value === locale.value)?.label ?? 'English',
}))
function focusSelected() {
choices.value?.querySelector<HTMLButtonElement>('button[aria-pressed="true"]')?.focus()
}
function selectLocale(value: Locale, close: () => void) {
setLocale(value)
close()
}
</script>
<template>
<ZPopover placement="top-end" @opened="focusSelected">
<template #reference="{ id, open }">
<ZIconButton :size="size" :variant="variant" :aria-label="label" :aria-expanded="open" :aria-controls="id">
<Languages :size="size === 'small' ? 18 : 19" />
</ZIconButton>
</template>
<template #default="{ close }">
<div ref="choices" role="group" :aria-label="t('common.language')" class="grid min-w-40 gap-1 p-1.5">
<ZMenuItem
v-for="option in localeOptions"
:key="option.value"
:aria-pressed="option.value === locale"
class="aria-pressed:bg-cp-control-item-bg-active aria-pressed:text-cp-primary-text aria-pressed:hover:bg-cp-control-item-bg-active"
@click="selectLocale(option.value, close)"
>
<template #icon>
<img :src="localeFlags[option.value]" alt="" aria-hidden="true" class="size-4.5 shrink-0">
</template>
<span class="flex items-center justify-between gap-3">
<span :lang="option.value">{{ option.label }}</span>
<Check v-if="option.value === locale" class="size-4 shrink-0" aria-hidden="true" />
</span>
</ZMenuItem>
</div>
</template>
</ZPopover>
</template>
+11 -1
View File
@@ -1,5 +1,15 @@
<script setup lang="ts">
defineProps<{ value: string | null, display: string, fullDisplay: string | null }>()
import { useTimeAgoIntl } from '@vueuse/core'
import { useI18n } from 'vue-i18n'
const props = defineProps<{ value: string | null, fullDisplay: string | null }>()
const { locale } = useI18n({ useScope: 'global' })
const display = useTimeAgoIntl(() => props.value ?? 0, {
get locale() { return locale.value },
relativeTimeFormatOptions: { numeric: 'auto', style: 'short' },
insertSpace: false,
})
</script>
<template>
+11 -4
View File
@@ -1,14 +1,21 @@
<script setup lang="ts">
import { ZSegmented } from '@codex-proxy/ui'
import { LayoutGrid } from '@lucide/vue'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { formatProviderLabel, PROVIDER_IDS, providerIcon } from '@/utils/providers'
defineProps<{ disabled?: boolean }>()
const { t } = useI18n({ useScope: 'global' })
const provider = defineModel<string>({ required: true })
const options = [
{ label: '全部平台', value: '', icon: LayoutGrid },
const options = computed(() => ([
{ label: t('common.providers.all'), value: '', icon: LayoutGrid },
...PROVIDER_IDS.map(value => ({ label: formatProviderLabel(value), value, icon: providerIcon(value) })),
]
]))
</script>
<template>
@@ -16,7 +23,7 @@ const options = [
<div class="min-w-0 overflow-x-auto">
<ZSegmented
v-model="provider"
aria-label="按平台筛选"
:aria-label="t('common.providers.filter')"
display="icon"
:style="{ width: `${options.length * 40 + 4}px` }"
:options="options"
@@ -1,5 +1,7 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { authenticationIcon, formatAuthenticationLabel, formatProviderLabel, providerIcon } from '@/utils/providers'
const props = withDefaults(
@@ -13,6 +15,8 @@ const props = withDefaults(
},
)
const { t } = useI18n({ useScope: 'global' })
const normalizedProvider = computed(() => (props.provider ?? '').trim().toLowerCase())
const providerIconComponent = computed(() => normalizedProvider.value ? providerIcon(normalizedProvider.value) : undefined)
const authenticationIconComponent = computed(() => authenticationIcon(props.authenticationKind))
@@ -33,7 +37,7 @@ const iconClass = computed(() => {
return props.size === 'sm' ? 'size-3' : 'size-4'
})
const providerLabel = computed(() => formatProviderLabel(props.provider, '未知平台'))
const providerLabel = computed(() => formatProviderLabel(props.provider, t('common.providers.unknown')))
const authenticationLabel = computed(() => formatAuthenticationLabel(props.authenticationKind))
</script>
@@ -1,16 +1,21 @@
<script setup lang="ts">
import { ZIconButton } from '@codex-proxy/ui'
import { LocateFixed } from '@lucide/vue'
import { useI18n } from 'vue-i18n'
defineProps<{ loading: boolean, disabled?: boolean }>()
const emit = defineEmits<{ detect: [] }>()
const { t } = useI18n({ useScope: 'global' })
</script>
<template>
<ZIconButton
size="default"
:aria-label="loading ? '正在解析出口位置' : '解析出口位置并填入表单'"
:title="loading ? '正在解析出口位置' : '解析出口位置并填入表单'"
:aria-label="loading ? t('common.location.resolving') : t('common.location.detect')"
:title="loading ? t('common.location.resolving') : t('common.location.detect')"
:aria-busy="loading"
:disabled="disabled || loading"
@click="emit('detect')"
@@ -1,8 +1,13 @@
<script setup lang="ts">
import type { RequestLocation } from '@/api'
import { ZFormItem, ZInput } from '@codex-proxy/ui'
import { useI18n } from 'vue-i18n'
defineProps<{ disabled?: boolean }>()
const { t } = useI18n({ useScope: 'global' })
const location = defineModel<RequestLocation>({ required: true })
function update(field: keyof RequestLocation, value: string) {
@@ -12,17 +17,17 @@ function update(field: keyof RequestLocation, value: string) {
<template>
<div class="grid gap-4 sm:grid-cols-2">
<ZFormItem label="国家代码" required>
<ZInput :model-value="location.country" :disabled="disabled" aria-label="国家代码" placeholder="请输入两位国家代码" maxlength="2" @update:model-value="update('country', $event)" />
<ZFormItem :label="t('common.location.countryCode')" required>
<ZInput :model-value="location.country" :disabled="disabled" :aria-label="t('common.location.countryCode')" :placeholder="t('common.location.countryCodePlaceholder')" maxlength="2" @update:model-value="update('country', $event)" />
</ZFormItem>
<ZFormItem label="地区" required>
<ZInput :model-value="location.region" :disabled="disabled" aria-label="地区" placeholder="请输入地区" maxlength="128" @update:model-value="update('region', $event)" />
<ZFormItem :label="t('common.location.region')" required>
<ZInput :model-value="location.region" :disabled="disabled" :aria-label="t('common.location.region')" :placeholder="t('common.location.regionPlaceholder')" maxlength="128" @update:model-value="update('region', $event)" />
</ZFormItem>
<ZFormItem label="城市" required>
<ZInput :model-value="location.city" :disabled="disabled" aria-label="城市" placeholder="请输入城市" maxlength="128" @update:model-value="update('city', $event)" />
<ZFormItem :label="t('common.location.city')" required>
<ZInput :model-value="location.city" :disabled="disabled" :aria-label="t('common.location.city')" :placeholder="t('common.location.cityPlaceholder')" maxlength="128" @update:model-value="update('city', $event)" />
</ZFormItem>
<ZFormItem label="IANA 时区" required>
<ZInput :model-value="location.timezone" :disabled="disabled" aria-label="IANA 时区" placeholder="请输入 IANA 时区" @update:model-value="update('timezone', $event)" />
<ZFormItem :label="t('common.location.timeZone')" required>
<ZInput :model-value="location.timezone" :disabled="disabled" :aria-label="t('common.location.timeZone')" :placeholder="t('common.location.timeZonePlaceholder')" @update:model-value="update('timezone', $event)" />
</ZFormItem>
</div>
</template>
@@ -1,7 +1,9 @@
<script setup lang="ts">
import type { AccountQuotaWindow } from '@/api/index'
import type { AccountUsageWindowVariant } from '@/components/account/account-usage-window/presenter'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import AccountRequestTimeline from '@/components/account/account-usage-window/AccountRequestTimeline.vue'
import { resolveAccountUsageWindowPresentation } from '@/components/account/account-usage-window/presenter'
@@ -21,6 +23,8 @@ const props = withDefaults(
},
)
const { t } = useI18n({ useScope: 'global' })
const view = computed(() => resolveAccountUsageWindowPresentation({
window: props.window,
variant: props.variant,
@@ -37,7 +41,7 @@ const view = computed(() => resolveAccountUsageWindowPresentation({
:class="view.classes.label"
:title="showNativeTooltip ? view.labelTooltip : undefined"
>
{{ window.labelDisplay }}
{{ view.label }}
</span>
<span
v-if="view.compactValues"
@@ -47,7 +51,7 @@ const view = computed(() => resolveAccountUsageWindowPresentation({
v-if="view.quota.localUsageVisible"
class="text-right text-cp-text-quaternary"
:class="view.classes.value"
:title="showNativeTooltip ? `窗口消耗:${view.quota.localUsageDisplay}` : undefined"
:title="showNativeTooltip ? t('accounts.quota.usageInThisWindow', { localUsageDisplay: view.quota.localUsageDisplay }) : undefined"
>
{{ view.quota.localUsageDisplay }}
</span>
@@ -55,7 +59,7 @@ const view = computed(() => resolveAccountUsageWindowPresentation({
v-if="showPercentage && view.quota.valueVisible"
class="text-right"
:class="[view.classes.value, view.quota.percentTextClass]"
:title="showNativeTooltip ? `额度已使用:${window.usedPercentDisplay}` : undefined"
:title="showNativeTooltip ? t('accounts.quota.quotaUsed', { rate: window.usedPercentDisplay }) : undefined"
>
{{ window.usedPercentDisplay }}
</span>
@@ -83,7 +87,7 @@ const view = computed(() => resolveAccountUsageWindowPresentation({
class="col-span-full"
:class="[view.classes.track, view.classes.trackOffset]"
role="progressbar"
:aria-label="window.labelDisplay"
:aria-label="view.label"
aria-valuemin="0"
aria-valuemax="100"
:aria-valuenow="window.usedPercent ?? undefined"
@@ -98,7 +102,7 @@ const view = computed(() => resolveAccountUsageWindowPresentation({
v-if="view.quota.resetVisible"
class="mt-3 text-cp-sm font-emphasis text-cp-text-secondary"
>
重置时间: {{ window.resetAtDisplay }}
{{ t('accounts.quota.resets', { resetAtDisplay: window.resetAtDisplay }) }}
</div>
</template>
@@ -125,7 +129,7 @@ const view = computed(() => resolveAccountUsageWindowPresentation({
</template>
<div v-else :class="view.classes.header">
<span class="min-w-0 text-cp-text-secondary">额度待观测</span>
<span class="min-w-0 text-cp-text-secondary">{{ t('accounts.quota.unobserved') }}</span>
</div>
</div>
</template>
@@ -1,5 +1,6 @@
import type { AccountQuotaWindow } from '@/api/index'
import { clamp } from 'es-toolkit'
import { t } from '@/i18n'
import { isRecord } from '@/utils/data'
import { formatInteger } from '@/utils/format'
@@ -125,15 +126,17 @@ export function resolveAccountUsageWindowPresentation(
const localRequestValueVisible = input.showLocalValue
&& typeof localUsage?.requestCount === 'number'
&& localUsage.requestCount > 0
const localRequestLabel = '日请求'
const localRequestLabel = t('accounts.quota.dailyRequests')
const quota = input.window
? quotaWindowPresentation(input.window, definition.minimumBarWidth)
: null
const label = input.window ? quotaWindowLabel(input.window) : undefined
return {
mode,
compactValues: definition.compactValues,
labelTooltip: definition.labelTooltip ? input.window?.labelDisplay : undefined,
label,
labelTooltip: definition.labelTooltip ? label : undefined,
classes: {
root: definition.rootClass,
header: definition.headerClass,
@@ -159,7 +162,7 @@ export function resolveAccountUsageWindowPresentation(
label: localRequestLabel,
requestDisplay: localRequestDisplay,
requestValueVisible: localRequestValueVisible,
timelineTitle: `${localRequestLabel} ${localRequestDisplay} 次`,
timelineTitle: t('accounts.quota.requests', { localRequestLabel, localRequestDisplay }),
requestBars: requestTimeline(localUsage?.requestBuckets ?? []),
durationDisplay: rollingWindowDurationDisplay(input.window?.windowSeconds),
},
@@ -237,6 +240,41 @@ export function quotaWindowLocalUsageDisplay(window: AccountQuotaWindow) {
return localTokenDisplay(localUsage) || null
}
const quotaWindowPeriods = [
{ seconds: 18_000, label: () => t('accounts.quota.windows.fiveHour') },
{ seconds: 86_400, label: () => t('accounts.quota.windows.daily') },
{ seconds: 604_800, label: () => t('accounts.quota.windows.weekly') },
{ seconds: 2_592_000, label: () => t('accounts.quota.windows.monthly') },
{ seconds: 31_536_000, label: () => t('accounts.quota.windows.annual') },
]
export function quotaWindowLabel(window: AccountQuotaWindow, includeLimitName = true) {
const seconds = window.windowSeconds
// 沿用 Codex 官方的显示时长容差;仅决定文案,不改变后端窗口归属或额度判定。
const period = seconds === null
? undefined
: quotaWindowPeriods.find(period =>
seconds >= period.seconds * 0.95 && seconds <= period.seconds * 1.05,
)
let label: string
if (period)
label = period.label()
else if (seconds !== null && seconds > 0)
label = t('accounts.quota.windows.duration', { duration: rollingWindowDurationDisplay(seconds) })
else if (window.role === 'monthly')
label = t('accounts.quota.windows.monthly')
else if (window.role === 'primary')
label = t('accounts.quota.windows.usage')
else if (window.role === 'secondary')
label = t('accounts.quota.windows.secondary')
else
label = window.windowLabelDisplay
return includeLimitName && window.limitName && window.limitId !== 'codex'
? `${window.limitName} · ${label}`
: label
}
function requestCountDisplay(localUsage: AccountLocalUsage | null) {
const display = localUsage?.requestCountDisplay
if (typeof display === 'string' && display.trim())
@@ -252,12 +290,12 @@ function rollingWindowDurationDisplay(windowSeconds: number | null | undefined)
const hourSeconds = 60 * 60
const daySeconds = 24 * hourSeconds
if (windowSeconds <= daySeconds * 2 && windowSeconds % hourSeconds === 0)
return `${formatInteger(windowSeconds / hourSeconds)} 小时`
return t('accounts.quota.h', { duration: formatInteger(windowSeconds / hourSeconds) })
if (windowSeconds % daySeconds === 0)
return `${formatInteger(windowSeconds / daySeconds)} 天`
return t('accounts.quota.d', { duration: formatInteger(windowSeconds / daySeconds) })
if (windowSeconds % hourSeconds === 0)
return `${formatInteger(windowSeconds / hourSeconds)} 小时`
return `${formatInteger(windowSeconds)} 秒`
return t('accounts.quota.h', { duration: formatInteger(windowSeconds / hourSeconds) })
return t('accounts.quota.s', { duration: formatInteger(windowSeconds) })
}
export function quotaWindowPresentation(window: AccountQuotaWindow, minimumWidth: string) {
+1 -1
View File
@@ -27,7 +27,7 @@ export function chartTooltipStyle(
textStyle: {
color: theme.textPrimary,
fontSize: 12,
fontFamily: options.fontFamily ?? 'Inter Variable, Inter, system-ui, sans-serif',
fontFamily: options.fontFamily ?? (getComputedStyle(document.documentElement).fontFamily),
fontWeight: options.fontWeight ?? 650,
},
extraCssText: 'border-radius: 12px; box-shadow: var(--cp-box-shadow);',
@@ -4,8 +4,10 @@ import type {
ClientProfilePreview,
ClientProfileSelection,
} from '@/api/modules/settings/profiles'
import { ZButton, ZEmpty, ZSegmented } from '@codex-proxy/ui'
import { computed, onMounted, shallowRef, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { getClientProfileOptions, previewClientProfile } from '@/api/modules/settings/profiles'
import { errorMessage } from '@/utils/operation'
import ClientProfilePresetFields from './ClientProfilePresetFields.vue'
@@ -16,6 +18,9 @@ const props = withDefaults(defineProps<{ active?: boolean, disabled?: boolean, a
disabled: false,
allowInherit: false,
})
const { t } = useI18n({ useScope: 'global' })
const model = defineModel<ClientProfileSelection | null>({ required: true })
const options = shallowRef<ClientProfileOptions>()
const preview = shallowRef<ClientProfilePreview>()
@@ -76,7 +81,7 @@ watch([model, () => props.active], ([configuration, active], _, onCleanup) => {
}
catch (error) {
if (!cancelled)
previewError.value = errorMessage(error).replaceAll('User-Agent', '用户代理')
previewError.value = errorMessage(error).replaceAll('User-Agent', t('settings.clientProfile.userAgent'))
}
finally {
if (!cancelled)
@@ -97,20 +102,20 @@ onMounted(() => load())
<div v-if="allowInherit" class="flex flex-wrap items-center justify-between gap-3">
<ZSegmented
v-model="profileSource"
aria-label="客户端身份来源"
:aria-label="t('settings.clientProfile.clientIdentitySource')"
class="shrink-0"
:options="[
{ label: '全局配置', value: 'global' },
{ label: '独立配置', value: 'independent' },
{ label: t('settings.clientProfile.globalConfiguration'), value: 'global' },
{ label: t('settings.clientProfile.customConfiguration'), value: 'independent' },
]"
:disabled="disabled || loading || !options"
/>
<slot name="source-extra" />
</div>
<ZEmpty v-if="loadError" title="预设加载失败" :description="loadError" size="small" surface="none" role="alert">
<ZEmpty v-if="loadError" :title="t('settings.clientProfile.presetLoadingFailed')" :description="loadError" size="small" surface="none" role="alert">
<template #action>
<ZButton size="small" :disabled="disabled || loading" @click="load()">
重试
{{ t('common.actions.retry') }}
</ZButton>
</template>
</ZEmpty>
@@ -1,7 +1,9 @@
<script setup lang="ts">
import type { ClientProfilePreset, ClientProfilePreview, ClientProfileSelection, CustomClientProfileSelection, PresetClientProfileSelection } from '@/api/modules/settings/profiles'
import { ZFormItem, ZInput, ZSelect, ZTextarea } from '@codex-proxy/ui'
import { computed, shallowRef } from 'vue'
import { useI18n } from 'vue-i18n'
const props = withDefaults(defineProps<{
presets: ClientProfilePreset[]
@@ -13,6 +15,9 @@ const props = withDefaults(defineProps<{
}>(), {
maxVersionLag: 10,
})
const { t } = useI18n({ useScope: 'global' })
const model = defineModel<ClientProfileSelection | null>({ required: true })
const presetDraft = shallowRef<PresetClientProfileSelection>()
const customDraft = shallowRef<CustomClientProfileSelection>()
@@ -78,7 +83,7 @@ const versionLag = computed({
const versionLagError = computed(() => {
const value = preset.value?.versionLag
return value != null && (!Number.isInteger(value) || value < 1 || value > props.maxVersionLag)
? `请输入 1~${props.maxVersionLag} 的正整数`
? t('settings.clientProfile.enterIntegerFromTo', { version: props.maxVersionLag })
: ''
})
const terminal = computed({
@@ -115,28 +120,28 @@ const userAgent = computed({
<template>
<div class="grid gap-4">
<div class="grid gap-4" :class="preset?.client === 'cli' && !custom ? 'sm:grid-cols-3' : 'sm:grid-cols-2'">
<ZFormItem label="客户端预设">
<ZSelect v-model="selectedPreset" class="w-full" :options="presetOptions" :placeholder="custom ? '使用自定义用户代理' : undefined" :disabled="disabled || custom || !presets.length" />
<ZFormItem :label="t('settings.clientProfile.clientDefault')">
<ZSelect v-model="selectedPreset" class="w-full" :options="presetOptions" :placeholder="custom ? t('settings.clientProfile.useCustomUserAgent') : undefined" :disabled="disabled || custom || !presets.length" />
</ZFormItem>
<ZFormItem v-if="preset?.client === 'cli' && !custom" label="CLI 入口">
<ZFormItem v-if="preset?.client === 'cli' && !custom" :label="t('settings.clientProfile.cliEntry')">
<ZSelect
v-model="cliEntry"
class="w-full"
:options="[
{ label: 'Core · 默认身份', value: 'core' },
{ label: 'TUI · 交互式终端', value: 'tui' },
{ label: 'Exec · 非交互执行', value: 'exec' },
{ label: t('settings.clientProfile.coreDefaultIdentity'), value: 'core' },
{ label: t('settings.clientProfile.tuiInteractiveTerminal'), value: 'tui' },
{ label: t('settings.clientProfile.execNonInteractiveExecution'), value: 'exec' },
]"
:disabled="disabled"
/>
</ZFormItem>
<ZFormItem label="版本策略">
<ZFormItem :label="t('settings.clientProfile.versionStrategy')">
<ZSelect
v-model="versionMode"
class="w-full"
:options="[
{ label: '跟随最新版本', value: 'latest', disabled: !presets.length },
{ label: '自定义版本', value: 'custom', disabled: !custom && (previewing || !preview) },
{ label: t('settings.clientProfile.followLatestVersion'), value: 'latest', disabled: !presets.length },
{ label: t('settings.clientProfile.customVersion'), value: 'custom', disabled: !custom && (previewing || !preview) },
]"
:disabled="disabled"
/>
@@ -146,37 +151,37 @@ const userAgent = computed({
{{ currentPreset.reason }}
</p>
<div v-if="!custom" class="grid gap-4 sm:grid-cols-2">
<ZFormItem label="版本滞后" :error="versionLagError">
<ZFormItem :label="t('settings.clientProfile.versionLag')" :error="versionLagError">
<ZInput
v-model="versionLag"
aria-label="版本滞后"
:aria-label="t('settings.clientProfile.versionLag')"
type="number"
inputmode="numeric"
min="1"
:max="maxVersionLag"
step="1"
:placeholder="`滞后 1~${maxVersionLag} 个版本,留空不滞后`"
:placeholder="t('settings.clientProfile.versionLagHelp', { version: maxVersionLag })"
:disabled="disabled"
/>
</ZFormItem>
<div class="grid gap-4" :class="{ 'sm:grid-cols-2': preset?.client === 'desktop' }">
<ZFormItem label="终端标识">
<ZFormItem :label="t('settings.clientProfile.terminalIdentification')">
<ZInput
v-model="terminal"
:disabled="disabled"
aria-label="终端标识"
placeholder="留空使用 unknown"
:aria-label="t('settings.clientProfile.terminalIdentification')"
:placeholder="t('settings.clientProfile.leaveBlankToUseUnknown')"
maxlength="128"
spellcheck="false"
autocomplete="off"
class="font-mono"
/>
</ZFormItem>
<ZFormItem v-if="preset?.client === 'desktop'" label="系统版本">
<ZFormItem v-if="preset?.client === 'desktop'" :label="t('settings.clientProfile.systemVersion')">
<ZInput
v-model="osVersion"
:disabled="disabled"
aria-label="系统版本"
:aria-label="t('settings.clientProfile.systemVersion')"
:placeholder="currentPreset?.defaults.osVersion ?? undefined"
maxlength="128"
spellcheck="false"
@@ -191,8 +196,8 @@ const userAgent = computed({
v-model="userAgent"
:rows="3"
:disabled="disabled || (!model?.mode && previewing)"
aria-label="用户代理"
placeholder="填写完整用户代理"
:aria-label="t('settings.clientProfile.userAgent')"
:placeholder="t('settings.clientProfile.userAgentPlaceholder')"
spellcheck="false"
autocomplete="off"
class="font-mono"
@@ -1,6 +1,8 @@
<script setup lang="ts">
import type { ClientProfilePreview } from '@/api/modules/settings/profiles'
import { ZEmpty, ZSkeleton } from '@codex-proxy/ui'
import { useI18n } from 'vue-i18n'
defineProps<{
preview?: Pick<ClientProfilePreview, 'userAgent' | 'versionSource' | 'checkedAtDisplay' | 'error'> & { versionLag?: number | null }
@@ -8,13 +10,15 @@ defineProps<{
needsVersionInput: boolean
error: string
}>()
const { t } = useI18n({ useScope: 'global' })
</script>
<template>
<p v-if="needsVersionInput" role="status" class="m-0 text-cp-sm text-cp-text-tertiary">
填写版本后预览
{{ t('settings.clientProfile.previewAfterFillingInVersion') }}
</p>
<ZEmpty v-else-if="error && !previewing" title="预览暂不可用" :description="error" size="small" surface="none" role="alert" />
<ZEmpty v-else-if="error && !previewing" :title="t('settings.clientProfile.previewIsNotAvailableYet')" :description="error" size="small" surface="none" role="alert" />
<div
v-else-if="previewing || preview"
class="grid min-h-20 min-w-0 content-center gap-2 rounded-cp bg-cp-fill-quaternary p-4"
@@ -22,7 +26,7 @@ defineProps<{
:aria-busy="previewing"
>
<template v-if="previewing">
<div class="flex h-lh items-center text-cp-sm" role="status" aria-label="正在解析客户端身份">
<div class="flex h-lh items-center text-cp-sm" role="status" :aria-label="t('settings.clientProfile.resolvingClientIdentity')">
<ZSkeleton shape="text" class="w-4/5" aria-hidden="true" />
</div>
<div class="flex h-lh items-center text-cp-xs" aria-hidden="true">
@@ -32,16 +36,16 @@ defineProps<{
<template v-else-if="preview">
<code class="break-all text-cp-sm text-cp-text">{{ preview.userAgent }}</code>
<p class="m-0 text-cp-xs text-cp-text-tertiary">
{{ preview.versionSource === 'custom' ? '固定身份' : '自动更新' }}
{{ preview.versionSource === 'custom' ? t('settings.clientProfile.fixedIdentity') : t('settings.clientProfile.automaticUpdates') }}
<template v-if="preview.versionSource === 'official'">
<template v-if="preview.versionLag">
· 滞后 {{ preview.versionLag }} 版
{{ t('settings.clientProfile.versionsBehind', { version: preview.versionLag }) }}
</template>
· {{ preview.checkedAtDisplay ? `检查于 ${preview.checkedAtDisplay}` : '待检查' }}
· {{ preview.checkedAtDisplay ? t('settings.clientProfile.checked', { checkedAtDisplay: preview.checkedAtDisplay }) : t('settings.clientProfile.toBeChecked') }}
</template>
</p>
<p v-if="preview.error && preview.versionSource !== 'custom'" :title="preview.error" class="m-0 text-cp-sm text-cp-warning">
更新失败 · 沿用上次版本
{{ t('settings.clientProfile.updateFailedUseLastVersion') }}
</p>
</template>
</div>
@@ -1,7 +1,9 @@
<script setup lang="ts">
import type { ClientProfileSelection, ProviderRequestProfile, ProviderRequestProfiles, XaiClientProfileSelection } from '@/api/modules/settings/profiles'
import { ZSegmented } from '@codex-proxy/ui'
import { computed, shallowRef } from 'vue'
import { useI18n } from 'vue-i18n'
import { formatProviderLabel, PROVIDER_IDS, providerIcon } from '@/utils/providers'
import ClientProfileEditor from './ClientProfileEditor.vue'
import XaiClientProfileEditor from './XaiClientProfileEditor.vue'
@@ -16,6 +18,8 @@ withDefaults(defineProps<{
allowInherit: false,
})
const { t } = useI18n({ useScope: 'global' })
const model = defineModel<ProviderRequestProfiles>({ required: true })
const provider = shallowRef<(typeof PROVIDER_IDS)[number]>('openai')
const providerOptions = PROVIDER_IDS.map(value => ({
@@ -51,7 +55,7 @@ function updateProfile(providerId: string, value: ProviderRequestProfile | null)
<ZSegmented
v-model="provider"
class="ml-auto max-w-full shrink-0"
aria-label="客户端身份 Provider"
:aria-label="t('settings.clientProfile.clientIdentityProvider')"
:options="providerOptions"
:disabled="disabled"
:style="providerSelectorStyle"
@@ -69,7 +73,7 @@ function updateProfile(providerId: string, value: ProviderRequestProfile | null)
<ZSegmented
v-model="provider"
class="max-w-full shrink-0"
aria-label="上游身份平台"
:aria-label="t('settings.clientProfile.upstreamIdentityPlatform')"
:options="providerOptions"
:disabled="disabled"
:style="providerSelectorStyle"
@@ -88,7 +92,7 @@ function updateProfile(providerId: string, value: ProviderRequestProfile | null)
<ZSegmented
v-model="provider"
class="max-w-full shrink-0"
aria-label="上游身份平台"
:aria-label="t('settings.clientProfile.upstreamIdentityPlatform')"
:options="providerOptions"
:disabled="disabled"
:style="providerSelectorStyle"
@@ -1,7 +1,9 @@
<script setup lang="ts">
import type { XaiClientProfilePreview, XaiClientProfileSelection } from '@/api/modules/settings/profiles'
import { ZButton, ZEmpty, ZFormItem, ZInput, ZSegmented, ZSelect } from '@codex-proxy/ui'
import { computed, onMounted, shallowRef, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { getXaiClientProfileOptions, previewXaiClientProfile } from '@/api/modules/settings/profiles'
import { errorMessage } from '@/utils/operation'
import ClientProfilePreviewPanel from './ClientProfilePreviewPanel.vue'
@@ -11,6 +13,9 @@ const props = withDefaults(defineProps<{ active?: boolean, disabled?: boolean, a
disabled: false,
allowInherit: false,
})
const { t } = useI18n({ useScope: 'global' })
const model = defineModel<XaiClientProfileSelection | null>({ required: true })
const globalConfiguration = shallowRef<XaiClientProfileSelection>()
const preview = shallowRef<XaiClientProfilePreview>()
@@ -18,12 +23,12 @@ const loadError = shallowRef('')
const previewError = shallowRef('')
const previewing = shallowRef(false)
const needsVersionInput = computed(() => model.value?.versionMode === 'fixed' && !model.value.clientVersion)
const fields = [
{ key: 'clientIdentifier', label: '客户端标识' },
{ key: 'clientMode', label: '运行模式' },
{ key: 'targetOs', label: '操作系统' },
{ key: 'targetArch', label: 'CPU 架构' },
] as const
const fields = computed(() => ([
{ key: 'clientIdentifier', label: t('settings.clientProfile.clientId') },
{ key: 'clientMode', label: t('settings.clientProfile.operatingMode') },
{ key: 'targetOs', label: t('settings.clientProfile.operatingSystem') },
{ key: 'targetArch', label: t('settings.clientProfile.cpuArchitecture') },
] as const))
const source = computed({
get: () => model.value === null ? 'global' : 'independent',
@@ -100,32 +105,32 @@ onMounted(() => props.allowInherit && void load())
<div v-if="allowInherit" class="flex flex-wrap items-center justify-between gap-3">
<ZSegmented
v-model="source"
aria-label="xAI 客户端身份来源"
:aria-label="t('settings.clientProfile.xaiClientIdentitySource')"
class="shrink-0"
:options="[{ label: '全局配置', value: 'global' }, { label: '独立配置', value: 'independent' }]"
:options="[{ label: t('settings.clientProfile.globalConfiguration'), value: 'global' }, { label: t('settings.clientProfile.customConfiguration'), value: 'independent' }]"
:disabled="disabled || !globalConfiguration"
/>
<slot name="source-extra" />
</div>
<ZEmpty v-if="loadError" title="全局配置加载失败" :description="loadError" size="small" surface="none" role="alert">
<ZEmpty v-if="loadError" :title="t('settings.clientProfile.loadFailed')" :description="loadError" size="small" surface="none" role="alert">
<template #action>
<ZButton size="small" @click="load">
重试
{{ t('common.actions.retry') }}
</ZButton>
</template>
</ZEmpty>
<template v-if="model">
<div class="grid gap-4 sm:grid-cols-2">
<ZFormItem label="客户端类型">
<ZFormItem :label="t('settings.clientProfile.clientType')">
<ZInput model-value="Grok CLI" readonly :disabled="disabled" />
</ZFormItem>
<ZFormItem label="版本策略">
<ZSelect v-model="versionMode" class="w-full" :disabled="disabled" :options="[{ label: '跟随最新版本', value: 'latest' }, { label: '自定义版本', value: 'fixed' }]" />
<ZFormItem :label="t('settings.clientProfile.versionStrategy')">
<ZSelect v-model="versionMode" class="w-full" :disabled="disabled" :options="[{ label: t('settings.clientProfile.followLatestVersion'), value: 'latest' }, { label: t('settings.clientProfile.customVersion'), value: 'fixed' }]" />
</ZFormItem>
</div>
<div v-if="model.versionMode === 'fixed'" class="grid gap-4 sm:grid-cols-2">
<ZFormItem label="Grok CLI 版本" required>
<ZInput :model-value="model.clientVersion ?? ''" :disabled="disabled" placeholder="例如:1.0.13" @update:model-value="updateField('clientVersion', $event)" />
<ZFormItem :label="t('settings.clientProfile.grokCliVersion')" required>
<ZInput :model-value="model.clientVersion ?? ''" :disabled="disabled" :placeholder="t('settings.clientProfile.forExample')" @update:model-value="updateField('clientVersion', $event)" />
</ZFormItem>
<ZFormItem v-for="field in fields" :key="field.key" :label="field.label" required>
<ZInput :model-value="model[field.key]" :disabled="disabled" @update:model-value="updateField(field.key, $event)" />
+11 -6
View File
@@ -1,8 +1,10 @@
<script setup lang="ts">
import type { InputField } from './schema'
import { ZForm, ZFormItem, ZIconButton, ZInput, ZPopover, ZSelect, ZTextarea } from '@codex-proxy/ui'
import { Braces, Info, List } from '@lucide/vue'
import { computed, nextTick, shallowRef, useTemplateRef } from 'vue'
import { useI18n } from 'vue-i18n'
import { parseJsonObject } from '@/utils/data'
import { inputFields } from './schema'
@@ -12,6 +14,9 @@ const props = defineProps<{
maximumBytes?: number
fieldErrors?: Record<string, string>
}>()
const { t } = useI18n({ useScope: 'global' })
const text = defineModel<string>({ required: true })
const jsonMode = shallowRef(false)
const root = useTemplateRef<HTMLElement>('root')
@@ -49,8 +54,8 @@ function inputValue(key: string) {
function fieldOptions(field: InputField) {
const options = field.values
? field.values.map((item, index) => ({ value: String(index), label: String(item) }))
: [{ value: 'true', label: '是' }, { value: 'false', label: '否' }]
return [{ value: '', label: '未填写' }, ...options]
: [{ value: 'true', label: t('common.values.yes') }, { value: 'false', label: t('common.values.no') }]
return [{ value: '', label: t('common.values.unspecified') }, ...options]
}
function update(field: InputField, input: string) {
@@ -95,9 +100,9 @@ defineExpose({ focusField })
<template>
<div v-if="!empty" ref="root" class="grid gap-3">
<ZForm v-if="showJson">
<ZFormItem label="输入内容" :error="error">
<ZFormItem :label="t('common.form.inputPlaceholder')" :error="error">
<template #extra>
<ZIconButton v-if="fields !== null" aria-label="使用表单" size="small" variant="solid" :disabled="disabled || Boolean(error) || hasExtra || incompatibleValue" @click="jsonMode = false">
<ZIconButton v-if="fields !== null" :aria-label="t('common.form.useForm')" size="small" variant="solid" :disabled="disabled || Boolean(error) || hasExtra || incompatibleValue" @click="jsonMode = false">
<List class="size-4" />
</ZIconButton>
</template>
@@ -115,7 +120,7 @@ defineExpose({ focusField })
<template v-if="field.description" #label-extra>
<ZPopover trigger="hover-click" placement="top-start">
<template #reference>
<ZIconButton :aria-label="`${field.label}说明`" class="size-3.5!" :title="undefined">
<ZIconButton :aria-label="t('common.form.fieldHelp', { label: field.label })" class="size-3.5!" :title="undefined">
<Info class="size-3.5" />
</ZIconButton>
</template>
@@ -125,7 +130,7 @@ defineExpose({ focusField })
</ZPopover>
</template>
<template v-if="index === 0" #extra>
<ZIconButton aria-label="编辑 JSON" size="small" variant="solid" :disabled="disabled" @click="jsonMode = true">
<ZIconButton :aria-label="t('common.form.editJson')" size="small" variant="solid" :disabled="disabled" @click="jsonMode = true">
<Braces class="size-4" />
</ZIconButton>
</template>
@@ -2,37 +2,41 @@
import type { DashboardHealthTimelinePoint } from '@/api'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { formatHealthCount, healthEligibleRequestCount, healthObservedRequestCount, healthServiceFailureCount, healthStatusMeta } from '@/components/usage/shared/health'
const props = defineProps<{
point: DashboardHealthTimelinePoint
}>()
const status = computed(() => healthStatusMeta[props.point.status])
const { t } = useI18n({ useScope: 'global' })
const status = computed(() => healthStatusMeta.value[props.point.status])
const eligibleRequests = computed(() => healthEligibleRequestCount(props.point))
const observedRequests = computed(() => healthObservedRequestCount(props.point))
// 结果标签、取值与配色集中维护,分段条与明细行都由此派生
const outcomeMeta = computed(() => [
{
label: '成功',
label: t('common.status.success'),
value: props.point.successRequests,
dotClass: 'bg-cp-success',
valueClass: 'text-cp-success-text',
},
{
label: '服务失败',
label: t('usage.health.point.serviceFailed'),
value: healthServiceFailureCount(props.point),
dotClass: 'bg-cp-error',
valueClass: 'text-cp-error-text',
},
{
label: '客户端取消',
label: t('usage.health.point.clientCancel'),
value: props.point.cancelledRequests,
dotClass: 'bg-cp-orange-solid',
valueClass: 'text-cp-orange-text',
},
{
label: '调用方错误',
label: t('usage.health.point.callerError'),
value: props.point.callerErrorRequests,
dotClass: 'bg-cp-info',
valueClass: 'text-cp-info-text',
@@ -57,7 +61,7 @@ const metricItems = outcomeMeta
<template>
<section
role="dialog"
:aria-label="`${point.time} 请求健康详情`"
:aria-label="t('usage.health.point.requestHealthDetailsFor', { time: point.time })"
class="overflow-hidden rounded-cp-lg bg-cp-bg-elevated"
>
<header class="flex items-center justify-between gap-3 bg-cp-popover-header-bg px-3.5 py-3">
@@ -73,14 +77,14 @@ const metricItems = outcomeMeta
{{ status.label }}
</span>
</div>
<span class="shrink-0 text-[10px] leading-none font-emphasis text-cp-text-quaternary"> 15 分钟 </span>
<span class="shrink-0 text-[10px] leading-none font-emphasis text-cp-text-quaternary"> {{ t('usage.health.point.minutes') }} </span>
</header>
<div class="grid gap-3.5 px-3.5 py-3.5">
<div class="flex items-end justify-between gap-4">
<div>
<p class="m-0 text-cp-xs leading-none font-emphasis text-cp-text-quaternary">
有效请求可用性
{{ t('usage.health.point.validRequestAvailability') }}
</p>
<strong
class="mt-2 block font-mono text-[25px] leading-none font-heavy tabular-nums"
@@ -90,7 +94,7 @@ const metricItems = outcomeMeta
</strong>
</div>
<div class="text-right">
<span class="block text-[10px] leading-none font-emphasis text-cp-text-quaternary"> 有效请求 </span>
<span class="block text-[10px] leading-none font-emphasis text-cp-text-quaternary"> {{ t('usage.health.point.validRequest') }} </span>
<strong class="mt-2 block font-mono text-cp-xl leading-none font-heavy tabular-nums text-cp-text">
{{ formatHealthCount(eligibleRequests) }}
</strong>
@@ -1,10 +1,12 @@
<script setup lang="ts">
import type { DashboardHealthTimeline, DashboardHealthTimelinePoint } from '@/api'
import { ZButton, ZCard, ZPopover } from '@codex-proxy/ui'
import { ZButton, ZCard, ZPopover } from '@codex-proxy/ui'
import { usePreferredReducedMotion, useResizeObserver } from '@vueuse/core'
import { gsap } from 'gsap'
import { computed, onBeforeUnmount, shallowRef, useTemplateRef, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import HealthTimelinePointPopover from '@/components/usage/HealthTimelinePointPopover.vue'
import { formatHealthCount, healthEligibleRequestCount, healthLegend, healthObservedRequestCount, healthStatusMeta } from '@/components/usage/shared/health'
@@ -12,6 +14,8 @@ const props = defineProps<{
timeline: DashboardHealthTimeline
}>()
const { t } = useI18n({ useScope: 'global' })
const healthPopoverArrowSurfaceClasses = {
top: 'bg-cp-popover-header-bg',
bottom: 'bg-cp-bg-elevated',
@@ -193,7 +197,7 @@ function releasePointWave() {
function pointAccessibilityLabel(point: DashboardHealthTimelinePoint) {
const eligibleRequests = healthEligibleRequestCount(point)
return `${point.time},${healthStatusMeta[point.status].label},有效请求 ${formatHealthCount(eligibleRequests)},可用性 ${point.reliabilityDisplay}`
return t('usage.health.validRequestsAvailability', { time: point.time, label: healthStatusMeta.value[point.status].label, count: formatHealthCount(eligibleRequests), reliabilityDisplay: point.reliabilityDisplay })
}
watch(popoverOpen, (open) => {
@@ -222,7 +226,7 @@ onBeforeUnmount(() => {
</script>
<template>
<ZCard as="article" :title="timeline.title" :description="timeline.description" class="w-full">
<ZCard as="article" :title="t('dashboard.health.title')" :description="t('dashboard.health.description')" class="w-full">
<template #actions>
<div class="flex w-full flex-wrap items-center justify-between gap-x-4 gap-y-2">
<div
@@ -2,7 +2,9 @@
import type { UsageListRecord } from '@/api'
import { Zap } from '@lucide/vue'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import UsageDetailPopover from '@/components/usage/UsageDetailPopover.vue'
import { usageBillingText } from './shared/presenter'
@@ -10,6 +12,8 @@ const props = defineProps<{
record: Pick<UsageListRecord, 'billing'>
}>()
const { t } = useI18n({ useScope: 'global' })
const billing = computed(() => props.record.billing)
const billingItems = computed(() => {
const value = billing.value
@@ -17,10 +21,10 @@ const billingItems = computed(() => {
return []
return [
{ label: '服务档位', value: value.serviceTierDisplay, tone: 'info' },
{ label: '倍率', value: value.multiplierDisplay, tone: 'info' },
{ label: '总费用', value: value.totalAmountDisplay, tone: 'success' },
{ label: '标准费用', value: value.standardAmountDisplay, tone: 'default' },
{ label: t('usage.billing.serviceLevel'), value: value.serviceTierDisplay, tone: 'info' },
{ label: t('settings.pricing.multiplier'), value: value.multiplierDisplay, tone: 'info' },
{ label: t('usage.billing.totalCost'), value: value.totalAmountDisplay, tone: 'success' },
{ label: t('usage.billing.standardFee'), value: value.standardAmountDisplay, tone: 'default' },
]
})
@@ -30,21 +34,21 @@ const amountItems = computed(() => {
return []
return [
{ label: value.image ? '文本输入费用' : '输入费用', value: value.inputAmountDisplay, accent: false },
{ label: value.image ? t('usage.billing.textInputCost') : t('usage.billing.inputCost'), value: value.inputAmountDisplay, accent: false },
...(value.image
? [
{ label: '图像输入费用', value: value.image.inputAmountDisplay, accent: false },
{ label: '图像缓存费用', value: value.image.cacheReadAmountDisplay, accent: false },
{ label: '图像输入单价', value: value.image.inputPriceDisplay, accent: true },
{ label: '图像缓存单价', value: value.image.cacheReadPriceDisplay, accent: true },
{ label: t('usage.billing.imageInputFee'), value: value.image.inputAmountDisplay, accent: false },
{ label: t('usage.billing.imageCachingCharges'), value: value.image.cacheReadAmountDisplay, accent: false },
{ label: t('usage.billing.imageInputUnitPrice'), value: value.image.inputPriceDisplay, accent: true },
{ label: t('usage.billing.imageCacheUnitPrice'), value: value.image.cacheReadPriceDisplay, accent: true },
]
: []),
{ label: value.image ? '图像输出费用' : '输出费用', value: value.outputAmountDisplay, accent: false },
{ label: value.image ? '文本输入单价' : '输入单价', value: value.inputPriceDisplay, accent: true },
{ label: value.image ? '图像输出单价' : '输出单价', value: value.outputPriceDisplay, accent: true },
{ label: value.image ? '文本缓存读取费用' : '缓存读取费用', value: value.cacheReadAmountDisplay, accent: false },
{ label: '缓存写入费用', value: value.cacheWriteAmountDisplay, accent: false },
{ label: '缓存写入单价', value: value.cacheWritePriceDisplay, accent: true },
{ label: value.image ? t('usage.billing.imageOutputFee') : t('usage.billing.outputFee'), value: value.outputAmountDisplay, accent: false },
{ label: value.image ? t('usage.billing.textInputUnitPrice') : t('usage.billing.inputUnitPrice'), value: value.inputPriceDisplay, accent: true },
{ label: value.image ? t('usage.billing.imageOutputUnitPrice') : t('usage.billing.outputUnitPrice'), value: value.outputPriceDisplay, accent: true },
{ label: value.image ? t('usage.billing.textCacheReadCost') : t('usage.billing.cacheReadCost'), value: value.cacheReadAmountDisplay, accent: false },
{ label: t('usage.billing.cacheWriteCost'), value: value.cacheWriteAmountDisplay, accent: false },
{ label: t('usage.billing.cacheWriteUnitPrice'), value: value.cacheWritePriceDisplay, accent: true },
]
})
@@ -67,15 +71,15 @@ function itemValueClass(tone?: string, accent?: boolean) {
<span
v-if="billing.serviceTierDisplay === 'Fast'"
class="inline-flex size-4 items-center justify-center rounded-full bg-cp-warning-container text-cp-warning-on-container"
title="Fast 模式"
:title="t('usage.billing.fastMode')"
role="img"
aria-label="Fast 模式"
:aria-label="t('usage.billing.fastMode')"
>
<Zap class="size-3" stroke-width="2.2" aria-hidden="true" />
</span>
<UsageDetailPopover
:title="billing.longContextBillingApplied ? '长上下文计费明细' : '计费明细'"
:trigger-label="billing.longContextBillingApplied ? '查看长上下文计费明细' : '查看费用明细'"
:title="billing.longContextBillingApplied ? t('usage.billing.longContextBillingDetails') : t('usage.billing.billingDetails')"
:trigger-label="billing.longContextBillingApplied ? t('usage.billing.viewLongContextBillingDetails') : t('usage.billing.viewCostDetails')"
:tone="billing.longContextBillingApplied ? 'warning' : 'primary'"
>
<div class="grid gap-1.5 text-cp-text-secondary">
@@ -29,7 +29,7 @@ defineProps<{
</button>
</template>
<div class="grid w-60 gap-2 p-3 text-cp-sm leading-none">
<div class="grid w-max min-w-60 max-w-[calc(100vw-2rem)] gap-2 p-3 text-cp-sm leading-none">
<p v-if="title" class="m-0 font-heavy text-cp-text">
{{ title }}
</p>
@@ -2,6 +2,8 @@
import type { UsageListRecord } from '@/api'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import UsageDetailPopover from '@/components/usage/UsageDetailPopover.vue'
import { usageLatencyDetails } from './shared/presenter'
@@ -9,6 +11,8 @@ const props = defineProps<{
record: Pick<UsageListRecord, 'latencyDetails' | 'firstTokenLatencyMs' | 'latencyMs'>
}>()
const { t } = useI18n({ useScope: 'global' })
const latencyDetails = computed(() => usageLatencyDetails(props.record))
const latencyTones = {
@@ -25,17 +29,17 @@ const latencyTones = {
<div
class="grid grid-cols-[auto_auto] items-center justify-end gap-x-2 gap-y-1.5 whitespace-nowrap font-mono text-cp-sm leading-none font-heavy tabular-nums"
>
<span class="text-cp-xs text-cp-text-quaternary">首字</span>
<span class="text-cp-xs text-cp-text-quaternary">{{ t('usage.ttft') }}</span>
<span :class="latencyDetails.firstOutputSeverity === null ? 'text-cp-text-quaternary' : latencyTones[latencyDetails.firstOutputSeverity]">
{{ latencyDetails.firstOutputDisplay }}
</span>
<span class="text-cp-xs text-cp-text-quaternary">总耗时</span>
<span class="text-cp-xs text-cp-text-quaternary">{{ t('usage.latency.total') }}</span>
<span :class="latencyDetails.totalSeverity === null ? 'text-cp-text-quaternary' : latencyTones[latencyDetails.totalSeverity]">
{{ latencyDetails.totalDisplay }}
</span>
</div>
<UsageDetailPopover trigger-label="查看延迟明细">
<UsageDetailPopover :trigger-label="t('usage.latency.viewLatencyDetails')">
<section
v-for="(section, index) in latencyDetails.sections"
:key="section.title"
@@ -50,7 +54,7 @@ const latencyTones = {
? 'bg-cp-primary-container text-cp-primary-on-container'
: 'bg-cp-fill-tertiary text-cp-text-tertiary'"
>
{{ section.source === 'official' ? '官方' : '本地' }}
{{ section.source === 'official' ? t('usage.latency.official') : t('usage.latency.local') }}
</span>
</p>
<div
@@ -4,6 +4,7 @@ import type { UsageModelRecord } from './shared/presenter'
import { CornerDownRight } from '@lucide/vue'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { usageModelDisplay } from './shared/presenter'
const props = defineProps<{
@@ -11,13 +12,14 @@ const props = defineProps<{
}>()
const modelDisplay = computed(() => usageModelDisplay(props.record))
const { t } = useI18n({ useScope: 'global' })
</script>
<template>
<div class="inline-grid max-w-full gap-1">
<code
class="block max-w-full truncate font-mono text-cp-sm leading-none font-heavy text-cp-text"
:title="`请求模型:${modelDisplay.primary}`"
:title="t('usage.status.requestedModel', { model: modelDisplay.primary })"
>
{{ modelDisplay.primary }}
</code>
@@ -2,12 +2,16 @@
import type { UsagePerformanceRecord } from './shared/presenter'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { usagePerformanceDetails } from './shared/presenter'
const props = defineProps<{
record: UsagePerformanceRecord
}>()
const { t } = useI18n({ useScope: 'global' })
const performance = computed(() => usagePerformanceDetails(props.record))
</script>
@@ -15,7 +19,7 @@ const performance = computed(() => usagePerformanceDetails(props.record))
<div class="grid justify-items-end gap-y-1.5 whitespace-nowrap font-mono text-cp-sm leading-none font-heavy tabular-nums">
<span class="text-cp-text">{{ performance.throughputDisplay }}</span>
<span class="text-cp-xs text-cp-text-secondary">
<span title="首字时间" class="text-cp-text-quaternary">TTFT</span>
<span :title="t('usage.performance.ttftHelp')" class="text-cp-text-quaternary">TTFT</span>
{{ performance.firstTokenDisplay }}
</span>
</div>
@@ -2,11 +2,15 @@
import type { UsageReasoningRecord } from './shared/presenter'
import { Bot, SquareDashedBottomCode } from '@lucide/vue'
import { useI18n } from 'vue-i18n'
import { usageReasoningEffort } from './shared/presenter'
defineProps<{
record: UsageReasoningRecord
}>()
const { t } = useI18n({ useScope: 'global' })
</script>
<template>
@@ -17,16 +21,16 @@ defineProps<{
<span
v-if="record.subagentKind"
class="inline-flex shrink-0 text-cp-purple-text"
title="子代理请求"
aria-label="子代理请求"
:title="t('usage.reasoning.subagentRequest')"
:aria-label="t('usage.reasoning.subagentRequest')"
>
<Bot class="size-3.5" stroke-width="2.2" />
</span>
<span
v-if="record.subagentKind === 'review'"
class="inline-flex shrink-0 text-cp-purple-text"
title="Review 子代理请求"
aria-label="Review 子代理请求"
:title="t('usage.reasoning.reviewSubagentRequest')"
:aria-label="t('usage.reasoning.reviewSubagentRequest')"
>
<SquareDashedBottomCode class="size-3.25" stroke-width="2.2" />
</span>
@@ -1,16 +1,22 @@
<script setup lang="ts">
import type { UsageRecordStatus } from '@/api/modules/usage'
import { ZSegmented } from '@codex-proxy/ui'
import { CloudRain, List, Sun } from '@lucide/vue'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
const { t } = useI18n({ useScope: 'global' })
const model = defineModel<UsageRecordStatus>({ required: true })
const options = [
{ label: '成功', value: 'success', icon: Sun },
{ label: '错误', value: 'error', icon: CloudRain },
{ label: '全部', value: 'all', icon: List },
]
const options = computed(() => ([
{ label: t('common.status.success'), value: 'success', icon: Sun },
{ label: t('usage.filters.error'), value: 'error', icon: CloudRain },
{ label: t('common.values.all'), value: 'all', icon: List },
]))
</script>
<template>
<ZSegmented v-model="model" aria-label="请求明细类型" :options="options" display="icon" class="w-30 shrink-0" />
<ZSegmented v-model="model" :aria-label="t('usage.filters.requestDetailType')" :options="options" display="icon" class="w-30 shrink-0" />
</template>
@@ -1,8 +1,10 @@
<script setup lang="ts">
import type { TableColumn } from '@codex-proxy/ui'
import type { UsageListRecord } from '@/api'
import type { UsageListRecord } from '@/api'
import { ZTable } from '@codex-proxy/ui'
import { useI18n } from 'vue-i18n'
import AccountPlanBadge from '@/components/account/AccountPlanBadge.vue'
import ProviderIconGroup from '@/components/ProviderIconGroup.vue'
import UsageBillingCell from '@/components/usage/UsageBillingCell.vue'
@@ -30,9 +32,10 @@ withDefaults(
}>(),
{
loading: false,
emptyText: '暂无使用记录',
},
)
const { t } = useI18n({ useScope: 'global' })
</script>
<template>
@@ -40,7 +43,7 @@ withDefaults(
:columns="columns"
:data="rows"
:loading="loading"
:empty-text="emptyText"
:empty-text="emptyText ?? t('usage.noUsageRecords')"
>
<template #clientApiKeyName="{ displayValue }">
<span
@@ -113,7 +116,7 @@ withDefaults(
<template #errorMessage="{ row }">
<div class="min-w-0 py-0.5" :title="row.errorMessage || row.errorCode || undefined">
<code class="block truncate font-mono text-cp-sm font-bold text-cp-error-text">
{{ row.errorCode || (row.logicalOutcome === 'incomplete' ? '响应未完成' : '请求失败') }}
{{ row.errorCode || (row.logicalOutcome === 'incomplete' ? t('usage.error.responseIsNotComplete') : t('usage.error.requestFailed')) }}
</code>
<p v-if="row.errorMessage" class="mt-1 mb-0 truncate text-cp-xs leading-[1.45] font-emphasis text-cp-text-secondary">
{{ row.errorMessage }}
@@ -1,7 +1,11 @@
<script setup lang="ts">
import { Minimize2 } from '@lucide/vue'
import { useI18n } from 'vue-i18n'
defineProps<{ record: { route: string | null, compact?: boolean } }>()
const { t } = useI18n({ useScope: 'global' })
</script>
<template>
@@ -10,8 +14,8 @@ defineProps<{ record: { route: string | null, compact?: boolean } }>()
<span
v-if="record.compact"
class="inline-flex shrink-0 text-cp-orange-text"
title="压缩请求"
aria-label="压缩请求"
:title="t('usage.route.compressionRequest')"
:aria-label="t('usage.route.compressionRequest')"
>
<Minimize2 class="size-3.5" stroke-width="2.4" />
</span>
@@ -4,6 +4,8 @@ import type { UsageListRecord } from '@/api'
import { Archive, ArrowDown, ArrowUp } from '@lucide/vue'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { usageTokenDetails } from '@/components/usage/shared/presenter'
import UsageDetailPopover from '@/components/usage/UsageDetailPopover.vue'
@@ -11,13 +13,15 @@ const props = defineProps<{
record: Pick<UsageListRecord, 'tokenDetails'>
}>()
const { t } = useI18n({ useScope: 'global' })
const tokenDetails = computed(() => usageTokenDetails(props.record.tokenDetails))
const tokenItems = computed(() => [
{ label: '输入 Token', value: tokenDetails.value.inputTokensDisplay },
{ label: '输出 Token', value: tokenDetails.value.outputTokensDisplay },
{ label: '缓存读取 Token', value: tokenDetails.value.cachedInputTokensDisplay },
{ label: '缓存写入 Token', value: tokenDetails.value.cacheWriteInputTokensDisplay },
{ label: '推理 Token', value: tokenDetails.value.reasoningOutputTokensDisplay },
{ label: t('usage.tokens.enterToken'), value: tokenDetails.value.inputTokensDisplay },
{ label: t('usage.tokens.outputToken'), value: tokenDetails.value.outputTokensDisplay },
{ label: t('usage.tokens.cacheReadTokens'), value: tokenDetails.value.cachedInputTokensDisplay },
{ label: t('usage.tokens.cacheWriteTokens'), value: tokenDetails.value.cacheWriteInputTokensDisplay },
{ label: t('usage.tokens.reasoningToken'), value: tokenDetails.value.reasoningOutputTokensDisplay },
])
</script>
@@ -40,7 +44,7 @@ const tokenItems = computed(() => [
</span>
</div>
<UsageDetailPopover title="Token 明细" trigger-label="查看 Token 明细">
<UsageDetailPopover :title="t('usage.tokens.tokenDetails')" :trigger-label="t('usage.tokens.viewTokenDetails')">
<div class="grid gap-1.5 text-cp-text-secondary">
<div v-for="item in tokenItems" :key="item.label" class="flex justify-between gap-4">
<span class="whitespace-nowrap">{{ item.label }}</span>
@@ -50,7 +54,7 @@ const tokenItems = computed(() => [
</div>
</div>
<div class="mt-1 flex justify-between border-t border-cp-split pt-2">
<span class="whitespace-nowrap text-cp-text-secondary">总 Token</span>
<span class="whitespace-nowrap text-cp-text-secondary">{{ t('usage.tokens.totalTokens') }}</span>
<span class="whitespace-nowrap font-mono font-heavy text-cp-info-text">
{{ tokenDetails.totalTokensDisplay }}
</span>
+21 -19
View File
@@ -1,41 +1,43 @@
import type { TableColumn } from '@codex-proxy/ui'
import type { UsageListRecord } from '@/api'
import { defineTableColumns } from '@codex-proxy/ui'
import { computed } from 'vue'
import { t } from '@/i18n'
import { formatProviderLabel } from '@/utils/providers'
export const usageDataColumns = [
{ key: 'model', label: '模型', kind: 'custom', size: 'xl' },
{ key: 'reasoningEffort', label: '推理强度', kind: 'status', size: 'md', align: 'left' },
{ key: 'route', label: '端点', kind: 'mono' },
{ key: 'upstreamTransport', label: '上游', kind: 'status', size: 'md' },
{ key: 'clientTransport', label: '接入', kind: 'status', size: 'md' },
export const usageDataColumns = computed(() => ([
{ key: 'model', label: t('usage.fields.model'), kind: 'custom', size: 'xl' },
{ key: 'reasoningEffort', label: t('usage.fields.reasoningEffort'), kind: 'status', size: 'md', align: 'left' },
{ key: 'route', label: t('usage.fields.endpoint'), kind: 'mono' },
{ key: 'upstreamTransport', label: t('usage.fields.upstream'), kind: 'status', size: 'md' },
{ key: 'clientTransport', label: t('usage.fields.access'), kind: 'status', size: 'md' },
{ key: 'tokenDetails', label: 'TOKEN', kind: 'numeric', size: 'xl' },
{ key: 'billing', label: '费用', kind: 'numeric', size: 'xl' },
{ key: 'latency', label: '延迟', kind: 'numeric', size: 'xl' },
{ key: 'performance', label: '速率', kind: 'numeric', size: 'lg' },
{ key: 'createdAtDisplay', label: '时间', kind: 'datetime' },
{ key: 'billing', label: t('usage.fields.cost'), kind: 'numeric', size: 'xl' },
{ key: 'latency', label: t('usage.fields.latency'), kind: 'numeric', size: 'xl' },
{ key: 'performance', label: t('usage.outputThroughput'), kind: 'numeric', size: 'lg' },
{ key: 'createdAtDisplay', label: t('usage.fields.time'), kind: 'datetime' },
{ key: 'clientIp', label: 'IP', kind: 'custom', size: '3xl' },
{ key: 'userAgent', label: 'User-Agent', kind: 'custom', size: '4xl' },
] satisfies TableColumn[]
] satisfies TableColumn[]))
export const usageRecordColumns = defineTableColumns<UsageListRecord>([
{ key: 'clientApiKeyName', label: '密钥名称', kind: 'identity', size: 'xl' },
export const usageRecordColumns = computed(() => (defineTableColumns<UsageListRecord>([
{ key: 'clientApiKeyName', label: t('usage.fields.keyName'), kind: 'identity', size: 'xl' },
{
key: 'accountEmail',
hideable: false,
label: '账号',
label: t('accounts.account'),
kind: 'identity',
size: '3xl',
},
{ key: 'accountPlanType', label: '订阅', kind: 'status', size: 'sm', fixedWidth: true },
{ key: 'accountPlanType', label: t('usage.fields.subscription'), kind: 'status', size: 'sm', fixedWidth: true },
{
key: 'provider',
label: '平台/类型',
label: t('usage.fields.platformType'),
kind: 'status',
size: 'md',
fixedWidth: true,
formatter: (value: unknown) => formatProviderLabel(typeof value === 'string' ? value : null),
},
...usageDataColumns,
{ key: 'actions', label: '操作', kind: 'actions', size: 'sm', hideable: false },
])
...usageDataColumns.value,
{ key: 'actions', label: t('common.fields.actions'), kind: 'actions', size: 'sm', hideable: false },
])))
+17 -15
View File
@@ -1,4 +1,6 @@
import type { DashboardHealthStatus, DashboardHealthTimelinePoint } from '@/api'
import { computed } from 'vue'
import { t } from '@/i18n'
import { formatInteger } from '@/utils/format'
interface DashboardHealthStatusMeta {
@@ -8,52 +10,52 @@ interface DashboardHealthStatusMeta {
valueClass: string
}
export const healthLegend = [
{ status: 'no_data', label: '无有效样本' },
{ status: 'unavailable', label: '不可达' },
{ status: 'unstable', label: '不稳定' },
{ status: 'low_sample', label: '低样本' },
{ status: 'stable', label: '稳定' },
] satisfies { status: DashboardHealthStatus, label: string }[]
export const healthLegend = computed(() => ([
{ status: 'no_data', label: t('usage.noValidSample') },
{ status: 'unavailable', label: t('usage.notReachable') },
{ status: 'unstable', label: t('usage.unstable') },
{ status: 'low_sample', label: t('usage.lowSample') },
{ status: 'stable', label: t('usage.stable') },
] satisfies { status: DashboardHealthStatus, label: string }[]))
export const healthStatusMeta: Record<DashboardHealthStatus, DashboardHealthStatusMeta> = {
export const healthStatusMeta = computed<Record<DashboardHealthStatus, DashboardHealthStatusMeta>>(() => ({
future: {
label: '未来',
label: t('usage.future'),
cellClass: 'bg-cp-bg-container-disabled opacity-60',
badgeClass: 'bg-cp-fill-tertiary text-cp-text-quaternary',
valueClass: 'text-cp-text-quaternary',
},
no_data: {
label: '无有效样本',
label: t('usage.noValidSample'),
cellClass: 'bg-cp-border',
badgeClass: 'bg-cp-fill-tertiary text-cp-text-secondary',
valueClass: 'text-cp-text-quaternary',
},
unavailable: {
label: '不可达',
label: t('usage.notReachable'),
cellClass: 'bg-cp-error',
badgeClass: 'bg-cp-error-container text-cp-error-on-container',
valueClass: 'text-cp-error-text',
},
unstable: {
label: '不稳定',
label: t('usage.unstable'),
cellClass: 'bg-cp-warning',
badgeClass: 'bg-cp-warning-container text-cp-warning-on-container',
valueClass: 'text-cp-warning-text',
},
low_sample: {
label: '低样本',
label: t('usage.lowSample'),
cellClass: 'bg-cp-cyan-solid',
badgeClass: 'bg-cp-cyan-container text-cp-cyan-on-container',
valueClass: 'text-cp-cyan-text',
},
stable: {
label: '稳定',
label: t('usage.stable'),
cellClass: 'bg-cp-success',
badgeClass: 'bg-cp-success-container text-cp-success-on-container',
valueClass: 'text-cp-success-text',
},
}
}))
export function healthServiceFailureCount(point: Pick<DashboardHealthTimelinePoint, 'failedRequests' | 'incompleteRequests'>) {
return point.failedRequests + point.incompleteRequests
@@ -1,4 +1,5 @@
import type { UsageListRecord, UsageRecordDetail, UsageTokenDetails } from '@/api'
import { t } from '@/i18n'
import { formatCompactNumber, formatDuration, formatInteger } from '@/utils/format'
// 列表与详情使用独立读模型,展示函数只依赖两者的公共字段。
@@ -99,7 +100,7 @@ export function usageModelDisplay(record: UsageModelRecord) {
routes.push({
model: secondary,
kind: 'mapped' as const,
description: `网关映射后发送给上游的模型:${secondary}`,
description: t('usage.status.mappedModel', { secondary }),
})
}
if (returned) {
@@ -107,8 +108,8 @@ export function usageModelDisplay(record: UsageModelRecord) {
model: returned,
kind: 'returned' as const,
description: returned === secondary
? `上游返回模型:${returned}(与网关映射后发送的模型一致)`
: `上游返回模型:${returned}`,
? t('usage.status.returnedModel', { returned })
: t('usage.status.returnedModelHelp', { returned }),
})
}
@@ -140,38 +141,38 @@ export function usageLatencyDetails(record: UsageLatencyRecord) {
const requestItems: UsageTimingItem[] = []
if (firstTokenMs !== null && totalMs !== null && firstTokenMs <= totalMs) {
requestItems.push({ label: '首个输出等待', value: formatDuration(firstTokenMs) })
requestItems.push({ label: t('usage.status.firstOutputWaiting'), value: formatDuration(firstTokenMs) })
if (firstTextMs !== null && firstTextMs >= firstTokenMs && firstTextMs <= totalMs) {
const beforeTextMs = firstTextMs - firstTokenMs
if (beforeTextMs > 0) {
requestItems.push({
label: firstReasoningMs === firstTokenMs ? '推理到正文' : '首个输出到正文',
label: firstReasoningMs === firstTokenMs ? t('usage.status.reasoningToText') : t('usage.status.firstOneIsOutputToText'),
value: formatDuration(beforeTextMs),
})
}
requestItems.push({ label: '正文到完成', value: formatDuration(totalMs - firstTextMs) })
requestItems.push({ label: t('usage.status.textToCompletion'), value: formatDuration(totalMs - firstTextMs) })
}
else {
requestItems.push({
label: '首个输出后完成',
label: t('usage.status.completedAfterFirstOutput'),
value: formatDuration(totalMs - firstTokenMs),
})
}
}
requestItems.push({ label: '总耗时', value: formatDuration(totalMs), emphasized: true })
requestItems.push({ label: t('usage.latency.totalLatency'), value: formatDuration(totalMs), emphasized: true })
const transportItems: UsageTimingItem[] = [
{ label: '准入判定', value: durationValue(latencyDetails?.admissionDecisionMs) },
{ label: '账号选择等待', value: durationValue(latencyDetails?.accountSelectionWaitMs) },
{ label: t('usage.status.admissionDecision'), value: durationValue(latencyDetails?.admissionDecisionMs) },
{ label: t('usage.status.accountSelectionWaiting'), value: durationValue(latencyDetails?.accountSelectionWaitMs) },
{
label: '传输决策等待',
label: t('usage.status.transferDecisionWaiting'),
value: durationValue(latencyDetails?.transportDecisionWaitMs),
},
{ label: 'WebSocket 连接', value: durationValue(latencyDetails?.wsConnectMs) },
{ label: '上游响应头', value: durationValue(latencyDetails?.upstreamHeadersMs) },
{ label: '首个上游事件', value: durationValue(latencyDetails?.firstEventMs) },
{ label: t('usage.status.websocketConnection'), value: durationValue(latencyDetails?.wsConnectMs) },
{ label: t('usage.status.upstreamResponseHeader'), value: durationValue(latencyDetails?.upstreamHeadersMs) },
{ label: t('usage.status.firstUpstreamEvent'), value: durationValue(latencyDetails?.firstEventMs) },
]
.filter(item => item.value !== null)
.map(item => ({ ...item, value: formatDuration(item.value) }))
@@ -181,7 +182,7 @@ export function usageLatencyDetails(record: UsageLatencyRecord) {
&& latencyDetails.capacityTotalSlots != null
) {
transportItems.push({
label: '账号槽位快照',
label: t('usage.status.accountSlotSnapshot'),
value: `${latencyDetails.capacityUsedSlots} / ${latencyDetails.capacityTotalSlots}`,
})
}
@@ -189,14 +190,14 @@ export function usageLatencyDetails(record: UsageLatencyRecord) {
const upstreamDisplay = formatDuration(upstreamMs)
const upstreamItems: UsageTimingItem[] = []
if (upstreamMs !== null)
upstreamItems.push({ label: '响应耗时', value: upstreamDisplay })
upstreamItems.push({ label: t('accounts.connectionTest.duration'), value: upstreamDisplay })
const processingMs = durationValue(latencyDetails?.openaiProcessingMs)
if (processingMs !== null)
upstreamItems.push({ label: '处理耗时', value: formatDuration(processingMs) })
upstreamItems.push({ label: t('usage.status.processingTime'), value: formatDuration(processingMs) })
const performanceItems = [
{ label: 'API 开销', value: durationValue(latencyDetails?.upstreamApiOverheadMs) },
{ label: '引擎耗时', value: durationValue(latencyDetails?.upstreamEngineMs) },
{ label: t('usage.status.apiOverhead'), value: durationValue(latencyDetails?.upstreamApiOverheadMs) },
{ label: t('usage.status.engineTime'), value: durationValue(latencyDetails?.upstreamEngineMs) },
]
for (const item of performanceItems) {
if (item.value !== null)
@@ -206,15 +207,15 @@ export function usageLatencyDetails(record: UsageLatencyRecord) {
const sections: UsageTimingSection[] = []
if (upstreamItems.length) {
sections.push({
title: '上游性能',
title: t('usage.status.upstreamPerformance'),
source: 'official',
items: upstreamItems,
})
}
sections.push({ title: '请求观测', source: 'local', items: requestItems })
sections.push({ title: t('usage.status.requestObservation'), source: 'local', items: requestItems })
if (transportItems.length) {
sections.push({
title: '传输观测',
title: t('usage.status.transport'),
source: 'local',
items: transportItems,
})
+4 -3
View File
@@ -1,7 +1,8 @@
import { ZNotification } from '@codex-proxy/ui'
import { shallowRef } from 'vue'
import { ApiError } from '@/api/request'
import { t } from '@/i18n'
import { notification as ZNotification } from '@/utils/notification'
import { errorMessage, withMinimumDuration } from '@/utils/operation'
type MaybePromise<T> = T | Promise<T>
@@ -18,7 +19,7 @@ function resolveErrorText(error: unknown, errorText: string | false | undefined)
return ''
}
return errorMessage(error, errorText || '操作失败')
return errorMessage(error, errorText || t('common.errors.operation'))
}
export function useAsyncAction(defaults: AsyncActionRunOptions = {}) {
+4 -3
View File
@@ -1,6 +1,7 @@
import { ZNotification } from '@codex-proxy/ui'
import { useClipboard } from '@vueuse/core'
import { t } from '@/i18n'
import { notification as ZNotification } from '@/utils/notification'
import { errorMessage } from '@/utils/operation'
interface CopyTextOptions {
@@ -27,7 +28,7 @@ export function useCopyText() {
ZNotification.success({ message: options.successText })
}
catch (error: unknown) {
ZNotification.error({ message: options.errorFromException ? errorMessage(error, '复制失败') : '复制失败' })
ZNotification.error({ message: options.errorFromException ? errorMessage(error, t('common.errors.copy')) : t('common.errors.copy') })
}
}
}
+13
View File
@@ -0,0 +1,13 @@
import { useI18n } from 'vue-i18n'
import { isLocale, localeOptions } from '@/i18n/locale'
export function useLocale() {
const { locale } = useI18n({ useScope: 'global' })
function setLocale(value: unknown) {
if (isLocale(value))
locale.value = value
}
return { locale, localeOptions, setLocale }
}
+14
View File
@@ -0,0 +1,14 @@
import { createI18n } from 'vue-i18n'
import { readInitialLocale } from './locale'
import messages from './messages'
export const i18n = createI18n({
legacy: false,
locale: readInitialLocale(),
fallbackLocale: 'en',
messages,
})
// 非组件入口与 Vue 组件共享同一 Composer,调用时读取当前语言
export const t: typeof i18n.global.t = i18n.global.t
export const { locale } = i18n.global
+52
View File
@@ -0,0 +1,52 @@
export type Locale = 'en' | 'zh-Hans' | 'zh-Hant'
export const localeOptions = [
{ label: '简体中文', value: 'zh-Hans' },
{ label: '繁體中文', value: 'zh-Hant' },
{ label: 'English', value: 'en' },
] satisfies { label: string, value: Locale }[]
const storageKey = 'codex-proxy-rs-locale'
export function isLocale(value: unknown): value is Locale {
return localeOptions.some(option => option.value === value)
}
export function normalizeLocale(language: string): Locale {
try {
const { language: base, script, region } = new Intl.Locale(language)
if (base === 'zh') {
if (script === 'Hant')
return 'zh-Hant'
if (script === 'Hans')
return 'zh-Hans'
return region && ['TW', 'HK', 'MO'].includes(region) ? 'zh-Hant' : 'zh-Hans'
}
}
catch {
// 无效的浏览器语言使用应用默认语言
}
return 'en'
}
export function readInitialLocale(): Locale {
try {
const saved = localStorage.getItem(storageKey)
if (isLocale(saved))
return saved
}
catch {
// 存储不可用时继续使用浏览器语言
}
return normalizeLocale(navigator.language)
}
export function applyLocale(value: string): void {
document.documentElement.lang = value
try {
localStorage.setItem(storageKey, value)
}
catch {
// 存储不可用不影响当前会话的语言切换
}
}
+620
View File
@@ -0,0 +1,620 @@
{
"accounts": {
"quota": {
"usageInThisWindow": "Usage in this window: {localUsageDisplay}",
"quotaUsed": "Quota used: {rate}",
"resets": "Resets: {resetAtDisplay}",
"unobserved": "Awaiting quota data",
"dailyRequests": "Daily requests",
"requests": "{localRequestLabel}: {localRequestDisplay} requests",
"h": "{duration} h",
"d": "{duration} d",
"s": "{duration} s",
"unlimited": "Unlimited",
"noPointsAvailableYet": "No credits available",
"quotaPoints": "Credits",
"point": "credits",
"requestsInThisWindow": "Requests in this window: {requestDisplay}",
"requestCount": "Requests: {requestDisplay}",
"statisticalRange": "Statistical range",
"rolling": "Rolling {duration}",
"awaitingData": "Awaiting data",
"remaining": "{remaining}% remaining",
"usageLimit": "Usage limit",
"reset": "Reset:",
"remainingQuota": "Remaining {label} quota",
"accountLimit": "Account limit",
"quota": "{provider} quota",
"lastRefreshed": "Last refreshed: {refreshedAtDisplay}",
"viewPersonalInformation": "View personal information",
"forecastWeeklyMonthlyQuota": "Forecast weekly/monthly quota",
"queryUnsupported": "Upstream quota queries are not supported",
"quotaDetails": "Quota details",
"viewDetails": "View {detailTitle} details",
"details": "{detailTitle} details",
"statisticalMethod": "Statistical method",
"rollingWindow": "Rolling window",
"windowConsumption": "Window consumption",
"resetTime": "Reset time",
"localTokens": "Locally accumulated tokens",
"unavailableHelp": "Upstream quota is unavailable, the green bar does not represent remaining quota",
"totalTokensFor": "Total tokens for {windowLabelDisplay}",
"usageRateHelp": "Current usage percentage for the most recently used quota",
"usageRate": "Usage rate",
"moreGroups": "{count} more quota groups, expand the account to view them",
"windows": {
"fiveHour": "5h limit",
"daily": "Daily limit",
"weekly": "Weekly limit",
"monthly": "Monthly limit",
"annual": "Annual limit",
"usage": "Usage limit",
"secondary": "Secondary usage limit",
"duration": "{duration} limit"
}
},
"account": "Account",
"connectionTest": {
"duration": "Response time",
"title": "Test connection",
"description": "Verify account credentials, identity binding, and upstream model access",
"model": "Test model",
"refreshModels": "Refresh upstream models",
"loadingModels": "Loading models…",
"modelPlaceholder": "Select an upstream model",
"noModels": "The upstream service returned no models",
"running": "Testing…",
"completedAt": "Completed",
"events": {
"title": "Event timeline",
"request": "Request sent",
"response": "Receiving response",
"completed": "Response complete"
},
"diagnostics": "Raw diagnostics",
"retry": "Test again",
"start": "Start test",
"errors": {
"invalidRequest": "Invalid test request",
"unsupported": "The current provider does not support connection testing",
"credentials": "Invalid account credentials",
"policyRejected": "Test request rejected by gateway policy",
"modelNotFound": "Test model not found",
"accountUnavailable": "This account is unavailable for connection testing",
"capacityUnavailable": "This account has no available capacity",
"infrastructureUnavailable": "The provider's local infrastructure is temporarily unavailable",
"rateLimited": "Upstream rate limit exceeded",
"upstreamUnavailable": "Upstream service temporarily unavailable",
"timeout": "Upstream request timed out",
"canceled": "Test canceled",
"internal": "Internal gateway error",
"unknown": "Unknown error",
"failed": "Connection test failed",
"modelRequired": "Select a model to test",
"browserUnsupported": "The current browser does not support connection testing",
"missingCompletion": "The connection test did not return a completion event",
"invalidResponse": "Could not parse the test response",
"disconnected": "Connection lost during the test"
},
"stages": {
"gateway": "Gateway validation",
"provider": "Provider setup",
"upstream": "Upstream response"
},
"failed": "Test failed",
"testing": "Testing",
"runningDescription": "Sending a request to the selected model and receiving its streaming response",
"successTitle": "Connection successful",
"completedDescription": "Request complete, view the model, response time, and event timeline below",
"failedDescription": "Request incomplete, view the failure source and raw diagnostics below",
"readyTitle": "Ready to test",
"readyDescription": "Select a model and choose Start test to send a real request",
"starting": "Starting a connection test for {value}",
"emptyResponse": "The upstream service completed without returning text",
"testCompleted": "Test completed",
"modelsRefreshed": "Refreshed {count} upstream model | Refreshed {count} upstream models",
"noModelsAvailable": "No models available for testing"
},
"credentials": {
"wsFirst": "WS first",
"accountName": "Account name",
"enterUpstreamName": "Enter the upstream name",
"baseUrlHelp": "Enter the API base URL, endpoint paths are appended automatically",
"apiPrefix": "API prefix",
"apiKeyPlaceholder": "Leave blank to keep the current key",
"enterUpstreamKey": "Enter the upstream key",
"transportLabel": "Transport",
"webSocketHelp": "WS first requires upstream support for Responses WebSocket",
"nameRequired": "Enter an account name",
"validation": {
"urlLength": "Upstream API URL must not exceed 2,048 characters",
"urlFormat": "Enter an HTTP or HTTPS URL without credentials, query parameters, or a fragment",
"urlRequired": "Enter the full upstream API URL",
"apiKeyFormat": "API key cannot contain spaces or control characters",
"transportRequired": "Select a transport"
},
"apiKeyRequired": "Enter an API key"
},
"batchEdit": {
"title": "Edit accounts",
"selectionTitle": "Edit {count} account | Edit {count} accounts",
"saveChanges": "Save changes",
"proxyRequired": "Select a proxy that passed the connection test",
"saved": "Updated {count} account | Updated {count} accounts",
"staleAccount": "Account {accountId} is out of date, select it again"
},
"capacity": {
"concurrentRequestsLimit": "Concurrent requests: {value}, limit: {value2}",
"viewConcurrencyDetails": "{label}, view concurrency details",
"viewDetails": "{label}, view details"
},
"concurrency": {
"title": "Concurrency details",
"description": "Requests currently being processed",
"unavailable": "Concurrency details are temporarily unavailable",
"empty": "No active concurrent requests",
"key": "Key",
"model": "Model",
"sourceIp": "Source IP",
"startTime": "Started",
"elapsed": "Elapsed"
},
"editor": {
"title": "Edit account",
"transportLabel": "Upstream transport",
"upstreamConnection": "Upstream connection",
"loadError": "Could not load upstream settings",
"notesHelp": "Up to 500 characters, leave blank to clear notes",
"oauthUnavailable": "This account has no OAuth upstream settings",
"apiKeyUnavailable": "This account has no upstream API key settings",
"saved": "Account updated"
},
"filters": {
"allGroups": "All",
"ungroupedAccounts": "Ungrouped",
"disabled": "{name} (disabled)",
"label": "Account filters and actions",
"searchLabel": "Search accounts",
"statusLabel": "Filter by account status",
"groupLabel": "Filter by account group",
"deleteSelected": "Delete selected ({count})",
"exportSelected": "Export selected ({count})",
"importTasks": "Import tasks",
"importAccount": "Import account"
},
"modelAccess": {
"reserve": "Reserve",
"allowlist": "Allowlist",
"blocklist": "Blocklist",
"modelLimitations": "Model limitations",
"refreshModel": "Refresh model",
"modelRestrictionMode": "Model restriction mode",
"searchOrAddModels": "Search or add models",
"searchOrEnterIdAndPressEnter": "Search or enter ID and press Enter to add",
"selectModel": "Select model",
"notInCurrentModelCatalog": "{id} (not in the current model catalog)",
"loadingModel": "Loading model…",
"noMatchingModels": "No matching models",
"noModels": "No models",
"modelListLoadingFailed": "Model list loading failed",
"retryHint": "Refresh and try again",
"selectOrAddAtLeastOneModel": "Please select or add at least one model",
"configureUpToModels": "Configure up to 256 models",
"invalidModelId": "Enter an exact model ID, wildcards are not supported",
"enterValidExactModelIdUpTo": "Please enter a valid exact model ID, up to 256 bytes, no wildcards are supported"
},
"notes": {
"viewAccountNotes": "View account notes",
"title": "Account notes"
},
"overview": {
"totalAccounts": "Total accounts",
"accountPoolSize": "Account pool size",
"availableAccounts": "Available accounts",
"availableHelp": "Available for scheduling",
"quotaLimited": "Quota limited",
"waitingForQuota": "Waiting for quota reset",
"pending": "Pending",
"disabledError": "Disabled / error"
},
"proxy": {
"keepCurrent": "Keep current",
"keepExisting": "Keep each account's connection settings",
"directConnection": "Direct",
"notUsingProxy": "No proxy",
"disabledSuffix": "(disabled)",
"testFailed": "(test failed)",
"notTested": "(not tested)",
"outboundTunnel": "Outbound tunnel"
},
"scheduling": {
"scheduling": "Scheduling",
"switchAccountSchedule": "Switch account schedule",
"concurrencyLimit": "Concurrency limit",
"accountConcurrencyLimit": "Account concurrency limit",
"defaultHint": "Blank uses the default",
"weight": "Weight",
"accountSchedulingWeight": "Account scheduling weight",
"weightHelp": "Higher values get priority, up to 100",
"groupLabel": "Group",
"invalidConcurrency": "Leave the concurrency limit blank or enter an integer from 1 to {value}",
"weightMustBeIntegerFromTo": "Weight must be an integer from 1 to 100"
},
"actions": {
"deleteAccount": "Delete account",
"moreActions": "More actions",
"disableScheduling": "Disable",
"enableScheduling": "Enable",
"refreshToken": "Refresh token",
"reauthorize": "Reauthorize",
"downloadModelCatalog": "Download model catalog",
"restoreState": "Reset status",
"staleSelection": "Selected account data is out of date, select the accounts again",
"exportUnsupported": "Some selected accounts belong to providers that do not support export",
"deleted": "Account deleted",
"deletedAccountDeletedAccounts": "Deleted {count} account | Deleted {count} accounts",
"partialDeletion": "Deleted {count} accounts, the remaining accounts were not deleted: {value}",
"batchDeletionFailed": "Batch deletion failed",
"exportSelectionRequired": "Select at least one account to export",
"exported": "Exported {count} account | Exported {count} accounts",
"exportFailed": "Export failed",
"modelCatalogDownloadedModels": "Model catalog downloaded, models: {count}",
"tokenIsBeingRefreshed": "Token is being refreshed",
"refreshFailed": "Refresh failed",
"tokenRefreshed": "Token refreshed",
"schedulingIsDisabled": "Scheduling is disabled",
"schedulingIsEnabled": "Scheduling is enabled",
"quotaRefreshed": "Quota refreshed",
"refreshQuotaManually": "Refresh the quota manually",
"resetRefreshFailed": "Quota reset succeeded, but the latest quota could not be loaded: {value}",
"statusRestored": "Account status restored",
"staleAccount": "Account {id} is out of date, select it again",
"unsupportedProvider": "Unsupported provider: {provider}"
},
"usage": {
"call": "Calls",
"successRate": "Success",
"input": "Input",
"output": "Output",
"cache": "Cached",
"total": "Total",
"billing": "Billing",
"tokensStructure": "Token usage",
"cacheRead": "Cache read",
"reasoning": "Reasoning",
"cacheWrites": "Cache writes",
"modelUsageRanking": "Model usage",
"totalTokens": "Total tokens",
"totalCharge": "Total cost",
"totalCharges": "Total cost",
"noModelUsageYet": "No model usage yet",
"windows": {
"general": "Total usage",
"weekly": "Weekly usage",
"monthly": "Monthly usage",
"quota": "Period usage"
},
"cost": "Cost"
},
"onboarding": {
"fileReadingFailedTryAgain": "File reading failed, please try again",
"uploadFiles": "Upload files",
"authorizationExpired": "Authorization expired, start again or check whether authorization completed",
"pollingPaused": "Polling paused, check the authorization result to continue",
"regenerateAuthorizationLink": "Regenerate authorization link",
"generateAuthorizationLink": "Generate authorization link",
"authorizationLink": "Authorization link",
"copyLink": "Copy link",
"authorizationLinkCopied": "Authorization link copied",
"batchImport": "Batch import",
"selectAccountPlatform": "Select account platform",
"accountPlatform": "Account platform",
"maximumWordsOptional": "Maximum 500 words, optional",
"copyAccount": "Copy account",
"accountCopied": "Account copied",
"howToAddAccount": "How to add an account",
"authorize": "Authorize",
"continueImporting": "Continue",
"jsonDescription": "Paste or upload account JSON to import accounts or update matching credentials",
"packageDescription": "Paste or upload a CPR account package to import accounts from multiple providers",
"oauthDescription": "Import a {label} account through browser authorization",
"apiKeyDescription": "Connect an upstream service compatible with the OpenAI Responses API",
"pasteAccessTokenLineByLineIf": "Paste the Access token line by line. If the Refresh token is not included, it cannot be automatically renewed",
"refreshTokenDescription": "Paste one refresh token per line, access tokens are obtained automatically during import",
"accountSettings": "Account settings",
"reauthorizeAccount": "Reauthorize account",
"settingsDescription": "These settings apply to accounts in this import",
"reauthorizeDescription": "Update account credentials after authorization",
"callbackLabel": "Callback URL or authorization code",
"callbackAddress": "Callback address",
"callbackPlaceholder": "Callback URL, ?code=...&state=..., or authorization code",
"callbackHelp": "Open the authorization link, authorize in your browser, then paste the callback URL or authorization code",
"pasteOneAccessTokenPerLine": "Paste one Access token per line",
"pasteOneRefreshTokenPerLine": "Paste one Refresh token per line",
"batchAccountFiles": "Batch account files",
"accountFile": "Account file",
"packagePlaceholder": "Paste a CPR account export",
"pasteAccountJsonContent": "Paste the account JSON content",
"completeReauthorization": "Complete reauthorization",
"completeImport": "Complete import",
"invalidExpiry": "Invalid authorization expiry, generate a new link",
"linkFailed": "Failed to generate authorization link",
"callbackRequired": "Paste a callback URL or authorization code",
"authorizationFailed": "Authorization failed, submit again to retry",
"reauthorized": "Account reauthorized",
"accountAdded": "Account added",
"providerRequired": "Select an account provider",
"accountPlatformIsNotSupported": "Account platform is not supported",
"apiKeyUnsupported": "This provider does not support API key accounts",
"apiKeyAccountAdded": "API key account added",
"importTasksCreated": "Import tasks created: {submitted}",
"importTaskCreated": "Import task created",
"partialSubmission": "Some import tasks were created, retry with the same input to submit the rest",
"accountName": "{provider} account",
"failedToStartAuthorization": "Failed to start authorization"
},
"importTasks": {
"needProcessing": "Need processing",
"importTaskDetails": "Import task details",
"created": "Created {createdAtDisplay}",
"waitForCurrentEntryToEnd": "Wait for the current entry to end",
"stopUnstartedEntries": "Stop unstarted entries",
"viewAccount": "View account",
"entryProgress": "Entry progress",
"accountsImported": "Accounts imported: {importedAccounts}",
"itemProcessingProgress": "Item processing progress",
"itemsToBeCheckedMayHaveBeen": "The items to be checked may have been stored in the database. Please check the account first before deciding whether to re-import it",
"filterImportDetails": "Filter import details",
"thereAreNoItemsToBeProcessed": "There are no items to be processed yet",
"importEntryResults": "Import entry results",
"items": "Items: {total} · {value}",
"description": "Imports continue after you close this page, reopen it to check progress",
"progressUnavailable": "Progress unavailable: {value}, updates resume when the connection is restored",
"loadingImportTasks": "Loading import tasks…",
"noImportTasks": "No import tasks",
"empty": "Start an account import to see results for each entry here",
"switchImportTasks": "Switch import tasks",
"loadingItemResults": "Loading item results…",
"selectTask": "Select a task",
"taskRetentionInstructions": "Task retention instructions",
"resultsRetainedForHour": "Results retained for 1 hour",
"retentionHelp": "Task records are cleared when the service restarts, imported accounts are kept",
"processing": "Processing",
"alreadyInStock": "Already in stock",
"toBeVerified": "To be verified",
"notExecuted": "Not executed",
"stopping": "Stopping",
"importing": "Importing",
"queuing": "Queuing",
"stopped": "Stopped",
"endedPendingItems": "Ended · Pending items",
"allDone": "All done",
"savedAccountSavedAccounts": "Saved {count} account | Saved {count} accounts",
"verifying": "Verifying and saving credentials",
"waitingForExecution": "Waiting for execution",
"thisArticleIsNotImplemented": "This article is not implemented",
"entryFailed": "This entry could not be imported",
"checkAccountList": "Check the account list to confirm whether the account was imported",
"progressReadingFailedTryAgain": "Progress reading failed, please try again"
},
"profile": {
"activity": {
"quickMode": "Quick mode",
"reasoningEffort": "Most used reasoning effort",
"exploredSkills": "Explored skills",
"totalNumberOfSkillsUsed": "Total number of skills used",
"totalNumberOfChats": "Total number of chats",
"activityInsights": "Activity Insights",
"pluginsAndSkills": "Most used plugins and skills",
"runs": "Runs: {count}",
"noToolCalls": "No plugin or skill calls",
"daily": "Daily",
"weekly": "Weekly",
"cumulative": "Cumulative",
"tokenActivity": "Token activity",
"tokenActivityStatisticsMethod": "Token activity statistics method",
"noTokenActivityYet": "No token activity yet",
"noDailyActivity": "Daily token activity was not available for this request",
"tokenActivityHeatmap": "Token activity heatmap, {rangeLabel}",
"weekOfTokens": "Week of {dateDisplay}: {value} tokens",
"throughTokens": "Through {dateDisplay}: {value} tokens"
},
"metrics": {
"cumulativeNumberOfTokens": "Total tokens",
"peakNumberOfTokens": "Peak number of tokens",
"maximumChatDuration": "Maximum chat duration",
"currentConsecutiveDays": "Current consecutive days",
"longestStreak": "Longest streak",
"dayCount": "{integer} d",
"dH": "{days} d {hours} h",
"elapsedDays": "{days} d",
"hMin": "{hours} h {minutes} min",
"elapsedHours": "{hours} h",
"min": "{totalMinutes} min",
"durationSeconds": "{value} s",
"cumulativeActivitySummary": "Cumulative activity summary"
},
"accountUser": "Account user",
"avatarFor": "Avatar for {displayName}",
"loadingCumulativeActivity": "Loading cumulative activity",
"subscription": {
"automaticRenewal": "Automatic renewal",
"noAutomaticRenewal": "No automatic renewal",
"byMonth": "By month",
"byYear": "By year",
"subscriptionStarts": "Subscription starts",
"subscriptionEnds": "Subscription ends",
"label": "Plan",
"renewalMethod": "Renewal method"
},
"personalInformation": "Personal information",
"subscriptionInformation": "Subscription information",
"loadingSubscription": "Loading subscription details…",
"loadFailed": "Failed to load profile",
"statisticsUnavailable": "Profile statistics are temporarily unavailable",
"statisticsEmpty": "No statistics were returned, refresh to try again",
"refreshIncomplete": "Refresh incomplete, showing the results received so far",
"noSubscriptionInformationYet": "No subscription information yet",
"refreshInformation": "Refresh information"
},
"quotaForecast": {
"tokenCapacity": "Token capacity",
"equivalentFeeUsd": "Equivalent cost · USD",
"capacityForecast": "Capacity forecast",
"usedThisCycle": "Used this cycle",
"preliminary": "Preliminary estimate · For reference only",
"estimateLabel": "Estimated value · For reference only",
"thisCycle": "This cycle",
"usedDescription": "{rate} used this period, the remaining area is projected",
"alreadyRecordedThisCycle": "Already recorded this cycle",
"equivalentCapacityOverDays": "Equivalent capacity over {targetDays} days",
"projectedTotal": "Projected total for this period",
"loadingQuotaForecast": "Loading quota forecast",
"weeklyQuota": "Weekly quota",
"monthlyQuota": "Monthly quota",
"windowExpired": "Quota window expired, refresh the account quota and try again",
"quotaForecast": "Quota forecast",
"periodHelp": "Estimated for this period, accumulation starts again after reset",
"forecastPeriod": "Forecast period",
"predictionLoadFailed": "Prediction load failed",
"loadFailed": "Forecast unavailable, reload to try again",
"reload": "Reload",
"unpredictableAtMoment": "Unpredictable at the moment",
"updated": "Updated {observedAtDisplay}",
"forecastDescription": "Forecast description",
"forReferenceOnly": "For reference only",
"methodDescription": "The projected total is recorded usage plus estimated remaining usage, based on recent usage within this period",
"limitations": "Missing usage or cost data can lower the estimate, which varies by model and usage pattern and is not an official quota commitment",
"limitedData": "Limited data, estimates may vary substantially",
"currentPeriod": "current period",
"forecastCalculatedByOverDays": "Forecast calculated by {value} over {targetDays} days",
"equivalentCostHelp": "Estimates reflect the last data update, equivalent cost is not an actual bill or account balance",
"refreshQuota": "Refresh quota"
},
"quotaReset": {
"automation": {
"confirming": "The last automatic reset is unconfirmed, verification will continue",
"unconfirmed": "The last automatic reset is unconfirmed",
"expiredUnconfirmed": "The last reset could not be confirmed and the reset credit has expired",
"queryFailed": "The last query failed, retrying on schedule",
"aboveThreshold": "Remaining weekly quota exceeds the threshold, checking again later",
"quotaUnavailable": "Weekly quota is unavailable, checking again later",
"resetNotNeeded": "This quota window does not need a reset, checking again later",
"resetIncomplete": "The upstream service did not complete the last automatic reset",
"scheduleHelp": "Check once a day at a random time, staggered across accounts",
"verifyHelp": "Verify reset credits before expiry, automatically skip credits already used elsewhere",
"label": "Automatically use expiring reset credits"
},
"automaticallyUseResetCard": "Automatically use resets",
"automaticallyUsed": "Auto use",
"automaticUsageRules": "Automatic usage rules",
"setGlobalLeadTime": "Set global lead time",
"minutesInAdvance": "{leadMinutes} minutes in advance",
"leadTime": "Lead time",
"nextUse": "Next use: {nextConsumeAtDisplay}",
"autoUsageSettingsFailedToLoad": "Auto usage settings failed to load",
"limitReset": "Limit reset",
"confirmLastReset": "Confirm last reset",
"confirmResetAmount": "Confirm reset amount",
"pendingAction": "View reset credits, an operation is awaiting confirmation",
"queryFailedWithCount": "View reset credits, query failed, last known available: {count}",
"queryFailedLabel": "View reset credits, query failed",
"availableCount": "View reset credits, last known available: {count}",
"viewCredits": "View reset credits",
"useResetSelectedByUpstream": "Use a reset (selected by upstream)",
"expires": "Expires {expiresAtDisplay}",
"expiryHelp": "Expiry is determined by the upstream service",
"querying": "Querying",
"toBeQueried": "To be queried",
"usesAvailable": "Uses available: {count}",
"usageReset": "Usage reset",
"thisTimeUse": "This time use",
"currentQuota": "Current quota",
"operationUnconfirmed": "The last operation is awaiting confirmation",
"confirmPrevious": "Continue verifying the previous reset",
"continueToConfirm": "Continue to confirm",
"availableResetCards": "Available resets",
"refreshCredits": "Refresh reset credits",
"resetCardLoadingFailed": "Could not load resets",
"refreshRequired": "Refresh and try again",
"queryingAvailableResetTimes": "Querying available reset times…",
"useResetCredit": "Use reset credit: {title}, {expiry}",
"useReset": "Use reset",
"noResetCardAvailableYet": "No resets available",
"confirmAgain": "Confirm again",
"confirmReset": "Confirm reset",
"lastResetCompleted": "Last reset completed",
"resetSuccess": "Quota reset",
"resultUnknown": "The result is uncertain, retrying will reuse the same request ID",
"quotaResetFailed": "Quota reset failed",
"alreadyProcessed": "This reset was already processed, refresh the reset credit list",
"noCredits": "No reset credits available",
"resetNotNeeded": "This quota window does not need a reset",
"upstreamDeclined": "The upstream service did not reset the quota: {code}"
},
"status": {
"accountStatus": "Account status",
"tryNextTime": "Try next time",
"recommendedAction": "Recommended Action",
"upstreamOriginalFeedback": "Upstream original feedback",
"forTroubleshootingOnly": "For troubleshooting only",
"retreating": "Retreating",
"oauthRefreshBackoff": "OAuth refresh backoff",
"refreshFailedHelp": "Refresh failed, waiting for the next automatic attempt",
"retryScheduledHelp": "The system will retry at the scheduled time",
"attentionHelp": "This account needs attention",
"retestHelp": "Test the connection again to update the status",
"rateLimitedHelp": "The upstream service rate limited this account, cooldown is in progress",
"cooldownHelp": "Scheduling resumes automatically after cooldown",
"credentialsHelp": "This account is excluded from scheduling, update its credentials and test the connection again",
"reauthorizeHelp": "Reauthorize the account to resume scheduling",
"replaceCredentialsHelp": "Update or reimport credentials, then test the connection again",
"upstreamRestrictionHelp": "Check the upstream account and resolve its restrictions before enabling it",
"capacityFailuresHelp": "Capacity failures reached the threshold, scheduling is paused for this account",
"recoveryProbeHelp": "After cooldown, a successful recovery probe resumes scheduling, or you can restore the account manually",
"recoveryHelp": "Scheduling resumes after cooldown, or you can restore the account manually",
"nextAttempt": ", next attempt: {nextRefreshDisplay}",
"clickOrFocusToViewDetails": "{title}, {description}{retry}, click or focus to view details",
"resumeDetection": "Resume detection",
"expectedToRecover": "Expected to recover"
},
"fields": {
"platformType": "Provider",
"accountGrouping": "Groups",
"lastUsed": "Last used",
"tokenExpires": "Token expires",
"quotaExhausted": "Quota exhausted",
"rateLimiting": "Rate limited",
"deactivated": "Deactivated",
"error": "Error",
"identityUnconfirmed": "Account identity has not yet been confirmed",
"accessTokenHasExpired": "Access token has expired",
"credentialsHaveExpired": "Credentials have expired",
"invalidCredentials": "Invalid credentials",
"accountUnavailable": "Account is unavailable or has been banned",
"count": "Accounts"
},
"page": {
"description": "Manage the account pool and monitor availability, quota, and usage",
"noAccountDataYet": "No account data yet",
"collapseStatistics": "Collapse statistics",
"expandStatistics": "Expand statistics",
"selectAccountOnCurrentPage": "Select the account on the current page",
"selectAccount": "Select account",
"deleteDescription": "This account will be removed from scheduling, deletion cannot be undone",
"batchDeleteDescription": "Delete the {count} selected account? This action cannot be undone | Delete the {count} selected accounts? This action cannot be undone",
"thisAccount": "This account",
"delete": "Delete {value}?"
},
"import": {
"jsonFormatIsIncorrect": "JSON format is incorrect",
"documentTooLarge": "An import document exceeds 4 MiB, split the file and try again",
"batchImportFileMustBeCprMulti": "The batch import file must be a CPR multi-platform export file",
"invalidProvider": "The import file contains an invalid provider document",
"noAccounts": "The import file contains no importable account documents",
"pasteAtLeastOne": "Paste at least one {label}",
"missingProvider": "The import file contains no {provider} accounts",
"importFilesMustBeJsonObjects": "Import files must be JSON objects"
}
}
}
@@ -0,0 +1,222 @@
{
"appearance": {
"switchToLight": "Switch to light mode",
"switchToDark": "Switch to dark mode",
"settings": {
"global": "Global",
"components": "Components",
"invalidTheme": "Invalid theme settings, check the edited values",
"themeSavedAndApplied": "Theme saved and applied",
"description": "Customize the admin theme in this browser",
"pendingChanges": "Pending changes: {count}",
"synced": "Synced",
"themeEditingLevel": "Theme editing level",
"undoDraft": "Undo draft",
"restoreDefault": "Restore default",
"saveAndApply": "Save and apply",
"saved": "Saved",
"themeEditor": "Theme editor",
"themeTokenEditingPanel": "Theme token editor",
"searchToken": "Search tokens",
"searchPlaceholder": "Search seed, alias, or component tokens"
},
"color": {
"modified": "Modified",
"edit": "Edit {label}",
"restoreDerivedValue": "Restore derived value"
},
"preview": {
"components": {
"relayAccount": "Relay account",
"stickyHelp": "Keep the current account until its quota is exhausted",
"notEditable": "Not editable",
"allPlatforms": "All platforms",
"restricted": "Restricted",
"accountAvailability": "Account availability",
"todaySQuota": "Today's quota",
"batchImport": "Batch import",
"platform": "Provider",
"requestToday": "Requests today",
"recentlyUsed": "Last used",
"justNow": "Just now",
"hoursAgo": "2 hours ago",
"componentOverview": "Component overview",
"description": "Inspect component states, data density, and overlays together",
"currentThemeSemanticColor": "Current theme semantic color",
"basicControlComponents": "Basic control components",
"buttonsAndActions": "Buttons and Actions",
"createAccount": "Create account",
"exportData": "Export data",
"dealWithItLater": "Deal with it later",
"sizeAndDisabledStatus": "Size and disabled status",
"inoperable": "Inoperable",
"processing": "Processing",
"notification": "Notification",
"moreActions": "More actions",
"deleteRecord": "Delete record",
"formsAndInput": "Forms and input",
"searchAccount": "Search account",
"choosePlatform": "Choose platform",
"accessKeyErrorExample": "Access key error example",
"disableInputBox": "Disable input box",
"brandColors": "Brand colors",
"editBrandColors": "Edit brand colors",
"schedulingNotes": "Scheduling notes",
"controlHeight": "Control height",
"componentExampleControlHeight": "Component example control height",
"choiceAndFeedbackComponents": "Choice and feedback components",
"selectAndSwitch": "Select and switch",
"accountView": "Account view",
"realTimeNotification": "Real time notification",
"automaticRotation": "Automatic rotation",
"selectCurrentPage": "Select current page",
"partialSelection": "Partial selection",
"equilibrium": "Equilibrium",
"sticky": "Sticky",
"manual": "Manual",
"feedbackSemantics": "Feedback semantics",
"themeSettingsSaved": "Theme settings saved",
"quotaOfAccountsIsCloseToUpper": "The quota of 3 accounts is close to the upper limit",
"connectionTestFailed": "Connection test failed",
"schedulingNotice": "Scheduling rules apply to the next request",
"statusAndProgress": "Status and progress",
"runningNormally": "Running normally",
"quotaLimited": "Quota limited",
"needToBeProcessed": "Need to be processed",
"synchronizing": "Synchronizing",
"restoreTag": "Restore tag",
"dataTable": "Data table",
"tableComponents": "ZTable · ZScrollbar · ZPagination (standard row height)",
"filterForm": "Filter form",
"filterAccounts": "Filter accounts",
"boundaryStateComponent": "Boundary state component",
"emptyState": "Empty state",
"noMatchingAccountYet": "No matching account yet",
"emptyHelp": "Adjust the filters or add an upstream account",
"addAccount": "Add account",
"loadingAndSkeleton": "Loading and Skeleton",
"synchronizingAccountStatus": "Synchronizing account status",
"overlaysAndMenus": "Overlays and menus",
"accountOperation": "Account operation",
"editAccount": "Edit account",
"deactivateAccount": "Deactivate account",
"overlayHelp": "Overlays use their own surface and shadow tokens",
"eyebrow": "Component preview",
"count": "{count} base component | {count} base components",
"buttonLabel": "Button / action",
"feedbackTypes": "Success · Warning · Error · Info",
"tagComponents": "ZTag · Progress tokens",
"loadingComponents": "ZSkeleton · ZButton loading",
"overlayComponents": "ZPopover · ZMenuItem · Elevated surface"
},
"dashboard": {
"justUpdated": "Just updated",
"demoKey": "Demo Key",
"requestHealthTimeline": "Request a health timeline",
"validRequestAvailability": "Valid request availability",
"clientId": "Client ID",
"tokenAuthentication": "Token authentication",
"todaySToken": "Today's tokens",
"hours": "5 hours",
"requests": "08-23 {value}:00–{value2}:00 · Requests: {count}",
"times": "Times",
"dailyLimit": "Daily limit"
},
"homeArtboard": "Home artboard",
"themeRealTimePreview": "Theme real-time preview",
"livePreview": "Live preview",
"description": "Preview real components in isolation, pan and zoom to inspect details",
"previewType": "Preview type",
"canvas": {
"homeThemePreviewArtboard": "Home theme preview artboard",
"dragBlankSpaceToPanUseScroll": "Drag the blank space to pan · Use the scroll wheel to zoom",
"reduceArtboard": "Reduce the artboard",
"recovery": "Recovery 100%",
"enlargeArtboard": "Enlarge artboard",
"adaptToArtboard": "Adapt to artboard"
}
},
"componentTokens": {
"cardsAndContainers": "Cards and Containers",
"dataDisplay": "Data display",
"navigation": "Navigation",
"layoutAndScrolling": "Layout and scrolling",
"mainButtonText": "Main button text",
"mainButtonBackground": "Main button background",
"mainButtonHover": "Main button Hover",
"mainButtonActive": "Main button Active",
"secondaryButtonBackground": "Secondary button background",
"secondaryButtonHover": "Secondary button Hover",
"secondaryButtonActive": "Secondary button Active",
"secondaryIconButtonBackground": "Secondary icon button background",
"secondaryIconButtonHover": "Secondary icon button hover",
"secondaryIconButtonActive": "Secondary icon button active",
"inputBoxBackground": "Input box background",
"inputBoxHover": "Input box Hover",
"inputBoxActive": "Input box Active",
"inputBoxShadow": "Input box shadow",
"inputBoxHoverShadow": "Input box Hover shadow",
"inputBoxFocusOuterCircle": "Input box focus outer circle",
"cardBackground": "Card background",
"popUpBackground": "Pop-up background",
"floatingTitleBackground": "Floating title background",
"cardRoundedCorners": "Card rounded corners",
"cardShadow": "Card shadow",
"tableRowHeight": "Table row height",
"headerBackground": "Header background",
"lineBackground": "Line background",
"zebraPatternBackground": "Zebra pattern background",
"rowHover": "Row hover",
"selectedRowBackground": "Selected row background",
"selectRowHover": "Select row Hover",
"progressTrack": "Progress track",
"menuSelectionBackground": "Menu selection background",
"sidebarBackground": "Sidebar background",
"sidebarShadow": "Sidebar shadow",
"scrollBarSlider": "Scroll bar slider",
"scrollBarHover": "Scroll bar Hover",
"componentTokenComponentFamily": "Component token family",
"description": "Adjust component tokens for {label}, unchanged values continue to use the global seed and alias algorithms",
"noMatchingComponentToken": "No matching component tokens",
"kindLabel": "Component tokens"
},
"globalTokens": {
"size": "Size",
"style": "Style",
"systemMode": "System",
"lightColor": "Light color",
"dark": "Dark",
"successColor": "Success color",
"successFeedbackAndStatus": "Success feedback and status",
"warningColor": "Warning color",
"limitAndRiskReminder": "Limit and risk reminder",
"wrongColor": "Wrong color",
"dangerHelp": "Failures and destructive actions",
"informationColor": "Information color",
"systemAndRequestInformation": "System and request information",
"linkColor": "Link color",
"linksAndJumps": "Links and jumps",
"basicTextColor": "Basic text color",
"textAndInformationLevels": "Text and information levels",
"basicBackgroundColor": "Basic background color",
"pageAndContainerBase": "Page and container base",
"themeMode": "Theme mode",
"globalTokenClassification": "Global token categories",
"brandColorLabel": "Preset theme · Brand color · colorPrimary",
"brandColor": "Brand color",
"presetThemes": "Preset themes",
"brandMainColor": "Brand main color",
"paletteDescription": "Color scales and overall appearance",
"semanticColorsTitle": "Semantic and neutral colors",
"derivedVariablesMapAliasToken": "Derived variables: map and alias tokens",
"sizeToken": "Size tokens",
"basicFontSize": "Basic font size",
"basicSpacing": "Basic spacing",
"sizeStep": "Size step",
"styleToken": "Style tokens",
"surfaceDescription": "Borderless surfaces, rounded corners, and layered shadows",
"universalFillet": "Universal fillet",
"shadowIntensity": "Shadow intensity"
}
}
}
+21
View File
@@ -0,0 +1,21 @@
{
"auth": {
"signOut": "Sign out",
"adminSignIn": "Admin sign-in",
"apiKeySignIn": "API key sign-in",
"signingIn": "Signing in…",
"signIn": "Sign in",
"method": "Sign-in method",
"title": "Sign in",
"welcome": "Welcome back",
"username": "Admin account",
"usernamePlaceholder": "Enter your admin account",
"passwordPlaceholder": "Enter your password",
"apiKeyPlaceholder": "Enter your API key",
"pageLabel": "Sign in to Codex Proxy RS",
"password": "Password",
"apiKey": "API key",
"adminRealm": "Admin",
"keyRealm": "API key"
}
}
+140
View File
@@ -0,0 +1,140 @@
{
"common": {
"errors": {
"canceled": "Request canceled",
"timeout": "Request timed out, try again later",
"network": "Connection failed, check your network and try again",
"invalidParameters": "Invalid request parameters",
"signInRequired": "Sign-in required",
"forbidden": "You do not have permission to perform this action",
"notFound": "Endpoint not found",
"conflict": "Resource conflict, refresh and try again",
"payloadTooLarge": "Request payload is too large",
"unsupportedFormat": "Unsupported request format",
"invalidContent": "Invalid request content",
"rateLimited": "Too many requests, try again later",
"internal": "Internal server error",
"upstreamFailure": "Upstream service request failed",
"unavailable": "Service temporarily unavailable, try again later",
"upstreamTimeout": "Upstream response timed out",
"http": "Request failed (HTTP {status})",
"request": "Request failed",
"responseTooLarge": "Response content exceeds size limit",
"unsupportedResponse": "The service returned an unsupported response",
"sessionExpired": "Your session has expired, sign in again",
"operation": "Operation failed",
"copy": "Failed to copy",
"load": "Failed to load",
"malformedJson": "The request body is not valid JSON",
"invalidTimeRange": "Invalid time range",
"invalidCredentials": "Invalid sign-in credentials",
"invalidAdminApiKey": "Invalid admin API key",
"tooManyLoginAttempts": "Too many sign-in attempts, try again later",
"upstreamResultUnknown": "The upstream result is unknown, refresh the status before deciding whether to retry"
},
"status": {
"disabled": "Disabled",
"disabledName": "{name} (disabled)",
"success": "Success",
"error": "Error",
"pending": "Pending",
"failed": "Failed",
"healthy": "Healthy",
"all": "All",
"available": "Available",
"unavailable": "Unavailable",
"enabled": "Enabled",
"loading": "Loading…",
"running": "Running",
"completed": "Completed",
"rateLimited": "Rate limited"
},
"actions": {
"copy": "Copy",
"close": "Close",
"retry": "Retry",
"cancel": "Cancel",
"previous": "Previous",
"reset": "Reset",
"back": "Back",
"delete": "Delete",
"create": "Create",
"enable": "Enable",
"next": "Next",
"confirm": "Confirm",
"refresh": "Refresh",
"save": "Save"
},
"providers": {
"all": "All platforms",
"filter": "Filter by platform",
"unknown": "Unknown platform",
"customAuth": "Custom authentication · {normalized}",
"unknownAuth": "Unknown authentication type"
},
"location": {
"resolving": "Resolving exit location…",
"detect": "Resolve exit location and fill in the form",
"countryCode": "Country code",
"countryCodePlaceholder": "Enter a two-letter country code",
"region": "Region",
"regionPlaceholder": "Enter a region",
"city": "City",
"cityPlaceholder": "Enter a city",
"timeZone": "IANA time zone",
"timeZonePlaceholder": "Enter an IANA time zone",
"required": "Enter a two-letter country code, region, city, and IANA time zone"
},
"values": {
"yes": "Yes",
"no": "No",
"unspecified": "Not specified",
"all": "All",
"unknown": "Unknown",
"unlimited": "Unlimited",
"default": "Default",
"on": "On",
"none": "None",
"off": "Off"
},
"form": {
"inputPlaceholder": "Enter a value",
"useForm": "Use form",
"fieldHelp": "About {label}",
"editJson": "Edit JSON"
},
"fields": {
"actions": "Actions",
"notes": "Notes",
"status": "Status",
"color": "Color",
"updatedAt": "Updated",
"name": "Name",
"createdAt": "Created",
"baseUrl": "Base URL",
"apiKey": "API key",
"build": "Build"
},
"language": "Language",
"validation": {
"invalidJson": "Enter a valid JSON object",
"jsonObject": "Input must be a JSON object",
"sizeLimit": "Input must not exceed {value} KiB"
},
"feedback": {
"deleted": "Deleted",
"copied": "Copied"
},
"time": {
"minutesAgo": "{count} minute ago | {count} minutes ago"
},
"units": {
"tokens": "Tokens"
},
"sizes": {
"small": "Small",
"medium": "Medium",
"large": "Large"
}
}
}
+111
View File
@@ -0,0 +1,111 @@
{
"dashboard": {
"scheduling": {
"defaultConcurrency": "Default concurrency",
"totalSlots": "Total slots",
"freeSlots": "Available slots",
"smart": "Smart scheduling",
"quotaReset": "Quota reset priority",
"sticky": "Sticky",
"title": "Account scheduling",
"description": "Capacity, concurrency and allocation strategies",
"occupiedSlots": "Slots in use",
"strategy": "Allocation strategy"
},
"accountPool": {
"empty": "No account pool data",
"quotaExhausted": "Quota exhausted",
"rateLimited": "Rate limited",
"pending": "Pending",
"issueCountsEmpty": "Disabled: — · Errors: —",
"availableDescription": "Account is currently available",
"exhaustedDescription": "Account quota has been exhausted",
"limitedDescription": "Account requests are temporarily restricted",
"issueCounts": "Disabled: {disabled} · Errors: {error}",
"title": "Account status",
"description": "Account pool health",
"healthyRate": "Healthy accounts",
"distribution": "State distribution",
"unavailableCount": "Unavailable: {value}"
},
"activeAccounts": {
"title": "Active account usage",
"sortByRecent": "Sort by recent use",
"empty": "No recent account requests",
"recent": "Recently"
},
"title": "System overview",
"today": "Today's statistics",
"refresh": {
"action": "Refresh overview",
"failed": "Refresh failed, showing the last available statistics",
"unavailable": "Statistics temporarily unavailable, try again later",
"lastUpdated": "Refreshes every 30 s, last refreshed {updatedAt}",
"waiting": "Refreshes every 30 s, waiting for the first update",
"interval": "Refreshes every 30 s"
},
"metrics": {
"title": "Key metrics",
"outputTokens": "Output",
"inputTokens": "Input",
"cachedInputTokens": "Cached input",
"cacheHits": "Cache hits",
"requests": "Requests",
"firstTokenP95Ms": "TTFT P95",
"latencyP95Ms": "Latency P95",
"outputThroughputP50": "Output throughput P50",
"errors": "Errors",
"successRate": "Success rate",
"totalRequests": "Total requests",
"requestCount": "Requests",
"totalTokens": "Total tokens",
"totalCharges": "Total cost",
"totalCacheHits": "Total cache hits",
"totalCache": "Total cache"
},
"comparedWithYesterday": "vs. yesterday",
"trends": {
"title": "Usage trends",
"metric": "Trend indicator",
"highlight": "Highlight the {label} series",
"empty": "No trend data",
"latency": "Latency",
"errors": "Errors"
},
"recentRequests": {
"title": "Usage records",
"description": "Last 10 successful requests",
"empty": "No successful requests"
},
"clientIdentity": {
"notChecked": "Not checked yet",
"versionPolicy": "Version policy",
"customVersion": "Custom version",
"active": "Active",
"activeDescription": "New requests using the global settings use this identity",
"upToDate": "Up to date",
"upToDateDescription": "The active version matches the latest official release",
"updateAvailable": "Update available",
"latestRelease": "Latest official version: {releaseLabel}",
"checkFailed": "Check failed",
"checkFailedDescription": "Official version check failed",
"pending": "Pending check",
"pendingDescription": "Official releases have not been checked yet",
"verifiedAt": "Profile verified: {verifiedAt}",
"checkedAt": "Release checked: {checkedAt}",
"clientId": "Client ID",
"tokenAuth": "Token authentication",
"title": "Default upstream identity",
"provider": "Upstream platform",
"empty": "No request identity available",
"attributes": "Request identity details",
"authProtocol": "Authentication protocol",
"emulatedEnvironment": "Emulated environment",
"environment": "Environment"
},
"health": {
"title": "Request health",
"description": "Valid request availability"
}
}
}
+78
View File
@@ -0,0 +1,78 @@
{
"groups": {
"selector": {
"loading": "Loading groups…",
"empty": "No groups available, create one in Account groups"
},
"actions": {
"editGroup": "Edit group",
"disableGroup": "Disable group",
"enableGroup": "Enable group",
"deleteGroup": "Delete group",
"enterGroupName": "Please enter a group name",
"selectValidGroupingColor": "Please select a valid grouping color",
"updated": "Group updated",
"created": "Group created",
"disabled": "Group disabled",
"enabled": "Group enabled",
"groupDeleted": "Group deleted",
"deletedGroupDeletedGroups": "Deleted {count} group | Deleted {count} groups",
"partialDeletion": "Deleted {count} groups, the remaining groups were not deleted: {value}",
"batchDeletionFailed": "Batch deletion failed"
},
"filters": {
"searchAccountGroup": "Search account group",
"searchGroupName": "Search group name",
"filterByGroupStatus": "Filter by group status",
"deleteSelected": "Delete selected ({count})",
"createGroup": "Create group"
},
"editor": {
"editDescription": "Edit group details and request permissions",
"createDescription": "After creating the group, add accounts to it in Accounts",
"groupName": "Group name",
"forExampleProductionAccount": "For example: production account",
"groupColor": "Group color",
"selectGroupColor": "Select group color",
"fastMode": "Fast mode",
"imageGeneration": "Image generation",
"descriptionOptional": "Description (optional)",
"groupDescription": "Group description",
"describePurposeOfThisGroup": "Describe the purpose of this group",
"saveGroup": "Save group"
},
"metrics": {
"restricted": "Restricted",
"total": "Total",
"concurrency": "Concurrency",
"today": "Today",
"cumulative": "Cumulative"
},
"group": "Group",
"fields": {
"capacity": "Capacity"
},
"page": {
"description": "Organize accounts and control which accounts each API key can use",
"empty": "No groups yet",
"selectCurrentPageGroup": "Select current page group",
"selectGroup": "Select group",
"fastModeIsOn": "Fast mode is on",
"fastModeIsOff": "Fast mode is off",
"imageGenerationDisabled": "Image generation disabled",
"colorLabel": "Group color: {color}",
"batchDeleteWarning": "These groups will stop working immediately, deletion cannot be undone",
"batchDeleteDescription": "Delete the {count} selected group? Accounts will be kept | Delete the {count} selected groups? Accounts will be kept",
"disableAccountGrouping": "Disable account grouping",
"disableDescription": "API keys using this group will lose access to its accounts while the group is disabled",
"confirmDisable": "Confirm disable",
"disable": "Disable “{name}”?",
"affectedApiKeys": "Affected API keys ({count}): {value}",
"affectedKeys": "Affected API keys: {count}",
"deleteAccountGroup": "Delete account group",
"deleteWarning": "This group will stop working immediately, deletion cannot be undone",
"unnamedGroup": "This group",
"deleteAccountsWillBeKept": "Delete “{name}”? Accounts will be kept"
}
}
}
+29
View File
@@ -0,0 +1,29 @@
import accounts from './accounts.json'
import appearance from './appearance.json'
import auth from './auth.json'
import common from './common.json'
import dashboard from './dashboard.json'
import groups from './groups.json'
import keys from './keys.json'
import navigation from './navigation.json'
import plugins from './plugins.json'
import proxies from './proxies.json'
import settings from './settings.json'
import systemUpdate from './systemUpdate.json'
import usage from './usage.json'
export default {
...accounts,
...appearance,
...auth,
...common,
...dashboard,
...groups,
...keys,
...navigation,
...plugins,
...proxies,
...settings,
...systemUpdate,
...usage,
}
+110
View File
@@ -0,0 +1,110 @@
{
"keys": {
"configuration": {
"description": "Save or merge the configuration below and then restart Codex",
"platform": "Platform",
"toggleWebSocket": "Switch WebSocket configuration",
"importCcSwitch": "Add to CC Switch",
"copiedToClipboard": "Copied to clipboard",
"fullApiKeyNotAvailable": "Full API key not available",
"title": "Use API key"
},
"actions": {
"editKey": "Edit key",
"useKey": "Use key",
"moreActions": "More actions",
"resetUsedCredit": "Reset usage",
"disableKey": "Disable",
"enableKey": "Enable",
"deleteKey": "Delete",
"deletedApiKeyDeletedApiKeys": "Deleted {count} API key | Deleted {count} API keys"
},
"day": "Day",
"dailyUsage": "Daily usage",
"week": "Week",
"weeklyUsage": "Weekly usage",
"viewUsageAndCostsFor": "View usage and costs for {name}",
"costDetailsTitle": "Cost details (USD)",
"confirmNextTime": "Confirm next time",
"budgetReset": {
"dailyQuota": "Daily quota",
"weeklyQuota": "Weekly quota",
"keyQuotaReset": "Key quota reset",
"description": "Clear spending for the selected period, the reset date is set again on the next request",
"targetKey": "Target key",
"resetScope": "Reset scope",
"currentlyUsed": "Currently used",
"afterReset": "After reset",
"remainUnchanged": "Remain unchanged",
"confirmReset": "Confirm reset"
},
"created": {
"apiKeyCreated": "API key created",
"description": "Copy the API key or import it into CC Switch",
"accessNotice": "This key grants gateway access, share it only with trusted callers",
"copyKey": "Copy key",
"iHaveSaved": "I have saved"
},
"filters": {
"apiKeyFilteringAndOperations": "API key filtering and operations",
"searchPlaceholder": "Search by name or label",
"searchLabel": "Search API keys by name or label",
"deleteSelected": "Delete selected ({count})",
"createApiKey": "Create API key"
},
"editor": {
"description": "Set API key details, account groups, and usage limits",
"namePlaceholder": "For example: Production",
"labelOptional": "Label (optional)",
"forExampleBackendService": "For example: backend service",
"customKeyOptional": "Custom Key (optional)",
"keyPlaceholder": "Leave blank to generate a key",
"upstreamIdentity": "Upstream identity",
"dailyLimit": "Daily limit",
"dailyLimitUsd": "Daily limit (USD)",
"weeklyLimit": "Weekly limit",
"weeklyLimitUsd": "Weekly limit (USD)",
"maximumConcurrency": "Maximum concurrency",
"requestsPerMinuteRpm": "Requests per minute (RPM)",
"saveChanges": "Save changes",
"updated": "API key updated",
"created": "API key created",
"validation": {
"amount": "{label} must be a non-negative amount with up to 10 decimal places",
"integer": "{label} must be a non-negative integer"
},
"enterApiKeyName": "Please enter API key name",
"invalidKey": "Use visible HTTP header characters, without spaces or line breaks",
"requestsPerMinute": "Requests per minute"
},
"fields": {
"copyFullKey": "Copy full key",
"allAccounts": "All accounts",
"keyPrefix": "Prefix",
"quotaUsage": "Quota",
"requestLimits": "Limits",
"lastUsed": "Last used"
},
"page": {
"description": "Manage API keys and account access",
"noApiKeyYet": "No API key yet",
"selectCurrentPageKey": "Select current page key",
"selectKey": "Select key",
"concurrency": "Concurrency",
"batchDeleteWarning": "These API keys will stop working immediately, deletion cannot be undone",
"batchDeleteDescription": "Delete the {count} selected API key? | Delete the {count} selected API keys?",
"deleteApiKey": "Delete API key",
"deleteWarning": "This API key will stop working immediately, deletion cannot be undone",
"apiKey": "The API key",
"delete": "Delete {name}?"
},
"scope": {
"allAccounts": {
"title": "Allow access to all accounts",
"summary": "After saving, this key can access all accounts",
"confirm": "Allow access",
"description": "This key can access all accounts, including ungrouped and future accounts"
}
}
}
}
@@ -0,0 +1,29 @@
{
"navigation": {
"overview": "Overview",
"accounts": "Accounts",
"proxies": "Proxies",
"groups": "Groups",
"apiKeys": "API keys",
"usage": "Analytics",
"plugins": "Plugins",
"appearance": "Theme",
"settings": "Settings",
"update": {
"available": "Update available, open System update",
"open": "Open System update"
},
"switchLanguage": "Switch language ({value})",
"mainLabel": "Main navigation",
"pluginsLabel": "Plugin navigation",
"pluginManagement": "Manage",
"online": "Online",
"sidebar": {
"close": "Close sidebar",
"expand": "Expand sidebar",
"collapse": "Collapse sidebar",
"open": "Open sidebar"
},
"missingEntryPoint": "No default entry point is configured for the {role} identity"
}
}
+533
View File
@@ -0,0 +1,533 @@
{
"plugins": {
"assets": {
"pluginPackage": "Plugin package: {name}",
"selectPluginPackage": "Select a plugin package",
"packageLabel": "Plugin package"
},
"bindings": {
"observationHelpTitle": "About request observation",
"observationHelp": "Observe requests without changing their results",
"applyToAllRequests": "Apply to all requests",
"scopeHelpTitle": "About request scope",
"scopeHelp": "When disabled, select at least one scope, all conditions must match and any value within a condition may match",
"clientKey": "Client key",
"accountGrouping": "Account grouping",
"modelScope": "Model scope",
"oneModelNamePerLineExactMatch": "One model name per line, exact match",
"providerScope": "Provider scope",
"oneProviderIdentifierPerLine": "One Provider identifier per line",
"executionOrder": "Execution order",
"executionSequenceDescription": "Execution sequence description",
"priorityHelp": "Lower values run first",
"whenPluginFails": "When the plugin fails",
"continueToNextHandler": "Continue to the next handler",
"rejectRequest": "Reject request"
},
"capabilities": {
"moreCapabilities": "{count} more declared capabilities"
},
"catalog": {
"cardView": "Card view",
"listView": "List view",
"currentVersion": "Current version",
"installedVersion": "Installed version",
"provideFunctionality": "Features",
"searchForInstalledPlugins": "Search for installed plugins",
"searchPluginsPublishers": "Search plugins, publishers",
"pluginStatus": "Plugin status",
"pluginDisplayMode": "plugin display mode",
"noMatchingPlugins": "No matching plugins",
"installYourFirstPlugin": "Install your first plugin",
"tryAnotherNameOrStatus": "Try another name or status",
"emptyDescription": "Install a plugin above after verifying its source",
"clearFilters": "Clear filters",
"pluginInstalled": "Plugin installed",
"noDescription": "The publisher provided no description",
"versions": "Versions: {count}",
"manage": "Manage {displayName}",
"versionCount": "Versions"
},
"configuration": {
"fillInRequiredConfiguration": "Please fill in the required configuration",
"incompatibleSecrets": "The target version does not support some saved secrets, choose to replace or clear them",
"requiredSecretsCannotClear": "Required secrets cannot be cleared: {labels}",
"requiredSecretsMissing": "No saved values for required secrets: {labels}",
"secretsRequired": "Enter the required secrets",
"checkBasicSettings": "Please check basic settings",
"noParameters": "No plugin parameters required",
"sensitiveConfiguration": "Sensitive configuration",
"secretsHelpTitle": "About secret configuration",
"secretsHelp": "Secrets are stored separately and never displayed, Keep preserves existing values and Replace overwrites them with all values entered here",
"settingsSaved": "Settings saved: {count}",
"clearSecretsHelp": "Clear all secrets when saving",
"about": "About {name}",
"enterNewValue": "Enter new value",
"pluginParameters": "plugin parameters",
"advancedSettings": "Advanced settings",
"clientAuthentication": "Client authentication",
"applyAndSwitch": "Apply and switch",
"saveAndEnable": "Save and enable",
"saveSettings": "Save settings",
"keepExistingValues": "Keep existing values",
"replaceAllValues": "Replace all values",
"clearAllValues": "Clear all values",
"checkPluginParameters": "Please check plugin parameters",
"setRequestScopeOrCheckApplyTo": "Please set the request scope, or check \"Apply to all requests\"",
"invalidIdentityMappings": "Check the client authentication identity mappings",
"switchTo": "Switch to {version}",
"pluginSettings": "Plugin settings",
"unchangedVersion": "The current version is unchanged, edit settings before applying",
"pluginSettingsPartition": "Plugin settings partition",
"secretsModeLabel": "Secret storage action",
"customScope": "Custom scope",
"applyGlobally": "Apply globally",
"requestHandling": "Request handling: {value}",
"description": "Provide extensions using this configuration",
"providesTerminalCommands": "Provides terminal commands",
"requestHandlingNotConfigured": "Request handling not configured",
"apiKeys": "API keys: {count}",
"groups": "Groups: {count}",
"providers": "Providers: {count}",
"identityMappings": "Identity mappings: {count}",
"allRequests": "All requests",
"noLimitOnScope": "No limit on scope",
"featureDetails": "Feature details",
"capabilitiesOf": "Capabilities of {name}",
"terminalCommands": "Terminal commands",
"legacy": {
"multipleEnabledNotice": "Multiple configurations are enabled, disable the unused one in configuration history",
"previousConfigurations": "Previous configurations · {count}",
"description": "Keep existing settings and data, activating a historical configuration replaces the current one",
"disableAction": "Disable historical configuration",
"start": "Start",
"deleteHistoricalConfiguration": "Delete historical configuration"
},
"stale": "Plugin settings changed, refresh and try again",
"incompatible": "Adjust incompatible settings and try again"
},
"details": {
"version": "Version",
"pendingDescription": "Configuration saved and awaiting activation, status updates automatically",
"requiredConfiguration": "Complete required settings to enable the plugin",
"versionInUse": "The old version has active calls, wait for them to finish before deleting it",
"pluginDetails": "Plugin details",
"pluginDetailsSection": "Plugin details section",
"manualInstallationVersion": "Manual installation version",
"pluginHasNotBeenInitialized": "Plugin has not been initialized",
"pluginIsNotInstalled": "Plugin is not installed",
"initializePlugin": "Initialize plugin",
"installation": "Installation",
"versionNotAvailable": "Version not available",
"configurationStatusOf": "Configuration status of {name}",
"settings": "Settings",
"restart": "Restart",
"deactivate": "Deactivate",
"completeSetupAndEnable": "Complete setup and enable",
"fallbackVersion": "Fallback version",
"uninstallPlugin": "Uninstall plugin"
},
"downloadAuth": {
"accessToken": "Access token",
"usernameAndPassword": "Username and password",
"customRequestHeader": "Custom request header",
"noCertificationRequired": "No certification required",
"fillInGithubToken": "Fill in the GitHub token",
"credentialsPlaceholder": "Enter credentials",
"useSavedCredentials": "Use saved credentials",
"download": "Download · {hostname}",
"downloadCertification": "Download certification",
"helpTitle": "About download authentication",
"githubHelp": "Public repositories need no authentication, private repositories require a GitHub token with read access",
"urlHelp": "Required only when the download URL needs authentication",
"storageHelp": "Credentials are saved during lookup or resolution, used only for this source, and never shared with the plugin",
"authenticationMethod": "Authentication method",
"githubToken": "GitHub token",
"downloadToken": "Download token",
"enterToken": "Enter token",
"username": "Username",
"downloadUsername": "Download username",
"password": "Password",
"downloadPassword": "Download password",
"requestHeaderName": "Request header name",
"requestHeaderValue": "Request header value"
},
"enable": {
"notSet": "Not set",
"switchActiveConfiguration": "Switch active configuration",
"enablePluginConfiguration": "Enable plugin configuration",
"willBeEnabled": "Will be enabled",
"configurationsToDisable": "Configurations to disable: {count}",
"toggleEnablementInstructions": "Toggle enablement instructions",
"disableDescription": "These configurations will stop receiving new requests, settings, secrets, and private data are kept",
"willBeDeactivated": "Will be deactivated",
"confirmSwitch": "Confirm switch",
"confirmEnable": "Confirm enable"
},
"extensions": {
"emptyTitle": "No plugin management pages",
"emptyDescription": "Enable a plugin with a management page to open it here or from the sidebar",
"configuration": "Configuration {value}",
"pages": "Pages: {count}",
"openPage": "Open page"
},
"frontendAuth": {
"exclusiveCertification": "Exclusive certification",
"fallbackApiKeyIfNoMatch": "Fallback API key if no match",
"disabled": "(disabled)",
"configuredUnavailable": "Configured but unavailable",
"invalidBinding": "Client authentication requires the authentication phase and a supported unmatched-identity policy",
"unsupportedScope": "Client authentication does not support provider, model, or group scopes, disable and reenable this binding",
"addAtLeastOneIdentityMapping": "Please add at least one identity mapping",
"mappingLimit": "Up to 256 identity mappings",
"invalidIdentity": "Identity must be 1–256 UTF-8 bytes without surrounding whitespace or control characters",
"duplicateIdentity": "Each identity can be mapped only once",
"keyRequired": "Select a client API key for each identity",
"repeatedCursor": "The service returned a repeated pagination cursor",
"failedToLoadClientKey": "Failed to load client Key",
"enableClientAuthentication": "Enable client authentication",
"helpTitle": "About client authentication",
"description": "The plugin identifies external callers, the host maps each identity to an existing client API key and applies its limits, account scope, and concurrency policy",
"loginNotice": "Applies to client API requests, independently of admin sign-in",
"unmatchedProcessing": "Unmatched processing",
"unmatchedHandlingInstructions": "Unmatched handling instructions",
"exclusiveHelp": "Exclusive authentication rejects requests when the plugin finds no identity",
"fallbackToApiKeyWhenNoMatch": "Fallback to API key when no match is found: When the plugin does not recognize the identity, it will continue to use the host’s original API key for authentication",
"rejectionHelp": "Explicit plugin rejection or a failed call always rejects the request, without fallback",
"unmatchedLabel": "Unmatched identity policy",
"identityMapping": "Identity mapping",
"identityMappingDescription": "Identity mapping description",
"identityHelp": "Match the identity returned by the plugin exactly, each identity can be mapped once",
"keyHelp": "Select the client API key for this identity, disabled or deleted keys grant no access",
"reloadClientKey": "Reload client Key",
"addMapping": "Add mapping",
"identityMark": "Identity mark",
"identityPlaceholder": "Enter the identity returned by the plugin",
"failedToLoadTryAgain": "Failed to load, try again",
"selectClientApiKey": "Select a client API key",
"noClientKeyYet": "No client Key yet",
"removeIdentityMapping": "Remove identity mapping {value}"
},
"installation": {
"uploadPackage": "Upload package",
"enterDigitHexadecimalDigest": "Please enter a 64-digit hexadecimal digest",
"installNewVersion": "Install new version",
"pluginPackageCannotExceedMib": "Plugin package cannot exceed 32 MiB",
"verificationRequired": "Verify the selected plugin package first",
"githubRepositoryRequired": "Enter a GitHub repository URL or owner/repo",
"prereleaseTagRequired": "Specify a tag to look up a prerelease",
"updatePlugin": "Update plugin",
"installPlugin": "Install plugin",
"installDescription": "Confirm the source and version before installing",
"switchDescription": "Check settings compatibility before switching versions",
"sourceHelp": "Supports local packages, URLs, and GitHub",
"installationMethod": "Installation method",
"tarGzTgzMaxMib": "tar.gz/tgz, max 32 MiB",
"replace": "Replace",
"browseFiles": "Browse files",
"downloadUrl": "Download URL",
"downloadAddressDescription": "Download address description",
"urlHelp": "Use HTTPS, HTTP is allowed for loopback addresses",
"githubRepository": "GitHub repository",
"repositoryLinkOrOwnerRepo": "Repository link or owner/repo",
"tagLabel": "Version tag",
"tagHelpTitle": "About version tags",
"tagHelp": "Leave blank for the latest stable release, specify a tag for prereleases",
"tagPlaceholder": "Leave blank for the latest stable release",
"allowPrereleaseLabel": "Allow prerelease lookup",
"verificationSummary": "Verification summary",
"digestHelpTitle": "About package verification",
"digestHelp": "Optional 64-character SHA-256 hexadecimal digest from the publisher, used to verify the download",
"shaChecksum": "SHA-256 checksum",
"optionalSha": "Optional, SHA-256",
"versionFound": "Version found",
"preRelease": "Pre-release",
"thereIsNoTarGzOrTgz": "There is no tar.gz or tgz plugin package for this release",
"pendingTitle": "Plugins to install",
"parsingCompleted": "Parsing completed",
"publisher": "Publisher",
"applicablePlatforms": "Applicable platforms",
"trustNotice": "Plugins can access all gateway data and settings, verify the source before installing",
"activateAfterInstall": "Confirm switching to the new version after installation",
"installNewVersionInstructions": "Install new version instructions",
"configurationHelp": "Reuse settings with the new version's defaults, open settings if changes are needed, previously used versions keep their restore settings",
"queryAgain": "Query again",
"queryingVersion": "Querying version",
"saveSourceAndContinue": "Save source and continue",
"parsingPluginPackage": "Parsing plugin package",
"pluginInstallationFailed": "Plugin installation failed",
"noSource": "No installation source available for this plugin",
"sourceChanged": "Installation source changed, close and reopen this dialog",
"sourceSaveFailed": "Failed to save installation source",
"githubReleaseQueryFailed": "GitHub Release query failed",
"installedNeedsConfiguration": "Plugin installed, complete the required settings",
"preparing": "Plugin installed, preparing…",
"pluginVersionInstalled": "Plugin version installed",
"updateSourceChanged": "Installation source changed, check for updates again",
"pluginUpgradeFailed": "plugin upgrade failed",
"versionRequired": "Select a plugin version to install",
"packageMismatch": "Package does not match the current plugin, select another package",
"verificationFailed": "Package verification failed"
},
"management": {
"installed": "Installed",
"extensions": "Extensions",
"description": "Manage versions, configurations, and extensions",
"tabsLabel": "Plugin management sections",
"refresh": "Refresh plugins",
"switchPluginVersion": "Switch plugin version",
"switchHelp": "Check target version settings before switching, keep the current version if the check fails",
"deletePluginVersion": "Delete plugin version",
"deleteVersionHelp": "Versions in use cannot be deleted, deleting a version also removes its restore settings",
"delete": "Delete {displayName} {version}?",
"versionDeletionDetails": "Version deletion details",
"deleteVersionInUse": "Versions referenced by configurations or active calls cannot be deleted, other configurations are not disabled automatically",
"deleteVersionCleanupHelp": "Remove download credentials used only by this version, deleting the last version also removes source rules, shared credentials and proxies are kept",
"deleteVersionCleanupLabel": "Remove exclusive download credentials and, for the last version, source rules",
"deletePluginConfiguration": "Delete plugin configuration",
"deleteConfigurationWarning": "Permanently delete this configuration, secrets, and private data",
"deleteConfigurationHelp": "This cannot be undone, installed versions and other configurations are kept",
"uninstallWarning": "Delete all versions, configurations, secrets, and private data",
"confirmUninstall": "Confirm uninstall",
"versionCount": "{displayName} · {count} versions",
"uninstallCleanupLabel": "Also remove sources and exclusive download credentials",
"uninstallCleanupInstructions": "Uninstall cleanup instructions",
"uninstallCleanupHelp": "Remove credentials used by uninstalled versions only when no other version references them, shared credentials, proxies, and audit records are kept",
"disableInsteadHelp": "Disable the configuration if you only need to stop using it temporarily",
"permanentDeleteLabel": "Confirm permanent deletion, this cannot be undone",
"deleteDownloadCredentials": "Delete download credentials",
"itCannotBeDeletedWhileItIs": "It cannot be deleted while it is still in use and cannot be restored after deletion",
"pageLoadFailed": "Failed to load plugin extension pages",
"pluginDataLoadingFailed": "Plugin data loading failed"
},
"frame": {
"pluginPageCannotBeLoaded": "Plugin page cannot be loaded",
"versionChanged": "Plugin page version changed, refreshing…",
"navigationBlocked": "The plugin page tried to leave its isolated document, loading stopped",
"invalidQueryParameter": "Invalid query parameter",
"queryParametersExceedKib": "Query parameters exceed 8 KiB",
"invalidBody": "Request body is invalid or exceeds 1 MiB",
"routesDoNotAcceptRequestBody": "{method} routes do not accept a request body",
"contentTypeIsInvalid": "Content-Type is invalid",
"unregisteredContentType": "Content-Type is not registered for this plugin route",
"contentTypeRequired": "Requests with a body must declare Content-Type",
"invalidRequestParameters": "Invalid request parameters",
"unregisteredRequest": "Request is not registered in the current plugin version",
"invalidCallbackTicket": "Invalid callback ticket parameters",
"unregisteredCallback": "Callback path is not registered in the current plugin version",
"invalidTicketLifetime": "Callback ticket lifetime must be 1–600 seconds",
"invalidModelRequest": "Invalid model request parameters",
"clientkeyidIsInvalid": "clientKeyId is invalid",
"invalidModelBody": "Responses request body is invalid or exceeds 8 MiB",
"invalidModelJson": "Responses request body is not valid JSON",
"modelObjectRequired": "Responses request body must be a JSON object",
"pageDidNotContinueToReadModel": "The page did not continue to read the model response for 30 seconds",
"modelConcurrencyLimit": "Model request concurrency limit reached",
"duplicateModelRequest": "Duplicate model request ID",
"modelTimeout": "Model request exceeded 10 minutes",
"unsupportedModelContentType": "Model endpoint returned an unsupported content type",
"modelRequestFailed": "Model request failed",
"invalidPullId": "Invalid model response pull ID",
"concurrentPull": "A model response pull is already in progress",
"stalePullId": "Model response pull ID is stale",
"modelResponseReadFailed": "Model response read failed",
"duplicateManagementRequest": "Duplicate plugin management request ID",
"managementConcurrencyLimit": "Plugin management concurrency limit reached",
"invalidEntryPoint": "Plugin page entry point is not a registered HTML resource",
"unregisteredAsset": "Plugin page references an unregistered resource: {path}",
"htmlSubresource": "Plugin HTML resources cannot be loaded as subresources",
"cyclicCss": "Cyclic plugin CSS import: {path}",
"invalidVersion": "Invalid plugin page version, refresh and try again",
"resourceCountLimit": "Plugin page resource count exceeds the limit",
"pageChanged": "Plugin page changed, refresh and try again",
"pluginAssetReturnedHttp": "Plugin asset returned HTTP {status}",
"resourceTypeMismatch": "Plugin resource type differs from its registration: {path}",
"pluginAssetExceedsMib": "Plugin asset exceeds 1 MiB: {path}",
"resourceSizeLimit": "Plugin page resources exceed 8 MiB in total",
"unsupportedElement": "Plugin page uses an unsupported {'<'}{value}{'>'} element",
"redirectForbidden": "Plugin pages cannot redirect automatically",
"moduleScriptUnsupported": "Plugin pages currently require classic script bundles, ES modules are not supported",
"invalidPluginScriptAssetType": "Invalid plugin script asset type: {path}",
"unsupportedLink": "Plugin pages support stylesheet and icon links only",
"invalidStylesheet": "Invalid plugin stylesheet resource type: {path}",
"invalidPluginIconAssetType": "Invalid plugin icon asset type: {path}",
"unsupportedSrc": "Plugin pages do not support src loading for {'<'}{value}{'>'}",
"invalidPluginImageAssetType": "Invalid plugin image asset type: {path}",
"invalidPluginPosterAssetType": "Invalid plugin poster asset type: {path}",
"emptySrcset": "Empty resource reference in plugin srcset",
"externalNavigation": "Plugin pages cannot navigate to external or unregistered URLs",
"pluginPageDoesNotSupportUrls": "The plugin page does not support {name} URLs",
"externalAttribute": "Plugin page attribute references an external resource: {name}",
"unsupportedPluginCssSyntax": "Unsupported plugin CSS syntax: {ownerPath}",
"invalidCss": "Unable to parse plugin CSS: {ownerPath}",
"escapedCssIdentifier": "Plugin CSS rule and function names cannot contain escapes: {ownerPath}",
"inlineStyleImport": "Inline style attributes cannot import stylesheets",
"unsupportedPluginImportSyntax": "Unsupported plugin {'@'}import syntax: {ownerPath}",
"pluginImportTargetIsNotCss": "Plugin {'@'}import target is not CSS: {path}",
"unsupportedPluginAssetUrl": "Unsupported plugin asset URL: {rawReference}",
"resourceQuery": "Plugin resource URLs cannot contain query parameters: {rawReference}",
"resourceFragment": "Plugin resource URLs cannot contain fragments: {rawReference}",
"resourceOutsideArtifact": "Plugin resource URL leaves the artifact boundary: {rawReference}",
"invalidPluginAssetPathSegment": "Invalid plugin asset path segment: {rawReference}",
"invalidResourcePath": "Plugin registered an invalid resource path: {path}",
"pluginTextAssetIsNotValidUtf": "Plugin text asset is not valid UTF-8: {path}"
},
"pluginPage": "Plugin page",
"page": {
"configurationDescription": "Use plugin features with configuration “{name}”",
"description": "Open management pages from enabled plugins",
"unpublished": "This configuration or page is unavailable, it may have been disabled or switched to another version",
"refreshFailed": "Failed to refresh the page directory, showing the last loaded version: {loadError}",
"loadingPage": "Loading page"
},
"refreshPage": "Refresh page",
"pluginPageIsUnavailable": "Plugin page is unavailable",
"returnToPluginManagement": "Return to plugin management",
"resources": {
"unavailable": "Unavailable · {id}",
"multipleSelectionsAllowed": "{label} (multiple selections allowed)",
"unlimitedPlaceholder": "Unlimited, multiple selections allowed",
"loading": "Loading…",
"isTemporarilyUnavailable": "{label} is temporarily unavailable",
"noMatches": "No matches",
"no": "No {label}",
"createOneInFirst": "Create one in {value} first"
},
"rollback": {
"rollBackPluginVersion": "Roll back plugin version",
"description": "Restore the version's settings while keeping its enabled state",
"targetVersion": "Target version",
"fallbackInstructions": "Fallback instructions",
"restoreHelp": "Restore parameters and secrets from when this version was last enabled, private data must still pass compatibility checks",
"loadingOlderVersions": "Loading older versions…",
"selectRollbackVersion": "Select a rollback version",
"rollBackToTargetVersion": "Roll back to target version",
"empty": "No older version has restore settings, use Versions to switch to other versions",
"reload": "Reload",
"confirmRollback": "Confirm rollback",
"completed": "Rolled back to {version} and restored its settings"
},
"sourceProxy": {
"noProxyDirectConnection": "No proxy (direct connection)",
"disabledSuffix": "(disabled)",
"catalogUnavailable": "Selected proxy, directory unavailable",
"label": "Download proxy"
},
"status": {
"unableToStart": "Unable to start",
"runFailed": "Run failed",
"compatibilityReminder": "Compatibility reminder",
"deprecatedApi": "API upgrade needed, currently compatible",
"startupUnverified": "Startup can be attempted, runtime behavior still needs verification",
"compatibilityWindow": "The old API remains supported for at least {remainingReleases} stable releases",
"compatibilityEnding": "The compatibility window has ended, a future stable release will remove the old API adapter",
"unsupportedVersionHelp": "Configuration and data are kept, install a supported plugin version",
"restartHelp": "The enabled configuration is kept, restart it in plugin details",
"upgradeHelp": "Update the plugin or ask its author to upgrade the API"
},
"updates": {
"packageRequired": "Select a plugin package to confirm its version and compatibility",
"currentlyUsingThisVersion": "Currently using this version",
"verifiedUpdate": "New version found and package verified",
"sameVersionDifferentContent": "Same version number, different package contents",
"noHigherVersionFound": "No higher version found",
"pluginUpdate": "Plugin update",
"checkingDescription": "Checking the version and verifying the package…",
"versionComparison": "Version comparison",
"postTag": "Post tag",
"updateInspectionInstructions": "Update inspection instructions",
"configurationHelp": "Compare the package version and reuse current settings, incompatible settings keep the current version active and open settings",
"trustNotice": "Plugins can access all gateway data and settings, verify the source before updating",
"thereIsNoTarGzOrTgzPlugin": "There is no tar.gz or tgz plugin package for this release",
"upgradeTo": "Upgrade to {version}",
"continueInstallation": "Continue installation",
"unsupportedSource": "This source does not support update checks, install a new version manually",
"sourceChanged": "Installation source changed, check again",
"checkForUpdatesFailed": "Check for updates failed"
},
"versionDetails": "Version details",
"toBeInstalled": "To be installed",
"historicalConfiguration": "Historical configuration",
"referenceConfiguration": "Reference configuration",
"versions": {
"detailsLabel": "Version {version} details",
"historicalVersion": "Historical version"
},
"install": "Install {version}",
"deleteVersion": "Delete version {version}",
"credentials": {
"selectDownloadCredentials": "Select download credentials {name}",
"deleteDownloadCredentials": "Delete download credentials {name}",
"saveDownloadCredentialsFailed": "Failed to save download credentials",
"sourceCredentialsDeleted": "Source credentials deleted",
"deleteFailed": "Failed to delete source credentials"
},
"artifacts": {
"pluginProductHasBeenDeleted": "plugin product has been deleted",
"pluginProductDeletionFailed": "plugin product deletion failed"
},
"instances": {
"saveFailed": "Failed to save plugin configuration",
"versionMissing": "The selected version no longer exists, select another version",
"loadFailed": "Failed to load enabled configuration",
"configurationEnablementFailed": "Configuration enablement failed",
"switchedCurrentConfiguration": "Switched current configuration",
"pluginSettingsApplied": "Plugin settings applied",
"savedDisabled": "Settings saved, plugin remains disabled",
"pluginDisabled": "Plugin disabled",
"pluginDeactivationFailed": "Plugin deactivation failed",
"deleted": "Configuration, secrets, and private data permanently deleted",
"pluginInstanceDeletionFailed": "plugin instance deletion failed"
},
"uninstall": {
"newConfiguration": "A new plugin configuration appeared, close this dialog and confirm the uninstall scope again",
"versionChanged": "“{name}” changed versions, confirm the uninstall scope again",
"removingConfiguration": "Disabling and deleting configuration: {name}",
"newVersion": "Confirmed items deleted, newly installed versions remain, close this dialog and confirm the remaining items",
"completed": "Plugin uninstalled, related data and source settings removed",
"incomplete": "Uninstall incomplete, retry the remaining steps"
},
"deletingVersion": "Deleting version: {version}",
"switchedTo": "Switched to {version}",
"versionSettingFailedToLoad": "Version setting failed to load",
"versionSwitchingFailed": "Version switching failed",
"fallbackVersionLoadingFailed": "Fallback version loading failed",
"pluginVersionRollbackFailed": "plugin version rollback failed",
"fields": {
"requestCompletionAndUsage": "Request completion and usage",
"upstreamWebsocketEvents": "Upstream WebSocket events",
"requestScheduling": "Request scheduling",
"modelRouting": "Model routing",
"modelCatalog": "Model catalog",
"retryStrategy": "Retry strategy",
"requestMiddleware": "Request middleware",
"upstreamAdapter": "Upstream adapter",
"eventObservation": "Event observation",
"commandLine": "Command line",
"manageExtensions": "Manage extensions",
"maintenanceTasks": "Maintenance tasks",
"httpRequest": "HTTP request",
"allHttpRequests": "All HTTP requests",
"websocketMessages": "WebSocket messages",
"allWebsocketMessages": "All WebSocket messages",
"serviceCall": "Service call",
"allServiceCalls": "All service calls",
"requestToStart": "Request to start",
"everyTry": "Every try",
"upstreamCall": "Upstream call",
"accountScheduling": "Account scheduling",
"retryDecision": "Retry decision",
"toBeConfigured": "To be configured",
"deactivated": "Deactivated",
"waitingForItToTakeEffect": "Waiting for it to take effect"
},
"validation": {
"suppliedWithVersion": "Supplied with version",
"localUpload": "Local upload",
"fixedUrl": "Fixed URL",
"releaseList": "Release list",
"noRemoteUpdateSource": "No remote update source"
},
"onePerLine": "One item per line"
}
}
+165
View File
@@ -0,0 +1,165 @@
{
"proxies": {
"accounts": {
"platformType": "Provider",
"subscription": "Plan",
"noMatches": "No matching accounts, try another name or email address",
"empty": "No linked accounts",
"linkAccount": "Linked accounts",
"searchAssociatedAccounts": "Search associated accounts",
"searchAccountNameOrEmail": "Search account name or email",
"removeAction": "Remove account from this proxy",
"removeAssociatedAccount": "Remove associated account",
"remove": "Remove",
"removeDescription": "Removing “{name}” from “{removeProxyName}” will switch the account to a direct connection",
"removed": "Account removed from this proxy, using a direct connection"
},
"actions": {
"test": "Test proxy",
"edit": "Edit proxy",
"moreActionsFor": "More actions for {name}",
"disableProxy": "Disable proxy",
"enableProxy": "Enable proxy",
"deleteProxy": "Delete proxy",
"testInProgress": "A proxy test is running, wait for it to finish",
"testFailed": "Proxy test failed",
"connectedWithDetails": "{name}: connected, {message}",
"timeZoneMismatch": "{name}: connected, IPv4 and IPv6 exit time zones differ",
"connected": "{name}: connected",
"fillInProxyConnectionAddress": "Please fill in the proxy connection address",
"connectedInMs": "Connected in {latencyMs} ms",
"locationFailed": "Proxy connection failed, unable to resolve its location",
"exitLocationFilledIn": "Exit location filled in",
"unableToObtainExitLocation": "Unable to obtain exit location",
"fieldsRequired": "Enter a proxy name and URL",
"invalidConnectionLimit": "Connection limit must be an integer from 0 to 4,294,967,295",
"saved": "Proxy saved",
"proxyEnabled": "Proxy enabled",
"disabled": "Proxy disabled, linked accounts now use direct connections",
"deleted": "Proxy deleted"
},
"batchCreate": {
"proxyList": "Proxy list",
"formatDescription": "Proxy list format",
"supportedFormats": "Supported formats",
"hostPortUsernamePassword": "host:port:username:password",
"httpUsernamePasswordHostPort": "http://username:password{'@'}host:port",
"protocolHelp": "Addresses without a protocol use the default below, complete URLs keep their own protocol",
"ipv6Help": "Enclose IPv6 addresses in square brackets, for example",
"onePerLineMaximum": "One per line · Maximum: {value}",
"bulkProxyList": "Bulk proxy list",
"totalReadyToAdd": "Total: {count}, ready to add: {count2}",
"needsChanges": ", needs changes: {count}",
"line": "Line {line}: {error}",
"additionalIssues": "{count} more entries need attention",
"defaultProtocol": "Default protocol",
"defaultProtocolLabel": "Default protocol for addresses without one",
"namePrefix": "Name prefix",
"proxy": "Proxy",
"conflict": "Proxy already exists or its configuration conflicts, existing records were kept",
"stopped": "Remaining additions stopped"
},
"batchTest": {
"resultsTitle": "Batch results",
"processed": "Processed",
"added": "Added: {created}",
"invalidFormat": "Invalid format: {invalid}",
"connected": "Connected: {succeeded}",
"connectionFailed": "Connection failed: {failed}",
"locationPending": "Location pending: {locationPending}",
"needsAttention": "Needs attention: {attention}",
"skipped": "Skipped: {skipped}",
"scrollListOfProxyResults": "Scroll list of proxy results",
"lineNumber": "Line {key}",
"addedStatus": "Added",
"connectionIsNormal": "The connection is normal",
"stopped": "Remaining tests stopped",
"proxyMissing": "The selected proxy no longer exists, refresh the list",
"batchTestCompletedConnected": "Batch test completed, connected: {succeeded}",
"unsuccessful": "Unsuccessful: {count}",
"locationsPending": "Location pending: {locationPending}",
"proxiesNoLongerAvailable": "Proxies no longer available: {missing}",
"toBeExecuted": "To be executed",
"requestFailed": "Request failed",
"configurationConflict": "Configuration conflict",
"testingIsBusy": "Testing is busy",
"resultToBeConfirmed": "Result to be confirmed",
"notExecuted": "Not executed",
"invalidProxyFormat": "Invalid proxy format",
"invalidAddress": "Invalid proxy host or port",
"duplicateOfLine": "Duplicate of line {earlier}",
"formatHelp": "Invalid format, check the format guide",
"proxyListCannotExceedKib": "Proxy list cannot exceed 512 KiB",
"addUpToProxiesAtTime": "Add up to {value} proxies at a time",
"resultUnknown": "Result unconfirmed, refresh the list to check",
"interrupted": "Request interrupted or service unavailable, refresh the list to check the result",
"skippedAfterFailure": "Skipped because the previous operation failed"
},
"editor": {
"single": "Single",
"batch": "Batch",
"timeZoneMismatch": "IPv4 and IPv6 exit time zones differ",
"createTitle": "Add proxy",
"connectionHelp": "Leave blank to keep the connection and credentials, include any required username and password in a new URL",
"protocolHelp": "Supports HTTP, HTTPS, SOCKS5, and SOCKS5H, with optional credentials in the URL",
"createDescription": "Add a proxy to route account traffic",
"methodLabel": "Add method",
"nameLabel": "Name",
"namePlaceholder": "Enter a proxy name",
"proxyAddress": "Address",
"addressPlaceholder": "Enter proxy URL",
"upstreamWsConnectionCap": "Upstream WS connection cap",
"connectionLimitHelp": "Shared by accounts using this proxy",
"noRestrictionsByDefault": "No restrictions by default",
"customTimeZoneLocation": "Custom time zone location",
"affectedAccounts": "The outgoing route will change for {count} linked accounts",
"pendingResultsHelp": "Pending entries may be saved, refresh and check before adding more",
"saveAction": "Save proxy",
"waitForCurrentOperationToEnd": "Wait for the current operation to end",
"stopSubsequentOperations": "Stop subsequent operations",
"testing": "Testing",
"adding": "Adding",
"editItemsNotAdded": "Edit items not added",
"testAddedProxies": "Test added proxies ({count})",
"testAfterAdding": "Test after adding",
"add": "Add ({count})",
"addProxy": "Add proxy"
},
"region": {
"connectionFailed": "Connection failed",
"regionalConflict": "Regional conflict",
"parsingFailed": "Parsing failed",
"exitNotRecognized": "Exit not recognized",
"ipv4AndIpv6EgressTimeZonesAre": "IPv4 and IPv6 egress time zones are inconsistent",
"exitLocation": "Exit location: {label} · {timezone}",
"detectHelp": "Resolve the exit location when testing proxies",
"customLocation": "Custom location: {customLabel} · {timezone}",
"custom": "Custom: {customLabel}"
},
"fields": {
"exitIp": "Exit IP",
"latency": "Latency",
"testTime": "Tested"
},
"page": {
"description": "Manage account proxies, test connections, and inspect exit IP addresses",
"searchLabel": "Search proxies",
"searchPlaceholder": "Search by proxy name",
"batchTestAction": "Test proxies",
"batchTest": "Batch test ({count})",
"noMatches": "No matching proxies, try another name",
"empty": "No proxies yet",
"selectCurrentPageProxy": "Select current page proxy",
"selectProxy": "Select proxy {name}",
"credentialsSaved": "Proxy credentials saved",
"underTest": "Under test",
"ms": "{message} ({latencyMs} ms)",
"notTested": "Not tested",
"viewAccountsAssociatedWith": "View the {count} accounts associated with {name}",
"disable": "Disable “{name}”?",
"disableDescription": "New requests from linked accounts will use direct connections, proxy settings and bindings are kept and resume when reenabled",
"delete": "Delete “{name}”?",
"deleteDescription": "Linked accounts will be unlinked and new requests will use direct connections"
}
}
}
+648
View File
@@ -0,0 +1,648 @@
{
"settings": {
"clientProfile": {
"userAgent": "User agent",
"clientIdentitySource": "Client identity source",
"globalConfiguration": "Global configuration",
"customConfiguration": "Custom configuration",
"presetLoadingFailed": "Preset loading failed",
"enterIntegerFromTo": "Enter an integer from 1 to {version}",
"clientDefault": "Client default",
"useCustomUserAgent": "Use a custom user agent",
"cliEntry": "CLI entry",
"coreDefaultIdentity": "Core · Default identity",
"tuiInteractiveTerminal": "TUI · Interactive terminal",
"execNonInteractiveExecution": "Exec · Non-interactive execution",
"versionStrategy": "Version strategy",
"followLatestVersion": "Follow the latest version",
"customVersion": "Custom version",
"versionLag": "Version lag",
"versionLagHelp": "Stay 1–{version} versions behind, or leave blank to use the latest version",
"terminalIdentification": "Terminal identification",
"leaveBlankToUseUnknown": "Leave blank to use unknown",
"systemVersion": "System version",
"userAgentPlaceholder": "Enter the full user agent",
"previewAfterFillingInVersion": "Preview after filling in the version",
"previewIsNotAvailableYet": "Preview is not available yet",
"resolvingClientIdentity": "Resolving client identity",
"fixedIdentity": "Fixed identity",
"automaticUpdates": "Automatic updates",
"versionsBehind": "· {version} versions behind",
"checked": "Checked {checkedAtDisplay}",
"toBeChecked": "To be checked",
"updateFailedUseLastVersion": "Update failed · Use the last version",
"clientIdentityProvider": "Client identity provider",
"upstreamIdentityPlatform": "Upstream identity platform",
"clientId": "Client ID",
"operatingMode": "Operating mode",
"operatingSystem": "Operating system",
"cpuArchitecture": "CPU architecture",
"xaiClientIdentitySource": "xAI client identity source",
"loadFailed": "Global configuration failed to load",
"clientType": "Client type",
"grokCliVersion": "Grok CLI version",
"forExample": "For example: 1.0.13",
"clientIdentity": "Client identity",
"description": "Set the client type, version, and request headers the gateway sends upstream"
},
"pricing": {
"multiplier": "Multiplier",
"clearOverrides": "Clear overrides",
"setMultipliers": "Set multipliers",
"batch": {
"description": "Only these {count} models will change, past costs will not be recalculated",
"resetHelp": "Restore source or built-in prices, mark unconfigured when neither is available",
"multiplierHelp": "Replace the current multiplier, 0–100 with up to four decimal places"
},
"targetMultiplier": "Target multiplier",
"enterLegalMultiplier": "Please enter legal multiplier",
"confirmClearOverride": "Confirm clear override",
"confirmSettingMultiplier": "Confirm setting multiplier",
"sourcePrice": "Source price",
"textToken": "Text tokens",
"validation": {
"modelId": "Model ID must be 1–128 bytes without whitespace or control characters",
"tierPrices": "Enter all four prices for this tier, 0–1,000,000 with up to four decimal places",
"standardTier": "New models require standard tier prices"
},
"multiplierRangeIsWithUpToFour": "The multiplier range is 0~100, with up to four decimal places",
"editModelPricing": "Edit model pricing",
"addModelPricing": "Add model pricing",
"upstreamModelId": "Upstream model ID",
"forExampleGpt": "For example gpt-5.4",
"customizedMultiplier": "Customized multiplier",
"gearPrice": "Gear price",
"priceRange": "Price range",
"unitPriceSource": "Unit price source",
"tier": {
"sourceUnavailable": "No source prices for this tier"
},
"fillInUnitPrice": "Fill in the unit price",
"pricingInstructions": "Pricing instructions",
"modelIdUsesNameActuallySentTo": "Model ID uses the name actually sent to upstream, not the client alias",
"customTierHelp": "Enter all four unit prices, up to 1,000,000 each; use 0 for free pricing and multipliers from 0 to 100, with up to four decimal places",
"estimateHelp": "Affects local estimates and spending limits, not actual subscription charges, applies to new requests after saving and leaves past costs unchanged",
"unitPrice": "{label} unit price",
"source": "Source",
"takeEffect": "Take effect",
"sync": {
"title": "Sync source prices",
"description": "Sync source prices for selected models, keeping custom prices and multipliers",
"skipped": "Skipped {count} models with incomplete prices or incompatible billing methods",
"action": "Sync"
},
"selectAll": "Select all",
"selected": "Selected: {count} / {count2}",
"keepManualCoverage": "Keep manual coverage",
"noChangeInSourcePrice": "No change in source price",
"skipSynchronizedModels": "Skip synchronized models",
"confirmSynchronization": "Confirm synchronization",
"model": "Model",
"input": "Input",
"output": "Output",
"cacheRead": "Cache read",
"noMatchingModel": "No matching model",
"selectModelOnThisPage": "Select model on this page",
"select": "Select {model}",
"image": "· Image",
"editPrice": "Edit price",
"deletePriceList": "Delete price list",
"notSyncedYet": "Not synced yet",
"searchModel": "Search model",
"searchModelId": "Search model ID",
"modelProvider": "Model provider",
"priceSource": "Price source",
"allSources": "All sources",
"batchOperation": "Batch operation",
"selectedCountLabel": "Selected",
"item": "item",
"setMultiplier": "Set multiplier",
"clearOverwrite": "Clear overwrite",
"deselect": "Deselect",
"synchronizationInstructions": "Synchronization instructions",
"sourceHelp": "Fetch community prices from models.dev, keeping custom prices and multipliers",
"lastSynced": "Last synced: {syncTime}",
"syncPriceList": "Sync price list",
"addModel": "Add model",
"unitHelp": "Prices in USD per million tokens, view pricing details",
"unitPriceUnitUsdMTokens": "Unit prices in USD per million tokens",
"priorityHelp": "Custom prices override source prices, then built-in prices, affecting local estimates and spending limits only",
"tableHelp": "Effective standard-tier prices; image models show image token prices and struck-through values show source prices; edit a model to view other tiers",
"priceListFailedToLoad": "Price list failed to load",
"deleteModelPriceList": "Delete model price list",
"deleteDescription": "Delete source and custom prices for this model, leaving past costs unchanged",
"standard": "Standard",
"longContextStandard": "Long context · standard",
"longContextPriority": "Long context · Fast",
"longContextUltrafast": "Long context · Ultrafast",
"longContextFlex": "Long context · Flex",
"imageToken": "Image tokens",
"cacheWrites": "Cache writes",
"builtInPriceList": "Built-in price list",
"manualCoverage": "Manual coverage",
"notConfigured": "Not configured",
"unableToLoadPriceList": "Unable to load price list",
"deleted": "Model price deleted",
"manualOverrideCleared": "Manual override cleared",
"modelPricingSaved": "Model pricing saved",
"synced": "Source prices synced, custom prices kept",
"unitLabel": "USD / 1M tokens"
},
"scheduling": {
"roundRobin": "Round robin",
"autoReviewSlotsHelp": "Applies to OpenAI accounts only: with a regular concurrency limit of 10 and 3 auto review slots, up to 10 regular requests and 3 auto review requests can run independently",
"autoReviewQueueHelp": "With dedicated slots, auto review uses a separate queue that may exceed account queue capacity, while total queue capacity, queue timeout, and API key limits still apply",
"weights": {
"load": "Load weight",
"loadHelp": "Higher values favor accounts with lower concurrency utilization",
"quota": "Remaining quota weight",
"quotaHelp": "Higher values favor accounts with more remaining quota",
"health": "Health weight",
"healthHelp": "Higher values favor accounts with fewer recent failures",
"latency": "Latency weight",
"latencyHelp": "Higher values favor accounts with faster first useful output",
"reset": "Quota reset weight",
"resetHelp": "Higher values favor accounts whose quota resets soon, unknown or past reset times receive no bonus",
"queue": "Queue weight",
"queueHelp": "When queuing is needed, higher values favor accounts with fewer waiting requests, set to 0 to use the shortest queue"
},
"enterValueFromToUpToOne": "Please enter a value from 0 to 10, up to one decimal place",
"description": "Adjust account selection preferences",
"enabledHelp": "Applies when smart scheduling is enabled",
"about": "About {label}",
"zeroWeightHelp": "Set to 0 to exclude a factor from scoring",
"weightsRequired": "At least one weight must be greater than 0"
},
"affinity": {
"modes": {
"relaxed": "Relaxed",
"preferred": "Preferred",
"strict": "Strict",
"relaxedHelp": "Relaxed: use the scheduling policy without preferring the session's primary account",
"preferredHelp": "Preferred: reuse the primary account, route elsewhere temporarily if busy or unavailable, and keep the session binding",
"strictHelp": "Strict: use one account per session, child threads wait and follow the parent thread's account switches"
},
"title": "Session affinity",
"mode": "Mode",
"description": "Account binding within a session",
"accountAffinityInstructions": "Account affinity instructions",
"policyHelp": "Reselection follows the current scheduling policy",
"duration": "Binding duration",
"durationHelp": "Renewed on successful scheduling",
"durationHours": "Binding duration (hours)",
"hours": "hours",
"maxAccountSwitches": "Max account switches",
"switchLimitHelp": "Per request, 0 disables switching"
},
"autoDisable": {
"overloadProtection": "Overload protection",
"description": "Pause scheduling and start cooldown when upstream capacity failures reach the threshold",
"enableOverloadProtection": "Enable overload protection",
"failureCountThreshold": "Failure threshold",
"thresholdHelp": "Capacity failures in the counting window",
"times": "times",
"statisticsWindow": "Counting window",
"windowHelp": "Extended after each failure",
"statisticsWindowSeconds": "Counting window (seconds)",
"seconds": "seconds",
"cooldownTime": "Cooldown",
"cooldownHelp": "Delay recovery if the probe fails",
"cooldownTimeInSeconds": "Cooldown (seconds)",
"recoveryProbeModel": "Recovery probe model",
"probeModelHelp": "Blank uses the first available model",
"requireSuccessfulProbe": "Require successful probe",
"modelPlaceholder": "Auto-select model",
"concurrencyReduction": {
"label": "Adaptive concurrency reduction",
"helpTitle": "About adaptive concurrency reduction",
"description": "Lower the account's concurrency limit, recovery does not raise it automatically"
}
},
"warmup": {
"title": "Account warmup",
"description": "Try to start quota windows for idle Codex OAuth accounts",
"enableDailyWarmup": "Enable daily warmup",
"executionTime": "Execution time",
"timesPlaceholder": "HH:MM, separate times with commas",
"scheduleLabel": "Daily warmup times",
"modelLabel": "Warmup model",
"modelHelp": "Required when enabled, use an available model",
"modelPlaceholder": "Enter model name",
"helpTitle": "About account warmup",
"help": "Send one request to each idle Codex OAuth account at the scheduled times, starting a quota window is not guaranteed"
},
"adminApiKey": {
"adminApiKey": "Admin API key",
"description": "For external integrations with administrator access",
"regenerate": "Regenerate",
"generate": "Generate",
"notGenerated": "Not generated",
"enabledDescription": "Admin API access is enabled, the full key is shown only when generated",
"disabledDescription": "External systems cannot currently access the admin API with an API key",
"generatedNotice": "The full key is shown once, save it now",
"adminApiKeyUpdated": "Admin API key updated",
"generated": "Admin API key generated",
"adminApiKeyDeleted": "Admin API key deleted"
},
"password": {
"administratorPassword": "Administrator password",
"description": "Used to sign in to the admin console",
"changePassword": "Change password",
"verifyCurrentPassword": "Verify current password",
"sessionNotice": "All administrators must sign in again after a password change",
"validation": {
"minLength": "The new password must have at least 12 characters",
"unchanged": "The new password must differ from the current password",
"mismatch": "The new passwords do not match"
},
"newPasswordCannotExceedBytes": "New password cannot exceed 1024 bytes",
"changed": "Password changed, sign in again with the new password",
"changeAdministratorPassword": "Change administrator password",
"changeDescription": "Verify your current password to set a new one",
"currentPassword": "Current password",
"enterCurrentPassword": "Enter current password",
"newPassword": "New password",
"passwordHelp": "At least 12 characters, a mix of letters, numbers, and symbols is recommended",
"setNewPassword": "Set new password",
"confirmNewPassword": "Confirm new password",
"enterNewPasswordAgain": "Enter new password again",
"saveAndLogInAgain": "Save and log in again"
},
"concurrency": {
"title": "Concurrency",
"accountLimit": {
"label": "Default account concurrency",
"help": "Used unless overridden, 0 means unlimited"
},
"keyQueueCapacity": "API key queue capacity",
"keyQueueHelp": "Per API key, 0 disables queuing",
"accountQueueCapacity": "Account queue capacity",
"accountQueueHelp": "Per account, 0 disables queuing",
"queueTimeoutLabel": "Queue timeout (s)",
"queueTimeoutHelp": "Shared by both queues, 1–120 s",
"autoReview": {
"label": "Reserved auto review slots",
"description": "Extra slots per OpenAI account, 0 shares regular concurrency",
"helpTitle": "About auto review concurrency"
},
"queueTimeoutHelpTitle": "About queue timeout",
"queueTimeoutDetails": "The API key and account queues share this timeout, measured from the first queue entry"
},
"modelMapping": "Model mapping",
"routing": {
"modelMapHelp": "Map client model names to the upstream models used"
},
"addMapping": "Add mapping",
"loadingModelMapping": "Loading model mapping…",
"requestModel": "Request model",
"upstreamModel": "Upstream model",
"upstreamModelName": "Upstream model name",
"deleteMapping": "Delete mapping",
"history": {
"title": "History retention",
"retentionHelp": "Auto-delete expired request records and statistics",
"retentionConstraints": "Minimum 1 day, deletion is permanent",
"retentionDaysLabel": "History retention (days)"
},
"retentionDays": "Retention days",
"enterDays": "Please enter 1–31 days",
"day": "days",
"location": {
"requestLocationOverride": "Request location override",
"description": "Override time zone and location fields in Codex requests, custom locations on account proxies take precedence",
"enableLocationOverlay": "Enable location overlay"
},
"quotaReset": {
"title": "Quota reset credits",
"enableHelp": "Enable automatic use in the account's Quota reset panel",
"description": "Global settings for accounts with automatic use enabled",
"thresholdHelp": "Skip automatic use when the remaining quota exceeds this threshold, leave blank for no limit",
"weeklyQuotaLimit": "Reset credit remaining weekly quota threshold"
},
"advanceUsageTimeMinutes": "Advance usage time (minutes)",
"resetCardAdvanceTime": "Reset card advance time",
"remainingWeeklyQuotaLimit": "Remaining weekly quota limit (%)",
"responseLimit": {
"requestBodyLimit": "Request body limit",
"description": "Limit decompressed request bodies for the Responses API",
"maximumSizeAfterDecompression": "Maximum size after decompression",
"sizeHelp": "Higher limits allow larger images and conversation history, increasing memory use",
"maxSizeLabel": "Maximum decompressed request body size"
},
"rotation": {
"title": "Scheduling",
"customized": "Custom",
"smartSchedulingSettings": "Smart scheduling settings",
"smartLabel": "Smart",
"smartDescription": "Adjustable weights for load, remaining quota, health, and latency",
"quotaResetLabel": "Soonest reset",
"quotaResetDescription": "Use remaining quota on accounts closest to reset",
"roundRobinLabel": "Round robin",
"roundRobinDescription": "Cycle through available accounts in order",
"stickyLabel": "Sticky",
"stickyDescription": "Reuse the most recent account until unavailable"
},
"access": {
"accessRestrictions": "Access restrictions",
"deleteAdminApiKey": "Delete Admin API key",
"deleteKeyDescription": "External systems will lose admin API access through this key",
"areYouSureYouWantToDelete": "Are you sure you want to delete the current administrator API key? This operation will take effect immediately"
},
"tokenRefresh": {
"title": "Credential refresh",
"leadTimeLabel": "Refresh lead time (s)",
"leadTimeHelp": "Refresh access tokens before they expire",
"concurrencyLabel": "Refresh concurrency limit",
"concurrencyHelp": "Concurrent refresh limit, lower to reduce rate limiting"
},
"backup": {
"fileName": "Filename",
"size": "Size",
"expirationTime": "Expires",
"triggerMode": "Trigger",
"startTime": "Started",
"manual": "Manual",
"plan": "Plan",
"exclusions": "Excludes request details and logs",
"backupRecords": "Backup records",
"backupScopeDescription": "Backup scope description",
"contents": "Includes accounts, API keys, settings, plugins, and consumed quota",
"usageRetentionHourSummary": "Usage retention hour summary",
"creating": "Creating…",
"createBackup": "Create backup",
"noBackupRecordYet": "No backup record yet",
"downloadBackup": "Download backup",
"deleteBackup": "Delete backup",
"deleteWarning": "The remote object and backup record will be deleted, this cannot be undone",
"deleteConfirmation": "Delete this backup?",
"message": "?",
"schedule": {
"backupPlan": "Backup plan",
"description": "Set automatic backup times and retention limits",
"saving": "Saving…",
"enableScheduledBackup": "Enable scheduled backup",
"cronExpression": "Cron expression",
"cronHelp": "Five-field cron expression, for example 0 2 * * * runs daily at 02:00",
"retentionDaysHelp": "Delete older backups, 0 disables age limits, count limits still apply",
"retentionDaysLabel": "Retention (days)",
"maxBackupsLabel": "Max backups",
"retentionCountHelp": "Delete excess backups, 0 disables count limits, age limits still apply"
},
"status": {
"queuing": "Queuing",
"exporting": "Exporting",
"uploading": "Uploading",
"deleting": "Deleting"
},
"storage": {
"s3StorageConfiguration": "S3 storage configuration",
"connectionTestPassed": "Connection test passed",
"connectionTestHasNotPassed": "Connection test has not passed",
"testing": "Testing…",
"endpointAddress": "Endpoint address",
"endpointHelp": "HTTPS endpoint for the S3-compatible service",
"region": "Region",
"regionHelp": "Use auto for R2, otherwise use the provider's region",
"bucket": "Bucket",
"privateBucketName": "Private bucket name",
"objectKeyPrefix": "Object key prefix",
"prefixHelp": "Storage path prefix for new backup objects, existing backups are unchanged",
"credentialsLabel": "Object storage credentials",
"objectStorageSpecificSecret": "Object storage-specific Secret",
"forcePathStyle": "Force path-style access",
"accessKeyId": "Access key ID",
"secretAccessKey": "Secret access key",
"description": "Configure S3-compatible storage, including {service}"
},
"r2": {
"cloudflareR2OnboardingGuide": "Cloudflare R2 Onboarding Guide",
"createBucket": "1. Create a bucket",
"createApiToken": "2. Create an API token",
"fillInConnectionParameters": "3. Fill in the connection parameters",
"credentialsHelp": "Access key ID / Secret access key: credentials generated in the previous step",
"forcePathStyleOff": "Force Path Style: Off",
"completeConnectionTest": "4. Complete the connection test",
"testDescription": "Save the configuration, then select Test connection to verify read and write permissions using a probe object, a successful test is required before enabling scheduled or manual backups, credentials are stored only on the server",
"gotIt": "Got it",
"bucketDescription": "In Cloudflare Dashboard, open R2 and create a private bucket such as {bucket}, keep public read access disabled",
"tokenDescription": "In Manage API Tokens, create an object storage token with read, write, list, and delete access to the target bucket only",
"endpointLabel": "Endpoint:",
"regionDescription": "Region: {region} (required by R2)"
},
"backupTaskCreated": "Backup task created",
"failedToDownloadBackup": "Failed to download backup",
"backupDeletionRequested": "Backup deletion requested",
"storageSaved": "Storage settings saved and scheduled backups paused, test the connection before reenabling them",
"storageConfigurationSaved": "Storage configuration saved",
"connectionVerified": "Connection test passed",
"backupPlanSaved": "Backup plan saved"
},
"clientVersion": {
"macosLinuxOfficialInstaller": "macOS/Linux · Official installer",
"windowsInstaller": "Windows PowerShell · Official installer",
"homebrewFirstTimeInstallation": "Homebrew · First time installation",
"homebrewUpgrade": "Homebrew · Upgrade",
"installOrUpgradeCodexCli": "Install or upgrade Codex CLI",
"cliInstallHelp": "Use the command for your installation source, the official installer selects your platform architecture automatically",
"selectInstallationSource": "Select installation source",
"cliUpgradeHelp": "Run the same command again to upgrade to the current release",
"viewOfficialDocumentation": "View official documentation",
"ubuntuDebianUpgrade": "Ubuntu/Debian · Upgrade",
"fedoraRhelUpgrade": "Fedora/RHEL · Upgrade",
"onlineInstallationAndUpgrade": "Online installation and upgrade",
"desktopUpgradeHelp": "Desktop apps usually update automatically, or you can reinstall from official sources",
"officialDownloadPage": "Official download page",
"openAiPackageHelp": "Official OpenAI installer, choose your device's architecture",
"storePackageHelp": "Offline Microsoft Store package, choose your device's architecture",
"msixInstallHelp": "After downloading, install or upgrade with PowerShell",
"sizeUnknown": "Size unknown",
"windowsOfflineInstallation": "Windows offline installation",
"cached": "Cached",
"refreshingDownloads": "Refreshing offline download links…",
"refreshOfflineDownloadLinks": "Refresh offline download links",
"loadingPackages": "Loading offline packages…",
"packagesFailed": "Failed to load offline packages",
"stableChannel": "Stable channel",
"linkExpired": "Link expired: {value}",
"downloadMsix": "Download {value} MSIX",
"downloadPackage": "Download MSIX",
"commandCopied": "Command copied",
"copyCommand": "Copy command",
"codexClientUpgrade": "Codex client upgrade",
"guideDescription": "Select a client to view its installation and upgrade instructions",
"clientVersionRestrictions": "Client version restrictions",
"openGuide": "View installation and upgrade instructions",
"codexDesktopMinimumVersion": "Codex Desktop minimum version",
"onlyCheckDesktopVersionEG": "Only check the desktop version, e.g. 26.825.51511",
"codexCliMinimumVersion": "Codex CLI minimum version",
"minimumVersionHelp": "Checks standalone CLI versions only, for example 0.152.0"
},
"privacy": {
"preview": {
"enterValidRequestSampleJson": "Please enter a valid request sample JSON",
"testRules": "Test rules",
"description": "Run enabled draft rules in order, the sample is used only for this test",
"requestSample": "Request sample",
"requestPlaceholder": "Paste request JSON containing body, headers, and turnMetadata",
"finalResult": "Final result",
"ruleExecutionResults": "Rule execution results",
"notEnabled": "Not enabled",
"skipped": "Skipped"
},
"skipCurrentRule": "Skip current rule",
"blockRequestFromBeingSent": "Block request from being sent",
"privacyPolicy": "Privacy policy",
"description": "Normalize or remove private information in Codex requests using rules",
"enableRequestRules": "Enable request rules",
"addRule": "Add rule",
"addFromPreset": "Add from preset",
"runsInListOrderRulesSteps": "Runs in list order · Rules: {count} · Steps: {count2} / 32",
"executionFailed": "Execution failed",
"ruleExecutionFailed": "Rule execution failed",
"ruleExecutionInstructions": "Rule execution instructions",
"skipHelp": "Skipping rolls back all changes from this rule and continues, this rule's redaction is not applied",
"overrideHelp": "Allow changes to selected fields, review their effects on authentication, sessions, and tools",
"rules": {
"fillInRuleName": "Please fill in the rule name",
"stepLimit": "Up to 32 steps across all rules",
"enterFieldPathForStep": "Enter a field path for step {value}",
"fixedValueForStepMustBeJson": "The fixed value for step {value} must be JSON, such as \"alias\", false, or 123",
"invalidSampleFormat": "Invalid sample format",
"ruleFormatIsInvalid": "Rule format is invalid",
"editRule": "Edit rule",
"description": "Configure field processing and preview privacy transformations",
"ruleName": "Rule name",
"namePlaceholder": "For example: Normalize workspace details",
"currentStepSettings": "Current step settings",
"testPreview": "Test preview",
"previewOfEntireRule": "Preview of the entire rule",
"ruleSkipped": "Rule skipped",
"matches": "Matches: {matches}",
"testThisRule": "Test this rule",
"test": "Test",
"testSample": "Test sample",
"samplePlaceholder": "Paste a request sample containing body, headers, and turnMetadata",
"afterProcessing": "After processing",
"applyToDraft": "Apply to draft",
"movedToPosition": "{name} moved to position {value}",
"ruleField": "Rule",
"scope": "Scope",
"processingMethod": "Action",
"reorderHelp": "Drag to reorder rules, or focus the handle and use the up and down arrow keys",
"noRulesYetAddOneOrStart": "No rules yet, add one or start from default",
"enableRule": "Enable rule: {name}",
"edit": "Edit {name}",
"delete": "Delete {name}",
"dragToReorder": "Drag to reorder {name}"
},
"steps": {
"pathPlaceholder": "For example: $.workspaces.*.associated_remote_urls.*",
"forExampleRemotesFetchurl": "For example: $.remotes[*].fetchUrl",
"environmentPathHelp": "Use $ to match the entire environment text",
"forExampleMetadataWorkspace": "For example: $.metadata.workspace",
"forExampleXClientName": "For example: x-client-name",
"requestHeaderName": "Request header name",
"fieldPath": "Field path",
"fieldPathSyntax": "Field path syntax",
"jsonPathHelp": "Supports object members, quoted keys, array indexes, and * wildcards, for example $[\"workspaces\"][\"/home/alex/demo\"]",
"targetHelp": "Use $ for environment text and a header name for request headers",
"commonFields": "Common fields",
"deleteMatchHelp": "Remove only fields or array items whose values match the regular expression",
"matchExpression": "Match expression",
"forExampleHome": "For example: ^/home/[^/]+/",
"forExamplePrivateOrg": "For example: private-org",
"replaceContent": "Replace content",
"regularSyntaxDescription": "Regular syntax description",
"useOrForCaptureGroupsAndFor": "Use ${'{'}1{'}'} or ${'{'}name{'}'} for capture groups, and $$ for a literal $",
"usesRustRegexSyntaxAndDoesNot": "Uses Rust regex syntax and does not support backreferences in lookahead and pattern patterns",
"forExampleHomeUser": "For example: /home/user/",
"forExampleTeamOrLeaveBlankTo": "For example: team, or leave blank to clear matching content",
"fixedValueJson": "Fixed value (JSON)",
"forExampleAnonymousNullOr": "For example: \"anonymous\", null, or {'{'}{'}'}",
"fixedJsonLabel": "Fixed JSON value",
"replaceAllMatches": "Replace all matches",
"ignoreCase": "Ignore case",
"matchMultipleLines": "Match multiple lines",
"entireEnvironmentText": "Entire environment text",
"fullContent": "Full content",
"noFieldsSelected": "No fields selected",
"deleteHelp": "Remove matching fields or array items",
"noExpressionEntered": "No expression entered",
"deleteAfterMatching": "Delete after matching: {value}",
"clearMatchingContent": "Clear matching content",
"stepMovedToPosition": "Step moved to position {value}",
"processingSteps": "Processing steps",
"helpTitle": "About processing steps",
"executionOrderHelp": "Drag to reorder execution, or focus the handle and use the up and down arrow keys",
"eachStepCanSetScopeFieldsAnd": "Each step can set the scope, fields and processing methods separately, and the next step will be processed based on the results of the previous step",
"failureHelp": "Steps share the rule's enabled state, any failure rolls back the rule's changes before the failure policy skips or blocks the request",
"addSteps": "Add steps",
"reorderHelp": "Drag to reorder steps, or focus the handle and use the up and down arrow keys",
"dragStep": "Drag step {value}: {field}",
"step": "Step {value}: {field}, {scope}, {action}, {effect}",
"deleteStep": "Delete step {value}: {field}"
},
"presets": {
"workspaceMetadata": "Additional workspace information",
"desktopGitInformation": "Desktop Git information",
"automaticEnvironmentContext": "Automatic environment context",
"specifyRequestFields": "Specify request fields",
"specifyRequestHeader": "Specify request header",
"regularReplacement": "Regular replacement",
"fixedValue": "Fixed value",
"fieldNameReplacement": "Field name replacement",
"deleteFieldArrayItem": "Delete field/array item",
"customFieldPath": "Custom field path",
"gitRemoteAddress": "Git remote address",
"workspacePathKey": "Workspace path key",
"gitCommitId": "Git commit ID",
"gitRemoteCollection": "Git remote collection",
"workspaceFingerprint": "Workspace fingerprint",
"unifyWorkspaceInformation": "Unify workspace information"
},
"testPlaceholder": "Run a test to see results"
},
"form": {
"enterStandardSemverForExample": "Please enter a standard SemVer, for example 0.152.0",
"exitLocationFilledIn": "Exit location filled in",
"ipv4AndIpv6ExportTimeZonesAre": "IPv4 and IPv6 export time zones are inconsistent, please fill in manually",
"unableToObtainExitLocation": "Unable to obtain exit location",
"fillInModelMappingCompletely": "Please fill in the model mapping completely",
"duplicateClientModel": "Duplicate client model: {requested}",
"requiredSettings": "Complete concurrency, queue, credential refresh, and scheduling settings",
"invalidAffinityDuration": "Affinity duration must be an integer from 1 to 720 hours",
"invalidSwitchLimit": "Maximum account switches must be an integer from 0 to 31, set to 0 to disable switching",
"invalidConcurrency": "Default account concurrency must be an integer from 0 to 4,294,967,295, set to 0 for unlimited",
"invalidReviewConcurrency": "Auto review concurrency must be an integer from 0 to 4,294,967,295, set to 0 to share regular concurrency",
"invalidBodyLimit": "Responses decompression limit must be a positive integer in MiB",
"invalidQuotaThreshold": "Remaining weekly quota threshold must be an integer from 0 to 100, leave blank for no limit",
"invalidResetLeadTime": "Reset credit lead time must be an integer from 1 to 1,440 minutes",
"invalidRetention": "History retention must be an integer from 1 to 31 days",
"invalidQueueSettings": "Queue capacity must be an integer from 0 to 1,000 and timeout from 1 to 120 seconds",
"invalidClientVersion": "Enter a valid minimum client version",
"overloadSettingsRequired": "Complete the overload protection settings",
"invalidOverloadSettings": "Use a failure threshold of 2–1,000, a counting window of 60–3,600 seconds, and a cooldown of 300–604,800 seconds",
"invalidProbeModel": "Probe model name must not exceed 128 characters",
"invalidWarmupTimes": "Use HH:MM for warmup times, for example 08:00 or 08:00,13:00",
"warmupModelRequired": "Select a model to enable warmup",
"invalidWarmupModel": "Warmup model name must not exceed 128 characters",
"settingsSaved": "Settings saved"
},
"page": {
"tabs": {
"runtime": "Runtime",
"upstream": "Upstream",
"pricing": "Pricing",
"access": "Security",
"backups": "Backups"
},
"description": "Manage scheduling, upstreams, pricing, security, history retention, and backups",
"sectionsLabel": "Settings sections",
"undoAllBasicSettingsChanges": "Undo all basic settings changes",
"saveChanges": "Save changes",
"settingsLoadingFailed": "Settings loading failed",
"reload": "Reload",
"basicSettings": "Basic settings"
}
}
}
@@ -0,0 +1,109 @@
{
"systemUpdate": {
"channels": {
"stable": {
"label": "Stable",
"description": "Stable releases only"
},
"rc": {
"label": "RC",
"description": "RC and stable releases"
},
"beta": {
"label": "Beta",
"description": "Beta, RC, and stable releases"
},
"alpha": {
"label": "Alpha",
"description": "All regular prereleases and stable releases"
},
"experimental": {
"label": "Experimental",
"description": "Current experimental release line only"
},
"loading": "Loading the current release channel…",
"label": "Update channel",
"help": "About update channels",
"description": "This selection applies to the current check only, reopening uses the installed version's channel and does not install or downgrade automatically"
},
"feedback": {
"available": "Update available",
"noUpdates": "No updates available",
"started": "Update has started"
},
"errors": {
"remoteTargetMissing": "No remote target version was returned",
"infoPending": "Wait for update information to finish loading",
"preRestartCheck": "Pre-restart check failed",
"restart": "Restart failed, please check again",
"unconfirmed": "Update task has not been confirmed, check its status and try again",
"updateFailed": "Update failed",
"startTimeout": "Service v{version} did not start within the expected time",
"activationTargetMissing": "No target version is pending activation"
},
"title": "System update",
"description": "Check versions, read release notes, and install updates",
"application": "Application updates",
"releasePage": "Release page",
"status": {
"checkingVersion": "Checking for updates…",
"lastFailed": "Last operation failed",
"updating": "Updating…",
"restarting": "Restarting",
"checking": "Checking…",
"restartRequired": "Restart required",
"available": "Update available",
"upToDate": "No updates available",
"notChecked": "Not checked",
"retrying": "Update status is temporarily unavailable, retrying…",
"confirmingStart": "Checking whether the update has started…"
},
"targetVersion": "Target version v{version}",
"releaseNotes": "Release notes",
"progress": "Update progress",
"actions": {
"check": "Check for updates",
"install": "Download and update",
"continueRestart": "Continue restart",
"restart": "Restart now"
},
"plugins": {
"title": "Plugin compatibility notice",
"description": "Keep enabled configurations and try starting each plugin after restarting",
"incompatible": "Incompatible plugins"
},
"versionAfterRestart": "Version after restart",
"confirmation": {
"newerVersion": "A newer update is available",
"channelChanged": "The latest version of the selected channel has changed",
"title": "Confirm update",
"description": "Confirm to close this dialog and update to the latest remote target version"
},
"logs": {
"live": "Live",
"disconnectedState": "Disconnected",
"waiting": "Waiting to connect",
"disconnected": "Update log connection lost",
"parseFailed": "Failed to parse update logs",
"unsupported": "This browser does not support live update logs",
"timeout": "Update log connection timed out"
},
"currentVersion": "Current version",
"latestVersion": "Latest in channel",
"build": "Build",
"deployment": "Deployment",
"displayedTarget": "Displayed target",
"remoteTarget": "Latest remote target",
"buildTypes": {
"release": "Release build",
"source": "Source build",
"dev": "Development build",
"experimental": "Experimental build"
},
"deploymentModes": {
"docker": "Docker",
"binary": "Binary",
"source": "From source"
}
}
}
+348
View File
@@ -0,0 +1,348 @@
{
"usage": {
"health": {
"point": {
"serviceFailed": "Failed",
"clientCancel": "Client cancel",
"callerError": "Caller error",
"requestHealthDetailsFor": "Request health details for {time}",
"minutes": "15 min",
"validRequestAvailability": "Valid request availability",
"validRequest": "Valid request"
},
"validRequestsAvailability": "{time}, {label}, valid requests: {count}, availability: {reliabilityDisplay}",
"hours": "hours",
"day": "day",
"serviceSuccessRate": "Service success",
"notCompleted": "Incomplete",
"requestVolume": "Requests",
"noServiceResult": "No service result",
"title": "Health",
"description": "Request outcomes · {granularityText}",
"completionRate": "Completion",
"abnormalEnd": "Abnormal",
"loading": "Loading requests…",
"empty": "No requests in this range"
},
"billing": {
"serviceLevel": "Service tier",
"totalCost": "Total cost",
"standardFee": "Standard cost",
"textInputCost": "Text input cost",
"inputCost": "Input cost",
"imageInputFee": "Image input cost",
"imageCachingCharges": "Image cache cost",
"imageInputUnitPrice": "Image input unit price",
"imageCacheUnitPrice": "Image cache unit price",
"imageOutputFee": "Image output cost",
"outputFee": "Output cost",
"textInputUnitPrice": "Text input unit price",
"inputUnitPrice": "Input unit price",
"imageOutputUnitPrice": "Image output unit price",
"outputUnitPrice": "Output unit price",
"textCacheReadCost": "Text cache read cost",
"cacheReadCost": "Cache read cost",
"cacheWriteCost": "Cache write cost",
"cacheWriteUnitPrice": "Cache write unit price",
"fastMode": "Fast mode",
"longContextBillingDetails": "Long-context cost details",
"billingDetails": "Cost details",
"viewLongContextBillingDetails": "View long-context cost details",
"viewCostDetails": "View cost details"
},
"ttft": "TTFT",
"latency": {
"totalLatency": "Total latency",
"viewLatencyDetails": "View latency details",
"official": "Official",
"local": "Local",
"total": "Total"
},
"performance": {
"ttftHelp": "TTFT: time to first token",
"scheduling": "Scheduling",
"admissionP95": "Admission P95",
"accountSelectionP95": "Selection P95",
"capacityP95": "Capacity P95",
"decisionCoverage": "Decision coverage",
"accountSelectionCoverage": "Selection coverage",
"capacityCoverage": "Capacity coverage",
"title": "Performance",
"description": "Latency, throughput, scheduling",
"performanceIndicators": "Performance indicators",
"loading": "Loading performance…",
"noTtftSamples": "No TTFT samples in this range",
"noThroughput": "No throughput samples in this range",
"noScheduling": "No scheduling or capacity samples in this range",
"noLatency": "No latency samples in this range"
},
"reasoning": {
"subagentRequest": "Subagent request",
"reviewSubagentRequest": "Review subagent request"
},
"filters": {
"error": "Error",
"requestDetailType": "Request detail type",
"label": "Usage record filters and actions",
"refreshUsageHistory": "Refresh usage history",
"keyName": "Key name",
"account": "Account",
"fieldLabel": "Request detail filter field",
"enterFilterValue": "Enter filter value",
"valueLabel": "Request detail filter value"
},
"route": {
"compressionRequest": "Compression request"
},
"tokens": {
"enterToken": "Uncached input tokens",
"outputToken": "Output tokens",
"cacheReadTokens": "Cache read tokens",
"cacheWriteTokens": "Cache write tokens",
"reasoningToken": "Reasoning tokens",
"tokenDetails": "Token details",
"viewTokenDetails": "View token details",
"totalTokens": "Total tokens"
},
"fields": {
"model": "Model",
"reasoningEffort": "Effort",
"endpoint": "Endpoint",
"upstream": "Upstream",
"access": "Access",
"cost": "Cost",
"latency": "Latency",
"time": "Time",
"keyName": "Key",
"subscription": "Plan",
"platformType": "Provider"
},
"outputThroughput": "Rate",
"noValidSample": "No valid sample",
"notReachable": "Not reachable",
"unstable": "Unstable",
"lowSample": "Low sample",
"stable": "Stable",
"future": "Future",
"status": {
"mappedModel": "Model sent upstream after gateway mapping: {secondary}",
"returnedModel": "Upstream response model: {returned} (matches the mapped request model)",
"returnedModelHelp": "Model returned by upstream: {returned}",
"firstOutputWaiting": "First output waiting",
"reasoningToText": "Reasoning to the text",
"firstOneIsOutputToText": "The first one is output to the text",
"textToCompletion": "Text to completion",
"completedAfterFirstOutput": "Completed after first output",
"admissionDecision": "Admission decision",
"accountSelectionWaiting": "Account selection waiting",
"transferDecisionWaiting": "Transfer decision wait",
"websocketConnection": "WebSocket connection",
"upstreamResponseHeader": "Upstream response header",
"firstUpstreamEvent": "First upstream event",
"accountSlotSnapshot": "Account slot snapshot",
"processingTime": "Processing time",
"apiOverhead": "API overhead",
"engineTime": "Engine time",
"upstreamPerformance": "Upstream performance",
"requestObservation": "Request observation",
"transport": "Transport",
"cancelled": "Cancelled",
"requestedModel": "Requested model: {model}"
},
"balanceUnavailable": "Balance unavailable",
"quota": "Quota",
"usage": "Usage",
"averageTtft": "Average TTFT",
"budget": {
"todaySQuota": "Daily quota",
"weeklyQuota": "Weekly quota",
"quotaOverview": "Quota",
"noLimit": "No limit",
"remaining": "Remaining / {value}",
"used": "{rate}% used",
"usedAmount": "Used: {value}",
"resetTime": "Resets",
"timingStartsAfterFirstUse": "Timing starts after first use",
"concurrencyLimit": "Concurrency",
"requestsPerMinute": "RPM"
},
"header": {
"currentKey": "Current key",
"keyPrefix": "Key prefix",
"keyConfiguration": "Key configuration",
"statisticsTimeRange": "Statistics time range",
"today": "Today",
"lastDays": "Last 7 days",
"lastThirtyDays": "Last 30 days",
"automaticRefreshFrequency": "Automatic refresh frequency",
"refreshEveryS": "Every 30 s",
"refreshInterval": "Every 60 s",
"pauseRefresh": "Paused",
"refreshUsage": "Refresh usage",
"switchTheme": "Switch theme"
},
"records": {
"requestLog": "Request log",
"currentRequestRecord": "Current request record",
"refreshFailed": "Failed to refresh request logs, showing the last available results",
"loadFailed": "Failed to load request logs, use the refresh button above to try again",
"noRecordsMatchTheseFilters": "No records match these filters"
},
"page": {
"cacheHitRate": "Token hit rate",
"loadingUsage": "Loading usage",
"usageSummaryLoading": "Usage summary loading",
"usageTrends": "Trends",
"changesInUsageOverTime": "Changes in usage over time",
"requestHealthTimeline": "Request health",
"updated": "Updated {asOfDisplay}",
"temporarilyRetainLastResult": ", temporarily retain the last result",
"clickRefreshAtTopToTryAgain": ", please click refresh at the top to try again",
"description": "View usage, performance trends, and request errors",
"dateRangeLabel": "Statistics date range, limited to the last 31 days",
"requestDetails": "Request details",
"recordsDescription": "Successful and failed request details",
"failedToLoad": "Failed to load: {error}",
"noRequestsMatchTheseFilters": "No requests match these filters",
"viewErrorDetails": "View error details",
"viewUsageRecordDetails": "View usage record details"
},
"summary": {
"usageSummary": "Usage summary",
"consumeTokens": "Tokens used",
"totalRequests": "Requests",
"totalCost": "Cost",
"usageDetails": "Usage details"
},
"trends": {
"cost": "Cost",
"cacheHit": "Cache hit",
"empty": "No requests in the selected range"
},
"configuration": {
"copiedToClipboard": "Copied to clipboard"
},
"metrics": {
"notPriced": "Not priced",
"newInput": "Uncached input",
"output": "Output",
"cacheCreation": "Cache write",
"reasoning": "Reasoning"
},
"firstTokenLatency": "TTFT",
"diagnostics": {
"downloadDiagnosticPackage": "Download diagnostic package",
"key": "Key",
"transport": "Transport",
"dimensions": "Dimensions",
"request": "Requests",
"performance": "Performance",
"title": "Diagnostics",
"groupBy": "By {resultDimensionLabel}",
"diagnosticDimension": "Diagnostic dimension",
"noDiagnosticDataYet": "No diagnostic data yet",
"successful": "Successful: {count}",
"failed": "Failed: {count}",
"failureRate": "Failure rate: {rate}",
"retryRate": "Retry rate: {rate}",
"retries": "Retries: {count}",
"loading": "Loading diagnostics…",
"empty": "No diagnostics in this range"
},
"cost": {
"savings": "Savings",
"cache": "Cache",
"cacheSavings": "Cache savings",
"cacheTokenProportion": "Cached tokens",
"hitRequestRate": "Request hit rate",
"actualCost": "Cost",
"withoutCacheEstimate": "Without cache",
"costEfficiency": "Costs",
"description": "Costs, cache savings, tier premiums",
"costView": "Cost view",
"tierPremium": "Tier premium",
"perSuccessfulRequest": "Cost/success",
"costCoverage": "Cost coverage",
"loading": "Loading costs…",
"empty": "No cost or cache savings data in this range"
},
"error": {
"noDetails": "No detailed error message was recorded",
"platform": "Provider",
"requestModel": "Request model",
"upstreamModel": "Upstream model",
"clientTransfer": "Client transfer",
"upstreamTransport": "Upstream transport",
"clientStatusCode": "Client status code",
"upstreamStatusCode": "Upstream status code",
"requestId": "Request ID",
"upstreamRequestId": "Upstream request ID",
"responseId": "Response ID",
"clientKeyId": "Client key ID",
"errorCode": "Error code",
"failureClassification": "Failure classification",
"duration": "Duration",
"triggerMode": "Trigger mode",
"sendStatus": "Send status",
"errorDetails": "Error details",
"description": "Failure reason and request context",
"responseIsNotComplete": "Response is not complete",
"requestFailed": "Request failed",
"requestContext": "Request context",
"errorLocation": "Error location",
"attempts": "Attempt history",
"attemptRecordMayBeIncomplete": "Attempt record may be incomplete",
"attempt": "Attempt {index}",
"diagnosticData": "Diagnostic data",
"responseContent": "Response content",
"metadata": "Metadata"
},
"insights": {
"useStatisticalObservations": "Use statistical observations"
},
"request": {
"statusCode": "Status code",
"message": "Message",
"upstreamTimeConsumption": "Upstream time consumption",
"storageModel": "Storage model",
"upstreamReturnModel": "Upstream return model",
"clientIp": "Client IP",
"eventType": "Event type",
"trySerialNumber": "Try serial number",
"accountId": "Account ID",
"serialNumber": "Attempt",
"result": "Result",
"textInput": "Text input",
"input": "Input",
"imageOutput": "Image output",
"textCacheRead": "Text cache read",
"cacheRead": "Cache read",
"cacheWrites": "Cache writes",
"textCacheUnitPrice": "Text cache unit price",
"cacheUnitPrice": "Cache unit price",
"nonInferentialOutput": "Non-reasoning output",
"totalOutput": "Total output",
"noneYet": "None yet",
"usageRecordDetails": "Usage record details",
"description": "End-to-end details for a single request",
"requestInformation": "Request information",
"transportAndUsage": "Transport and usage",
"modelsAndRouting": "Models and routing",
"clientAndUpstream": "Client and upstream",
"requestId": "Request ID",
"incompleteDetails": "Incomplete details",
"total": "Total",
"requestContent": "Request content",
"inProgress": "In progress"
},
"successfulRequest": "Successful requests",
"withinFilterRange": "Within filter range",
"inputOutput": "Input: {inputTokens} / Output: {outputTokens}",
"cachedTokens": "Cached tokens",
"cacheReadHit": "Cache read hit",
"averageTimeTaken": "Average latency",
"successfulRequestAverage": "Successful requests only",
"usageOverview": "Usage overview",
"noUsageRecords": "No usage records"
}
}
@@ -0,0 +1,620 @@
{
"accounts": {
"quota": {
"usageInThisWindow": "窗口消耗:{localUsageDisplay}",
"quotaUsed": "额度已使用:{rate}",
"resets": "重置时间: {resetAtDisplay}",
"unobserved": "额度待观测",
"dailyRequests": "日请求",
"requests": "{localRequestLabel} {localRequestDisplay} 次",
"h": "{duration} 小时",
"d": "{duration} 天",
"s": "{duration} 秒",
"unlimited": "无限",
"noPointsAvailableYet": "暂无可用点数",
"quotaPoints": "额度点数",
"point": "点",
"requestsInThisWindow": "窗口请求:{requestDisplay} 次",
"requestCount": "{requestDisplay} 次",
"statisticalRange": "统计范围",
"rolling": "滚动 {duration}",
"awaitingData": "待观测",
"remaining": "剩余 {remaining}%",
"usageLimit": "使用限额",
"reset": "重置:",
"remainingQuota": "{label}剩余额度",
"accountLimit": "账号额度",
"quota": "{provider} 额度",
"lastRefreshed": "最近刷新: {refreshedAtDisplay}",
"viewPersonalInformation": "查看个人信息",
"forecastWeeklyMonthlyQuota": "预测周/月额度",
"queryUnsupported": "暂不支持查询上游额度",
"quotaDetails": "额度详情",
"viewDetails": "查看{detailTitle}详情",
"details": "{detailTitle}详情",
"statisticalMethod": "统计方式",
"rollingWindow": "滚动窗口",
"windowConsumption": "窗口消耗",
"resetTime": "重置时间",
"localTokens": "本地累计总 Token",
"unavailableHelp": "上游额度未提供,绿色条不表示剩余额度",
"totalTokensFor": "{windowLabelDisplay}总 Token",
"usageRateHelp": "最近使用额度的当前已用比例",
"usageRate": "使用率",
"moreGroups": "另有 {count} 个额度组,可展开账号查看",
"windows": {
"fiveHour": "5h 额度",
"daily": "日额度",
"weekly": "周额度",
"monthly": "月额度",
"annual": "年额度",
"usage": "用量上限",
"secondary": "次级用量上限",
"duration": "{duration}额度"
}
},
"account": "账号",
"connectionTest": {
"duration": "响应耗时",
"title": "测试连接",
"description": "验证账号凭据、身份绑定与上游模型端点是否可用",
"model": "测试模型",
"refreshModels": "刷新上游模型",
"loadingModels": "加载模型中",
"modelPlaceholder": "选择上游模型",
"noModels": "上游没有返回模型",
"running": "检测中",
"completedAt": "完成时间",
"events": {
"title": "事件轨迹",
"request": "发起请求",
"response": "接收响应内容",
"completed": "响应完成"
},
"diagnostics": "原始诊断",
"retry": "重新测试",
"start": "开始测试",
"errors": {
"invalidRequest": "测试请求不合法",
"unsupported": "当前 Provider 不支持连接测试",
"credentials": "账号凭据无效",
"policyRejected": "测试请求被网关策略拒绝",
"modelNotFound": "测试模型不存在",
"accountUnavailable": "指定账号当前不可用于连接测试",
"capacityUnavailable": "指定账号当前没有可用容量",
"infrastructureUnavailable": "Provider 本地基础设施暂不可用",
"rateLimited": "上游请求过于频繁",
"upstreamUnavailable": "上游服务暂不可用",
"timeout": "上游请求超时",
"canceled": "测试请求已取消",
"internal": "网关内部错误",
"unknown": "未分类错误",
"failed": "测试连接失败",
"modelRequired": "未选择模型",
"browserUnsupported": "当前浏览器不支持连接测试",
"missingCompletion": "测试连接未返回完成事件",
"invalidResponse": "测试响应解析失败",
"disconnected": "测试连接已断开"
},
"stages": {
"gateway": "网关校验",
"provider": "Provider 本地准备",
"upstream": "上游响应"
},
"failed": "测试失败",
"testing": "正在测试",
"runningDescription": "正在向所选模型发送请求并接收流式响应",
"successTitle": "连接正常",
"completedDescription": "请求已完成,可在下方查看模型、耗时和事件轨迹",
"failedDescription": "请求未完成,请在下方查看失败来源与原始诊断",
"readyTitle": "准备测试",
"readyDescription": "选择模型后,点击“开始测试”发送真实请求",
"starting": "开始测试 {value}",
"emptyResponse": "上游已完成,没有返回文本内容",
"testCompleted": "测试完成",
"modelsRefreshed": "已刷新 {count} 个上游模型",
"noModelsAvailable": "没有可测试模型"
},
"credentials": {
"wsFirst": "WS 优先",
"accountName": "账号名称",
"enterUpstreamName": "输入上游名称",
"baseUrlHelp": "填写 API 前缀,接口路径会自动追加",
"apiPrefix": "API 前缀",
"apiKeyPlaceholder": "留空保留当前密钥",
"enterUpstreamKey": "输入上游密钥",
"transportLabel": "传输方式",
"webSocketHelp": "WS 优先需要上游支持 Responses WebSocket",
"nameRequired": "请输入账号名称",
"validation": {
"urlLength": "上游 API 地址不能超过 2048 个字符",
"urlFormat": "请输入不含认证、查询参数或片段的 HTTP 或 HTTPS 地址",
"urlRequired": "请输入完整的上游 API 地址",
"apiKeyFormat": "API Key 不能包含空格或控制字符",
"transportRequired": "请选择传输方式"
},
"apiKeyRequired": "请输入 API Key"
},
"batchEdit": {
"title": "批量编辑账号",
"selectionTitle": "编辑 {count} 个账号",
"saveChanges": "保存更改",
"proxyRequired": "请选择已通过测试的代理",
"saved": "已更新 {count} 个账号",
"staleAccount": "账号 {accountId} 的页面数据已失效,请重新选择"
},
"capacity": {
"concurrentRequestsLimit": "账号并发占用 {value},上限 {value2}",
"viewConcurrencyDetails": "{label},查看并发明细",
"viewDetails": "{label},查看明细"
},
"concurrency": {
"title": "并发明细",
"description": "当前正在处理的请求",
"unavailable": "暂时无法读取并发明细",
"empty": "当前没有并发占用",
"key": "密钥",
"model": "模型",
"sourceIp": "来源 IP",
"startTime": "开始时间",
"elapsed": "占用时长"
},
"editor": {
"title": "编辑账号",
"transportLabel": "上游传输方式",
"upstreamConnection": "上游连接",
"loadError": "上游设置读取失败",
"notesHelp": "最多 500 字,留空可清除备注",
"oauthUnavailable": "该账号没有 OAuth 上游设置",
"apiKeyUnavailable": "该账号没有 API Key 上游设置",
"saved": "账号已更新"
},
"filters": {
"allGroups": "全部分组",
"ungroupedAccounts": "未分组账号",
"disabled": "{name}(已禁用)",
"label": "账号筛选与操作",
"searchLabel": "搜索账号",
"statusLabel": "按账号状态筛选",
"groupLabel": "按账号分组筛选",
"deleteSelected": "删除选中 ({count})",
"exportSelected": "导出选中 ({count})",
"importTasks": "导入任务",
"importAccount": "导入账号"
},
"modelAccess": {
"reserve": "保留",
"allowlist": "白名单",
"blocklist": "黑名单",
"modelLimitations": "模型限制",
"refreshModel": "刷新模型",
"modelRestrictionMode": "模型限制模式",
"searchOrAddModels": "搜索或添加模型",
"searchOrEnterIdAndPressEnter": "搜索或输入 ID,回车添加",
"selectModel": "选择模型",
"notInCurrentModelCatalog": "{id}(当前目录未返回)",
"loadingModel": "加载模型中…",
"noMatchingModels": "无匹配模型",
"noModels": "暂无模型",
"modelListLoadingFailed": "模型列表加载失败",
"retryHint": "请刷新后重试",
"selectOrAddAtLeastOneModel": "请至少选择或添加一个模型",
"configureUpToModels": "最多配置 256 个模型",
"invalidModelId": "请使用有效的精确模型 ID,不支持通配符",
"enterValidExactModelIdUpTo": "请输入有效的精确模型 ID,最多 256 字节,不支持通配符"
},
"notes": {
"viewAccountNotes": "查看账号备注",
"title": "账号备注"
},
"overview": {
"totalAccounts": "总账号",
"accountPoolSize": "账号池规模",
"availableAccounts": "可用账号",
"availableHelp": "可参与调度",
"quotaLimited": "额度受限",
"waitingForQuota": "等待额度恢复",
"pending": "待处理",
"disabledError": "已停用 / 错误"
},
"proxy": {
"keepCurrent": "保持当前",
"keepExisting": "保留各账号的连接设置",
"directConnection": "直连",
"notUsingProxy": "不使用代理",
"disabledSuffix": "(已禁用)",
"testFailed": "(测试失败)",
"notTested": "(未测试)",
"outboundTunnel": "出站隧道"
},
"scheduling": {
"scheduling": "调度",
"switchAccountSchedule": "切换账号调度",
"concurrencyLimit": "并发限制",
"accountConcurrencyLimit": "账号并发限制",
"defaultHint": "留空使用默认值",
"weight": "权重",
"accountSchedulingWeight": "账号调度权重",
"weightHelp": "数值越高越优先,最高 100",
"groupLabel": "所属分组",
"invalidConcurrency": "并发限制必须留空,或为 1 到 {value} 的整数",
"weightMustBeIntegerFromTo": "权重必须是 1 到 100 的整数"
},
"actions": {
"deleteAccount": "删除账号",
"moreActions": "更多操作",
"disableScheduling": "停用",
"enableScheduling": "启用",
"refreshToken": "刷新令牌",
"reauthorize": "重新授权",
"downloadModelCatalog": "下载模型目录",
"restoreState": "重置状态",
"staleSelection": "所选账号数据已失效,请重新选择",
"exportUnsupported": "所选账号包含不支持导出的平台",
"deleted": "账号已删除",
"deletedAccountDeletedAccounts": "已删除 {count} 个账号",
"partialDeletion": "已删除 {count} 个账号,其余未删除:{value}",
"batchDeletionFailed": "批量删除失败",
"exportSelectionRequired": "请选择要导出的账号",
"exported": "已导出 {count} 个账号",
"exportFailed": "导出失败",
"modelCatalogDownloadedModels": "已下载模型目录,共 {count} 个模型",
"tokenIsBeingRefreshed": "Token 正在刷新中",
"refreshFailed": "刷新失败",
"tokenRefreshed": "Token 已刷新",
"schedulingIsDisabled": "调度已停用",
"schedulingIsEnabled": "调度已启用",
"quotaRefreshed": "额度已刷新",
"refreshQuotaManually": "请手动刷新额度",
"resetRefreshFailed": "额度已重置,但最新额度加载失败:{value}",
"statusRestored": "账号状态已恢复",
"staleAccount": "账号 {id} 的页面数据已失效,请重新选择",
"unsupportedProvider": "不支持的 Provider:{provider}"
},
"usage": {
"call": "调用",
"successRate": "成功率",
"input": "输入",
"output": "输出",
"cache": "缓存",
"total": "总计",
"billing": "计费",
"tokensStructure": "Token 用量",
"cacheRead": "缓存读取",
"reasoning": "推理",
"cacheWrites": "缓存写入",
"modelUsageRanking": "模型用量",
"totalTokens": "总 Token",
"totalCharge": "总计费",
"totalCharges": "总计费:",
"noModelUsageYet": "暂无模型用量",
"windows": {
"general": "累计用量",
"weekly": "周用量",
"monthly": "月用量",
"quota": "周期用量"
},
"cost": "费用"
},
"onboarding": {
"fileReadingFailedTryAgain": "文件读取失败,请重新选择",
"uploadFiles": "上传文件",
"authorizationExpired": "授权已过期,可重新开始或检查已完成的授权结果",
"pollingPaused": "查询已暂停,可检查授权结果后继续",
"regenerateAuthorizationLink": "重新生成授权链接",
"generateAuthorizationLink": "生成授权链接",
"authorizationLink": "授权链接",
"copyLink": "复制链接",
"authorizationLinkCopied": "授权链接已复制",
"batchImport": "批量导入",
"selectAccountPlatform": "选择账号平台",
"accountPlatform": "账号平台",
"maximumWordsOptional": "最多 500 字,可不填",
"copyAccount": "复制账号",
"accountCopied": "账号已复制",
"howToAddAccount": "账号添加方式",
"authorize": "授权",
"continueImporting": "继续",
"jsonDescription": "粘贴或上传账号 JSON,匹配已有账号时更新凭据",
"packageDescription": "粘贴或上传 CPR 账号包,一次导入多个平台账号",
"oauthDescription": "通过浏览器授权导入 {label} 账号",
"apiKeyDescription": "接入 OpenAI Responses 兼容上游",
"pasteAccessTokenLineByLineIf": "逐行粘贴 Access Token,未包含 Refresh Token 时无法自动续期",
"refreshTokenDescription": "逐行粘贴 Refresh Token,导入时将自动换取 Access Token",
"accountSettings": "账号设置",
"reauthorizeAccount": "重新授权账号",
"settingsDescription": "设置将应用于本次导入的账号",
"reauthorizeDescription": "完成授权后更新账号凭据",
"callbackLabel": "回调地址或授权码",
"callbackAddress": "回调地址",
"callbackPlaceholder": "回调地址、?code=...&state=... 或授权码",
"callbackHelp": "打开授权链接,完成浏览器授权后粘贴回调地址或授权码",
"pasteOneAccessTokenPerLine": "每行粘贴一个 Access Token",
"pasteOneRefreshTokenPerLine": "每行粘贴一个 Refresh Token",
"batchAccountFiles": "批量账号文件",
"accountFile": "账号文件",
"packagePlaceholder": "粘贴 CPR 多平台导出文件内容",
"pasteAccountJsonContent": "粘贴账号 JSON 内容",
"completeReauthorization": "完成重新授权",
"completeImport": "完成导入",
"invalidExpiry": "授权有效期无效,请重新生成链接",
"linkFailed": "生成授权链接失败",
"callbackRequired": "请粘贴回调地址或授权码",
"authorizationFailed": "完成授权失败,可重试提交",
"reauthorized": "账号重新授权成功",
"accountAdded": "账号已添加",
"providerRequired": "请选择账号平台",
"accountPlatformIsNotSupported": "账号平台不受支持",
"apiKeyUnsupported": "当前平台不支持 API Key 账号",
"apiKeyAccountAdded": "API Key 账号已添加",
"importTasksCreated": "已创建 {submitted} 个导入任务",
"importTaskCreated": "导入任务已创建",
"partialSubmission": "部分导入任务已创建,保持输入不变重试可继续提交",
"accountName": "{provider} 账号",
"failedToStartAuthorization": "启动授权失败"
},
"importTasks": {
"needProcessing": "需处理",
"importTaskDetails": "导入任务详情",
"created": "{createdAtDisplay} 创建",
"waitForCurrentEntryToEnd": "等待当前条目结束",
"stopUnstartedEntries": "停止未开始条目",
"viewAccount": "查看账号",
"entryProgress": "条目进度",
"accountsImported": "已入库 {importedAccounts} 个账号",
"itemProcessingProgress": "条目处理进度",
"itemsToBeCheckedMayHaveBeen": "待核对条目可能已入库,请先查看账号,再决定是否重新导入",
"filterImportDetails": "筛选导入明细",
"thereAreNoItemsToBeProcessed": "暂无需要处理的条目",
"importEntryResults": "导入条目结果",
"items": "{total} 个条目 · {value}",
"description": "关闭页面后继续导入,再次打开即可查看进度",
"progressUnavailable": "进度暂未更新:{value},恢复连接后将自动刷新",
"loadingImportTasks": "正在读取导入任务",
"noImportTasks": "暂无导入任务",
"empty": "新建一次账号导入,即可在这里查看逐条入库结果",
"switchImportTasks": "切换导入任务",
"loadingItemResults": "正在读取条目结果",
"selectTask": "请选择一个任务",
"taskRetentionInstructions": "任务保留说明",
"resultsRetainedForHour": "结果保留 1 小时",
"retentionHelp": "服务重启后任务记录消失,已入库账号保留",
"processing": "处理中",
"alreadyInStock": "已入库",
"toBeVerified": "待核对",
"notExecuted": "未执行",
"stopping": "正在停止",
"importing": "导入中",
"queuing": "排队中",
"stopped": "已停止",
"endedPendingItems": "已结束 · 有待处理项",
"allDone": "全部完成",
"savedAccountSavedAccounts": "已保存 {count} 个账号",
"verifying": "正在校验凭据并入库",
"waitingForExecution": "等待执行",
"thisArticleIsNotImplemented": "本条未执行",
"entryFailed": "本条导入未成功",
"checkAccountList": "请检查账号列表,确认是否已入库",
"progressReadingFailedTryAgain": "进度读取失败,请重试"
},
"profile": {
"activity": {
"quickMode": "快速模式",
"reasoningEffort": "最常用的推理强度",
"exploredSkills": "已探索的技能",
"totalNumberOfSkillsUsed": "使用的技能总数",
"totalNumberOfChats": "聊天总数",
"activityInsights": "活动洞察",
"pluginsAndSkills": "最常用的插件与技能",
"runs": "{count} 次运行",
"noToolCalls": "暂无插件或技能调用记录",
"daily": "每日",
"weekly": "每周",
"cumulative": "累计",
"tokenActivity": "Token 活动",
"tokenActivityStatisticsMethod": "Token 活动统计方式",
"noTokenActivityYet": "暂无 Token 活动",
"noDailyActivity": "本次未获取到每日 Token 活动",
"tokenActivityHeatmap": "Token 活动热力图,{rangeLabel}",
"weekOfTokens": "{dateDisplay}所在周:{value} Tokens",
"throughTokens": "截至{dateDisplay}:{value} Tokens"
},
"metrics": {
"cumulativeNumberOfTokens": "累计 Token 数",
"peakNumberOfTokens": "峰值 Token 数",
"maximumChatDuration": "最长聊天时长",
"currentConsecutiveDays": "当前连续天数",
"longestStreak": "最长连续天数",
"dayCount": "{integer} 天",
"dH": "{days} 天 {hours} 小时",
"elapsedDays": "{days} 天",
"hMin": "{hours} 小时 {minutes} 分",
"elapsedHours": "{hours} 小时",
"min": "{totalMinutes} 分",
"durationSeconds": "{value} 秒",
"cumulativeActivitySummary": "累计活动摘要"
},
"accountUser": "账号用户",
"avatarFor": "{displayName} 的头像",
"loadingCumulativeActivity": "正在加载累计活动",
"subscription": {
"automaticRenewal": "自动续费",
"noAutomaticRenewal": "不自动续费",
"byMonth": "按月",
"byYear": "按年",
"subscriptionStarts": "订阅开始",
"subscriptionEnds": "订阅结束",
"label": "订阅",
"renewalMethod": "续费方式"
},
"personalInformation": "个人信息",
"subscriptionInformation": "订阅信息",
"loadingSubscription": "正在加载订阅信息",
"loadFailed": "个人信息加载失败",
"statisticsUnavailable": "个人统计暂不可用",
"statisticsEmpty": "本次未获取到统计数据,可以点击刷新信息重试",
"refreshIncomplete": "本次信息刷新未完成,保留已获取的结果",
"noSubscriptionInformationYet": "暂无订阅信息",
"refreshInformation": "刷新信息"
},
"quotaForecast": {
"tokenCapacity": "Token 容量",
"equivalentFeeUsd": "等价费用 · USD",
"capacityForecast": "容量预测",
"usedThisCycle": "本周期已用",
"preliminary": "初步估算 · 仅供参考",
"estimateLabel": "估算值 · 仅供参考",
"thisCycle": "本周期",
"usedDescription": "本周期已用 {rate},其余为推算区域",
"alreadyRecordedThisCycle": "本周期已记录",
"equivalentCapacityOverDays": "{targetDays}天折算容量",
"projectedTotal": "本周期预计总量",
"loadingQuotaForecast": "正在加载额度预测",
"weeklyQuota": "周额度",
"monthlyQuota": "月额度",
"windowExpired": "额度窗口已过期,请刷新账号额度后重试",
"quotaForecast": "额度预测",
"periodHelp": "按本周期估算,重置后重新累计",
"forecastPeriod": "预测周期",
"predictionLoadFailed": "预测加载失败",
"loadFailed": "暂时无法取得预测数据,请重新加载",
"reload": "重新加载",
"unpredictableAtMoment": "暂时无法预测",
"updated": "更新于 {observedAtDisplay}",
"forecastDescription": "预测说明",
"forReferenceOnly": "仅供参考",
"methodDescription": "本周期预计总量为已记录用量加预计剩余,剩余量按本周期内近期用量估算",
"limitations": "缺失的用量或费用可能使结果偏低,结果会随使用的模型和方式变化,并非官方承诺额度",
"limitedData": "目前数据还较少,结果可能有较大波动",
"currentPeriod": "当前周期",
"forecastCalculatedByOverDays": "本页预测由{value}按 {targetDays} 天折算",
"equivalentCostHelp": "预测以数据更新时间为准,等价费用不是实际账单或账户余额",
"refreshQuota": "刷新额度"
},
"quotaReset": {
"automation": {
"confirming": "上次自动重置结果待确认,将继续核对",
"unconfirmed": "上次自动重置结果待确认",
"expiredUnconfirmed": "上次重置结果未能确认,卡片已到期",
"queryFailed": "最近查询失败,将按计划重试",
"aboveThreshold": "剩余周额度高于上限,稍后检查",
"quotaUnavailable": "暂时无法确认周额度,稍后检查",
"resetNotNeeded": "当前额度窗口不需要重置,稍后检查",
"resetIncomplete": "上游未完成最近一次自动重置",
"scheduleHelp": "每天随机查询一次,各账号错开时间",
"verifyHelp": "临期使用前核对卡片,已在其他地方使用的会自动跳过",
"label": "自动使用临期重置卡"
},
"automaticallyUseResetCard": "自动使用重置卡",
"automaticallyUsed": "自动使用",
"automaticUsageRules": "自动使用规则",
"setGlobalLeadTime": "设置全局提前时间",
"minutesInAdvance": "提前 {leadMinutes} 分钟",
"leadTime": "提前时间",
"nextUse": "下次使用 {nextConsumeAtDisplay}",
"autoUsageSettingsFailedToLoad": "自动使用设置加载失败",
"limitReset": "额度重置",
"confirmLastReset": "确认上次重置",
"confirmResetAmount": "确认重置额度",
"pendingAction": "查看主动重置卡,有一项操作待确认",
"queryFailedWithCount": "查看主动重置卡,查询失败,最近查询 {count} 张可用",
"queryFailedLabel": "查看主动重置卡,查询失败",
"availableCount": "查看主动重置卡,最近查询 {count} 张可用",
"viewCredits": "查看主动重置卡",
"useResetSelectedByUpstream": "使用一次重置(由上游选择)",
"expires": "将于 {expiresAtDisplay} 到期",
"expiryHelp": "有效期由上游决定",
"querying": "查询中",
"toBeQueried": "待查询",
"usesAvailable": "可用 {count} 次",
"usageReset": "用量重置",
"thisTimeUse": "本次使用",
"currentQuota": "当前额度",
"operationUnconfirmed": "上次操作结果待确认",
"confirmPrevious": "请继续确认上次重置结果",
"continueToConfirm": "继续确认",
"availableResetCards": "可用重置卡",
"refreshCredits": "刷新主动重置卡",
"resetCardLoadingFailed": "重置卡加载失败",
"refreshRequired": "请刷新重试",
"queryingAvailableResetTimes": "正在查询可用重置次数…",
"useResetCredit": "使用重置:{title},{expiry}",
"useReset": "使用重置",
"noResetCardAvailableYet": "暂无可用重置卡",
"confirmAgain": "再次确认",
"confirmReset": "确认重置",
"lastResetCompleted": "上次重置已完成",
"resetSuccess": "额度已重置",
"resultUnknown": "消费结果暂不确定,重试会复用同一个请求标识",
"quotaResetFailed": "额度重置失败",
"alreadyProcessed": "该重置操作已被处理,请先刷新重置卡列表",
"noCredits": "当前没有可用的主动重置卡",
"resetNotNeeded": "当前额度窗口不需要重置",
"upstreamDeclined": "上游未执行额度重置:{code}"
},
"status": {
"accountStatus": "账号状态",
"tryNextTime": "下次尝试",
"recommendedAction": "建议操作",
"upstreamOriginalFeedback": "上游原始反馈",
"forTroubleshootingOnly": "仅供排查",
"retreating": "退避中",
"oauthRefreshBackoff": "OAuth 刷新退避",
"refreshFailedHelp": "刷新失败,系统正在等待下一次自动尝试",
"retryScheduledHelp": "系统会在计划时间自动重试",
"attentionHelp": "该账号当前状态需要关注",
"retestHelp": "重新测试连接以获取最新状态",
"rateLimitedHelp": "上游暂时限制了请求频率,系统正在冷却该账号",
"cooldownHelp": "冷却结束后,系统会自动恢复调度",
"credentialsHelp": "该账号暂不参与调度,处理凭据后可重新测试连接",
"reauthorizeHelp": "重新授权后,账号会重新参与调度",
"replaceCredentialsHelp": "请更新或重新导入凭据,再次测试连接",
"upstreamRestrictionHelp": "请确认上游账号状态,解除限制后再启用",
"capacityFailuresHelp": "容量类请求失败累计达到阈值,系统已暂停该账号的调度",
"recoveryProbeHelp": "冷却结束后进行恢复探测,成功后恢复调度,也可手动恢复账号",
"recoveryHelp": "冷却结束后自动恢复调度,也可手动恢复账号",
"nextAttempt": ",下次尝试:{nextRefreshDisplay}",
"clickOrFocusToViewDetails": "{title},{description}{retry},点击或聚焦查看详情",
"resumeDetection": "恢复探测",
"expectedToRecover": "预计恢复"
},
"fields": {
"platformType": "平台",
"accountGrouping": "分组",
"lastUsed": "最后使用",
"tokenExpires": "令牌过期",
"quotaExhausted": "配额耗尽",
"rateLimiting": "限流中",
"deactivated": "已停用",
"error": "错误",
"identityUnconfirmed": "账号身份尚未确认",
"accessTokenHasExpired": "Access Token 已过期",
"credentialsHaveExpired": "凭据已过期",
"invalidCredentials": "凭据无效",
"accountUnavailable": "账号不可用或已被封禁",
"count": "账号数"
},
"page": {
"description": "维护账号池,查看可用性、配额与使用状态",
"noAccountDataYet": "暂无账号数据",
"collapseStatistics": "收起统计",
"expandStatistics": "展开统计",
"selectAccountOnCurrentPage": "选择当前页账号",
"selectAccount": "选择账号",
"deleteDescription": "删除后该账号将不再参与调度,此操作不可撤销",
"batchDeleteDescription": "确定要删除选中的 {count} 个账号吗?此操作不可撤销",
"thisAccount": "该账号",
"delete": "确定要删除 {value} 吗?"
},
"import": {
"jsonFormatIsIncorrect": "JSON 格式不正确",
"documentTooLarge": "单条导入文档超过 4 MiB,请拆分文件后重试",
"batchImportFileMustBeCprMulti": "批量导入文件必须是 CPR 多平台导出文件",
"invalidProvider": "批量导入文件包含无效的 Provider 文档",
"noAccounts": "批量文件没有可导入的账号文档",
"pasteAtLeastOne": "请至少粘贴一个 {label}",
"missingProvider": "批量导入文件不包含 {provider} 账号文档",
"importFilesMustBeJsonObjects": "导入文件必须是 JSON 对象"
}
}
}
@@ -0,0 +1,222 @@
{
"appearance": {
"switchToLight": "切换浅色模式",
"switchToDark": "切换暗黑模式",
"settings": {
"global": "全局",
"components": "组件",
"invalidTheme": "主题设置无效,请检查编辑值",
"themeSavedAndApplied": "主题已保存并应用",
"description": "自定义当前浏览器中的管理端主题",
"pendingChanges": "{count} 处修改待应用",
"synced": "已同步",
"themeEditingLevel": "主题编辑层级",
"undoDraft": "撤销草稿",
"restoreDefault": "恢复默认",
"saveAndApply": "保存并应用",
"saved": "已保存",
"themeEditor": "主题编辑器",
"themeTokenEditingPanel": "主题 Token 编辑面板",
"searchToken": "搜索 Token",
"searchPlaceholder": "搜索 Seed、Alias 或 Component Token"
},
"color": {
"modified": "已修改",
"edit": "编辑 {label}",
"restoreDerivedValue": "恢复派生值"
},
"preview": {
"components": {
"relayAccount": "中继账号",
"stickyHelp": "优先保持当前账号,额度耗尽后再切换",
"notEditable": "不可编辑",
"allPlatforms": "全部平台",
"restricted": "受限",
"accountAvailability": "账号可用率",
"todaySQuota": "今日额度",
"batchImport": "批量导入",
"platform": "平台",
"requestToday": "今日请求",
"recentlyUsed": "最近使用",
"justNow": "刚刚",
"hoursAgo": "2 小时前",
"componentOverview": "组件概览",
"description": "在同一张校样板中检查控制态、数据密度与浮层关系",
"currentThemeSemanticColor": "当前主题语义色",
"basicControlComponents": "基础控制组件",
"buttonsAndActions": "按钮与动作",
"createAccount": "创建账号",
"exportData": "导出数据",
"dealWithItLater": "稍后处理",
"sizeAndDisabledStatus": "尺寸与禁用状态",
"inoperable": "不可操作",
"processing": "处理中",
"notification": "通知",
"moreActions": "更多操作",
"deleteRecord": "删除记录",
"formsAndInput": "表单与输入",
"searchAccount": "搜索账号",
"choosePlatform": "选择平台",
"accessKeyErrorExample": "访问密钥错误示例",
"disableInputBox": "禁用输入框",
"brandColors": "品牌颜色",
"editBrandColors": "编辑品牌颜色",
"schedulingNotes": "调度备注",
"controlHeight": "控件高度",
"componentExampleControlHeight": "组件示例控件高度",
"choiceAndFeedbackComponents": "选择与反馈组件",
"selectAndSwitch": "选择与切换",
"accountView": "账号视图",
"realTimeNotification": "实时通知",
"automaticRotation": "自动轮换",
"selectCurrentPage": "选择当前页",
"partialSelection": "部分选择",
"equilibrium": "均衡",
"sticky": "粘性",
"manual": "手动",
"feedbackSemantics": "反馈语义",
"themeSettingsSaved": "主题设置已保存",
"quotaOfAccountsIsCloseToUpper": "3 个账号额度接近上限",
"connectionTestFailed": "连接测试未通过",
"schedulingNotice": "调度规则将在下次请求生效",
"statusAndProgress": "状态与进度",
"runningNormally": "运行正常",
"quotaLimited": "额度受限",
"needToBeProcessed": "需要处理",
"synchronizing": "同步中",
"restoreTag": "恢复标签",
"dataTable": "数据表格",
"tableComponents": "ZTable · ZScrollbar · ZPagination(标准行高)",
"filterForm": "筛选表格",
"filterAccounts": "筛选账号",
"boundaryStateComponent": "边界状态组件",
"emptyState": "空状态",
"noMatchingAccountYet": "暂无匹配账号",
"emptyHelp": "调整筛选条件,或添加一个新的上游账号",
"addAccount": "添加账号",
"loadingAndSkeleton": "加载与骨架",
"synchronizingAccountStatus": "正在同步账号状态",
"overlaysAndMenus": "浮层与菜单",
"accountOperation": "账号操作",
"editAccount": "编辑账号",
"deactivateAccount": "停用账号",
"overlayHelp": "浮层始终使用独立 Surface 与 Shadow Token",
"eyebrow": "组件预览",
"count": "{count} 个基础组件",
"buttonLabel": "按钮 / 操作",
"feedbackTypes": "成功 · 警告 · 错误 · 信息",
"tagComponents": "ZTag · 进度 Token",
"loadingComponents": "ZSkeleton · ZButton 加载态",
"overlayComponents": "ZPopover · ZMenuItem · 浮层表面"
},
"dashboard": {
"justUpdated": "刚刚更新",
"demoKey": "演示 Key",
"requestHealthTimeline": "请求健康时间线",
"validRequestAvailability": "有效请求可用性",
"clientId": "客户端 ID",
"tokenAuthentication": "Token 认证",
"todaySToken": "今日 Token",
"hours": "5 小时",
"requests": "08-23 {value}:00–{value2}:00 · {count} 次请求",
"times": "次数",
"dailyLimit": "日限额"
},
"homeArtboard": "首页画板",
"themeRealTimePreview": "主题实时预览",
"livePreview": "实时预览",
"description": "真实组件在影子环境隔离渲染,拖动画板并缩放检查细节",
"previewType": "预览类型",
"canvas": {
"homeThemePreviewArtboard": "首页主题预览画板",
"dragBlankSpaceToPanUseScroll": "拖动空白处平移 · 滚轮缩放",
"reduceArtboard": "缩小画板",
"recovery": "恢复 100%",
"enlargeArtboard": "放大画板",
"adaptToArtboard": "适应画板"
}
},
"componentTokens": {
"cardsAndContainers": "卡片与容器",
"dataDisplay": "数据展示",
"navigation": "导航",
"layoutAndScrolling": "布局与滚动",
"mainButtonText": "主按钮文字",
"mainButtonBackground": "主按钮背景",
"mainButtonHover": "主按钮 Hover",
"mainButtonActive": "主按钮 Active",
"secondaryButtonBackground": "次要按钮背景",
"secondaryButtonHover": "次要按钮 Hover",
"secondaryButtonActive": "次要按钮 Active",
"secondaryIconButtonBackground": "次要图标按钮背景",
"secondaryIconButtonHover": "次要图标按钮 Hover",
"secondaryIconButtonActive": "次要图标按钮 Active",
"inputBoxBackground": "输入框背景",
"inputBoxHover": "输入框 Hover",
"inputBoxActive": "输入框 Active",
"inputBoxShadow": "输入框阴影",
"inputBoxHoverShadow": "输入框 Hover 阴影",
"inputBoxFocusOuterCircle": "输入框焦点外圈",
"cardBackground": "卡片背景",
"popUpBackground": "弹窗背景",
"floatingTitleBackground": "浮层标题背景",
"cardRoundedCorners": "卡片圆角",
"cardShadow": "卡片阴影",
"tableRowHeight": "表格行高",
"headerBackground": "表头背景",
"lineBackground": "行背景",
"zebraPatternBackground": "斑马纹背景",
"rowHover": "行 Hover",
"selectedRowBackground": "选中行背景",
"selectRowHover": "选中行 Hover",
"progressTrack": "进度轨道",
"menuSelectionBackground": "菜单选中背景",
"sidebarBackground": "侧栏背景",
"sidebarShadow": "侧栏阴影",
"scrollBarSlider": "滚动条滑块",
"scrollBarHover": "滚动条 Hover",
"componentTokenComponentFamily": "Component Token 组件族",
"description": "调整 {label} 的 Component Token,未修改的值继续由全局 Seed / Alias 算法生成",
"noMatchingComponentToken": "没有匹配的 Component Token",
"kindLabel": "组件 Token"
},
"globalTokens": {
"size": "尺寸",
"style": "风格",
"systemMode": "跟随系统",
"lightColor": "浅色",
"dark": "深色",
"successColor": "成功色",
"successFeedbackAndStatus": "成功反馈与状态",
"warningColor": "警告色",
"limitAndRiskReminder": "额度与风险提醒",
"wrongColor": "错误色",
"dangerHelp": "失败与破坏性操作",
"informationColor": "信息色",
"systemAndRequestInformation": "系统与请求信息",
"linkColor": "链接色",
"linksAndJumps": "链接与跳转",
"basicTextColor": "基础文本色",
"textAndInformationLevels": "正文与信息层级",
"basicBackgroundColor": "基础背景色",
"pageAndContainerBase": "页面与容器基底",
"themeMode": "主题模式",
"globalTokenClassification": "全局 Token 分类",
"brandColorLabel": "预置主题 品牌色 colorPrimary",
"brandColor": "品牌色",
"presetThemes": "预置主题",
"brandMainColor": "品牌主色",
"paletteDescription": "完整色阶与界面基调",
"semanticColorsTitle": "功能色与中性色",
"derivedVariablesMapAliasToken": "派生变量 Map / Alias Token",
"sizeToken": "尺寸 Token",
"basicFontSize": "基础字号",
"basicSpacing": "基础间距",
"sizeStep": "尺寸步长",
"styleToken": "风格 Token",
"surfaceDescription": "固定无边设计,圆角塑形,阴影分层",
"universalFillet": "通用圆角",
"shadowIntensity": "阴影强度"
}
}
}
@@ -0,0 +1,21 @@
{
"auth": {
"signOut": "退出登录",
"adminSignIn": "管理员登录",
"apiKeySignIn": "API Key 登录",
"signingIn": "正在登录...",
"signIn": "登录",
"method": "选择登录方式",
"title": "控制台登录",
"welcome": "「 欢迎回来,登录以开始您的数据之旅 」",
"username": "管理员账号",
"usernamePlaceholder": "输入会话账号",
"passwordPlaceholder": "输入会话密钥",
"apiKeyPlaceholder": "输入 API Key",
"pageLabel": "Codex Proxy RS 登录",
"password": "密码",
"apiKey": "API 密钥",
"adminRealm": "管理员",
"keyRealm": "API 密钥"
}
}
@@ -0,0 +1,140 @@
{
"common": {
"errors": {
"canceled": "请求已取消",
"timeout": "请求超时,请稍后重试",
"network": "网络连接失败,请检查网络后重试",
"invalidParameters": "请求参数不合法",
"signInRequired": "需要登录",
"forbidden": "没有权限执行此操作",
"notFound": "请求的接口不存在",
"conflict": "资源状态冲突,请刷新后重试",
"payloadTooLarge": "请求内容过大",
"unsupportedFormat": "请求格式不受支持",
"invalidContent": "请求内容不合法",
"rateLimited": "请求过于频繁,请稍后重试",
"internal": "服务内部错误",
"upstreamFailure": "上游服务请求失败",
"unavailable": "服务暂不可用,请稍后重试",
"upstreamTimeout": "上游服务响应超时",
"http": "请求失败(HTTP {status})",
"request": "请求失败",
"responseTooLarge": "响应内容超过大小限制",
"unsupportedResponse": "服务返回了不受支持的响应",
"sessionExpired": "登录已失效,请重新登录",
"operation": "操作失败",
"copy": "复制失败",
"load": "加载失败",
"malformedJson": "请求体不是合法 JSON",
"invalidTimeRange": "时间范围不合法",
"invalidCredentials": "登录凭据错误",
"invalidAdminApiKey": "管理 API 密钥无效",
"tooManyLoginAttempts": "登录尝试过多,请稍后重试",
"upstreamResultUnknown": "上游执行结果未知,请刷新状态后再决定是否重试"
},
"status": {
"disabled": "已禁用",
"disabledName": "{name}(已禁用)",
"success": "成功",
"error": "异常",
"pending": "等待中",
"failed": "失败",
"healthy": "正常",
"all": "全部状态",
"available": "可用",
"unavailable": "不可用",
"enabled": "已启用",
"loading": "加载中",
"running": "执行中",
"completed": "已完成",
"rateLimited": "限流"
},
"actions": {
"copy": "复制",
"close": "关闭",
"retry": "重试",
"cancel": "取消",
"previous": "上一步",
"reset": "重置",
"back": "返回",
"delete": "确认删除",
"create": "创建",
"enable": "启用",
"next": "下一步",
"confirm": "确定",
"refresh": "刷新",
"save": "保存"
},
"providers": {
"all": "全部平台",
"filter": "按平台筛选",
"unknown": "未知平台",
"customAuth": "自定义认证 · {normalized}",
"unknownAuth": "未知认证类型"
},
"location": {
"resolving": "正在解析出口位置",
"detect": "解析出口位置并填入表单",
"countryCode": "国家代码",
"countryCodePlaceholder": "请输入两位国家代码",
"region": "地区",
"regionPlaceholder": "请输入地区",
"city": "城市",
"cityPlaceholder": "请输入城市",
"timeZone": "IANA 时区",
"timeZonePlaceholder": "请输入 IANA 时区",
"required": "请填写两位国家代码、地区、城市和 IANA 时区"
},
"values": {
"yes": "是",
"no": "否",
"unspecified": "未填写",
"all": "全部",
"unknown": "未知",
"unlimited": "不限",
"default": "默认",
"on": "开启",
"none": "无",
"off": "关闭"
},
"form": {
"inputPlaceholder": "输入内容",
"useForm": "使用表单",
"fieldHelp": "{label}说明",
"editJson": "编辑 JSON"
},
"fields": {
"actions": "操作",
"notes": "备注",
"status": "状态",
"color": "颜色",
"updatedAt": "更新时间",
"name": "名称",
"createdAt": "创建时间",
"baseUrl": "基础 URL",
"apiKey": "API 密钥",
"build": "构建"
},
"language": "界面语言",
"validation": {
"invalidJson": "请输入有效的 JSON 对象",
"jsonObject": "输入必须是 JSON 对象",
"sizeLimit": "输入不能超过 {value} KiB"
},
"feedback": {
"deleted": "删除成功",
"copied": "已复制"
},
"time": {
"minutesAgo": "{count} 分钟前"
},
"units": {
"tokens": "Token"
},
"sizes": {
"small": "小",
"medium": "中",
"large": "大"
}
}
}
@@ -0,0 +1,111 @@
{
"dashboard": {
"scheduling": {
"defaultConcurrency": "默认并发",
"totalSlots": "总槽位",
"freeSlots": "空闲槽位",
"smart": "智能调度",
"quotaReset": "额度重置优先",
"sticky": "粘滞",
"title": "账号调度",
"description": "容量、并发与分配策略",
"occupiedSlots": "槽位占用",
"strategy": "分配策略"
},
"accountPool": {
"empty": "暂无账号池观测",
"quotaExhausted": "配额耗尽",
"rateLimited": "限流中",
"pending": "待处理",
"issueCountsEmpty": "停用 — · 错误 —",
"availableDescription": "账号当前可用",
"exhaustedDescription": "账号额度已耗尽",
"limitedDescription": "账号请求暂时受限",
"issueCounts": "停用 {disabled} · 错误 {error}",
"title": "账号状态",
"description": "账号池健康结构",
"healthyRate": "正常率",
"distribution": "状态分布",
"unavailableCount": "不可用 {value}"
},
"activeAccounts": {
"title": "活跃账号用量",
"sortByRecent": "最近使用排序",
"empty": "暂无账号请求记录",
"recent": "最近"
},
"title": "系统概览",
"today": "当日统计",
"refresh": {
"action": "刷新概览",
"failed": "刷新失败,显示上次统计",
"unavailable": "统计暂不可用,请稍后重试",
"lastUpdated": "自动刷新 30s,最近刷新 {updatedAt}",
"waiting": "自动刷新 30s,等待首次刷新",
"interval": "自动刷新 30s"
},
"metrics": {
"title": "核心指标",
"outputTokens": "输出",
"inputTokens": "输入",
"cachedInputTokens": "缓存",
"cacheHits": "缓存命中",
"requests": "请求",
"firstTokenP95Ms": "TTFT P95",
"latencyP95Ms": "总耗时 P95",
"outputThroughputP50": "速率 P50",
"errors": "错误数",
"successRate": "成功率",
"totalRequests": "总请求",
"requestCount": "请求次数",
"totalTokens": "总 Token",
"totalCharges": "总计费",
"totalCacheHits": "总缓存命中",
"totalCache": "总缓存"
},
"comparedWithYesterday": "较昨日",
"trends": {
"title": "使用趋势",
"metric": "趋势指标",
"highlight": "突出显示{label}曲线",
"empty": "暂无趋势数据",
"latency": "延迟",
"errors": "错误"
},
"recentRequests": {
"title": "使用记录",
"description": "最近 10 条成功请求",
"empty": "暂无成功记录"
},
"clientIdentity": {
"notChecked": "尚未检查",
"versionPolicy": "版本策略",
"customVersion": "固定自定义",
"active": "当前生效",
"activeDescription": "跟随通用设置的新请求使用此身份",
"upToDate": "制品一致",
"upToDateDescription": "当前生效版本与官方最新发布一致",
"updateAvailable": "发现新版",
"latestRelease": "官方最新版本 {releaseLabel}",
"checkFailed": "检查失败",
"checkFailedDescription": "官方版本检查失败",
"pending": "待检查",
"pendingDescription": "尚未检查官方发布渠道",
"verifiedAt": "画像核验 {verifiedAt}",
"checkedAt": "发布检查 {checkedAt}",
"clientId": "客户端 ID",
"tokenAuth": "Token 认证",
"title": "通用上游身份",
"provider": "上游平台",
"empty": "暂无请求身份",
"attributes": "请求身份组成",
"authProtocol": "认证协议",
"emulatedEnvironment": "模拟运行环境",
"environment": "运行环境"
},
"health": {
"title": "请求健康时间线",
"description": "有效请求可用性"
}
}
}
@@ -0,0 +1,78 @@
{
"groups": {
"selector": {
"loading": "正在加载分组...",
"empty": "暂无分组,请先在分组管理中创建"
},
"actions": {
"editGroup": "编辑分组",
"disableGroup": "禁用分组",
"enableGroup": "启用分组",
"deleteGroup": "删除分组",
"enterGroupName": "请输入分组名称",
"selectValidGroupingColor": "请选择有效的分组颜色",
"updated": "分组已更新",
"created": "分组已创建",
"disabled": "分组已禁用",
"enabled": "分组已启用",
"groupDeleted": "分组已删除",
"deletedGroupDeletedGroups": "已删除 {count} 个分组",
"partialDeletion": "已删除 {count} 个分组,其余未删除:{value}",
"batchDeletionFailed": "批量删除失败"
},
"filters": {
"searchAccountGroup": "搜索账号分组",
"searchGroupName": "搜索分组名称",
"filterByGroupStatus": "按分组状态筛选",
"deleteSelected": "删除选中 ({count})",
"createGroup": "创建分组"
},
"editor": {
"editDescription": "修改分组信息和请求权限",
"createDescription": "创建后,可在账号管理中将账号加入这个分组",
"groupName": "分组名称",
"forExampleProductionAccount": "例如:生产账号",
"groupColor": "分组颜色",
"selectGroupColor": "选择分组颜色",
"fastMode": "快速模式",
"imageGeneration": "图像生成",
"descriptionOptional": "描述(可选)",
"groupDescription": "分组描述",
"describePurposeOfThisGroup": "说明这个分组的用途",
"saveGroup": "保存分组"
},
"metrics": {
"restricted": "受限",
"total": "总数",
"concurrency": "并发",
"today": "今日",
"cumulative": "累计"
},
"group": "分组",
"fields": {
"capacity": "容量"
},
"page": {
"description": "将账号归类管理,并为每个 API 密钥指定可使用的账号",
"empty": "暂无分组",
"selectCurrentPageGroup": "选择当前页分组",
"selectGroup": "选择分组",
"fastModeIsOn": "Fast 已开启",
"fastModeIsOff": "Fast 已关闭",
"imageGenerationDisabled": "生图已关闭",
"colorLabel": "分组颜色 {color}",
"batchDeleteWarning": "删除后这些分组将立即失效,此操作不可撤销",
"batchDeleteDescription": "确定删除选中的 {count} 个分组吗?账号本身不会被删除",
"disableAccountGrouping": "禁用账号分组",
"disableDescription": "禁用后,使用该分组的 API 密钥将无法再使用其中的账号",
"confirmDisable": "确认禁用",
"disable": "确定禁用“{name}”吗?",
"affectedApiKeys": "将影响 {count} 个 API 密钥:{value}",
"affectedKeys": "将影响 {count} 个 API 密钥",
"deleteAccountGroup": "删除账号分组",
"deleteWarning": "删除后该分组将立即失效,此操作不可撤销",
"unnamedGroup": "该分组",
"deleteAccountsWillBeKept": "确定删除“{name}”吗?账号本身不会被删除"
}
}
}
@@ -0,0 +1,29 @@
import accounts from './accounts.json'
import appearance from './appearance.json'
import auth from './auth.json'
import common from './common.json'
import dashboard from './dashboard.json'
import groups from './groups.json'
import keys from './keys.json'
import navigation from './navigation.json'
import plugins from './plugins.json'
import proxies from './proxies.json'
import settings from './settings.json'
import systemUpdate from './systemUpdate.json'
import usage from './usage.json'
export default {
...accounts,
...appearance,
...auth,
...common,
...dashboard,
...groups,
...keys,
...navigation,
...plugins,
...proxies,
...settings,
...systemUpdate,
...usage,
}
+110
View File
@@ -0,0 +1,110 @@
{
"keys": {
"configuration": {
"description": "保存或合并下方配置后重启 Codex",
"platform": "配置平台",
"toggleWebSocket": "切换 WebSocket 配置",
"importCcSwitch": "添加到 CC Switch",
"copiedToClipboard": "已复制到剪贴板",
"fullApiKeyNotAvailable": "完整 API Key 不可用",
"title": "使用密钥"
},
"actions": {
"editKey": "编辑密钥",
"useKey": "使用密钥",
"moreActions": "更多操作",
"resetUsedCredit": "重置用量",
"disableKey": "停用",
"enableKey": "启用",
"deleteKey": "删除",
"deletedApiKeyDeletedApiKeys": "已删除 {count} 个 API Key"
},
"day": "日",
"dailyUsage": "日用量",
"week": "周",
"weeklyUsage": "周用量",
"viewUsageAndCostsFor": "查看 {name} 的费用用量",
"costDetailsTitle": "费用详情(USD)",
"confirmNextTime": "下次使用时确定",
"budgetReset": {
"dailyQuota": "日额度",
"weeklyQuota": "周额度",
"keyQuotaReset": "已重置密钥额度",
"description": "清零所选周期的已用金额,下次使用时重新确定重置日期",
"targetKey": "目标密钥",
"resetScope": "重置范围",
"currentlyUsed": "当前已用",
"afterReset": "重置后",
"remainUnchanged": "保持不变",
"confirmReset": "确认重置"
},
"created": {
"apiKeyCreated": "API Key 已创建",
"description": "复制密钥,或直接导入 CCSwitch",
"accessNotice": "该密钥具有网关访问权限,请仅发送给可信调用方",
"copyKey": "复制密钥",
"iHaveSaved": "我已保存"
},
"filters": {
"apiKeyFilteringAndOperations": "API Key 筛选与操作",
"searchPlaceholder": "搜索名称或标签",
"searchLabel": "搜索 API Key 名称或标签",
"deleteSelected": "删除选中 ({count})",
"createApiKey": "创建 API Key"
},
"editor": {
"description": "配置密钥信息、分组与使用限制",
"namePlaceholder": "例如:生产环境",
"labelOptional": "标签(可选)",
"forExampleBackendService": "例如:后端服务",
"customKeyOptional": "自定义 Key(可选)",
"keyPlaceholder": "留空自动生成",
"upstreamIdentity": "上游身份",
"dailyLimit": "日限额",
"dailyLimitUsd": "日限额(USD)",
"weeklyLimit": "周限额",
"weeklyLimitUsd": "周限额(USD)",
"maximumConcurrency": "最大并发",
"requestsPerMinuteRpm": "每分钟请求数(RPM)",
"saveChanges": "保存更改",
"updated": "API Key 已更新",
"created": "API Key 已创建",
"validation": {
"amount": "{label}必须是非负金额,最多 10 位小数",
"integer": "{label}必须是非负整数"
},
"enterApiKeyName": "请输入 API Key 名称",
"invalidKey": "自定义 Key 只能包含 HTTP 可传输的可见字符,不能包含空格或换行",
"requestsPerMinute": "每分钟请求数"
},
"fields": {
"copyFullKey": "复制完整密钥",
"allAccounts": "全部账号",
"keyPrefix": "密钥前缀",
"quotaUsage": "额度使用",
"requestLimits": "请求限制",
"lastUsed": "最后使用"
},
"page": {
"description": "管理 API 密钥及账号访问范围",
"noApiKeyYet": "暂无 API Key",
"selectCurrentPageKey": "选择当前页密钥",
"selectKey": "选择密钥",
"concurrency": "并发",
"batchDeleteWarning": "删除后这些 API Key 将立即失效,此操作不可撤销",
"batchDeleteDescription": "确定删除选中的 {count} 个 API Key 吗?",
"deleteApiKey": "删除 API Key",
"deleteWarning": "删除后该 API Key 将立即失效,此操作不可撤销",
"apiKey": "该 API Key",
"delete": "确定删除 {name} 吗?"
},
"scope": {
"allAccounts": {
"title": "允许访问全部账号",
"summary": "保存后,此密钥可访问全部账号",
"confirm": "允许访问",
"description": "此密钥可访问全部账号,包括未分组和以后新增的账号"
}
}
}
}
@@ -0,0 +1,29 @@
{
"navigation": {
"overview": "概览",
"accounts": "账号管理",
"proxies": "代理管理",
"groups": "分组管理",
"apiKeys": "API 密钥",
"usage": "分析统计",
"plugins": "插件",
"appearance": "主题设置",
"settings": "系统设置",
"update": {
"available": "发现新版本,打开系统更新",
"open": "打开系统更新"
},
"switchLanguage": "切换语言({value})",
"mainLabel": "主导航",
"pluginsLabel": "插件导航",
"pluginManagement": "插件管理",
"online": "在线",
"sidebar": {
"close": "关闭侧边栏",
"expand": "展开侧边栏",
"collapse": "收缩侧边栏",
"open": "打开侧边栏"
},
"missingEntryPoint": "未配置 {role} 身份的默认入口"
}
}
@@ -0,0 +1,533 @@
{
"plugins": {
"assets": {
"pluginPackage": "插件包:{name}",
"selectPluginPackage": "选择插件包",
"packageLabel": "插件包"
},
"bindings": {
"observationHelpTitle": "请求观察说明",
"observationHelp": "仅观察请求,不改变请求结果",
"applyToAllRequests": "应用于所有请求",
"scopeHelpTitle": "生效请求范围说明",
"scopeHelp": "关闭后至少选择一项范围,不同条件同时满足才生效,同一条件内任意一项匹配即可",
"clientKey": "客户端 Key",
"accountGrouping": "账号分组",
"modelScope": "模型范围",
"oneModelNamePerLineExactMatch": "每行一个模型名称,精确匹配",
"providerScope": "Provider 范围",
"oneProviderIdentifierPerLine": "每行一个 Provider 标识",
"executionOrder": "执行顺序",
"executionSequenceDescription": "执行顺序说明",
"priorityHelp": "数值较小的先执行",
"whenPluginFails": "插件失败时",
"continueToNextHandler": "交给后续处理",
"rejectRequest": "拒绝请求"
},
"capabilities": {
"moreCapabilities": "另有 {count} 项声明能力"
},
"catalog": {
"cardView": "卡片视图",
"listView": "列表视图",
"currentVersion": "当前版本",
"installedVersion": "已安装版本",
"provideFunctionality": "功能",
"searchForInstalledPlugins": "搜索已安装插件",
"searchPluginsPublishers": "搜索插件、发布者",
"pluginStatus": "插件状态",
"pluginDisplayMode": "插件显示方式",
"noMatchingPlugins": "没有匹配的插件",
"installYourFirstPlugin": "安装第一个插件",
"tryAnotherNameOrStatus": "试试其他名称或状态",
"emptyDescription": "从上方安装插件,请先确认来源可信",
"clearFilters": "清除筛选",
"pluginInstalled": "已安装插件",
"noDescription": "发布者未提供说明",
"versions": "{count} 个版本",
"manage": "管理 {displayName}",
"versionCount": "版本数"
},
"configuration": {
"fillInRequiredConfiguration": "请填写必填配置",
"incompatibleSecrets": "目标版本不支持部分已保存的敏感配置,请选择替换或清除",
"requiredSecretsCannotClear": "必填敏感配置不能清除:{labels}",
"requiredSecretsMissing": "没有可保留的必填敏感配置:{labels}",
"secretsRequired": "请填写必填敏感配置",
"checkBasicSettings": "请检查基本设置",
"noParameters": "无需填写插件参数",
"sensitiveConfiguration": "敏感配置",
"secretsHelpTitle": "敏感配置说明",
"secretsHelp": "敏感配置单独保存,不回显已有值,选择保留时不会更改,选择替换时以本次填写的全部值覆盖",
"settingsSaved": "已保存 {count} 项",
"clearSecretsHelp": "保存时清除全部敏感配置",
"about": "{name}说明",
"enterNewValue": "输入新值",
"pluginParameters": "插件参数",
"advancedSettings": "高级设置",
"clientAuthentication": "客户端认证",
"applyAndSwitch": "应用并切换",
"saveAndEnable": "保存并启用",
"saveSettings": "保存设置",
"keepExistingValues": "保留已有值",
"replaceAllValues": "替换全部值",
"clearAllValues": "清除全部值",
"checkPluginParameters": "请检查插件参数",
"setRequestScopeOrCheckApplyTo": "请设置请求范围,或勾选“应用于所有请求”",
"invalidIdentityMappings": "请检查客户端认证身份映射",
"switchTo": "切换至 {version}",
"pluginSettings": "插件设置",
"unchangedVersion": "当前版本保持不变,修改后再应用",
"pluginSettingsPartition": "插件设置分区",
"secretsModeLabel": "敏感配置保存方式",
"customScope": "自定义范围",
"applyGlobally": "全局生效",
"requestHandling": "请求处理:{value}",
"description": "按配置提供扩展功能",
"providesTerminalCommands": "提供终端命令",
"requestHandlingNotConfigured": "未配置请求处理",
"apiKeys": "{count} 个 Key",
"groups": "{count} 个分组",
"providers": "{count} 个 Provider",
"identityMappings": "{count} 组身份映射",
"allRequests": "所有请求",
"noLimitOnScope": "不限制范围",
"featureDetails": "功能详情",
"capabilitiesOf": "{name} 的功能详情",
"terminalCommands": "终端命令",
"legacy": {
"multipleEnabledNotice": "检测到多套启用配置,请在历史配置中停用不再使用的一套",
"previousConfigurations": "历史配置 · {count}",
"description": "保留已有设置和数据,使用历史配置会替换当前启用配置",
"disableAction": "停用历史配置",
"start": "启动",
"deleteHistoricalConfiguration": "删除历史配置"
},
"stale": "插件设置已变更,请刷新后重试",
"incompatible": "请调整不兼容的设置后重试"
},
"details": {
"version": "版本",
"pendingDescription": "配置已保存,等待生效,状态会自动刷新",
"requiredConfiguration": "补充必填配置后即可启用",
"versionInUse": "旧版本仍有进行中的调用,完成前暂不能删除",
"pluginDetails": "插件详情",
"pluginDetailsSection": "插件详情分区",
"manualInstallationVersion": "手动安装版本",
"pluginHasNotBeenInitialized": "插件尚未初始化",
"pluginIsNotInstalled": "插件待安装",
"initializePlugin": "初始化插件",
"installation": "安装",
"versionNotAvailable": "版本不可用",
"configurationStatusOf": "{name}配置状态说明",
"settings": "设置",
"restart": "重新启动",
"deactivate": "停用",
"completeSetupAndEnable": "完成设置并启用",
"fallbackVersion": "回退版本",
"uninstallPlugin": "卸载插件"
},
"downloadAuth": {
"accessToken": "访问令牌",
"usernameAndPassword": "用户名与密码",
"customRequestHeader": "自定义请求头",
"noCertificationRequired": "无需认证",
"fillInGithubToken": "填写 GitHub 令牌",
"credentialsPlaceholder": "填写认证信息",
"useSavedCredentials": "使用已保存凭据",
"download": "下载 · {hostname}",
"downloadCertification": "下载认证",
"helpTitle": "下载认证说明",
"githubHelp": "公开仓库无需认证,私有仓库需要有读取权限的 GitHub 令牌",
"urlHelp": "仅在下载地址要求认证时填写",
"storageHelp": "认证信息在查询或解析时保存,仅用于当前来源,不会提供给插件",
"authenticationMethod": "认证方式",
"githubToken": "GitHub 令牌",
"downloadToken": "下载令牌",
"enterToken": "输入令牌",
"username": "用户名",
"downloadUsername": "下载用户名",
"password": "密码",
"downloadPassword": "下载密码",
"requestHeaderName": "请求头名称",
"requestHeaderValue": "请求头值"
},
"enable": {
"notSet": "未设置",
"switchActiveConfiguration": "切换启用配置",
"enablePluginConfiguration": "启用插件配置",
"willBeEnabled": "将启用",
"configurationsToDisable": "将停用 {count} 项",
"toggleEnablementInstructions": "切换启用说明",
"disableDescription": "以下配置将停止处理新请求,设置、密钥与私有数据保留",
"willBeDeactivated": "将停用",
"confirmSwitch": "确认切换",
"confirmEnable": "确认启用"
},
"extensions": {
"emptyTitle": "暂无插件管理页面",
"emptyDescription": "启用带有管理页面的插件后,可从此处或侧栏进入",
"configuration": "配置 {value}",
"pages": "{count} 页",
"openPage": "打开页面"
},
"frontendAuth": {
"exclusiveCertification": "独占认证",
"fallbackApiKeyIfNoMatch": "未匹配时回退 API Key",
"disabled": "(已停用)",
"configuredUnavailable": "已配置但当前不可用",
"invalidBinding": "客户端认证绑定必须使用认证阶段和受支持的未匹配处理",
"unsupportedScope": "客户端认证不支持 Provider、模型或分组范围,请关闭后重新启用该绑定",
"addAtLeastOneIdentityMapping": "请添加至少一条身份映射",
"mappingLimit": "身份映射不能超过 256 条",
"invalidIdentity": "身份标识必须是 1–256 个 UTF-8 字节,且不能含首尾空白或控制字符",
"duplicateIdentity": "同一身份标识只能配置一次",
"keyRequired": "请为每个身份标识选择客户端 Key",
"repeatedCursor": "服务返回了重复的分页位置",
"failedToLoadClientKey": "加载客户端 Key 失败",
"enableClientAuthentication": "启用客户端认证",
"helpTitle": "客户端认证说明",
"description": "插件识别请求中的外部身份,宿主再将该身份映射到已有 Client Key,沿用这个 Key 的限额、账号范围与并发策略",
"loginNotice": "此功能用于客户端 API 请求,不替代管理端登录",
"unmatchedProcessing": "未匹配处理",
"unmatchedHandlingInstructions": "未匹配处理说明",
"exclusiveHelp": "独占认证:插件未识别到身份时拒绝请求",
"fallbackToApiKeyWhenNoMatch": "未匹配时回退 API Key:插件未识别到身份时,继续使用宿主原有的 API Key 认证",
"rejectionHelp": "插件明确拒绝或调用失败时始终拒绝请求,不会回退",
"unmatchedLabel": "客户端认证未匹配处理",
"identityMapping": "身份映射",
"identityMappingDescription": "身份映射说明",
"identityHelp": "身份标识必须与插件返回的值完全一致,同一身份只能映射一次",
"keyHelp": "选择该身份使用的 Client Key,已停用或删除的 Key 不会获得执行权限",
"reloadClientKey": "重新加载客户端 Key",
"addMapping": "添加映射",
"identityMark": "身份标识",
"identityPlaceholder": "填写插件返回的身份标识",
"failedToLoadTryAgain": "加载失败,请重试",
"selectClientApiKey": "选择客户端 Key",
"noClientKeyYet": "暂无客户端 Key",
"removeIdentityMapping": "移除第 {value} 条身份映射"
},
"installation": {
"uploadPackage": "上传包",
"enterDigitHexadecimalDigest": "请输入 64 位十六进制摘要",
"installNewVersion": "安装新版本",
"pluginPackageCannotExceedMib": "插件包不能超过 32 MiB",
"verificationRequired": "请先校验当前选择的插件包",
"githubRepositoryRequired": "请输入 GitHub 仓库链接或 owner/repo",
"prereleaseTagRequired": "查询预发行版需要明确填写 tag",
"updatePlugin": "更新插件",
"installPlugin": "安装插件",
"installDescription": "确认来源与版本后安装",
"switchDescription": "检查设置兼容性后切换版本",
"sourceHelp": "支持本地插件包、URL 与 GitHub",
"installationMethod": "安装方式",
"tarGzTgzMaxMib": "tar.gz / tgz,最大 32 MiB",
"replace": "更换",
"browseFiles": "浏览文件",
"downloadUrl": "下载 URL",
"downloadAddressDescription": "下载地址说明",
"urlHelp": "仅支持 HTTPS,本机回环地址可使用 HTTP",
"githubRepository": "GitHub 仓库",
"repositoryLinkOrOwnerRepo": "仓库链接或 owner/repo",
"tagLabel": "版本标签",
"tagHelpTitle": "版本标签说明",
"tagHelp": "留空查询最新稳定版,查询预发行版时必须指定标签",
"tagPlaceholder": "留空查最新稳定版",
"allowPrereleaseLabel": "允许查询预发行版",
"verificationSummary": "校验摘要",
"digestHelpTitle": "校验摘要说明",
"digestHelp": "可选,填写发布者提供的 64 位 SHA-256 十六进制摘要,用于核对下载内容",
"shaChecksum": "SHA-256 校验摘要",
"optionalSha": "可选,SHA-256",
"versionFound": "已找到版本",
"preRelease": "预发行版",
"thereIsNoTarGzOrTgz": "此版本没有 tar.gz 或 tgz 插件包",
"pendingTitle": "待安装插件",
"parsingCompleted": "解析完成",
"publisher": "发布者",
"applicablePlatforms": "适用平台",
"trustNotice": "插件可访问全部网关数据与配置,安装前请确认来源可信",
"activateAfterInstall": "安装后确认切换到新版本",
"installNewVersionInstructions": "安装新版本说明",
"configurationHelp": "沿用设置并补充新版本默认值,需要调整时会打开设置,已使用版本保留恢复设置",
"queryAgain": "重新查询",
"queryingVersion": "正在查询版本",
"saveSourceAndContinue": "保存来源并继续",
"parsingPluginPackage": "正在解析插件包",
"pluginInstallationFailed": "插件安装失败",
"noSource": "此插件没有可用的安装来源",
"sourceChanged": "安装来源已变更,请关闭后重新打开",
"sourceSaveFailed": "安装来源保存失败",
"githubReleaseQueryFailed": "GitHub Release 查询失败",
"installedNeedsConfiguration": "插件已安装,请补充必要配置",
"preparing": "插件已安装,正在准备",
"pluginVersionInstalled": "插件版本已安装",
"updateSourceChanged": "安装来源已变更,请重新检查更新",
"pluginUpgradeFailed": "插件升级失败",
"versionRequired": "请选择待安装的插件版本",
"packageMismatch": "插件包与当前插件不符,请重新选择",
"verificationFailed": "插件包校验失败"
},
"management": {
"installed": "已安装",
"extensions": "扩展页",
"description": "管理版本、配置与扩展页",
"tabsLabel": "插件管理分区",
"refresh": "刷新插件",
"switchPluginVersion": "切换插件版本",
"switchHelp": "切换前会检查目标版本设置,失败时保留当前版本",
"deletePluginVersion": "删除插件版本",
"deleteVersionHelp": "使用中的版本不可删除,删除版本也会清除对应的恢复设置",
"delete": "删除 {displayName} {version}?",
"versionDeletionDetails": "版本删除详情",
"deleteVersionInUse": "被配置或运行中的调用引用时不能删除,不会自动停用其他配置",
"deleteVersionCleanupHelp": "只清理此版本独用的下载认证,删除最后一个版本时同时清理来源规则,共享认证与代理不受影响",
"deleteVersionCleanupLabel": "同时清理独用下载认证,最后一版还会清理来源",
"deletePluginConfiguration": "删除插件配置",
"deleteConfigurationWarning": "配置、密钥与私有数据将永久删除",
"deleteConfigurationHelp": "无法恢复,已安装版本与其他配置不受影响",
"uninstallWarning": "删除全部版本、配置、密钥与私有数据",
"confirmUninstall": "确认卸载",
"versionCount": "{displayName} · {count} 个版本",
"uninstallCleanupLabel": "同时清理来源与独用下载认证",
"uninstallCleanupInstructions": "卸载清理说明",
"uninstallCleanupHelp": "只清理被卸载版本使用且不再被其他版本引用的下载认证,不删除共享认证、代理或审计记录",
"disableInsteadHelp": "暂时不用可停用配置,无需卸载",
"permanentDeleteLabel": "确认永久删除,无法恢复",
"deleteDownloadCredentials": "删除下载认证",
"itCannotBeDeletedWhileItIs": "仍被使用时不可删除,删除后无法恢复",
"pageLoadFailed": "插件扩展页加载失败",
"pluginDataLoadingFailed": "插件数据加载失败"
},
"frame": {
"pluginPageCannotBeLoaded": "插件页面无法加载",
"versionChanged": "插件页面版本已变更,正在刷新",
"navigationBlocked": "插件页面尝试离开已隔离的管理文档,已停止加载",
"invalidQueryParameter": "查询参数无效",
"queryParametersExceedKib": "查询参数超过 8 KiB",
"invalidBody": "请求正文无效或超过 1 MiB",
"routesDoNotAcceptRequestBody": "{method} 路由不接受请求正文",
"contentTypeIsInvalid": "Content-Type 无效",
"unregisteredContentType": "Content-Type 未在插件路由中注册",
"contentTypeRequired": "包含正文的请求必须声明 Content-Type",
"invalidRequestParameters": "请求参数无效",
"unregisteredRequest": "请求未在当前插件版本中注册",
"invalidCallbackTicket": "回调票据参数无效",
"unregisteredCallback": "回调路径未在当前插件版本中注册",
"invalidTicketLifetime": "回调票据有效期必须为 1 到 600 秒",
"invalidModelRequest": "模型请求参数无效",
"clientkeyidIsInvalid": "clientKeyId 无效",
"invalidModelBody": "Responses 请求正文无效或超过 8 MiB",
"invalidModelJson": "Responses 请求正文不是有效 JSON",
"modelObjectRequired": "Responses 请求正文必须是 JSON 对象",
"pageDidNotContinueToReadModel": "页面 30 秒未继续读取模型响应",
"modelConcurrencyLimit": "模型请求已达并发上限",
"duplicateModelRequest": "模型请求序号重复",
"modelTimeout": "模型请求超过 10 分钟",
"unsupportedModelContentType": "模型接口返回了不受支持的内容类型",
"modelRequestFailed": "模型请求失败",
"invalidPullId": "模型响应拉取序号无效",
"concurrentPull": "模型响应拉取发生重入",
"stalePullId": "模型响应拉取序号已失效",
"modelResponseReadFailed": "模型响应读取失败",
"duplicateManagementRequest": "插件管理请求序号重复",
"managementConcurrencyLimit": "插件管理请求已达并发上限",
"invalidEntryPoint": "插件页面入口不是已注册的 HTML 资源",
"unregisteredAsset": "插件页面引用了未注册资源:{path}",
"htmlSubresource": "插件 HTML 资源不能作为子资源加载",
"cyclicCss": "插件 CSS 资源存在循环引用:{path}",
"invalidVersion": "插件页面版本无效,请刷新后重试",
"resourceCountLimit": "插件页面资源数量超过限制",
"pageChanged": "插件页面已变更,请刷新后重试",
"pluginAssetReturnedHttp": "插件资源返回 HTTP {status}",
"resourceTypeMismatch": "插件资源类型与注册值不一致:{path}",
"pluginAssetExceedsMib": "插件资源超过 1 MiB:{path}",
"resourceSizeLimit": "插件页面资源总量超过 8 MiB",
"unsupportedElement": "插件页面使用了不受支持的 {'<'}{value}{'>'} 元素",
"redirectForbidden": "插件页面不能使用自动跳转",
"moduleScriptUnsupported": "插件页面暂不支持 ES Module 脚本,请使用经典脚本包",
"invalidPluginScriptAssetType": "插件脚本资源类型无效:{path}",
"unsupportedLink": "插件页面只支持 stylesheet 和 icon 链接资源",
"invalidStylesheet": "插件样式资源类型无效:{path}",
"invalidPluginIconAssetType": "插件图标资源类型无效:{path}",
"unsupportedSrc": "插件页面不支持 {'<'}{value}{'>'} 的 src 加载",
"invalidPluginImageAssetType": "插件图像资源类型无效:{path}",
"invalidPluginPosterAssetType": "插件 poster 资源类型无效:{path}",
"emptySrcset": "插件 srcset 资源引用为空",
"externalNavigation": "插件页面不能导航到外部或未注册地址",
"pluginPageDoesNotSupportUrls": "插件页面不支持 {name} 地址",
"externalAttribute": "插件页面属性不能引用外部资源:{name}",
"unsupportedPluginCssSyntax": "插件 CSS 语法不受支持:{ownerPath}",
"invalidCss": "插件 CSS 包含无法解析的内容:{ownerPath}",
"escapedCssIdentifier": "插件 CSS 规则或函数名不能使用转义:{ownerPath}",
"inlineStyleImport": "内联 style 属性不能导入样式表",
"unsupportedPluginImportSyntax": "插件 {'@'}import 语法不受支持:{ownerPath}",
"pluginImportTargetIsNotCss": "插件 {'@'}import 目标不是 CSS:{path}",
"unsupportedPluginAssetUrl": "插件资源地址不受支持:{rawReference}",
"resourceQuery": "插件资源地址不支持查询参数:{rawReference}",
"resourceFragment": "插件资源地址不支持片段标识:{rawReference}",
"resourceOutsideArtifact": "插件资源地址越过制品边界:{rawReference}",
"invalidPluginAssetPathSegment": "插件资源路径片段无效:{rawReference}",
"invalidResourcePath": "插件注册了无效资源路径:{path}",
"pluginTextAssetIsNotValidUtf": "插件文本资源不是有效 UTF-8:{path}"
},
"pluginPage": "插件页面",
"page": {
"configurationDescription": "使用插件提供的功能,当前配置为「{name}」",
"description": "加载已启用插件的管理页面",
"unpublished": "该配置或页面未发布,可能已停用或切换版本",
"refreshFailed": "页面目录刷新失败,当前显示上次成功加载的版本:{loadError}",
"loadingPage": "正在加载页面"
},
"refreshPage": "刷新页面",
"pluginPageIsUnavailable": "插件页面不可用",
"returnToPluginManagement": "返回插件管理",
"resources": {
"unavailable": "不可用 · {id}",
"multipleSelectionsAllowed": "{label}(可多选)",
"unlimitedPlaceholder": "不限(可多选)",
"loading": "正在加载…",
"isTemporarilyUnavailable": "暂时无法获取{label}",
"noMatches": "没有匹配项",
"no": "暂无{label}",
"createOneInFirst": "请先在{value}中创建"
},
"rollback": {
"rollBackPluginVersion": "回退插件版本",
"description": "恢复对应版本的设置,保持当前启停状态",
"targetVersion": "目标版本",
"fallbackInstructions": "回退说明",
"restoreHelp": "恢复目标版本上次启用时的参数和密钥,私有数据仍须通过兼容检查",
"loadingOlderVersions": "正在加载旧版",
"selectRollbackVersion": "请选择回退目标",
"rollBackToTargetVersion": "回退目标版本",
"empty": "没有保留恢复设置的旧版,其他版本可在“版本”中切换",
"reload": "重新加载",
"confirmRollback": "确认回退",
"completed": "已回退至 {version},并恢复对应设置"
},
"sourceProxy": {
"noProxyDirectConnection": "不使用代理(直连)",
"disabledSuffix": "(已禁用)",
"catalogUnavailable": "已选代理(目录暂不可用)",
"label": "下载代理"
},
"status": {
"unableToStart": "无法启动",
"runFailed": "运行失败",
"compatibilityReminder": "兼容性提醒",
"deprecatedApi": "接口待升级,当前仍兼容",
"startupUnverified": "可以尝试启动,运行结果仍需验证",
"compatibilityWindow": "旧接口还将兼容至少 {remainingReleases} 个正式版本",
"compatibilityEnding": "兼容窗口已满,后续正式版本将移除旧接口转换",
"unsupportedVersionHelp": "配置与数据保留,请安装可加载的插件版本",
"restartHelp": "启用配置保留,可在插件详情中重新启动",
"upgradeHelp": "请更新插件,或联系作者升级接口"
},
"updates": {
"packageRequired": "请选择插件包以确认版本与兼容性",
"currentlyUsingThisVersion": "当前已使用此版本",
"verifiedUpdate": "发现新版本,插件包已校验",
"sameVersionDifferentContent": "版本号相同,插件包内容不同",
"noHigherVersionFound": "未发现更高版本",
"pluginUpdate": "插件更新",
"checkingDescription": "正在检查版本并校验插件包",
"versionComparison": "版本对比",
"postTag": "发布标签",
"updateInspectionInstructions": "更新检查说明",
"configurationHelp": "按插件包内版本判断升级,沿用当前设置,配置不兼容时保留当前版本并打开设置",
"trustNotice": "插件可访问全部网关数据与配置,更新前请确认来源可信",
"thereIsNoTarGzOrTgzPlugin": "此发布没有 tar.gz 或 tgz 插件包",
"upgradeTo": "升级到 {version}",
"continueInstallation": "继续安装",
"unsupportedSource": "此来源不支持检查更新,请安装新版本",
"sourceChanged": "安装来源已变更,请重新检查",
"checkForUpdatesFailed": "检查更新失败"
},
"versionDetails": "版本详情",
"toBeInstalled": "待安装",
"historicalConfiguration": "历史配置",
"referenceConfiguration": "引用配置",
"versions": {
"detailsLabel": "{version} 版本详情",
"historicalVersion": "历史版本"
},
"install": "安装 {version}",
"deleteVersion": "删除版本 {version}",
"credentials": {
"selectDownloadCredentials": "选择下载认证 {name}",
"deleteDownloadCredentials": "删除下载认证 {name}",
"saveDownloadCredentialsFailed": "下载认证保存失败",
"sourceCredentialsDeleted": "来源凭据已删除",
"deleteFailed": "来源凭据删除失败"
},
"artifacts": {
"pluginProductHasBeenDeleted": "插件制品已删除",
"pluginProductDeletionFailed": "插件制品删除失败"
},
"instances": {
"saveFailed": "插件配置保存失败",
"versionMissing": "所选版本已不存在,请重新选择",
"loadFailed": "启用配置加载失败",
"configurationEnablementFailed": "配置启用失败",
"switchedCurrentConfiguration": "已切换当前配置",
"pluginSettingsApplied": "插件设置已应用",
"savedDisabled": "设置已保存,插件保持停用",
"pluginDisabled": "插件已停用",
"pluginDeactivationFailed": "插件停用失败",
"deleted": "配置、密钥与私有数据已删除,无法恢复",
"pluginInstanceDeletionFailed": "插件实例删除失败"
},
"uninstall": {
"newConfiguration": "出现了新的插件配置,请关闭并重新确认卸载范围",
"versionChanged": "“{name}”已切换版本,请重新确认卸载范围",
"removingConfiguration": "正在停用并删除配置:{name}",
"newVersion": "已删除确认范围,但还有新安装的版本,请关闭并重新确认剩余内容",
"completed": "插件已卸载,相关数据与来源设置已清理",
"incomplete": "卸载尚未完成,可重试剩余步骤"
},
"deletingVersion": "正在删除版本:{version}",
"switchedTo": "已切换至 {version}",
"versionSettingFailedToLoad": "版本设置加载失败",
"versionSwitchingFailed": "版本切换失败",
"fallbackVersionLoadingFailed": "回退版本加载失败",
"pluginVersionRollbackFailed": "插件版本回退失败",
"fields": {
"requestCompletionAndUsage": "请求完成与用量",
"upstreamWebsocketEvents": "上游 WebSocket 事件",
"requestScheduling": "请求调度",
"modelRouting": "模型路由",
"modelCatalog": "模型目录",
"retryStrategy": "重试策略",
"requestMiddleware": "请求中间件",
"upstreamAdapter": "上游适配器",
"eventObservation": "事件观察",
"commandLine": "命令行",
"manageExtensions": "管理扩展",
"maintenanceTasks": "维护任务",
"httpRequest": "HTTP 请求",
"allHttpRequests": "所有 HTTP 请求",
"websocketMessages": "WebSocket 消息",
"allWebsocketMessages": "所有 WebSocket 消息",
"serviceCall": "服务调用",
"allServiceCalls": "所有服务调用",
"requestToStart": "请求开始",
"everyTry": "每次尝试",
"upstreamCall": "上游调用",
"accountScheduling": "账号调度",
"retryDecision": "重试决策",
"toBeConfigured": "待配置",
"deactivated": "已停用",
"waitingForItToTakeEffect": "等待生效"
},
"validation": {
"suppliedWithVersion": "随版本提供",
"localUpload": "本地上传",
"fixedUrl": "固定 URL",
"releaseList": "发行清单",
"noRemoteUpdateSource": "无远程更新来源"
},
"onePerLine": "每行一项"
}
}
@@ -0,0 +1,165 @@
{
"proxies": {
"accounts": {
"platformType": "平台",
"subscription": "订阅",
"noMatches": "没有找到匹配的账号,请尝试其他名称或邮箱",
"empty": "暂无关联账号",
"linkAccount": "关联账号",
"searchAssociatedAccounts": "搜索关联账号",
"searchAccountNameOrEmail": "搜索账号名称或邮箱",
"removeAction": "从当前代理移除账号",
"removeAssociatedAccount": "移除关联账号",
"remove": "移除",
"removeDescription": "将“{name}”从“{removeProxyName}”移除后,该账号将改为直连",
"removed": "账号已移出当前代理,改为直连"
},
"actions": {
"test": "测试代理",
"edit": "编辑代理",
"moreActionsFor": "{name} 的更多操作",
"disableProxy": "禁用代理",
"enableProxy": "启用代理",
"deleteProxy": "删除代理",
"testInProgress": "代理正在测试,请等待当前测试结束",
"testFailed": "代理测试失败",
"connectedWithDetails": "{name}:连接成功,{message}",
"timeZoneMismatch": "{name}:连接成功,IPv4 与 IPv6 出口时区不一致",
"connected": "{name}:连接成功",
"fillInProxyConnectionAddress": "请填写代理连接地址",
"connectedInMs": "连接成功,耗时 {latencyMs} ms",
"locationFailed": "代理连接失败,未能解析位置",
"exitLocationFilledIn": "已填入出口位置",
"unableToObtainExitLocation": "未获取到出口位置",
"fieldsRequired": "请填写代理名称和连接地址",
"invalidConnectionLimit": "连接上限须为 0 到 4294967295 之间的整数",
"saved": "代理已保存",
"proxyEnabled": "代理已启用",
"disabled": "代理已禁用,关联账号已改为直连",
"deleted": "代理已删除"
},
"batchCreate": {
"proxyList": "代理列表",
"formatDescription": "代理列表格式说明",
"supportedFormats": "支持以下格式",
"hostPortUsernamePassword": "host:port:用户名:密码",
"httpUsernamePasswordHostPort": "http://用户名:密码{'@'}host:port",
"protocolHelp": "未写协议时使用下方默认协议,完整 URL 保留各自协议",
"ipv6Help": "IPv6 地址需加方括号,例如",
"onePerLineMaximum": "每行一条 · 最多 {value} 条",
"bulkProxyList": "批量代理列表",
"totalReadyToAdd": "共 {count} 条,{count2} 条可添加",
"needsChanges": ",{count} 条需修改",
"line": "第 {line} 行:{error}",
"additionalIssues": "另有 {count} 条需处理",
"defaultProtocol": "默认协议",
"defaultProtocolLabel": "无协议代理的默认协议",
"namePrefix": "名称前缀",
"proxy": "代理",
"conflict": "代理已存在或配置冲突,未覆盖已有记录",
"stopped": "已停止后续添加"
},
"batchTest": {
"resultsTitle": "批量添加结果",
"processed": "已处理",
"added": "已添加 {created}",
"invalidFormat": "格式错误 {invalid}",
"connected": "连接正常 {succeeded}",
"connectionFailed": "连接失败 {failed}",
"locationPending": "地区待处理 {locationPending}",
"needsAttention": "需处理 {attention}",
"skipped": "未执行 {skipped}",
"scrollListOfProxyResults": "代理结果滚动列表",
"lineNumber": "第 {key} 行",
"addedStatus": "已添加",
"connectionIsNormal": "连接正常",
"stopped": "已停止后续测试",
"proxyMissing": "所选代理已不存在,请刷新列表",
"batchTestCompletedConnected": "批量测试完成,连接正常 {succeeded} 条",
"unsuccessful": "未成功 {count} 条",
"locationsPending": "地区待处理 {locationPending} 条",
"proxiesNoLongerAvailable": "{missing} 条代理已不存在",
"toBeExecuted": "待执行",
"requestFailed": "请求失败",
"configurationConflict": "配置冲突",
"testingIsBusy": "测试繁忙",
"resultToBeConfirmed": "结果待确认",
"notExecuted": "未执行",
"invalidProxyFormat": "代理格式不正确",
"invalidAddress": "代理主机或端口不合法",
"duplicateOfLine": "与第 {earlier} 行重复",
"formatHelp": "格式不正确,请参考格式说明",
"proxyListCannotExceedKib": "代理列表不能超过 512 KiB",
"addUpToProxiesAtTime": "一次最多添加 {value} 条代理",
"resultUnknown": "未取得确定结果,请刷新列表核对",
"interrupted": "请求中断或服务异常,请刷新列表核对结果",
"skippedAfterFailure": "前序操作异常,未执行"
},
"editor": {
"single": "单条",
"batch": "批量",
"timeZoneMismatch": "IPv4 与 IPv6 出口时区不一致,请手动填写",
"createTitle": "新增代理",
"connectionHelp": "留空保留当前连接和认证信息,填写新地址时,请包含所需的用户名和密码",
"protocolHelp": "支持 HTTP、HTTPS、SOCKS5 和 SOCKS5H,可在地址中包含用户名和密码",
"createDescription": "添加代理,为账号配置网络出口",
"methodLabel": "代理添加方式",
"nameLabel": "代理名称",
"namePlaceholder": "请输入代理名称",
"proxyAddress": "代理地址",
"addressPlaceholder": "输入代理地址",
"upstreamWsConnectionCap": "上游 WS 连接上限",
"connectionLimitHelp": "使用此代理的账号共享连接额度",
"noRestrictionsByDefault": "默认不限制",
"customTimeZoneLocation": "自定义时区位置",
"affectedAccounts": "将更新 {count} 个关联账号的出口",
"pendingResultsHelp": "待确认项可能已保存,继续添加前请刷新核对",
"saveAction": "保存代理",
"waitForCurrentOperationToEnd": "等待当前操作结束",
"stopSubsequentOperations": "停止后续操作",
"testing": "正在测试",
"adding": "正在添加",
"editItemsNotAdded": "修改未添加项",
"testAddedProxies": "测试已添加的 {count} 条",
"testAfterAdding": "添加后测试",
"add": "添加 {count} 条",
"addProxy": "添加代理"
},
"region": {
"connectionFailed": "连接失败",
"regionalConflict": "地区冲突",
"parsingFailed": "解析失败",
"exitNotRecognized": "出口未识别",
"ipv4AndIpv6EgressTimeZonesAre": "IPv4 与 IPv6 出口时区不一致",
"exitLocation": "出口地区:{label} · {timezone}",
"detectHelp": "测试代理时解析出口地区",
"customLocation": "自定义位置:{customLabel} · {timezone}",
"custom": "自定义:{customLabel}"
},
"fields": {
"exitIp": "出口 IP",
"latency": "耗时",
"testTime": "测试时间"
},
"page": {
"description": "管理账号使用的代理,测试连接并查看出口 IP",
"searchLabel": "搜索代理",
"searchPlaceholder": "搜索代理名称",
"batchTestAction": "批量测试代理",
"batchTest": "批量测试 ({count})",
"noMatches": "没有找到匹配的代理,请尝试其他名称",
"empty": "暂无代理",
"selectCurrentPageProxy": "选择当前页代理",
"selectProxy": "选择代理 {name}",
"credentialsSaved": "代理凭据已保存",
"underTest": "测试中",
"ms": "{message}(耗时 {latencyMs} ms)",
"notTested": "未测试",
"viewAccountsAssociatedWith": "查看 {name} 的 {count} 个关联账号",
"disable": "确定禁用“{name}”吗?",
"disableDescription": "关联账号的新请求将改为直连,代理配置和绑定会保留,重新启用后恢复使用",
"delete": "确定删除“{name}”吗?",
"deleteDescription": "将自动解除关联账号,关联账号的新请求将改为直连"
}
}
}
@@ -0,0 +1,648 @@
{
"settings": {
"clientProfile": {
"userAgent": "用户代理",
"clientIdentitySource": "客户端身份来源",
"globalConfiguration": "全局配置",
"customConfiguration": "独立配置",
"presetLoadingFailed": "预设加载失败",
"enterIntegerFromTo": "请输入 1~{version} 的正整数",
"clientDefault": "客户端预设",
"useCustomUserAgent": "使用自定义用户代理",
"cliEntry": "CLI 入口",
"coreDefaultIdentity": "Core · 默认身份",
"tuiInteractiveTerminal": "TUI · 交互式终端",
"execNonInteractiveExecution": "Exec · 非交互执行",
"versionStrategy": "版本策略",
"followLatestVersion": "跟随最新版本",
"customVersion": "自定义版本",
"versionLag": "版本滞后",
"versionLagHelp": "滞后 1~{version} 个版本,留空不滞后",
"terminalIdentification": "终端标识",
"leaveBlankToUseUnknown": "留空使用 unknown",
"systemVersion": "系统版本",
"userAgentPlaceholder": "填写完整用户代理",
"previewAfterFillingInVersion": "填写版本后预览",
"previewIsNotAvailableYet": "预览暂不可用",
"resolvingClientIdentity": "正在解析客户端身份",
"fixedIdentity": "固定身份",
"automaticUpdates": "自动更新",
"versionsBehind": "· 滞后 {version} 版",
"checked": "检查于 {checkedAtDisplay}",
"toBeChecked": "待检查",
"updateFailedUseLastVersion": "更新失败 · 沿用上次版本",
"clientIdentityProvider": "客户端身份 Provider",
"upstreamIdentityPlatform": "上游身份平台",
"clientId": "客户端 ID",
"operatingMode": "运行模式",
"operatingSystem": "操作系统",
"cpuArchitecture": "CPU 架构",
"xaiClientIdentitySource": "xAI 客户端身份来源",
"loadFailed": "全局配置加载失败",
"clientType": "客户端类型",
"grokCliVersion": "Grok CLI 版本",
"forExample": "例如:1.0.13",
"clientIdentity": "客户端身份",
"description": "配置网关向上游声明的客户端类型、版本与请求头"
},
"pricing": {
"multiplier": "倍率",
"clearOverrides": "清除人工覆盖",
"setMultipliers": "批量设置倍率",
"batch": {
"description": "仅修改下列 {count} 个模型,不重算历史账单",
"resetHelp": "恢复来源或内置价格,无可用价格时设为未配置",
"multiplierHelp": "设置为此倍率,不与已有倍率相乘,0~100,最多四位小数"
},
"targetMultiplier": "目标倍率",
"enterLegalMultiplier": "请输入合法倍率",
"confirmClearOverride": "确认清除覆盖",
"confirmSettingMultiplier": "确认设置倍率",
"sourcePrice": "来源价",
"textToken": "文本 Token",
"validation": {
"modelId": "模型 ID 必须为 1~128 字节,不含空白或控制字符",
"tierPrices": "请完整填写该档位的四项单价:0~1000000,最多四位小数",
"standardTier": "新模型需要配置标准档单价"
},
"multiplierRangeIsWithUpToFour": "倍率范围为 0~100,最多四位小数",
"editModelPricing": "编辑模型价格",
"addModelPricing": "添加模型价格",
"upstreamModelId": "上游模型 ID",
"forExampleGpt": "例如 gpt-5.4",
"customizedMultiplier": "自定义倍率",
"gearPrice": "档位价格",
"priceRange": "价格档位",
"unitPriceSource": "单价来源",
"tier": {
"sourceUnavailable": "此档位暂无来源价格"
},
"fillInUnitPrice": "填写单价",
"pricingInstructions": "计价说明",
"modelIdUsesNameActuallySentTo": "模型 ID 使用实际发送给上游的名称,不是客户端别名",
"customTierHelp": "自定义档位需填写四项单价,0 表示免费,单价上限 1000000,倍率范围 0~100,最多四位小数",
"estimateHelp": "仅调整本地估算与金额限额,不代表订阅实际扣费,保存后仅新请求生效,历史账单不变",
"unitPrice": "{label}单价",
"source": "来源",
"takeEffect": "生效",
"sync": {
"title": "确认同步来源价目",
"description": "仅同步所选模型的来源价格,保留自定义单价和倍率",
"skipped": "跳过 {count} 个缺少完整价格或计价方式不匹配的模型",
"action": "同步"
},
"selectAll": "全选",
"selected": "已选 {count} / {count2}",
"keepManualCoverage": "保留人工覆盖",
"noChangeInSourcePrice": "来源价格没有变化",
"skipSynchronizedModels": "跳过同步的模型",
"confirmSynchronization": "确认同步",
"model": "模型",
"input": "输入",
"output": "输出",
"cacheRead": "缓存读取",
"noMatchingModel": "没有匹配的模型",
"selectModelOnThisPage": "选择本页模型",
"select": "选择 {model}",
"image": "· 图像",
"editPrice": "编辑价格",
"deletePriceList": "删除价目",
"notSyncedYet": "尚未同步",
"searchModel": "搜索模型",
"searchModelId": "搜索模型 ID",
"modelProvider": "模型提供商",
"priceSource": "价格来源",
"allSources": "全部来源",
"batchOperation": "批量操作",
"selectedCountLabel": "已选",
"item": "项",
"setMultiplier": "设置倍率",
"clearOverwrite": "清除覆盖",
"deselect": "取消选择",
"synchronizationInstructions": "同步说明",
"sourceHelp": "从 models.dev 获取社区价目,保留人工单价与倍率",
"lastSynced": "最近同步:{syncTime}",
"syncPriceList": "同步价目",
"addModel": "添加模型",
"unitHelp": "价格单位:USD / 百万 Token,查看定价说明",
"unitPriceUnitUsdMTokens": "单价单位:USD / 1M Tokens",
"priorityHelp": "人工覆盖优先于同步价目,再继承内置价格,仅影响本地估算与金额限额",
"tableHelp": "表中为标准档生效价,图像模型显示图像 Token 价格,划线为来源价,其他档位在编辑中查看",
"priceListFailedToLoad": "价目加载失败",
"deleteModelPriceList": "删除模型价目",
"deleteDescription": "删除该模型的同步与自定义价格,历史账单不变",
"standard": "标准",
"longContextStandard": "长上下文 · 标准",
"longContextPriority": "长上下文 · Fast",
"longContextUltrafast": "长上下文 · Ultrafast",
"longContextFlex": "长上下文 · Flex",
"imageToken": "图像 Token",
"cacheWrites": "缓存写入",
"builtInPriceList": "内置价目",
"manualCoverage": "人工覆盖",
"notConfigured": "未配置",
"unableToLoadPriceList": "无法加载价目",
"deleted": "模型价目已删除",
"manualOverrideCleared": "已清除人工覆盖",
"modelPricingSaved": "模型定价已保存",
"synced": "来源价目已同步,人工覆盖保持不变",
"unitLabel": "USD / 百万 Token"
},
"scheduling": {
"roundRobin": "轮询",
"autoReviewSlotsHelp": "仅对 OpenAI 账号生效,普通并发为 10、审批名额为 3 时,两类请求分别最多运行 10 个和 3 个,互不占用名额",
"autoReviewQueueHelp": "开启独立额度后,审批请求单独排队,可超过账号队列容量,仍受总等待容量、排队超时与密钥限额约束",
"weights": {
"load": "负载系数",
"loadHelp": "越大越偏向并发占用比例较低的账号",
"quota": "剩余额度系数",
"quotaHelp": "越大越偏向剩余额度比例较高的账号",
"health": "健康系数",
"healthHelp": "越大越偏向近期失败率较低的账号",
"latency": "延迟系数",
"latencyHelp": "越大越偏向首个有效输出较快的账号",
"reset": "额度重置系数",
"resetHelp": "越大越偏向即将重置额度的账号,重置时间未知或已过期时不加分",
"queue": "排队系数",
"queueHelp": "需要排队时,越大越偏向等待请求较少的账号,设为 0 时沿用最短队列规则"
},
"enterValueFromToUpToOne": "请输入 0~10 的数值,最多一位小数",
"description": "调整账号选择偏好",
"enabledHelp": "仅在启用智能调度后生效",
"about": "{label}说明",
"zeroWeightHelp": "0 表示不参与评分",
"weightsRequired": "至少一项系数需要大于 0"
},
"affinity": {
"modes": {
"relaxed": "宽松",
"preferred": "优先",
"strict": "严格",
"relaxedHelp": "宽松:会话内请求直接按调度策略选号,不优先主账号",
"preferredHelp": "优先:会话内请求优先沿用主账号,繁忙或不可用时临时分流,不改变会话绑定",
"strictHelp": "严格:同一会话共用账号,子线程等待当前账号,并跟随主线程换号"
},
"title": "亲和策略",
"mode": "账号亲和",
"description": "控制同一会话内的账号绑定方式",
"accountAffinityInstructions": "账号亲和说明",
"policyHelp": "重新选号仍遵循当前调度策略",
"duration": "亲和时长",
"durationHelp": "账号绑定的保留时间,成功调度后续期",
"durationHours": "亲和时长(小时)",
"hours": "小时",
"maxAccountSwitches": "最大换号次数",
"switchLimitHelp": "单请求最多换号次数,0 表示不换号"
},
"autoDisable": {
"overloadProtection": "过载保护",
"description": "上游容量类错误累计达到阈值时,暂停账号调度并进入冷却",
"enableOverloadProtection": "启用过载保护",
"failureCountThreshold": "失败阈值",
"thresholdHelp": "统计窗口内累计容量类失败达到此次数后触发",
"times": "次",
"statisticsWindow": "统计窗口",
"windowHelp": "每次失败后,计数有效期向后顺延",
"statisticsWindowSeconds": "统计窗口秒数",
"seconds": "秒",
"cooldownTime": "冷却时长",
"cooldownHelp": "探测失败时,按此时长延后恢复",
"cooldownTimeInSeconds": "冷却时长秒数",
"recoveryProbeModel": "恢复探测模型",
"probeModelHelp": "留空选用首个可用模型",
"requireSuccessfulProbe": "探测成功后恢复",
"modelPlaceholder": "留空自动选择",
"concurrencyReduction": {
"label": "自适应并发下调",
"helpTitle": "自适应并发下调说明",
"description": "修改账号并发上限,恢复后不自动调高"
}
},
"warmup": {
"title": "账号预热",
"description": "尝试启动空闲 Codex OAuth 账号的额度窗口",
"enableDailyWarmup": "启用每日预热",
"executionTime": "执行时间",
"timesPlaceholder": "HH:MM,多个时间用逗号分隔",
"scheduleLabel": "每日预热时间",
"modelLabel": "预热模型",
"modelHelp": "启用时必填,需为账号可用模型",
"modelPlaceholder": "输入模型名称",
"helpTitle": "账号预热说明",
"help": "在设定时间向每个空闲的 Codex OAuth 账号发送一次请求,不保证额度窗口成功启动"
},
"adminApiKey": {
"adminApiKey": "管理员 API Key",
"description": "用于外部系统集成,具有管理员权限",
"regenerate": "重新生成",
"generate": "生成",
"notGenerated": "未生成",
"enabledDescription": "管理员 API 访问已启用,完整 Key 仅在生成时回显",
"disabledDescription": "外部系统暂时无法通过 API Key 调用管理接口",
"generatedNotice": "完整 Key 仅显示一次,请立即保存",
"adminApiKeyUpdated": "管理员 API Key 已更新",
"generated": "管理员 API Key 已生成",
"adminApiKeyDeleted": "管理员 API Key 已删除"
},
"password": {
"administratorPassword": "管理员密码",
"description": "用于登录管理后台",
"changePassword": "修改密码",
"verifyCurrentPassword": "验证当前密码",
"sessionNotice": "修改后,所有管理员需重新登录",
"validation": {
"minLength": "新密码至少需要 12 个字符",
"unchanged": "新密码不能与当前密码相同",
"mismatch": "两次输入的新密码不一致"
},
"newPasswordCannotExceedBytes": "新密码不能超过 1024 字节",
"changed": "密码已修改,请使用新密码重新登录",
"changeAdministratorPassword": "修改管理员密码",
"changeDescription": "验证当前密码后,设置新的登录密码",
"currentPassword": "当前密码",
"enterCurrentPassword": "输入当前密码",
"newPassword": "新密码",
"passwordHelp": "至少 12 个字符,建议混合使用字母、数字和符号",
"setNewPassword": "设置新密码",
"confirmNewPassword": "确认新密码",
"enterNewPasswordAgain": "再次输入新密码",
"saveAndLogInAgain": "保存并重新登录"
},
"concurrency": {
"title": "并发策略",
"accountLimit": {
"label": "默认账号并发",
"help": "未单独设置时使用,0 不限"
},
"keyQueueCapacity": "密钥队列容量",
"keyQueueHelp": "每个密钥的等待上限,0 不排队",
"accountQueueCapacity": "账号队列容量",
"accountQueueHelp": "每个账号的等待上限,0 不排队",
"queueTimeoutLabel": "排队超时(秒)",
"queueTimeoutHelp": "两个队列共用,1–120 秒",
"autoReview": {
"label": "自动审批独立并发",
"description": "每个 OpenAI 账号的额外名额,0 共用普通并发",
"helpTitle": "自动审批独立并发说明"
},
"queueTimeoutHelpTitle": "排队超时说明",
"queueTimeoutDetails": "密钥与账号队列共用此时限,从首次入队起计时"
},
"modelMapping": "模型映射",
"routing": {
"modelMapHelp": "将客户端请求的模型名称映射为实际使用的上游模型"
},
"addMapping": "添加映射",
"loadingModelMapping": "正在加载模型映射...",
"requestModel": "请求模型",
"upstreamModel": "上游模型",
"upstreamModelName": "上游模型名称",
"deleteMapping": "删除映射",
"history": {
"title": "历史保留",
"retentionHelp": "自动删除过期请求记录及统计数据",
"retentionConstraints": "至少 1 天,删除后不可恢复",
"retentionDaysLabel": "历史保留天数"
},
"retentionDays": "保留天数",
"enterDays": "请输入 1–31 天",
"day": "天",
"location": {
"requestLocationOverride": "请求位置覆盖",
"description": "覆盖 Codex 请求中的时区与位置字段,账号出站代理的自定义位置优先",
"enableLocationOverlay": "启用位置覆盖"
},
"quotaReset": {
"title": "主动重置卡",
"enableHelp": "在账号的「额度重置」中开启自动使用",
"description": "全局设置,对已开启自动使用的账号生效",
"thresholdHelp": "高于此值时暂不自动使用,留空表示不限制",
"weeklyQuotaLimit": "重置卡剩余周额度上限"
},
"advanceUsageTimeMinutes": "提前使用时间(分钟)",
"resetCardAdvanceTime": "重置卡提前使用时间",
"remainingWeeklyQuotaLimit": "剩余周额度上限(%)",
"responseLimit": {
"requestBodyLimit": "请求体限制",
"description": "限制 Responses 请求解压后的请求体大小",
"maximumSizeAfterDecompression": "解压后大小上限",
"sizeHelp": "调高可接收更大的图片和历史上下文,也会增加内存占用",
"maxSizeLabel": "解压后请求体大小上限"
},
"rotation": {
"title": "调度策略",
"customized": "自定义",
"smartSchedulingSettings": "智能调度设置",
"smartLabel": "智能调度",
"smartDescription": "综合负载、剩余额度、健康和延迟评分,支持自定义评分偏好",
"quotaResetLabel": "额度重置优先",
"quotaResetDescription": "优先选择额度窗口更快重置的账号,适合在重置前消耗剩余额度",
"roundRobinLabel": "轮询调度",
"roundRobinDescription": "在可用候选账号间按顺序轮转,分配结果最可预测",
"stickyLabel": "粘性调度",
"stickyDescription": "优先复用最近使用的账号,直到不可用后再切换"
},
"access": {
"accessRestrictions": "访问限制",
"deleteAdminApiKey": "删除管理员 API Key",
"deleteKeyDescription": "删除后外部系统将无法继续使用该 Key 调用管理接口",
"areYouSureYouWantToDelete": "确定要删除当前管理员 API Key 吗?此操作会立即生效"
},
"tokenRefresh": {
"title": "凭据刷新",
"leadTimeLabel": "提前刷新(秒)",
"leadTimeHelp": "在访问令牌到期前触发刷新",
"concurrencyLabel": "刷新并发上限",
"concurrencyHelp": "同时刷新的上限,调低可减少限流"
},
"backup": {
"fileName": "文件名",
"size": "大小",
"expirationTime": "过期时间",
"triggerMode": "触发方式",
"startTime": "开始时间",
"manual": "手动",
"plan": "计划",
"exclusions": "不包含请求明细与日志",
"backupRecords": "备份记录",
"backupScopeDescription": "备份范围说明",
"contents": "保留账号、Key、设置、插件及已用额度",
"usageRetentionHourSummary": "用量保留小时汇总",
"creating": "创建中...",
"createBackup": "创建备份",
"noBackupRecordYet": "暂无备份记录",
"downloadBackup": "下载备份",
"deleteBackup": "删除备份",
"deleteWarning": "将删除远端对象并移除记录,此操作不可撤销",
"deleteConfirmation": "确定要删除备份",
"message": "吗?",
"schedule": {
"backupPlan": "备份计划",
"description": "配置自动备份的执行时间与保留策略",
"saving": "保存中...",
"enableScheduledBackup": "启用定时备份",
"cronExpression": "Cron 表达式",
"cronHelp": "5 段格式,例如 0 2 * * * 表示每天凌晨 2 点",
"retentionDaysHelp": "超期删除,0 不限天数,仍受份数限制",
"retentionDaysLabel": "保留天数",
"maxBackupsLabel": "最多保留",
"retentionCountHelp": "超额删除,0 不限份数,仍受天数限制"
},
"status": {
"queuing": "排队中",
"exporting": "导出中",
"uploading": "上传中",
"deleting": "删除中"
},
"storage": {
"s3StorageConfiguration": "S3 存储配置",
"connectionTestPassed": "已通过连接测试",
"connectionTestHasNotPassed": "尚未通过连接测试",
"testing": "测试中...",
"endpointAddress": "端点地址",
"endpointHelp": "S3 兼容服务的 HTTPS 地址",
"region": "区域",
"regionHelp": "R2 使用 auto,其他服务按提供方填写",
"bucket": "存储桶",
"privateBucketName": "私有存储桶名称",
"objectKeyPrefix": "对象键前缀",
"prefixHelp": "备份对象的存储路径前缀,不影响已有备份",
"credentialsLabel": "对象存储专用凭据",
"objectStorageSpecificSecret": "对象存储专用 Secret",
"forcePathStyle": "强制路径式访问",
"accessKeyId": "访问密钥 ID",
"secretAccessKey": "私有访问密钥",
"description": "配置 S3 兼容存储(支持 {service})"
},
"r2": {
"cloudflareR2OnboardingGuide": "Cloudflare R2 接入指南",
"createBucket": "1. 创建存储桶",
"createApiToken": "2. 创建 API Token",
"fillInConnectionParameters": "3. 填写连接参数",
"credentialsHelp": "Access Key ID / Secret Access Key:上一步生成的 Token",
"forcePathStyleOff": "Force Path Style:关闭",
"completeConnectionTest": "4. 完成连接测试",
"testDescription": "保存配置后点击「测试连接」,系统会写入一个探针对象并校验读写权限,测试通过后 才能启用自动计划或手动创建备份,凭据只保存在服务端,不会写入浏览器",
"gotIt": "知道了",
"bucketDescription": "在 Cloudflare Dashboard 进入 R2,创建私有存储桶(例如 {bucket}),保持关闭公共读取",
"tokenDescription": "在「管理 API Token」创建对象存储专用 Token,仅授予目标桶的对象读取、写入、列出与删除权限",
"endpointLabel": "Endpoint:",
"regionDescription": "Region:{region}(R2 固定值)"
},
"backupTaskCreated": "备份任务已创建",
"failedToDownloadBackup": "下载备份失败",
"backupDeletionRequested": "已请求删除备份",
"storageSaved": "存储配置已保存,定时备份已暂停,请测试连接后重新启用",
"storageConfigurationSaved": "存储配置已保存",
"connectionVerified": "连接测试通过",
"backupPlanSaved": "备份计划已保存"
},
"clientVersion": {
"macosLinuxOfficialInstaller": "macOS / Linux · 官方安装器",
"windowsInstaller": "Windows PowerShell · 官方安装器",
"homebrewFirstTimeInstallation": "Homebrew · 首次安装",
"homebrewUpgrade": "Homebrew · 升级",
"installOrUpgradeCodexCli": "安装或升级 Codex CLI",
"cliInstallHelp": "按当前安装来源执行一种命令,官方安装器会自动选择当前平台架构",
"selectInstallationSource": "选择安装来源",
"cliUpgradeHelp": "重新执行对应命令即可升级到当前发布版本",
"viewOfficialDocumentation": "查看官方文档",
"ubuntuDebianUpgrade": "Ubuntu / Debian · 升级",
"fedoraRhelUpgrade": "Fedora / RHEL · 升级",
"onlineInstallationAndUpgrade": "在线安装与升级",
"desktopUpgradeHelp": "桌面应用通常会自动更新,也可以从官方渠道重新安装",
"officialDownloadPage": "官方下载页",
"openAiPackageHelp": "OpenAI 官方安装包,请选择与设备一致的架构",
"storePackageHelp": "Microsoft Store 离线安装包,请选择与设备一致的架构",
"msixInstallHelp": "下载后使用 PowerShell 安装 / 升级",
"sizeUnknown": "大小未知",
"windowsOfflineInstallation": "Windows 离线安装",
"cached": "已缓存",
"refreshingDownloads": "正在刷新离线下载链接",
"refreshOfflineDownloadLinks": "刷新离线下载链接",
"loadingPackages": "正在加载离线安装包",
"packagesFailed": "离线安装包加载失败",
"stableChannel": "稳定通道",
"linkExpired": "链接失效:{value}",
"downloadMsix": "下载 {value} MSIX",
"downloadPackage": "下载 MSIX",
"commandCopied": "命令已复制",
"copyCommand": "复制命令",
"codexClientUpgrade": "Codex 客户端升级",
"guideDescription": "先选择客户端,再查看对应的安装与升级方式",
"clientVersionRestrictions": "客户端版本限制",
"openGuide": "查看安装与升级说明",
"codexDesktopMinimumVersion": "Codex Desktop 最低版本",
"onlyCheckDesktopVersionEG": "只检查桌面端应用版本,例如 26.825.51511",
"codexCliMinimumVersion": "Codex CLI 最低版本",
"minimumVersionHelp": "只检查独立终端版本,例如 0.152.0"
},
"privacy": {
"preview": {
"enterValidRequestSampleJson": "请输入有效的请求样本 JSON",
"testRules": "测试规则",
"description": "按草稿顺序执行已启用的规则,样本仅用于本次测试",
"requestSample": "请求样本",
"requestPlaceholder": "粘贴包含 body、headers、turnMetadata 的请求 JSON",
"finalResult": "最终结果",
"ruleExecutionResults": "规则执行结果",
"notEnabled": "未启用",
"skipped": "已跳过"
},
"skipCurrentRule": "跳过当前规则",
"blockRequestFromBeingSent": "阻止请求发送",
"privacyPolicy": "隐私策略",
"description": "按规则统一或移除 Codex 请求中的隐私信息",
"enableRequestRules": "启用请求规则",
"addRule": "添加规则",
"addFromPreset": "从预设添加",
"runsInListOrderRulesSteps": "按列表顺序执行 · {count} 条规则 · {count2} / 32 个步骤",
"executionFailed": "执行失败",
"ruleExecutionFailed": "规则执行失败",
"ruleExecutionInstructions": "规则执行说明",
"skipHelp": "跳过时撤销本条规则所有步骤的修改并继续执行,未完成本条脱敏",
"overrideHelp": "允许改写选定字段,认证、会话与工具行为的影响由配置者负责",
"rules": {
"fillInRuleName": "请填写规则名称",
"stepLimit": "所有规则合计最多 32 个处理步骤",
"enterFieldPathForStep": "请填写步骤 {value} 的字段路径",
"fixedValueForStepMustBeJson": "步骤 {value} 的固定值应为 JSON,例如 \"别名\"、false 或 123",
"invalidSampleFormat": "样本格式无效",
"ruleFormatIsInvalid": "规则格式无效",
"editRule": "编辑规则",
"description": "配置字段处理方式,预览隐私信息处理效果",
"ruleName": "规则名称",
"namePlaceholder": "例如:统一工作区信息",
"currentStepSettings": "当前步骤设置",
"testPreview": "测试预览",
"previewOfEntireRule": "整条规则预览",
"ruleSkipped": "规则已跳过",
"matches": "命中 {matches} 处",
"testThisRule": "测试本条规则",
"test": "测试",
"testSample": "测试样本",
"samplePlaceholder": "粘贴包含 body、headers、turnMetadata 的请求样本",
"afterProcessing": "处理后",
"applyToDraft": "应用到草稿",
"movedToPosition": "{name}已移到第 {value} 条",
"ruleField": "规则",
"scope": "作用范围",
"processingMethod": "处理方式",
"reorderHelp": "拖动手柄调整规则顺序,也可聚焦手柄后使用上下方向键移动",
"noRulesYetAddOneOrStart": "暂无规则,添加一条或从预设开始",
"enableRule": "启用规则:{name}",
"edit": "编辑{name}",
"delete": "删除{name}",
"dragToReorder": "拖动调整{name}顺序"
},
"steps": {
"pathPlaceholder": "例如:$.workspaces.*.associated_remote_urls.*",
"forExampleRemotesFetchurl": "例如:$.remotes[*].fetchUrl",
"environmentPathHelp": "填写 $,匹配整段环境文本",
"forExampleMetadataWorkspace": "例如:$.metadata.workspace",
"forExampleXClientName": "例如:x-client-name",
"requestHeaderName": "请求头名称",
"fieldPath": "字段路径",
"fieldPathSyntax": "字段路径语法",
"jsonPathHelp": "支持对象成员、双引号键名、数组索引和 * 通配,例如 $[\"workspaces\"][\"/home/alex/demo\"]",
"targetHelp": "环境文本使用 $,请求头直接填写名称",
"commonFields": "常用字段",
"deleteMatchHelp": "仅删除值匹配正则的字段或数组项",
"matchExpression": "匹配表达式",
"forExampleHome": "例如:^/home/[^/]+/",
"forExamplePrivateOrg": "例如:private-org",
"replaceContent": "替换内容",
"regularSyntaxDescription": "正则语法说明",
"useOrForCaptureGroupsAndFor": "${'{'}1{'}'} 或 ${'{'}name{'}'} 引用捕获组,$$ 表示字面 $",
"usesRustRegexSyntaxAndDoesNot": "使用 Rust regex 语法,不支持前后顾和模式中的反向引用",
"forExampleHomeUser": "例如:/home/user/",
"forExampleTeamOrLeaveBlankTo": "例如:team,留空则清除匹配内容",
"fixedValueJson": "固定值(JSON)",
"forExampleAnonymousNullOr": "例如:\"匿名\"、null 或 {'{'}{'}'}",
"fixedJsonLabel": "固定值 JSON",
"replaceAllMatches": "替换全部匹配",
"ignoreCase": "忽略大小写",
"matchMultipleLines": "多行匹配",
"entireEnvironmentText": "整段环境文本",
"fullContent": "完整内容",
"noFieldsSelected": "未选择字段",
"deleteHelp": "删除匹配的字段或数组项",
"noExpressionEntered": "未填写表达式",
"deleteAfterMatching": "匹配后删除:{value}",
"clearMatchingContent": "清空匹配内容",
"stepMovedToPosition": "步骤已移到第 {value} 位",
"processingSteps": "处理步骤",
"helpTitle": "处理步骤说明",
"executionOrderHelp": "拖动手柄调整执行顺序,也可聚焦手柄后使用上下方向键移动",
"eachStepCanSetScopeFieldsAnd": "每一步可分别设置作用范围、字段和处理方式,后一步基于前一步的结果处理",
"failureHelp": "所有步骤共用规则开关,任一步骤失败会撤销本条规则的全部修改,再按失败策略跳过或阻止请求",
"addSteps": "添加步骤",
"reorderHelp": "拖动手柄调整步骤顺序,也可聚焦手柄后使用上下方向键移动",
"dragStep": "拖动步骤 {value}:{field}",
"step": "步骤 {value}:{field},{scope},{action},{effect}",
"deleteStep": "删除步骤 {value}:{field}"
},
"presets": {
"workspaceMetadata": "工作区附加信息",
"desktopGitInformation": "Desktop Git 信息",
"automaticEnvironmentContext": "自动环境上下文",
"specifyRequestFields": "指定请求字段",
"specifyRequestHeader": "指定请求头",
"regularReplacement": "正则替换",
"fixedValue": "固定值",
"fieldNameReplacement": "字段名替换",
"deleteFieldArrayItem": "删除字段 / 数组项",
"customFieldPath": "自定义字段路径",
"gitRemoteAddress": "Git 远端地址",
"workspacePathKey": "工作区路径键",
"gitCommitId": "Git 提交 ID",
"gitRemoteCollection": "Git 远端集合",
"workspaceFingerprint": "工作区指纹",
"unifyWorkspaceInformation": "统一工作区信息"
},
"testPlaceholder": "点击测试查看结果"
},
"form": {
"enterStandardSemverForExample": "请输入标准 SemVer,例如 0.152.0",
"exitLocationFilledIn": "已填入出口位置",
"ipv4AndIpv6ExportTimeZonesAre": "IPv4 与 IPv6 出口时区不一致,请手动填写",
"unableToObtainExitLocation": "未获取到出口位置",
"fillInModelMappingCompletely": "请完整填写模型映射",
"duplicateClientModel": "存在重复的客户端模型:{requested}",
"requiredSettings": "请完整填写并发、队列、凭据刷新参数和调度策略",
"invalidAffinityDuration": "亲和时长应为 1~720 小时的整数",
"invalidSwitchLimit": "最大换号次数应为 0~31 的整数,0 表示不换号",
"invalidConcurrency": "默认账号并发上限应为 0~4294967295 的整数,0 表示不限制",
"invalidReviewConcurrency": "自动审批独立并发应为 0~4294967295 的整数,0 表示共用普通并发",
"invalidBodyLimit": "Responses 解压上限应为有效的正整数(MiB)",
"invalidQuotaThreshold": "剩余周额度上限应为 0~100 的整数,留空表示不限制",
"invalidResetLeadTime": "重置卡提前使用时间应为 1~1440 分钟的整数",
"invalidRetention": "历史保留天数应为 1–31 的整数",
"invalidQueueSettings": "队列容量应为 0~1000 的整数,排队超时应为 1~120 秒的整数",
"invalidClientVersion": "请修正客户端最低版本格式",
"overloadSettingsRequired": "请完整填写过载保护参数",
"invalidOverloadSettings": "失败次数阈值应为 2~1000,统计窗口为 60~3600 秒,冷却时长为 300~604800 秒",
"invalidProbeModel": "探测模型名称不能超过 128 个字符",
"invalidWarmupTimes": "预激活时间格式无效,请输入 HH:MM 格式(如 08:00 或 08:00,13:00)",
"warmupModelRequired": "启用预激活时请选择模型",
"invalidWarmupModel": "预激活模型名称不能超过 128 个字符",
"settingsSaved": "设置已保存"
},
"page": {
"tabs": {
"runtime": "运行设置",
"upstream": "上游配置",
"pricing": "模型定价",
"access": "安全与访问",
"backups": "数据备份"
},
"description": "配置网关调度、上游与定价,管理访问安全、历史保留与备份",
"sectionsLabel": "设置分区",
"undoAllBasicSettingsChanges": "撤销全部基础设置更改",
"saveChanges": "保存基础设置",
"settingsLoadingFailed": "设置加载失败",
"reload": "重新加载",
"basicSettings": "基础设置"
}
}
}
@@ -0,0 +1,109 @@
{
"systemUpdate": {
"channels": {
"stable": {
"label": "Stable · 正式",
"description": "仅正式版本"
},
"rc": {
"label": "RC · 候选",
"description": "包含 RC 和正式版本"
},
"beta": {
"label": "Beta · 测试",
"description": "包含 Beta、RC 和正式版本"
},
"alpha": {
"label": "Alpha · 早期",
"description": "包含所有常规预发布和正式版本"
},
"experimental": {
"label": "Exp · 实验",
"description": "仅当前实验线"
},
"loading": "正在读取运行通道",
"label": "更新通道",
"help": "更新通道说明",
"description": "选择仅用于本次检查,重新打开时按运行版本选择通道,不会自动安装或降级"
},
"feedback": {
"available": "发现可用更新",
"noUpdates": "当前没有可用更新",
"started": "更新已开始"
},
"errors": {
"remoteTargetMissing": "远端目标版本为空",
"infoPending": "请等待系统更新信息加载完成",
"preRestartCheck": "重启前检查失败",
"restart": "重启失败,请重新检查",
"unconfirmed": "尚未确认更新任务,请检查状态后重试",
"updateFailed": "更新失败",
"startTimeout": "服务未在预期时间内启动 v{version}",
"activationTargetMissing": "缺少待生效的目标版本"
},
"title": "系统更新",
"description": "检查版本、查看发布说明并执行在线更新",
"application": "应用包更新",
"releasePage": "发布页",
"status": {
"checkingVersion": "正在检查版本",
"lastFailed": "上次操作失败",
"updating": "更新中",
"restarting": "重启中",
"checking": "检查中",
"restartRequired": "待重启",
"available": "有可用更新",
"upToDate": "无可用更新",
"notChecked": "未检查",
"retrying": "暂时无法确认更新状态,正在重试",
"confirmingStart": "正在确认更新是否已开始"
},
"targetVersion": "目标版本 v{version}",
"releaseNotes": "发布说明",
"progress": "更新进度",
"actions": {
"check": "检查更新",
"install": "下载并更新",
"continueRestart": "继续重启",
"restart": "立即重启"
},
"plugins": {
"title": "插件兼容性提醒",
"description": "重启后保留启用配置,逐个尝试启动插件",
"incompatible": "不兼容插件"
},
"versionAfterRestart": "重启后版本",
"confirmation": {
"newerVersion": "发现新的更新版本",
"channelChanged": "所选通道的最新版本已变化",
"title": "确认更新",
"description": "点击确认后弹窗会关闭,并按远端最新目标版本开始更新"
},
"logs": {
"live": "实时",
"disconnectedState": "断开",
"waiting": "待连接",
"disconnected": "更新日志连接中断",
"parseFailed": "更新日志解析失败",
"unsupported": "当前浏览器不支持实时更新日志",
"timeout": "更新日志连接超时"
},
"currentVersion": "当前版本",
"latestVersion": "通道最新",
"build": "构建",
"deployment": "部署",
"displayedTarget": "已显示目标",
"remoteTarget": "远端最新目标",
"buildTypes": {
"release": "正式构建",
"source": "源码构建",
"dev": "开发构建",
"experimental": "实验构建"
},
"deploymentModes": {
"docker": "Docker",
"binary": "二进制",
"source": "源码运行"
}
}
}
@@ -0,0 +1,348 @@
{
"usage": {
"health": {
"point": {
"serviceFailed": "服务失败",
"clientCancel": "客户端取消",
"callerError": "调用方错误",
"requestHealthDetailsFor": "{time} 请求健康详情",
"minutes": "15 分钟",
"validRequestAvailability": "有效请求可用性",
"validRequest": "有效请求"
},
"validRequestsAvailability": "{time},{label},有效请求 {count},可用性 {reliabilityDisplay}",
"hours": "小时",
"day": "天",
"serviceSuccessRate": "服务成功率",
"notCompleted": "未完成",
"requestVolume": "请求量",
"noServiceResult": "无服务结果",
"title": "请求健康",
"description": "请求状态分布 · {granularityText}",
"completionRate": "完成率",
"abnormalEnd": "非正常结束",
"loading": "正在加载请求数据",
"empty": "当前范围暂无请求"
},
"billing": {
"serviceLevel": "服务档位",
"totalCost": "总费用",
"standardFee": "标准费用",
"textInputCost": "文本输入费用",
"inputCost": "输入费用",
"imageInputFee": "图像输入费用",
"imageCachingCharges": "图像缓存费用",
"imageInputUnitPrice": "图像输入单价",
"imageCacheUnitPrice": "图像缓存单价",
"imageOutputFee": "图像输出费用",
"outputFee": "输出费用",
"textInputUnitPrice": "文本输入单价",
"inputUnitPrice": "输入单价",
"imageOutputUnitPrice": "图像输出单价",
"outputUnitPrice": "输出单价",
"textCacheReadCost": "文本缓存读取费用",
"cacheReadCost": "缓存读取费用",
"cacheWriteCost": "缓存写入费用",
"cacheWriteUnitPrice": "缓存写入单价",
"fastMode": "Fast 模式",
"longContextBillingDetails": "长上下文计费明细",
"billingDetails": "计费明细",
"viewLongContextBillingDetails": "查看长上下文计费明细",
"viewCostDetails": "查看费用明细"
},
"ttft": "TTFT",
"latency": {
"totalLatency": "总耗时",
"viewLatencyDetails": "查看延迟明细",
"official": "官方",
"local": "本地",
"total": "总耗时"
},
"performance": {
"ttftHelp": "TTFT:首个 Token 耗时",
"scheduling": "调度",
"admissionP95": "准入 P95",
"accountSelectionP95": "选号 P95",
"capacityP95": "容量 P95",
"decisionCoverage": "判定覆盖",
"accountSelectionCoverage": "选号覆盖",
"capacityCoverage": "容量覆盖",
"title": "响应性能",
"description": "延迟、速率与调度分位",
"performanceIndicators": "性能指标",
"loading": "正在加载性能数据",
"noTtftSamples": "当前范围暂无 TTFT 样本",
"noThroughput": "当前范围暂无速率样本",
"noScheduling": "当前范围暂无调度或容量样本",
"noLatency": "当前范围暂无延迟样本"
},
"reasoning": {
"subagentRequest": "子代理请求",
"reviewSubagentRequest": "Review 子代理请求"
},
"filters": {
"error": "错误",
"requestDetailType": "请求明细类型",
"label": "使用记录筛选与操作",
"refreshUsageHistory": "刷新使用记录",
"keyName": "密钥名称",
"account": "账号",
"fieldLabel": "请求明细筛选字段",
"enterFilterValue": "输入筛选内容",
"valueLabel": "请求明细筛选内容"
},
"route": {
"compressionRequest": "压缩请求"
},
"tokens": {
"enterToken": "普通输入 Token",
"outputToken": "输出 Token",
"cacheReadTokens": "缓存读取 Token",
"cacheWriteTokens": "缓存写入 Token",
"reasoningToken": "推理 Token",
"tokenDetails": "Token 明细",
"viewTokenDetails": "查看 Token 明细",
"totalTokens": "总 Token"
},
"fields": {
"model": "模型",
"reasoningEffort": "推理强度",
"endpoint": "端点",
"upstream": "上游",
"access": "接入",
"cost": "费用",
"latency": "延迟",
"time": "时间",
"keyName": "密钥名称",
"subscription": "订阅",
"platformType": "平台"
},
"outputThroughput": "输出速率",
"noValidSample": "无有效样本",
"notReachable": "不可达",
"unstable": "不稳定",
"lowSample": "低样本",
"stable": "稳定",
"future": "未来",
"status": {
"mappedModel": "网关映射后发送给上游的模型:{secondary}",
"returnedModel": "上游返回模型:{returned}(与网关映射后发送的模型一致)",
"returnedModelHelp": "上游返回模型:{returned}",
"firstOutputWaiting": "首个输出等待",
"reasoningToText": "推理到正文",
"firstOneIsOutputToText": "首个输出到正文",
"textToCompletion": "正文到完成",
"completedAfterFirstOutput": "首个输出后完成",
"admissionDecision": "准入判定",
"accountSelectionWaiting": "账号选择等待",
"transferDecisionWaiting": "传输决策等待",
"websocketConnection": "WebSocket 连接",
"upstreamResponseHeader": "上游响应头",
"firstUpstreamEvent": "首个上游事件",
"accountSlotSnapshot": "账号槽位快照",
"processingTime": "处理耗时",
"apiOverhead": "API 开销",
"engineTime": "引擎耗时",
"upstreamPerformance": "上游性能",
"requestObservation": "请求观测",
"transport": "传输观测",
"cancelled": "已取消",
"requestedModel": "请求模型:{model}"
},
"balanceUnavailable": "未提供余额",
"quota": "额度",
"usage": "用量",
"averageTtft": "平均 TTFT",
"budget": {
"todaySQuota": "今日额度",
"weeklyQuota": "周额度",
"quotaOverview": "额度概览",
"noLimit": "不限额",
"remaining": "剩余 / {value}",
"used": "已用 {rate}%",
"usedAmount": "已用 {value}",
"resetTime": "重置时间",
"timingStartsAfterFirstUse": "首次使用后开始计时",
"concurrencyLimit": "并发上限",
"requestsPerMinute": "RPM"
},
"header": {
"currentKey": "当前密钥",
"keyPrefix": "密钥前缀",
"keyConfiguration": "密钥配置",
"statisticsTimeRange": "统计时间范围",
"today": "今天",
"lastDays": "近 7 天",
"lastThirtyDays": "近 30 天",
"automaticRefreshFrequency": "自动刷新频率",
"refreshEveryS": "30 秒刷新",
"refreshInterval": "60 秒刷新",
"pauseRefresh": "暂停刷新",
"refreshUsage": "刷新用量",
"switchTheme": "切换主题"
},
"records": {
"requestLog": "请求日志",
"currentRequestRecord": "当前请求记录",
"refreshFailed": "请求日志刷新失败,暂时保留上次结果",
"loadFailed": "请求日志加载失败,请点击顶部刷新重试",
"noRecordsMatchTheseFilters": "所选条件下暂无记录"
},
"page": {
"cacheHitRate": "Token 命中率",
"loadingUsage": "正在加载用量",
"usageSummaryLoading": "用量汇总加载中",
"usageTrends": "使用趋势",
"changesInUsageOverTime": "用量随时间的变化",
"requestHealthTimeline": "请求健康时间线",
"updated": "更新于 {asOfDisplay}",
"temporarilyRetainLastResult": ",暂时保留上次结果",
"clickRefreshAtTopToTryAgain": ",请点击顶部刷新重试",
"description": "查看请求用量、性能趋势与调用错误记录",
"dateRangeLabel": "统计日期范围,仅可选择最近 31 天",
"requestDetails": "请求明细",
"recordsDescription": "成功请求与失败请求明细",
"failedToLoad": "加载失败:{error}",
"noRequestsMatchTheseFilters": "所选条件下暂无请求记录",
"viewErrorDetails": "查看错误详情",
"viewUsageRecordDetails": "查看使用记录详情"
},
"summary": {
"usageSummary": "用量汇总",
"consumeTokens": "消耗 Tokens",
"totalRequests": "总请求",
"totalCost": "总成本",
"usageDetails": "用量明细"
},
"trends": {
"cost": "成本",
"cacheHit": "缓存命中",
"empty": "所选时间内暂无请求"
},
"configuration": {
"copiedToClipboard": "已复制到剪贴板"
},
"metrics": {
"notPriced": "未定价",
"newInput": "普通输入",
"output": "输出",
"cacheCreation": "缓存创建",
"reasoning": "推理"
},
"firstTokenLatency": "TTFT",
"diagnostics": {
"downloadDiagnosticPackage": "下载诊断包",
"key": "密钥",
"transport": "传输",
"dimensions": "维度",
"request": "请求",
"performance": "性能",
"title": "热点诊断",
"groupBy": "按{resultDimensionLabel}聚合",
"diagnosticDimension": "诊断维度",
"noDiagnosticDataYet": "暂无诊断数据",
"successful": "成功 {count}",
"failed": "失败 {count} 次",
"failureRate": "失败率 {rate}",
"retryRate": "重试率 {rate}",
"retries": "重试 {count}",
"loading": "正在加载诊断数据",
"empty": "当前范围暂无诊断数据"
},
"cost": {
"savings": "节省",
"cache": "缓存",
"cacheSavings": "缓存节省",
"cacheTokenProportion": "缓存 Token 占比",
"hitRequestRate": "请求命中率",
"actualCost": "费用",
"withoutCacheEstimate": "无缓存估算",
"costEfficiency": "成本效率",
"description": "费用、缓存节省与服务层溢价",
"costView": "成本视图",
"tierPremium": "层级溢价",
"perSuccessfulRequest": "每次成功请求",
"costCoverage": "费用覆盖",
"loading": "正在加载费用数据",
"empty": "当前范围暂无费用或缓存节省数据"
},
"error": {
"noDetails": "未记录具体错误消息",
"platform": "平台",
"requestModel": "请求模型",
"upstreamModel": "上游模型",
"clientTransfer": "客户端传输",
"upstreamTransport": "上游传输",
"clientStatusCode": "客户端状态码",
"upstreamStatusCode": "上游状态码",
"requestId": "请求 ID",
"upstreamRequestId": "上游请求 ID",
"responseId": "响应 ID",
"clientKeyId": "客户端 Key ID",
"errorCode": "错误码",
"failureClassification": "失败分类",
"duration": "耗时",
"triggerMode": "触发方式",
"sendStatus": "发送状态",
"errorDetails": "错误详情",
"description": "失败原因与请求上下文",
"responseIsNotComplete": "响应未完成",
"requestFailed": "请求失败",
"requestContext": "请求上下文",
"errorLocation": "错误定位",
"attempts": "尝试记录",
"attemptRecordMayBeIncomplete": "尝试记录可能不完整",
"attempt": "尝试 {index}",
"diagnosticData": "诊断数据",
"responseContent": "响应内容",
"metadata": "元数据"
},
"insights": {
"useStatisticalObservations": "使用统计观测"
},
"request": {
"statusCode": "状态码",
"message": "消息",
"upstreamTimeConsumption": "上游耗时",
"storageModel": "存储模型",
"upstreamReturnModel": "上游返回模型",
"clientIp": "客户端 IP",
"eventType": "事件类型",
"trySerialNumber": "尝试序号",
"accountId": "账号 ID",
"serialNumber": "序号",
"result": "结果",
"textInput": "文本输入",
"input": "输入",
"imageOutput": "图像输出",
"textCacheRead": "文本缓存读取",
"cacheRead": "缓存读取",
"cacheWrites": "缓存写入",
"textCacheUnitPrice": "文本缓存单价",
"cacheUnitPrice": "缓存单价",
"nonInferentialOutput": "非推理输出",
"totalOutput": "总输出",
"noneYet": "暂无",
"usageRecordDetails": "使用记录详情",
"description": "单次请求的完整链路信息",
"requestInformation": "请求信息",
"transportAndUsage": "传输与用量",
"modelsAndRouting": "模型与路由",
"clientAndUpstream": "客户端与上游",
"requestId": "请求 ID",
"incompleteDetails": "明细不完整",
"total": "总计",
"requestContent": "请求内容",
"inProgress": "进行中"
},
"successfulRequest": "成功请求",
"withinFilterRange": "筛选范围内",
"inputOutput": "输入 {inputTokens} / 输出 {outputTokens}",
"cachedTokens": "缓存 Token",
"cacheReadHit": "缓存读取命中",
"averageTimeTaken": "平均耗时",
"successfulRequestAverage": "成功请求平均值",
"usageOverview": "使用概览",
"noUsageRecords": "暂无使用记录"
}
}
@@ -0,0 +1,620 @@
{
"accounts": {
"quota": {
"usageInThisWindow": "窗口消耗:{localUsageDisplay}",
"quotaUsed": "額度已使用:{rate}",
"resets": "重置時間: {resetAtDisplay}",
"unobserved": "額度待觀測",
"dailyRequests": "日請求",
"requests": "{localRequestLabel} {localRequestDisplay} 次",
"h": "{duration} 小時",
"d": "{duration} 天",
"s": "{duration} 秒",
"unlimited": "無限",
"noPointsAvailableYet": "暫無可用點數",
"quotaPoints": "額度點數",
"point": "點",
"requestsInThisWindow": "窗口請求:{requestDisplay} 次",
"requestCount": "{requestDisplay} 次",
"statisticalRange": "統計範圍",
"rolling": "滾動 {duration}",
"awaitingData": "待觀測",
"remaining": "剩餘 {remaining}%",
"usageLimit": "使用限額",
"reset": "重置:",
"remainingQuota": "{label}剩餘額度",
"accountLimit": "賬號額度",
"quota": "{provider} 額度",
"lastRefreshed": "最近刷新: {refreshedAtDisplay}",
"viewPersonalInformation": "查看個人信息",
"forecastWeeklyMonthlyQuota": "預測周/月額度",
"queryUnsupported": "暫不支持查詢上游額度",
"quotaDetails": "額度詳情",
"viewDetails": "查看{detailTitle}詳情",
"details": "{detailTitle}詳情",
"statisticalMethod": "統計方式",
"rollingWindow": "滾動窗口",
"windowConsumption": "窗口消耗",
"resetTime": "重置時間",
"localTokens": "本地累計總 Token",
"unavailableHelp": "上游額度未提供,綠色條不表示剩餘額度",
"totalTokensFor": "{windowLabelDisplay}總 Token",
"usageRateHelp": "最近使用額度的當前已用比例",
"usageRate": "使用率",
"moreGroups": "另有 {count} 個額度組,可展開賬號查看",
"windows": {
"fiveHour": "5h 額度",
"daily": "日額度",
"weekly": "周額度",
"monthly": "月額度",
"annual": "年額度",
"usage": "用量上限",
"secondary": "次級用量上限",
"duration": "{duration}額度"
}
},
"account": "賬號",
"connectionTest": {
"duration": "響應耗時",
"title": "測試連接",
"description": "驗證賬號憑據、身份綁定與上游模型端點是否可用",
"model": "測試模型",
"refreshModels": "刷新上游模型",
"loadingModels": "加載模型中",
"modelPlaceholder": "選擇上游模型",
"noModels": "上游沒有返回模型",
"running": "檢測中",
"completedAt": "完成時間",
"events": {
"title": "事件軌跡",
"request": "發起請求",
"response": "接收響應內容",
"completed": "響應完成"
},
"diagnostics": "原始診斷",
"retry": "重新測試",
"start": "開始測試",
"errors": {
"invalidRequest": "測試請求不合法",
"unsupported": "當前 Provider 不支持連接測試",
"credentials": "賬號憑據無效",
"policyRejected": "測試請求被網關策略拒絕",
"modelNotFound": "測試模型不存在",
"accountUnavailable": "指定賬號當前不可用於連接測試",
"capacityUnavailable": "指定賬號當前沒有可用容量",
"infrastructureUnavailable": "Provider 本地基礎設施暫不可用",
"rateLimited": "上游請求過於頻繁",
"upstreamUnavailable": "上游服務暫不可用",
"timeout": "上游請求超時",
"canceled": "測試請求已取消",
"internal": "網關內部錯誤",
"unknown": "未分類錯誤",
"failed": "測試連接失敗",
"modelRequired": "未選擇模型",
"browserUnsupported": "當前瀏覽器不支持連接測試",
"missingCompletion": "測試連接未返回完成事件",
"invalidResponse": "測試響應解析失敗",
"disconnected": "測試連接已斷開"
},
"stages": {
"gateway": "網關校驗",
"provider": "Provider 本地準備",
"upstream": "上游響應"
},
"failed": "測試失敗",
"testing": "正在測試",
"runningDescription": "正在向所選模型發送請求並接收流式響應",
"successTitle": "連接正常",
"completedDescription": "請求已完成,可在下方查看模型、耗時和事件軌跡",
"failedDescription": "請求未完成,請在下方查看失敗來源與原始診斷",
"readyTitle": "準備測試",
"readyDescription": "選擇模型後,點擊“開始測試”發送真實請求",
"starting": "開始測試 {value}",
"emptyResponse": "上游已完成,沒有返回文本內容",
"testCompleted": "測試完成",
"modelsRefreshed": "已刷新 {count} 個上游模型",
"noModelsAvailable": "沒有可測試模型"
},
"credentials": {
"wsFirst": "WS 優先",
"accountName": "賬號名稱",
"enterUpstreamName": "輸入上游名稱",
"baseUrlHelp": "填寫 API 前綴,接口路徑會自動追加",
"apiPrefix": "API 前綴",
"apiKeyPlaceholder": "留空保留當前密鑰",
"enterUpstreamKey": "輸入上游密鑰",
"transportLabel": "傳輸方式",
"webSocketHelp": "WS 優先需要上游支持 Responses WebSocket",
"nameRequired": "請輸入賬號名稱",
"validation": {
"urlLength": "上游 API 地址不能超過 2048 個字符",
"urlFormat": "請輸入不含認證、查詢參數或片段的 HTTP 或 HTTPS 地址",
"urlRequired": "請輸入完整的上游 API 地址",
"apiKeyFormat": "API Key 不能包含空格或控制字符",
"transportRequired": "請選擇傳輸方式"
},
"apiKeyRequired": "請輸入 API Key"
},
"batchEdit": {
"title": "批量編輯賬號",
"selectionTitle": "編輯 {count} 個賬號",
"saveChanges": "保存更改",
"proxyRequired": "請選擇已通過測試的代理",
"saved": "已更新 {count} 個賬號",
"staleAccount": "賬號 {accountId} 的頁面數據已失效,請重新選擇"
},
"capacity": {
"concurrentRequestsLimit": "賬號併發佔用 {value},上限 {value2}",
"viewConcurrencyDetails": "{label},查看併發明細",
"viewDetails": "{label},查看明細"
},
"concurrency": {
"title": "併發明細",
"description": "當前正在處理的請求",
"unavailable": "暫時無法讀取併發明細",
"empty": "當前沒有併發佔用",
"key": "密鑰",
"model": "模型",
"sourceIp": "來源 IP",
"startTime": "開始時間",
"elapsed": "佔用時長"
},
"editor": {
"title": "編輯賬號",
"transportLabel": "上游傳輸方式",
"upstreamConnection": "上游連接",
"loadError": "上游設置讀取失敗",
"notesHelp": "最多 500 字,留空可清除備註",
"oauthUnavailable": "該賬號沒有 OAuth 上游設置",
"apiKeyUnavailable": "該賬號沒有 API Key 上游設置",
"saved": "賬號已更新"
},
"filters": {
"allGroups": "全部分組",
"ungroupedAccounts": "未分組賬號",
"disabled": "{name}(已禁用)",
"label": "賬號篩選與操作",
"searchLabel": "搜索賬號",
"statusLabel": "按賬號狀態篩選",
"groupLabel": "按賬號分組篩選",
"deleteSelected": "刪除選中 ({count})",
"exportSelected": "導出選中 ({count})",
"importTasks": "導入任務",
"importAccount": "導入賬號"
},
"modelAccess": {
"reserve": "保留",
"allowlist": "白名單",
"blocklist": "黑名單",
"modelLimitations": "模型限制",
"refreshModel": "刷新模型",
"modelRestrictionMode": "模型限制模式",
"searchOrAddModels": "搜索或添加模型",
"searchOrEnterIdAndPressEnter": "搜索或輸入 ID,回車添加",
"selectModel": "選擇模型",
"notInCurrentModelCatalog": "{id}(當前目錄未返回)",
"loadingModel": "加載模型中…",
"noMatchingModels": "無匹配模型",
"noModels": "暫無模型",
"modelListLoadingFailed": "模型列表加載失敗",
"retryHint": "請刷新後重試",
"selectOrAddAtLeastOneModel": "請至少選擇或添加一個模型",
"configureUpToModels": "最多配置 256 個模型",
"invalidModelId": "請使用有效的精確模型 ID,不支持通配符",
"enterValidExactModelIdUpTo": "請輸入有效的精確模型 ID,最多 256 字節,不支持通配符"
},
"notes": {
"viewAccountNotes": "查看賬號備註",
"title": "賬號備註"
},
"overview": {
"totalAccounts": "總賬號",
"accountPoolSize": "賬號池規模",
"availableAccounts": "可用賬號",
"availableHelp": "可參與調度",
"quotaLimited": "額度受限",
"waitingForQuota": "等待額度恢復",
"pending": "待處理",
"disabledError": "已停用 / 錯誤"
},
"proxy": {
"keepCurrent": "保持當前",
"keepExisting": "保留各賬號的連接設置",
"directConnection": "直連",
"notUsingProxy": "不使用代理",
"disabledSuffix": "(已禁用)",
"testFailed": "(測試失敗)",
"notTested": "(未測試)",
"outboundTunnel": "出站隧道"
},
"scheduling": {
"scheduling": "調度",
"switchAccountSchedule": "切換賬號調度",
"concurrencyLimit": "併發限制",
"accountConcurrencyLimit": "賬號併發限制",
"defaultHint": "留空使用默認值",
"weight": "權重",
"accountSchedulingWeight": "賬號調度權重",
"weightHelp": "數值越高越優先,最高 100",
"groupLabel": "所屬分組",
"invalidConcurrency": "併發限制必須留空,或爲 1 到 {value} 的整數",
"weightMustBeIntegerFromTo": "權重必須是 1 到 100 的整數"
},
"actions": {
"deleteAccount": "刪除賬號",
"moreActions": "更多操作",
"disableScheduling": "停用",
"enableScheduling": "啓用",
"refreshToken": "刷新令牌",
"reauthorize": "重新授權",
"downloadModelCatalog": "下載模型目錄",
"restoreState": "重置狀態",
"staleSelection": "所選賬號數據已失效,請重新選擇",
"exportUnsupported": "所選賬號包含不支持導出的平臺",
"deleted": "賬號已刪除",
"deletedAccountDeletedAccounts": "已刪除 {count} 個賬號",
"partialDeletion": "已刪除 {count} 個賬號,其餘未刪除:{value}",
"batchDeletionFailed": "批量刪除失敗",
"exportSelectionRequired": "請選擇要導出的賬號",
"exported": "已導出 {count} 個賬號",
"exportFailed": "導出失敗",
"modelCatalogDownloadedModels": "已下載模型目錄,共 {count} 個模型",
"tokenIsBeingRefreshed": "Token 正在刷新中",
"refreshFailed": "刷新失敗",
"tokenRefreshed": "Token 已刷新",
"schedulingIsDisabled": "調度已停用",
"schedulingIsEnabled": "調度已啓用",
"quotaRefreshed": "額度已刷新",
"refreshQuotaManually": "請手動刷新額度",
"resetRefreshFailed": "額度已重置,但最新額度加載失敗:{value}",
"statusRestored": "賬號狀態已恢復",
"staleAccount": "賬號 {id} 的頁面數據已失效,請重新選擇",
"unsupportedProvider": "不支持的 Provider:{provider}"
},
"usage": {
"call": "調用",
"successRate": "成功率",
"input": "輸入",
"output": "輸出",
"cache": "緩存",
"total": "總計",
"billing": "計費",
"tokensStructure": "Token 用量",
"cacheRead": "緩存讀取",
"reasoning": "推理",
"cacheWrites": "緩存寫入",
"modelUsageRanking": "模型用量",
"totalTokens": "總 Token",
"totalCharge": "總計費",
"totalCharges": "總計費:",
"noModelUsageYet": "暫無模型用量",
"windows": {
"general": "累計用量",
"weekly": "周用量",
"monthly": "月用量",
"quota": "週期用量"
},
"cost": "費用"
},
"onboarding": {
"fileReadingFailedTryAgain": "文件讀取失敗,請重新選擇",
"uploadFiles": "上傳文件",
"authorizationExpired": "授權已過期,可重新開始或檢查已完成的授權結果",
"pollingPaused": "查詢已暫停,可檢查授權結果後繼續",
"regenerateAuthorizationLink": "重新生成授權鏈接",
"generateAuthorizationLink": "生成授權鏈接",
"authorizationLink": "授權鏈接",
"copyLink": "複製鏈接",
"authorizationLinkCopied": "授權鏈接已複製",
"batchImport": "批量導入",
"selectAccountPlatform": "選擇賬號平臺",
"accountPlatform": "賬號平臺",
"maximumWordsOptional": "最多 500 字,可不填",
"copyAccount": "複製賬號",
"accountCopied": "賬號已複製",
"howToAddAccount": "賬號添加方式",
"authorize": "授權",
"continueImporting": "繼續",
"jsonDescription": "粘貼或上傳賬號 JSON,匹配已有賬號時更新憑據",
"packageDescription": "粘貼或上傳 CPR 賬號包,一次導入多個平臺賬號",
"oauthDescription": "通過瀏覽器授權導入 {label} 賬號",
"apiKeyDescription": "接入 OpenAI Responses 兼容上游",
"pasteAccessTokenLineByLineIf": "逐行粘貼 Access Token,未包含 Refresh Token 時無法自動續期",
"refreshTokenDescription": "逐行粘貼 Refresh Token,導入時將自動換取 Access Token",
"accountSettings": "賬號設置",
"reauthorizeAccount": "重新授權賬號",
"settingsDescription": "設置將應用於本次導入的賬號",
"reauthorizeDescription": "完成授權後更新賬號憑據",
"callbackLabel": "回調地址或授權碼",
"callbackAddress": "回調地址",
"callbackPlaceholder": "回調地址、?code=...&state=... 或授權碼",
"callbackHelp": "打開授權鏈接,完成瀏覽器授權後粘貼回調地址或授權碼",
"pasteOneAccessTokenPerLine": "每行粘貼一個 Access Token",
"pasteOneRefreshTokenPerLine": "每行粘貼一個 Refresh Token",
"batchAccountFiles": "批量賬號文件",
"accountFile": "賬號文件",
"packagePlaceholder": "粘貼 CPR 多平臺導出文件內容",
"pasteAccountJsonContent": "粘貼賬號 JSON 內容",
"completeReauthorization": "完成重新授權",
"completeImport": "完成導入",
"invalidExpiry": "授權有效期無效,請重新生成鏈接",
"linkFailed": "生成授權鏈接失敗",
"callbackRequired": "請粘貼回調地址或授權碼",
"authorizationFailed": "完成授權失敗,可重試提交",
"reauthorized": "賬號重新授權成功",
"accountAdded": "賬號已添加",
"providerRequired": "請選擇賬號平臺",
"accountPlatformIsNotSupported": "賬號平臺不受支持",
"apiKeyUnsupported": "當前平臺不支持 API Key 賬號",
"apiKeyAccountAdded": "API Key 賬號已添加",
"importTasksCreated": "已創建 {submitted} 個導入任務",
"importTaskCreated": "導入任務已創建",
"partialSubmission": "部分導入任務已創建,保持輸入不變重試可繼續提交",
"accountName": "{provider} 賬號",
"failedToStartAuthorization": "啓動授權失敗"
},
"importTasks": {
"needProcessing": "需處理",
"importTaskDetails": "導入任務詳情",
"created": "{createdAtDisplay} 創建",
"waitForCurrentEntryToEnd": "等待當前條目結束",
"stopUnstartedEntries": "停止未開始條目",
"viewAccount": "查看賬號",
"entryProgress": "條目進度",
"accountsImported": "已入庫 {importedAccounts} 個賬號",
"itemProcessingProgress": "條目處理進度",
"itemsToBeCheckedMayHaveBeen": "待覈對條目可能已入庫,請先查看賬號,再決定是否重新導入",
"filterImportDetails": "篩選導入明細",
"thereAreNoItemsToBeProcessed": "暫無需要處理的條目",
"importEntryResults": "導入條目結果",
"items": "{total} 個條目 · {value}",
"description": "關閉頁面後繼續導入,再次打開即可查看進度",
"progressUnavailable": "進度暫未更新:{value},恢復連接後將自動刷新",
"loadingImportTasks": "正在讀取導入任務",
"noImportTasks": "暫無導入任務",
"empty": "新建一次賬號導入,即可在這裏查看逐條入庫結果",
"switchImportTasks": "切換導入任務",
"loadingItemResults": "正在讀取條目結果",
"selectTask": "請選擇一個任務",
"taskRetentionInstructions": "任務保留說明",
"resultsRetainedForHour": "結果保留 1 小時",
"retentionHelp": "服務重啓後任務記錄消失,已入庫賬號保留",
"processing": "處理中",
"alreadyInStock": "已入庫",
"toBeVerified": "待覈對",
"notExecuted": "未執行",
"stopping": "正在停止",
"importing": "導入中",
"queuing": "排隊中",
"stopped": "已停止",
"endedPendingItems": "已結束 · 有待處理項",
"allDone": "全部完成",
"savedAccountSavedAccounts": "已保存 {count} 個賬號",
"verifying": "正在校驗憑據併入庫",
"waitingForExecution": "等待執行",
"thisArticleIsNotImplemented": "本條未執行",
"entryFailed": "本條導入未成功",
"checkAccountList": "請檢查賬號列表,確認是否已入庫",
"progressReadingFailedTryAgain": "進度讀取失敗,請重試"
},
"profile": {
"activity": {
"quickMode": "快速模式",
"reasoningEffort": "最常用的推理強度",
"exploredSkills": "已探索的技能",
"totalNumberOfSkillsUsed": "使用的技能總數",
"totalNumberOfChats": "聊天總數",
"activityInsights": "活動洞察",
"pluginsAndSkills": "最常用的插件與技能",
"runs": "{count} 次運行",
"noToolCalls": "暫無插件或技能調用記錄",
"daily": "每日",
"weekly": "每週",
"cumulative": "累計",
"tokenActivity": "Token 活動",
"tokenActivityStatisticsMethod": "Token 活動統計方式",
"noTokenActivityYet": "暫無 Token 活動",
"noDailyActivity": "本次未獲取到每日 Token 活動",
"tokenActivityHeatmap": "Token 活動熱力圖,{rangeLabel}",
"weekOfTokens": "{dateDisplay}所在周:{value} Tokens",
"throughTokens": "截至{dateDisplay}:{value} Tokens"
},
"metrics": {
"cumulativeNumberOfTokens": "累計 Token 數",
"peakNumberOfTokens": "峯值 Token 數",
"maximumChatDuration": "最長聊天時長",
"currentConsecutiveDays": "當前連續天數",
"longestStreak": "最長連續天數",
"dayCount": "{integer} 天",
"dH": "{days} 天 {hours} 小時",
"elapsedDays": "{days} 天",
"hMin": "{hours} 小時 {minutes} 分",
"elapsedHours": "{hours} 小時",
"min": "{totalMinutes} 分",
"durationSeconds": "{value} 秒",
"cumulativeActivitySummary": "累計活動摘要"
},
"accountUser": "賬號用戶",
"avatarFor": "{displayName} 的頭像",
"loadingCumulativeActivity": "正在加載累計活動",
"subscription": {
"automaticRenewal": "自動續費",
"noAutomaticRenewal": "不自動續費",
"byMonth": "按月",
"byYear": "按年",
"subscriptionStarts": "訂閱開始",
"subscriptionEnds": "訂閱結束",
"label": "訂閱",
"renewalMethod": "續費方式"
},
"personalInformation": "個人信息",
"subscriptionInformation": "訂閱信息",
"loadingSubscription": "正在加載訂閱信息",
"loadFailed": "個人信息加載失敗",
"statisticsUnavailable": "個人統計暫不可用",
"statisticsEmpty": "本次未獲取到統計數據,可以點擊刷新信息重試",
"refreshIncomplete": "本次信息刷新未完成,保留已獲取的結果",
"noSubscriptionInformationYet": "暫無訂閱信息",
"refreshInformation": "刷新信息"
},
"quotaForecast": {
"tokenCapacity": "Token 容量",
"equivalentFeeUsd": "等價費用 · USD",
"capacityForecast": "容量預測",
"usedThisCycle": "本週期已用",
"preliminary": "初步估算 · 僅供參考",
"estimateLabel": "估算值 · 僅供參考",
"thisCycle": "本週期",
"usedDescription": "本週期已用 {rate},其餘爲推算區域",
"alreadyRecordedThisCycle": "本週期已記錄",
"equivalentCapacityOverDays": "{targetDays}天折算容量",
"projectedTotal": "本週期預計總量",
"loadingQuotaForecast": "正在加載額度預測",
"weeklyQuota": "周額度",
"monthlyQuota": "月額度",
"windowExpired": "額度窗口已過期,請刷新賬號額度後重試",
"quotaForecast": "額度預測",
"periodHelp": "按本週期估算,重置後重新累計",
"forecastPeriod": "預測週期",
"predictionLoadFailed": "預測加載失敗",
"loadFailed": "暫時無法取得預測數據,請重新加載",
"reload": "重新加載",
"unpredictableAtMoment": "暫時無法預測",
"updated": "更新於 {observedAtDisplay}",
"forecastDescription": "預測說明",
"forReferenceOnly": "僅供參考",
"methodDescription": "本週期預計總量爲已記錄用量加預計剩餘,剩餘量按本週期內近期用量估算",
"limitations": "缺失的用量或費用可能使結果偏低,結果會隨使用的模型和方式變化,並非官方承諾額度",
"limitedData": "目前數據還較少,結果可能有較大波動",
"currentPeriod": "當前週期",
"forecastCalculatedByOverDays": "本頁預測由{value}按 {targetDays} 天折算",
"equivalentCostHelp": "預測以數據更新時間爲準,等價費用不是實際賬單或賬戶餘額",
"refreshQuota": "刷新額度"
},
"quotaReset": {
"automation": {
"confirming": "上次自動重置結果待確認,將繼續覈對",
"unconfirmed": "上次自動重置結果待確認",
"expiredUnconfirmed": "上次重置結果未能確認,卡片已到期",
"queryFailed": "最近查詢失敗,將按計劃重試",
"aboveThreshold": "剩餘周額度高於上限,稍後檢查",
"quotaUnavailable": "暫時無法確認周額度,稍後檢查",
"resetNotNeeded": "當前額度窗口不需要重置,稍後檢查",
"resetIncomplete": "上游未完成最近一次自動重置",
"scheduleHelp": "每天隨機查詢一次,各賬號錯開時間",
"verifyHelp": "臨期使用前核對卡片,已在其他地方使用的會自動跳過",
"label": "自動使用臨期重置卡"
},
"automaticallyUseResetCard": "自動使用重置卡",
"automaticallyUsed": "自動使用",
"automaticUsageRules": "自動使用規則",
"setGlobalLeadTime": "設置全局提前時間",
"minutesInAdvance": "提前 {leadMinutes} 分鐘",
"leadTime": "提前時間",
"nextUse": "下次使用 {nextConsumeAtDisplay}",
"autoUsageSettingsFailedToLoad": "自動使用設置加載失敗",
"limitReset": "額度重置",
"confirmLastReset": "確認上次重置",
"confirmResetAmount": "確認重置額度",
"pendingAction": "查看主動重置卡,有一項操作待確認",
"queryFailedWithCount": "查看主動重置卡,查詢失敗,最近查詢 {count} 張可用",
"queryFailedLabel": "查看主動重置卡,查詢失敗",
"availableCount": "查看主動重置卡,最近查詢 {count} 張可用",
"viewCredits": "查看主動重置卡",
"useResetSelectedByUpstream": "使用一次重置(由上游選擇)",
"expires": "將於 {expiresAtDisplay} 到期",
"expiryHelp": "有效期由上游決定",
"querying": "查詢中",
"toBeQueried": "待查詢",
"usesAvailable": "可用 {count} 次",
"usageReset": "用量重置",
"thisTimeUse": "本次使用",
"currentQuota": "當前額度",
"operationUnconfirmed": "上次操作結果待確認",
"confirmPrevious": "請繼續確認上次重置結果",
"continueToConfirm": "繼續確認",
"availableResetCards": "可用重置卡",
"refreshCredits": "刷新主動重置卡",
"resetCardLoadingFailed": "重置卡加載失敗",
"refreshRequired": "請刷新重試",
"queryingAvailableResetTimes": "正在查詢可用重置次數…",
"useResetCredit": "使用重置:{title},{expiry}",
"useReset": "使用重置",
"noResetCardAvailableYet": "暫無可用重置卡",
"confirmAgain": "再次確認",
"confirmReset": "確認重置",
"lastResetCompleted": "上次重置已完成",
"resetSuccess": "額度已重置",
"resultUnknown": "消費結果暫不確定,重試會複用同一個請求標識",
"quotaResetFailed": "額度重置失敗",
"alreadyProcessed": "該重置操作已被處理,請先刷新重置卡列表",
"noCredits": "當前沒有可用的主動重置卡",
"resetNotNeeded": "當前額度窗口不需要重置",
"upstreamDeclined": "上游未執行額度重置:{code}"
},
"status": {
"accountStatus": "賬號狀態",
"tryNextTime": "下次嘗試",
"recommendedAction": "建議操作",
"upstreamOriginalFeedback": "上游原始反饋",
"forTroubleshootingOnly": "僅供排查",
"retreating": "退避中",
"oauthRefreshBackoff": "OAuth 刷新退避",
"refreshFailedHelp": "刷新失敗,系統正在等待下一次自動嘗試",
"retryScheduledHelp": "系統會在計劃時間自動重試",
"attentionHelp": "該賬號當前狀態需要關注",
"retestHelp": "重新測試連接以獲取最新狀態",
"rateLimitedHelp": "上游暫時限制了請求頻率,系統正在冷卻該賬號",
"cooldownHelp": "冷卻結束後,系統會自動恢復調度",
"credentialsHelp": "該賬號暫不參與調度,處理憑據後可重新測試連接",
"reauthorizeHelp": "重新授權後,賬號會重新參與調度",
"replaceCredentialsHelp": "請更新或重新導入憑據,再次測試連接",
"upstreamRestrictionHelp": "請確認上游賬號狀態,解除限制後再啓用",
"capacityFailuresHelp": "容量類請求失敗累計達到閾值,系統已暫停該賬號的調度",
"recoveryProbeHelp": "冷卻結束後進行恢復探測,成功後恢復調度,也可手動恢復賬號",
"recoveryHelp": "冷卻結束後自動恢復調度,也可手動恢復賬號",
"nextAttempt": ",下次嘗試:{nextRefreshDisplay}",
"clickOrFocusToViewDetails": "{title},{description}{retry},點擊或聚焦查看詳情",
"resumeDetection": "恢復探測",
"expectedToRecover": "預計恢復"
},
"fields": {
"platformType": "平臺",
"accountGrouping": "分組",
"lastUsed": "最後使用",
"tokenExpires": "令牌過期",
"quotaExhausted": "配額耗盡",
"rateLimiting": "限流中",
"deactivated": "已停用",
"error": "錯誤",
"identityUnconfirmed": "賬號身份尚未確認",
"accessTokenHasExpired": "Access Token 已過期",
"credentialsHaveExpired": "憑據已過期",
"invalidCredentials": "憑據無效",
"accountUnavailable": "賬號不可用或已被封禁",
"count": "賬號數"
},
"page": {
"description": "維護賬號池,查看可用性、配額與使用狀態",
"noAccountDataYet": "暫無賬號數據",
"collapseStatistics": "收起統計",
"expandStatistics": "展開統計",
"selectAccountOnCurrentPage": "選擇當前頁賬號",
"selectAccount": "選擇賬號",
"deleteDescription": "刪除後該賬號將不再參與調度,此操作不可撤銷",
"batchDeleteDescription": "確定要刪除選中的 {count} 個賬號嗎?此操作不可撤銷",
"thisAccount": "該賬號",
"delete": "確定要刪除 {value} 嗎?"
},
"import": {
"jsonFormatIsIncorrect": "JSON 格式不正確",
"documentTooLarge": "單條導入文檔超過 4 MiB,請拆分文件後重試",
"batchImportFileMustBeCprMulti": "批量導入文件必須是 CPR 多平臺導出文件",
"invalidProvider": "批量導入文件包含無效的 Provider 文檔",
"noAccounts": "批量文件沒有可導入的賬號文檔",
"pasteAtLeastOne": "請至少粘貼一個 {label}",
"missingProvider": "批量導入文件不包含 {provider} 賬號文檔",
"importFilesMustBeJsonObjects": "導入文件必須是 JSON 對象"
}
}
}
@@ -0,0 +1,222 @@
{
"appearance": {
"switchToLight": "切換淺色模式",
"switchToDark": "切換暗黑模式",
"settings": {
"global": "全局",
"components": "組件",
"invalidTheme": "主題設置無效,請檢查編輯值",
"themeSavedAndApplied": "主題已保存並應用",
"description": "自定義當前瀏覽器中的管理端主題",
"pendingChanges": "{count} 處修改待應用",
"synced": "已同步",
"themeEditingLevel": "主題編輯層級",
"undoDraft": "撤銷草稿",
"restoreDefault": "恢復默認",
"saveAndApply": "保存並應用",
"saved": "已保存",
"themeEditor": "主題編輯器",
"themeTokenEditingPanel": "主題 Token 編輯面板",
"searchToken": "搜索 Token",
"searchPlaceholder": "搜索 Seed、Alias 或 Component Token"
},
"color": {
"modified": "已修改",
"edit": "編輯 {label}",
"restoreDerivedValue": "恢復派生值"
},
"preview": {
"components": {
"relayAccount": "中繼賬號",
"stickyHelp": "優先保持當前賬號,額度耗盡後再切換",
"notEditable": "不可編輯",
"allPlatforms": "全部平臺",
"restricted": "受限",
"accountAvailability": "賬號可用率",
"todaySQuota": "今日額度",
"batchImport": "批量導入",
"platform": "平臺",
"requestToday": "今日請求",
"recentlyUsed": "最近使用",
"justNow": "剛剛",
"hoursAgo": "2 小時前",
"componentOverview": "組件概覽",
"description": "在同一張校樣板中檢查控制態、數據密度與浮層關係",
"currentThemeSemanticColor": "當前主題語義色",
"basicControlComponents": "基礎控制組件",
"buttonsAndActions": "按鈕與動作",
"createAccount": "創建賬號",
"exportData": "導出數據",
"dealWithItLater": "稍後處理",
"sizeAndDisabledStatus": "尺寸與禁用狀態",
"inoperable": "不可操作",
"processing": "處理中",
"notification": "通知",
"moreActions": "更多操作",
"deleteRecord": "刪除記錄",
"formsAndInput": "表單與輸入",
"searchAccount": "搜索賬號",
"choosePlatform": "選擇平臺",
"accessKeyErrorExample": "訪問密鑰錯誤示例",
"disableInputBox": "禁用輸入框",
"brandColors": "品牌顏色",
"editBrandColors": "編輯品牌顏色",
"schedulingNotes": "調度備註",
"controlHeight": "控件高度",
"componentExampleControlHeight": "組件示例控件高度",
"choiceAndFeedbackComponents": "選擇與反饋組件",
"selectAndSwitch": "選擇與切換",
"accountView": "賬號視圖",
"realTimeNotification": "實時通知",
"automaticRotation": "自動輪換",
"selectCurrentPage": "選擇當前頁",
"partialSelection": "部分選擇",
"equilibrium": "均衡",
"sticky": "粘性",
"manual": "手動",
"feedbackSemantics": "反饋語義",
"themeSettingsSaved": "主題設置已保存",
"quotaOfAccountsIsCloseToUpper": "3 個賬號額度接近上限",
"connectionTestFailed": "連接測試未通過",
"schedulingNotice": "調度規則將在下次請求生效",
"statusAndProgress": "狀態與進度",
"runningNormally": "運行正常",
"quotaLimited": "額度受限",
"needToBeProcessed": "需要處理",
"synchronizing": "同步中",
"restoreTag": "恢復標籤",
"dataTable": "數據表格",
"tableComponents": "ZTable · ZScrollbar · ZPagination(標準行高)",
"filterForm": "篩選表格",
"filterAccounts": "篩選賬號",
"boundaryStateComponent": "邊界狀態組件",
"emptyState": "空狀態",
"noMatchingAccountYet": "暫無匹配賬號",
"emptyHelp": "調整篩選條件,或添加一個新的上游賬號",
"addAccount": "添加賬號",
"loadingAndSkeleton": "加載與骨架",
"synchronizingAccountStatus": "正在同步賬號狀態",
"overlaysAndMenus": "浮層與菜單",
"accountOperation": "賬號操作",
"editAccount": "編輯賬號",
"deactivateAccount": "停用賬號",
"overlayHelp": "浮層始終使用獨立 Surface 與 Shadow Token",
"eyebrow": "組件預覽",
"count": "{count} 個基礎組件",
"buttonLabel": "按鈕 / 操作",
"feedbackTypes": "成功 · 警告 · 錯誤 · 信息",
"tagComponents": "ZTag · 進度 Token",
"loadingComponents": "ZSkeleton · ZButton 加載態",
"overlayComponents": "ZPopover · ZMenuItem · 浮層表面"
},
"dashboard": {
"justUpdated": "剛剛更新",
"demoKey": "演示 Key",
"requestHealthTimeline": "請求健康時間線",
"validRequestAvailability": "有效請求可用性",
"clientId": "客戶端 ID",
"tokenAuthentication": "Token 認證",
"todaySToken": "今日 Token",
"hours": "5 小時",
"requests": "08-23 {value}:00–{value2}:00 · {count} 次請求",
"times": "次數",
"dailyLimit": "日限額"
},
"homeArtboard": "首頁畫板",
"themeRealTimePreview": "主題實時預覽",
"livePreview": "實時預覽",
"description": "真實組件在影子環境隔離渲染,拖動畫板並縮放檢查細節",
"previewType": "預覽類型",
"canvas": {
"homeThemePreviewArtboard": "首頁主題預覽畫板",
"dragBlankSpaceToPanUseScroll": "拖動空白處平移 · 滾輪縮放",
"reduceArtboard": "縮小畫板",
"recovery": "恢復 100%",
"enlargeArtboard": "放大畫板",
"adaptToArtboard": "適應畫板"
}
},
"componentTokens": {
"cardsAndContainers": "卡片與容器",
"dataDisplay": "數據展示",
"navigation": "導航",
"layoutAndScrolling": "佈局與滾動",
"mainButtonText": "主按鈕文字",
"mainButtonBackground": "主按鈕背景",
"mainButtonHover": "主按鈕 Hover",
"mainButtonActive": "主按鈕 Active",
"secondaryButtonBackground": "次要按鈕背景",
"secondaryButtonHover": "次要按鈕 Hover",
"secondaryButtonActive": "次要按鈕 Active",
"secondaryIconButtonBackground": "次要圖標按鈕背景",
"secondaryIconButtonHover": "次要圖標按鈕 Hover",
"secondaryIconButtonActive": "次要圖標按鈕 Active",
"inputBoxBackground": "輸入框背景",
"inputBoxHover": "輸入框 Hover",
"inputBoxActive": "輸入框 Active",
"inputBoxShadow": "輸入框陰影",
"inputBoxHoverShadow": "輸入框 Hover 陰影",
"inputBoxFocusOuterCircle": "輸入框焦點外圈",
"cardBackground": "卡片背景",
"popUpBackground": "彈窗背景",
"floatingTitleBackground": "浮層標題背景",
"cardRoundedCorners": "卡片圓角",
"cardShadow": "卡片陰影",
"tableRowHeight": "表格行高",
"headerBackground": "表頭背景",
"lineBackground": "行背景",
"zebraPatternBackground": "斑馬紋背景",
"rowHover": "行 Hover",
"selectedRowBackground": "選中行背景",
"selectRowHover": "選中行 Hover",
"progressTrack": "進度軌道",
"menuSelectionBackground": "菜單選中背景",
"sidebarBackground": "側欄背景",
"sidebarShadow": "側欄陰影",
"scrollBarSlider": "滾動條滑塊",
"scrollBarHover": "滾動條 Hover",
"componentTokenComponentFamily": "Component Token 組件族",
"description": "調整 {label} 的 Component Token,未修改的值繼續由全局 Seed / Alias 算法生成",
"noMatchingComponentToken": "沒有匹配的 Component Token",
"kindLabel": "組件 Token"
},
"globalTokens": {
"size": "尺寸",
"style": "風格",
"systemMode": "跟隨系統",
"lightColor": "淺色",
"dark": "深色",
"successColor": "成功色",
"successFeedbackAndStatus": "成功反饋與狀態",
"warningColor": "警告色",
"limitAndRiskReminder": "額度與風險提醒",
"wrongColor": "錯誤色",
"dangerHelp": "失敗與破壞性操作",
"informationColor": "信息色",
"systemAndRequestInformation": "系統與請求信息",
"linkColor": "鏈接色",
"linksAndJumps": "鏈接與跳轉",
"basicTextColor": "基礎文本色",
"textAndInformationLevels": "正文與信息層級",
"basicBackgroundColor": "基礎背景色",
"pageAndContainerBase": "頁面與容器基底",
"themeMode": "主題模式",
"globalTokenClassification": "全局 Token 分類",
"brandColorLabel": "預置主題 品牌色 colorPrimary",
"brandColor": "品牌色",
"presetThemes": "預置主題",
"brandMainColor": "品牌主色",
"paletteDescription": "完整色階與界面基調",
"semanticColorsTitle": "功能色與中性色",
"derivedVariablesMapAliasToken": "派生變量 Map / Alias Token",
"sizeToken": "尺寸 Token",
"basicFontSize": "基礎字號",
"basicSpacing": "基礎間距",
"sizeStep": "尺寸步長",
"styleToken": "風格 Token",
"surfaceDescription": "固定無邊設計,圓角塑形,陰影分層",
"universalFillet": "通用圓角",
"shadowIntensity": "陰影強度"
}
}
}
@@ -0,0 +1,21 @@
{
"auth": {
"signOut": "退出登錄",
"adminSignIn": "管理員登錄",
"apiKeySignIn": "API Key 登錄",
"signingIn": "正在登錄...",
"signIn": "登錄",
"method": "選擇登錄方式",
"title": "控制檯登錄",
"welcome": "「 歡迎回來,登錄以開始您的數據之旅 」",
"username": "管理員賬號",
"usernamePlaceholder": "輸入會話賬號",
"passwordPlaceholder": "輸入會話密鑰",
"apiKeyPlaceholder": "輸入 API Key",
"pageLabel": "Codex Proxy RS 登錄",
"password": "密碼",
"apiKey": "API 密鑰",
"adminRealm": "管理員",
"keyRealm": "API 密鑰"
}
}
@@ -0,0 +1,140 @@
{
"common": {
"errors": {
"canceled": "請求已取消",
"timeout": "請求超時,請稍後重試",
"network": "網絡連接失敗,請檢查網絡後重試",
"invalidParameters": "請求參數不合法",
"signInRequired": "需要登錄",
"forbidden": "沒有權限執行此操作",
"notFound": "請求的接口不存在",
"conflict": "資源狀態衝突,請刷新後重試",
"payloadTooLarge": "請求內容過大",
"unsupportedFormat": "請求格式不受支持",
"invalidContent": "請求內容不合法",
"rateLimited": "請求過於頻繁,請稍後重試",
"internal": "服務內部錯誤",
"upstreamFailure": "上游服務請求失敗",
"unavailable": "服務暫不可用,請稍後重試",
"upstreamTimeout": "上游服務響應超時",
"http": "請求失敗(HTTP {status})",
"request": "請求失敗",
"responseTooLarge": "響應內容超過大小限制",
"unsupportedResponse": "服務返回了不受支持的響應",
"sessionExpired": "登錄已失效,請重新登錄",
"operation": "操作失敗",
"copy": "複製失敗",
"load": "加載失敗",
"malformedJson": "請求體不是合法 JSON",
"invalidTimeRange": "時間範圍不合法",
"invalidCredentials": "登錄憑據錯誤",
"invalidAdminApiKey": "管理 API 密鑰無效",
"tooManyLoginAttempts": "登錄嘗試過多,請稍後重試",
"upstreamResultUnknown": "上游執行結果未知,請刷新狀態後再決定是否重試"
},
"status": {
"disabled": "已禁用",
"disabledName": "{name}(已禁用)",
"success": "成功",
"error": "異常",
"pending": "等待中",
"failed": "失敗",
"healthy": "正常",
"all": "全部狀態",
"available": "可用",
"unavailable": "不可用",
"enabled": "已啓用",
"loading": "加載中",
"running": "執行中",
"completed": "已完成",
"rateLimited": "限流"
},
"actions": {
"copy": "複製",
"close": "關閉",
"retry": "重試",
"cancel": "取消",
"previous": "上一步",
"reset": "重置",
"back": "返回",
"delete": "確認刪除",
"create": "創建",
"enable": "啓用",
"next": "下一步",
"confirm": "確定",
"refresh": "刷新",
"save": "保存"
},
"providers": {
"all": "全部平臺",
"filter": "按平臺篩選",
"unknown": "未知平臺",
"customAuth": "自定義認證 · {normalized}",
"unknownAuth": "未知認證類型"
},
"location": {
"resolving": "正在解析出口位置",
"detect": "解析出口位置並填入表單",
"countryCode": "國家代碼",
"countryCodePlaceholder": "請輸入兩位國家代碼",
"region": "地區",
"regionPlaceholder": "請輸入地區",
"city": "城市",
"cityPlaceholder": "請輸入城市",
"timeZone": "IANA 時區",
"timeZonePlaceholder": "請輸入 IANA 時區",
"required": "請填寫兩位國家代碼、地區、城市和 IANA 時區"
},
"values": {
"yes": "是",
"no": "否",
"unspecified": "未填寫",
"all": "全部",
"unknown": "未知",
"unlimited": "不限",
"default": "默認",
"on": "開啓",
"none": "無",
"off": "關閉"
},
"form": {
"inputPlaceholder": "輸入內容",
"useForm": "使用表單",
"fieldHelp": "{label}說明",
"editJson": "編輯 JSON"
},
"fields": {
"actions": "操作",
"notes": "備註",
"status": "狀態",
"color": "顏色",
"updatedAt": "更新時間",
"name": "名稱",
"createdAt": "創建時間",
"baseUrl": "基礎 URL",
"apiKey": "API 密鑰",
"build": "構建"
},
"language": "界面語言",
"validation": {
"invalidJson": "請輸入有效的 JSON 對象",
"jsonObject": "輸入必須是 JSON 對象",
"sizeLimit": "輸入不能超過 {value} KiB"
},
"feedback": {
"deleted": "刪除成功",
"copied": "已複製"
},
"time": {
"minutesAgo": "{count} 分鐘前"
},
"units": {
"tokens": "Token"
},
"sizes": {
"small": "小",
"medium": "中",
"large": "大"
}
}
}
@@ -0,0 +1,111 @@
{
"dashboard": {
"scheduling": {
"defaultConcurrency": "默認併發",
"totalSlots": "總槽位",
"freeSlots": "空閒槽位",
"smart": "智能調度",
"quotaReset": "額度重置優先",
"sticky": "粘滯",
"title": "賬號調度",
"description": "容量、併發與分配策略",
"occupiedSlots": "槽位佔用",
"strategy": "分配策略"
},
"accountPool": {
"empty": "暫無賬號池觀測",
"quotaExhausted": "配額耗盡",
"rateLimited": "限流中",
"pending": "待處理",
"issueCountsEmpty": "停用 — · 錯誤 —",
"availableDescription": "賬號當前可用",
"exhaustedDescription": "賬號額度已耗盡",
"limitedDescription": "賬號請求暫時受限",
"issueCounts": "停用 {disabled} · 錯誤 {error}",
"title": "賬號狀態",
"description": "賬號池健康結構",
"healthyRate": "正常率",
"distribution": "狀態分佈",
"unavailableCount": "不可用 {value}"
},
"activeAccounts": {
"title": "活躍賬號用量",
"sortByRecent": "最近使用排序",
"empty": "暫無賬號請求記錄",
"recent": "最近"
},
"title": "系統概覽",
"today": "當日統計",
"refresh": {
"action": "刷新概覽",
"failed": "刷新失敗,顯示上次統計",
"unavailable": "統計暫不可用,請稍後重試",
"lastUpdated": "自動刷新 30s,最近刷新 {updatedAt}",
"waiting": "自動刷新 30s,等待首次刷新",
"interval": "自動刷新 30s"
},
"metrics": {
"title": "核心指標",
"outputTokens": "輸出",
"inputTokens": "輸入",
"cachedInputTokens": "緩存",
"cacheHits": "緩存命中",
"requests": "請求",
"firstTokenP95Ms": "TTFT P95",
"latencyP95Ms": "總耗時 P95",
"outputThroughputP50": "速率 P50",
"errors": "錯誤數",
"successRate": "成功率",
"totalRequests": "總請求",
"requestCount": "請求次數",
"totalTokens": "總 Token",
"totalCharges": "總計費",
"totalCacheHits": "總緩存命中",
"totalCache": "總緩存"
},
"comparedWithYesterday": "較昨日",
"trends": {
"title": "使用趨勢",
"metric": "趨勢指標",
"highlight": "突出顯示{label}曲線",
"empty": "暫無趨勢數據",
"latency": "延遲",
"errors": "錯誤"
},
"recentRequests": {
"title": "使用記錄",
"description": "最近 10 條成功請求",
"empty": "暫無成功記錄"
},
"clientIdentity": {
"notChecked": "尚未檢查",
"versionPolicy": "版本策略",
"customVersion": "固定自定義",
"active": "當前生效",
"activeDescription": "跟隨通用設置的新請求使用此身份",
"upToDate": "製品一致",
"upToDateDescription": "當前生效版本與官方最新發布一致",
"updateAvailable": "發現新版",
"latestRelease": "官方最新版本 {releaseLabel}",
"checkFailed": "檢查失敗",
"checkFailedDescription": "官方版本檢查失敗",
"pending": "待檢查",
"pendingDescription": "尚未檢查官方發佈渠道",
"verifiedAt": "畫像覈驗 {verifiedAt}",
"checkedAt": "發佈檢查 {checkedAt}",
"clientId": "客戶端 ID",
"tokenAuth": "Token 認證",
"title": "通用上游身份",
"provider": "上游平臺",
"empty": "暫無請求身份",
"attributes": "請求身份組成",
"authProtocol": "認證協議",
"emulatedEnvironment": "模擬運行環境",
"environment": "運行環境"
},
"health": {
"title": "請求健康時間線",
"description": "有效請求可用性"
}
}
}
@@ -0,0 +1,78 @@
{
"groups": {
"selector": {
"loading": "正在加載分組...",
"empty": "暫無分組,請先在分組管理中創建"
},
"actions": {
"editGroup": "編輯分組",
"disableGroup": "禁用分組",
"enableGroup": "啓用分組",
"deleteGroup": "刪除分組",
"enterGroupName": "請輸入分組名稱",
"selectValidGroupingColor": "請選擇有效的分組顏色",
"updated": "分組已更新",
"created": "分組已創建",
"disabled": "分組已禁用",
"enabled": "分組已啓用",
"groupDeleted": "分組已刪除",
"deletedGroupDeletedGroups": "已刪除 {count} 個分組",
"partialDeletion": "已刪除 {count} 個分組,其餘未刪除:{value}",
"batchDeletionFailed": "批量刪除失敗"
},
"filters": {
"searchAccountGroup": "搜索賬號分組",
"searchGroupName": "搜索分組名稱",
"filterByGroupStatus": "按分組狀態篩選",
"deleteSelected": "刪除選中 ({count})",
"createGroup": "創建分組"
},
"editor": {
"editDescription": "修改分組信息和請求權限",
"createDescription": "創建後,可在賬號管理中將賬號加入這個分組",
"groupName": "分組名稱",
"forExampleProductionAccount": "例如:生產賬號",
"groupColor": "分組顏色",
"selectGroupColor": "選擇分組顏色",
"fastMode": "快速模式",
"imageGeneration": "圖像生成",
"descriptionOptional": "描述(可選)",
"groupDescription": "分組描述",
"describePurposeOfThisGroup": "說明這個分組的用途",
"saveGroup": "保存分組"
},
"metrics": {
"restricted": "受限",
"total": "總數",
"concurrency": "併發",
"today": "今日",
"cumulative": "累計"
},
"group": "分組",
"fields": {
"capacity": "容量"
},
"page": {
"description": "將賬號歸類管理,併爲每個 API 密鑰指定可使用的賬號",
"empty": "暫無分組",
"selectCurrentPageGroup": "選擇當前頁分組",
"selectGroup": "選擇分組",
"fastModeIsOn": "Fast 已開啓",
"fastModeIsOff": "Fast 已關閉",
"imageGenerationDisabled": "生圖已關閉",
"colorLabel": "分組顏色 {color}",
"batchDeleteWarning": "刪除後這些分組將立即失效,此操作不可撤銷",
"batchDeleteDescription": "確定刪除選中的 {count} 個分組嗎?賬號本身不會被刪除",
"disableAccountGrouping": "禁用賬號分組",
"disableDescription": "禁用後,使用該分組的 API 密鑰將無法再使用其中的賬號",
"confirmDisable": "確認禁用",
"disable": "確定禁用“{name}”嗎?",
"affectedApiKeys": "將影響 {count} 個 API 密鑰:{value}",
"affectedKeys": "將影響 {count} 個 API 密鑰",
"deleteAccountGroup": "刪除賬號分組",
"deleteWarning": "刪除後該分組將立即失效,此操作不可撤銷",
"unnamedGroup": "該分組",
"deleteAccountsWillBeKept": "確定刪除“{name}”嗎?賬號本身不會被刪除"
}
}
}
@@ -0,0 +1,29 @@
import accounts from './accounts.json'
import appearance from './appearance.json'
import auth from './auth.json'
import common from './common.json'
import dashboard from './dashboard.json'
import groups from './groups.json'
import keys from './keys.json'
import navigation from './navigation.json'
import plugins from './plugins.json'
import proxies from './proxies.json'
import settings from './settings.json'
import systemUpdate from './systemUpdate.json'
import usage from './usage.json'
export default {
...accounts,
...appearance,
...auth,
...common,
...dashboard,
...groups,
...keys,
...navigation,
...plugins,
...proxies,
...settings,
...systemUpdate,
...usage,
}
+110
View File
@@ -0,0 +1,110 @@
{
"keys": {
"configuration": {
"description": "保存或合併下方配置後重啓 Codex",
"platform": "配置平臺",
"toggleWebSocket": "切換 WebSocket 配置",
"importCcSwitch": "添加到 CC Switch",
"copiedToClipboard": "已複製到剪貼板",
"fullApiKeyNotAvailable": "完整 API Key 不可用",
"title": "使用密鑰"
},
"actions": {
"editKey": "編輯密鑰",
"useKey": "使用密鑰",
"moreActions": "更多操作",
"resetUsedCredit": "重置用量",
"disableKey": "停用",
"enableKey": "啓用",
"deleteKey": "刪除",
"deletedApiKeyDeletedApiKeys": "已刪除 {count} 個 API Key"
},
"day": "日",
"dailyUsage": "日用量",
"week": "周",
"weeklyUsage": "周用量",
"viewUsageAndCostsFor": "查看 {name} 的費用用量",
"costDetailsTitle": "費用詳情(USD)",
"confirmNextTime": "下次使用時確定",
"budgetReset": {
"dailyQuota": "日額度",
"weeklyQuota": "周額度",
"keyQuotaReset": "已重置密鑰額度",
"description": "清零所選週期的已用金額,下次使用時重新確定重置日期",
"targetKey": "目標密鑰",
"resetScope": "重置範圍",
"currentlyUsed": "當前已用",
"afterReset": "重置後",
"remainUnchanged": "保持不變",
"confirmReset": "確認重置"
},
"created": {
"apiKeyCreated": "API Key 已創建",
"description": "複製密鑰,或直接導入 CCSwitch",
"accessNotice": "該密鑰具有網關訪問權限,請僅發送給可信調用方",
"copyKey": "複製密鑰",
"iHaveSaved": "我已保存"
},
"filters": {
"apiKeyFilteringAndOperations": "API Key 篩選與操作",
"searchPlaceholder": "搜索名稱或標籤",
"searchLabel": "搜索 API Key 名稱或標籤",
"deleteSelected": "刪除選中 ({count})",
"createApiKey": "創建 API Key"
},
"editor": {
"description": "配置密鑰信息、分組與使用限制",
"namePlaceholder": "例如:生產環境",
"labelOptional": "標籤(可選)",
"forExampleBackendService": "例如:後端服務",
"customKeyOptional": "自定義 Key(可選)",
"keyPlaceholder": "留空自動生成",
"upstreamIdentity": "上游身份",
"dailyLimit": "日限額",
"dailyLimitUsd": "日限額(USD)",
"weeklyLimit": "周限額",
"weeklyLimitUsd": "周限額(USD)",
"maximumConcurrency": "最大併發",
"requestsPerMinuteRpm": "每分鐘請求數(RPM)",
"saveChanges": "保存更改",
"updated": "API Key 已更新",
"created": "API Key 已創建",
"validation": {
"amount": "{label}必須是非負金額,最多 10 位小數",
"integer": "{label}必須是非負整數"
},
"enterApiKeyName": "請輸入 API Key 名稱",
"invalidKey": "自定義 Key 只能包含 HTTP 可傳輸的可見字符,不能包含空格或換行",
"requestsPerMinute": "每分鐘請求數"
},
"fields": {
"copyFullKey": "複製完整密鑰",
"allAccounts": "全部賬號",
"keyPrefix": "密鑰前綴",
"quotaUsage": "額度使用",
"requestLimits": "請求限制",
"lastUsed": "最後使用"
},
"page": {
"description": "管理 API 密鑰及賬號訪問範圍",
"noApiKeyYet": "暫無 API Key",
"selectCurrentPageKey": "選擇當前頁密鑰",
"selectKey": "選擇密鑰",
"concurrency": "併發",
"batchDeleteWarning": "刪除後這些 API Key 將立即失效,此操作不可撤銷",
"batchDeleteDescription": "確定刪除選中的 {count} 個 API Key 嗎?",
"deleteApiKey": "刪除 API Key",
"deleteWarning": "刪除後該 API Key 將立即失效,此操作不可撤銷",
"apiKey": "該 API Key",
"delete": "確定刪除 {name} 嗎?"
},
"scope": {
"allAccounts": {
"title": "允許訪問全部賬號",
"summary": "保存後,此密鑰可訪問全部賬號",
"confirm": "允許訪問",
"description": "此密鑰可訪問全部賬號,包括未分組和以後新增的賬號"
}
}
}
}
@@ -0,0 +1,29 @@
{
"navigation": {
"overview": "概覽",
"accounts": "賬號管理",
"proxies": "代理管理",
"groups": "分組管理",
"apiKeys": "API 密鑰",
"usage": "分析統計",
"plugins": "插件",
"appearance": "主題設置",
"settings": "系統設置",
"update": {
"available": "發現新版本,打開系統更新",
"open": "打開系統更新"
},
"switchLanguage": "切換語言({value})",
"mainLabel": "主導航",
"pluginsLabel": "插件導航",
"pluginManagement": "插件管理",
"online": "在線",
"sidebar": {
"close": "關閉側邊欄",
"expand": "展開側邊欄",
"collapse": "收縮側邊欄",
"open": "打開側邊欄"
},
"missingEntryPoint": "未配置 {role} 身份的默認入口"
}
}
@@ -0,0 +1,533 @@
{
"plugins": {
"assets": {
"pluginPackage": "插件包:{name}",
"selectPluginPackage": "選擇插件包",
"packageLabel": "插件包"
},
"bindings": {
"observationHelpTitle": "請求觀察說明",
"observationHelp": "僅觀察請求,不改變請求結果",
"applyToAllRequests": "應用於所有請求",
"scopeHelpTitle": "生效請求範圍說明",
"scopeHelp": "關閉後至少選擇一項範圍,不同條件同時滿足才生效,同一條件內任意一項匹配即可",
"clientKey": "客戶端 Key",
"accountGrouping": "賬號分組",
"modelScope": "模型範圍",
"oneModelNamePerLineExactMatch": "每行一個模型名稱,精確匹配",
"providerScope": "Provider 範圍",
"oneProviderIdentifierPerLine": "每行一個 Provider 標識",
"executionOrder": "執行順序",
"executionSequenceDescription": "執行順序說明",
"priorityHelp": "數值較小的先執行",
"whenPluginFails": "插件失敗時",
"continueToNextHandler": "交給後續處理",
"rejectRequest": "拒絕請求"
},
"capabilities": {
"moreCapabilities": "另有 {count} 項聲明能力"
},
"catalog": {
"cardView": "卡片視圖",
"listView": "列表視圖",
"currentVersion": "當前版本",
"installedVersion": "已安裝版本",
"provideFunctionality": "功能",
"searchForInstalledPlugins": "搜索已安裝插件",
"searchPluginsPublishers": "搜索插件、發佈者",
"pluginStatus": "插件狀態",
"pluginDisplayMode": "插件顯示方式",
"noMatchingPlugins": "沒有匹配的插件",
"installYourFirstPlugin": "安裝第一個插件",
"tryAnotherNameOrStatus": "試試其他名稱或狀態",
"emptyDescription": "從上方安裝插件,請先確認來源可信",
"clearFilters": "清除篩選",
"pluginInstalled": "已安裝插件",
"noDescription": "發佈者未提供說明",
"versions": "{count} 個版本",
"manage": "管理 {displayName}",
"versionCount": "版本數"
},
"configuration": {
"fillInRequiredConfiguration": "請填寫必填配置",
"incompatibleSecrets": "目標版本不支持部分已保存的敏感配置,請選擇替換或清除",
"requiredSecretsCannotClear": "必填敏感配置不能清除:{labels}",
"requiredSecretsMissing": "沒有可保留的必填敏感配置:{labels}",
"secretsRequired": "請填寫必填敏感配置",
"checkBasicSettings": "請檢查基本設置",
"noParameters": "無需填寫插件參數",
"sensitiveConfiguration": "敏感配置",
"secretsHelpTitle": "敏感配置說明",
"secretsHelp": "敏感配置單獨保存,不回顯已有值,選擇保留時不會更改,選擇替換時以本次填寫的全部值覆蓋",
"settingsSaved": "已保存 {count} 項",
"clearSecretsHelp": "保存時清除全部敏感配置",
"about": "{name}說明",
"enterNewValue": "輸入新值",
"pluginParameters": "插件參數",
"advancedSettings": "高級設置",
"clientAuthentication": "客戶端認證",
"applyAndSwitch": "應用並切換",
"saveAndEnable": "保存並啓用",
"saveSettings": "保存設置",
"keepExistingValues": "保留已有值",
"replaceAllValues": "替換全部值",
"clearAllValues": "清除全部值",
"checkPluginParameters": "請檢查插件參數",
"setRequestScopeOrCheckApplyTo": "請設置請求範圍,或勾選“應用於所有請求”",
"invalidIdentityMappings": "請檢查客戶端認證身份映射",
"switchTo": "切換至 {version}",
"pluginSettings": "插件設置",
"unchangedVersion": "當前版本保持不變,修改後再應用",
"pluginSettingsPartition": "插件設置分區",
"secretsModeLabel": "敏感配置保存方式",
"customScope": "自定義範圍",
"applyGlobally": "全局生效",
"requestHandling": "請求處理:{value}",
"description": "按配置提供擴展功能",
"providesTerminalCommands": "提供終端命令",
"requestHandlingNotConfigured": "未配置請求處理",
"apiKeys": "{count} 個 Key",
"groups": "{count} 個分組",
"providers": "{count} 個 Provider",
"identityMappings": "{count} 組身份映射",
"allRequests": "所有請求",
"noLimitOnScope": "不限制範圍",
"featureDetails": "功能詳情",
"capabilitiesOf": "{name} 的功能詳情",
"terminalCommands": "終端命令",
"legacy": {
"multipleEnabledNotice": "檢測到多套啓用配置,請在歷史配置中停用不再使用的一套",
"previousConfigurations": "歷史配置 · {count}",
"description": "保留已有設置和數據,使用歷史配置會替換當前啓用配置",
"disableAction": "停用歷史配置",
"start": "啓動",
"deleteHistoricalConfiguration": "刪除歷史配置"
},
"stale": "插件設置已變更,請刷新後重試",
"incompatible": "請調整不兼容的設置後重試"
},
"details": {
"version": "版本",
"pendingDescription": "配置已保存,等待生效,狀態會自動刷新",
"requiredConfiguration": "補充必填配置後即可啓用",
"versionInUse": "舊版本仍有進行中的調用,完成前暫不能刪除",
"pluginDetails": "插件詳情",
"pluginDetailsSection": "插件詳情分區",
"manualInstallationVersion": "手動安裝版本",
"pluginHasNotBeenInitialized": "插件尚未初始化",
"pluginIsNotInstalled": "插件待安裝",
"initializePlugin": "初始化插件",
"installation": "安裝",
"versionNotAvailable": "版本不可用",
"configurationStatusOf": "{name}配置狀態說明",
"settings": "設置",
"restart": "重新啓動",
"deactivate": "停用",
"completeSetupAndEnable": "完成設置並啓用",
"fallbackVersion": "回退版本",
"uninstallPlugin": "卸載插件"
},
"downloadAuth": {
"accessToken": "訪問令牌",
"usernameAndPassword": "用戶名與密碼",
"customRequestHeader": "自定義請求頭",
"noCertificationRequired": "無需認證",
"fillInGithubToken": "填寫 GitHub 令牌",
"credentialsPlaceholder": "填寫認證信息",
"useSavedCredentials": "使用已保存憑據",
"download": "下載 · {hostname}",
"downloadCertification": "下載認證",
"helpTitle": "下載認證說明",
"githubHelp": "公開倉庫無需認證,私有倉庫需要有讀取權限的 GitHub 令牌",
"urlHelp": "僅在下載地址要求認證時填寫",
"storageHelp": "認證信息在查詢或解析時保存,僅用於當前來源,不會提供給插件",
"authenticationMethod": "認證方式",
"githubToken": "GitHub 令牌",
"downloadToken": "下載令牌",
"enterToken": "輸入令牌",
"username": "用戶名",
"downloadUsername": "下載用戶名",
"password": "密碼",
"downloadPassword": "下載密碼",
"requestHeaderName": "請求頭名稱",
"requestHeaderValue": "請求頭值"
},
"enable": {
"notSet": "未設置",
"switchActiveConfiguration": "切換啓用配置",
"enablePluginConfiguration": "啓用插件配置",
"willBeEnabled": "將啓用",
"configurationsToDisable": "將停用 {count} 項",
"toggleEnablementInstructions": "切換啓用說明",
"disableDescription": "以下配置將停止處理新請求,設置、密鑰與私有數據保留",
"willBeDeactivated": "將停用",
"confirmSwitch": "確認切換",
"confirmEnable": "確認啓用"
},
"extensions": {
"emptyTitle": "暫無插件管理頁面",
"emptyDescription": "啓用帶有管理頁面的插件後,可從此處或側欄進入",
"configuration": "配置 {value}",
"pages": "{count} 頁",
"openPage": "打開頁面"
},
"frontendAuth": {
"exclusiveCertification": "獨佔認證",
"fallbackApiKeyIfNoMatch": "未匹配時回退 API Key",
"disabled": "(已停用)",
"configuredUnavailable": "已配置但當前不可用",
"invalidBinding": "客戶端認證綁定必須使用認證階段和受支持的未匹配處理",
"unsupportedScope": "客戶端認證不支持 Provider、模型或分組範圍,請關閉後重新啓用該綁定",
"addAtLeastOneIdentityMapping": "請添加至少一條身份映射",
"mappingLimit": "身份映射不能超過 256 條",
"invalidIdentity": "身份標識必須是 1–256 個 UTF-8 字節,且不能含首尾空白或控制字符",
"duplicateIdentity": "同一身份標識只能配置一次",
"keyRequired": "請爲每個身份標識選擇客戶端 Key",
"repeatedCursor": "服務返回了重複的分頁位置",
"failedToLoadClientKey": "加載客戶端 Key 失敗",
"enableClientAuthentication": "啓用客戶端認證",
"helpTitle": "客戶端認證說明",
"description": "插件識別請求中的外部身份,宿主再將該身份映射到已有 Client Key,沿用這個 Key 的限額、賬號範圍與併發策略",
"loginNotice": "此功能用於客戶端 API 請求,不替代管理端登錄",
"unmatchedProcessing": "未匹配處理",
"unmatchedHandlingInstructions": "未匹配處理說明",
"exclusiveHelp": "獨佔認證:插件未識別到身份時拒絕請求",
"fallbackToApiKeyWhenNoMatch": "未匹配時回退 API Key:插件未識別到身份時,繼續使用宿主原有的 API Key 認證",
"rejectionHelp": "插件明確拒絕或調用失敗時始終拒絕請求,不會回退",
"unmatchedLabel": "客戶端認證未匹配處理",
"identityMapping": "身份映射",
"identityMappingDescription": "身份映射說明",
"identityHelp": "身份標識必須與插件返回的值完全一致,同一身份只能映射一次",
"keyHelp": "選擇該身份使用的 Client Key,已停用或刪除的 Key 不會獲得執行權限",
"reloadClientKey": "重新加載客戶端 Key",
"addMapping": "添加映射",
"identityMark": "身份標識",
"identityPlaceholder": "填寫插件返回的身份標識",
"failedToLoadTryAgain": "加載失敗,請重試",
"selectClientApiKey": "選擇客戶端 Key",
"noClientKeyYet": "暫無客戶端 Key",
"removeIdentityMapping": "移除第 {value} 條身份映射"
},
"installation": {
"uploadPackage": "上傳包",
"enterDigitHexadecimalDigest": "請輸入 64 位十六進制摘要",
"installNewVersion": "安裝新版本",
"pluginPackageCannotExceedMib": "插件包不能超過 32 MiB",
"verificationRequired": "請先校驗當前選擇的插件包",
"githubRepositoryRequired": "請輸入 GitHub 倉庫鏈接或 owner/repo",
"prereleaseTagRequired": "查詢預發行版需要明確填寫 tag",
"updatePlugin": "更新插件",
"installPlugin": "安裝插件",
"installDescription": "確認來源與版本後安裝",
"switchDescription": "檢查設置兼容性後切換版本",
"sourceHelp": "支持本地插件包、URL 與 GitHub",
"installationMethod": "安裝方式",
"tarGzTgzMaxMib": "tar.gz / tgz,最大 32 MiB",
"replace": "更換",
"browseFiles": "瀏覽文件",
"downloadUrl": "下載 URL",
"downloadAddressDescription": "下載地址說明",
"urlHelp": "僅支持 HTTPS,本機迴環地址可使用 HTTP",
"githubRepository": "GitHub 倉庫",
"repositoryLinkOrOwnerRepo": "倉庫鏈接或 owner/repo",
"tagLabel": "版本標籤",
"tagHelpTitle": "版本標籤說明",
"tagHelp": "留空查詢最新穩定版,查詢預發行版時必須指定標籤",
"tagPlaceholder": "留空查最新穩定版",
"allowPrereleaseLabel": "允許查詢預發行版",
"verificationSummary": "校驗摘要",
"digestHelpTitle": "校驗摘要說明",
"digestHelp": "可選,填寫發佈者提供的 64 位 SHA-256 十六進制摘要,用於覈對下載內容",
"shaChecksum": "SHA-256 校驗摘要",
"optionalSha": "可選,SHA-256",
"versionFound": "已找到版本",
"preRelease": "預發行版",
"thereIsNoTarGzOrTgz": "此版本沒有 tar.gz 或 tgz 插件包",
"pendingTitle": "待安裝插件",
"parsingCompleted": "解析完成",
"publisher": "發佈者",
"applicablePlatforms": "適用平臺",
"trustNotice": "插件可訪問全部網關數據與配置,安裝前請確認來源可信",
"activateAfterInstall": "安裝後確認切換到新版本",
"installNewVersionInstructions": "安裝新版本說明",
"configurationHelp": "沿用設置並補充新版本默認值,需要調整時會打開設置,已使用版本保留恢復設置",
"queryAgain": "重新查詢",
"queryingVersion": "正在查詢版本",
"saveSourceAndContinue": "保存來源並繼續",
"parsingPluginPackage": "正在解析插件包",
"pluginInstallationFailed": "插件安裝失敗",
"noSource": "此插件沒有可用的安裝來源",
"sourceChanged": "安裝來源已變更,請關閉後重新打開",
"sourceSaveFailed": "安裝來源保存失敗",
"githubReleaseQueryFailed": "GitHub Release 查詢失敗",
"installedNeedsConfiguration": "插件已安裝,請補充必要配置",
"preparing": "插件已安裝,正在準備",
"pluginVersionInstalled": "插件版本已安裝",
"updateSourceChanged": "安裝來源已變更,請重新檢查更新",
"pluginUpgradeFailed": "插件升級失敗",
"versionRequired": "請選擇待安裝的插件版本",
"packageMismatch": "插件包與當前插件不符,請重新選擇",
"verificationFailed": "插件包校驗失敗"
},
"management": {
"installed": "已安裝",
"extensions": "擴展頁",
"description": "管理版本、配置與擴展頁",
"tabsLabel": "插件管理分區",
"refresh": "刷新插件",
"switchPluginVersion": "切換插件版本",
"switchHelp": "切換前會檢查目標版本設置,失敗時保留當前版本",
"deletePluginVersion": "刪除插件版本",
"deleteVersionHelp": "使用中的版本不可刪除,刪除版本也會清除對應的恢復設置",
"delete": "刪除 {displayName} {version}?",
"versionDeletionDetails": "版本刪除詳情",
"deleteVersionInUse": "被配置或運行中的調用引用時不能刪除,不會自動停用其他配置",
"deleteVersionCleanupHelp": "只清理此版本獨用的下載認證,刪除最後一個版本時同時清理來源規則,共享認證與代理不受影響",
"deleteVersionCleanupLabel": "同時清理獨用下載認證,最後一版還會清理來源",
"deletePluginConfiguration": "刪除插件配置",
"deleteConfigurationWarning": "配置、密鑰與私有數據將永久刪除",
"deleteConfigurationHelp": "無法恢復,已安裝版本與其他配置不受影響",
"uninstallWarning": "刪除全部版本、配置、密鑰與私有數據",
"confirmUninstall": "確認卸載",
"versionCount": "{displayName} · {count} 個版本",
"uninstallCleanupLabel": "同時清理來源與獨用下載認證",
"uninstallCleanupInstructions": "卸載清理說明",
"uninstallCleanupHelp": "只清理被卸載版本使用且不再被其他版本引用的下載認證,不刪除共享認證、代理或審計記錄",
"disableInsteadHelp": "暫時不用可停用配置,無需卸載",
"permanentDeleteLabel": "確認永久刪除,無法恢復",
"deleteDownloadCredentials": "刪除下載認證",
"itCannotBeDeletedWhileItIs": "仍被使用時不可刪除,刪除後無法恢復",
"pageLoadFailed": "插件擴展頁加載失敗",
"pluginDataLoadingFailed": "插件數據加載失敗"
},
"frame": {
"pluginPageCannotBeLoaded": "插件頁面無法加載",
"versionChanged": "插件頁面版本已變更,正在刷新",
"navigationBlocked": "插件頁面嘗試離開已隔離的管理文檔,已停止加載",
"invalidQueryParameter": "查詢參數無效",
"queryParametersExceedKib": "查詢參數超過 8 KiB",
"invalidBody": "請求正文無效或超過 1 MiB",
"routesDoNotAcceptRequestBody": "{method} 路由不接受請求正文",
"contentTypeIsInvalid": "Content-Type 無效",
"unregisteredContentType": "Content-Type 未在插件路由中註冊",
"contentTypeRequired": "包含正文的請求必須聲明 Content-Type",
"invalidRequestParameters": "請求參數無效",
"unregisteredRequest": "請求未在當前插件版本中註冊",
"invalidCallbackTicket": "回調票據參數無效",
"unregisteredCallback": "回調路徑未在當前插件版本中註冊",
"invalidTicketLifetime": "回調票據有效期必須爲 1 到 600 秒",
"invalidModelRequest": "模型請求參數無效",
"clientkeyidIsInvalid": "clientKeyId 無效",
"invalidModelBody": "Responses 請求正文無效或超過 8 MiB",
"invalidModelJson": "Responses 請求正文不是有效 JSON",
"modelObjectRequired": "Responses 請求正文必須是 JSON 對象",
"pageDidNotContinueToReadModel": "頁面 30 秒未繼續讀取模型響應",
"modelConcurrencyLimit": "模型請求已達併發上限",
"duplicateModelRequest": "模型請求序號重複",
"modelTimeout": "模型請求超過 10 分鐘",
"unsupportedModelContentType": "模型接口返回了不受支持的內容類型",
"modelRequestFailed": "模型請求失敗",
"invalidPullId": "模型響應拉取序號無效",
"concurrentPull": "模型響應拉取發生重入",
"stalePullId": "模型響應拉取序號已失效",
"modelResponseReadFailed": "模型響應讀取失敗",
"duplicateManagementRequest": "插件管理請求序號重複",
"managementConcurrencyLimit": "插件管理請求已達併發上限",
"invalidEntryPoint": "插件頁面入口不是已註冊的 HTML 資源",
"unregisteredAsset": "插件頁面引用了未註冊資源:{path}",
"htmlSubresource": "插件 HTML 資源不能作爲子資源加載",
"cyclicCss": "插件 CSS 資源存在循環引用:{path}",
"invalidVersion": "插件頁面版本無效,請刷新後重試",
"resourceCountLimit": "插件頁面資源數量超過限制",
"pageChanged": "插件頁面已變更,請刷新後重試",
"pluginAssetReturnedHttp": "插件資源返回 HTTP {status}",
"resourceTypeMismatch": "插件資源類型與註冊值不一致:{path}",
"pluginAssetExceedsMib": "插件資源超過 1 MiB:{path}",
"resourceSizeLimit": "插件頁面資源總量超過 8 MiB",
"unsupportedElement": "插件頁面使用了不受支持的 {'<'}{value}{'>'} 元素",
"redirectForbidden": "插件頁面不能使用自動跳轉",
"moduleScriptUnsupported": "插件頁面暫不支持 ES Module 腳本,請使用經典腳本包",
"invalidPluginScriptAssetType": "插件腳本資源類型無效:{path}",
"unsupportedLink": "插件頁面只支持 stylesheet 和 icon 鏈接資源",
"invalidStylesheet": "插件樣式資源類型無效:{path}",
"invalidPluginIconAssetType": "插件圖標資源類型無效:{path}",
"unsupportedSrc": "插件頁面不支持 {'<'}{value}{'>'} 的 src 加載",
"invalidPluginImageAssetType": "插件圖像資源類型無效:{path}",
"invalidPluginPosterAssetType": "插件 poster 資源類型無效:{path}",
"emptySrcset": "插件 srcset 資源引用爲空",
"externalNavigation": "插件頁面不能導航到外部或未註冊地址",
"pluginPageDoesNotSupportUrls": "插件頁面不支持 {name} 地址",
"externalAttribute": "插件頁面屬性不能引用外部資源:{name}",
"unsupportedPluginCssSyntax": "插件 CSS 語法不受支持:{ownerPath}",
"invalidCss": "插件 CSS 包含無法解析的內容:{ownerPath}",
"escapedCssIdentifier": "插件 CSS 規則或函數名不能使用轉義:{ownerPath}",
"inlineStyleImport": "內聯 style 屬性不能導入樣式表",
"unsupportedPluginImportSyntax": "插件 {'@'}import 語法不受支持:{ownerPath}",
"pluginImportTargetIsNotCss": "插件 {'@'}import 目標不是 CSS:{path}",
"unsupportedPluginAssetUrl": "插件資源地址不受支持:{rawReference}",
"resourceQuery": "插件資源地址不支持查詢參數:{rawReference}",
"resourceFragment": "插件資源地址不支持片段標識:{rawReference}",
"resourceOutsideArtifact": "插件資源地址越過製品邊界:{rawReference}",
"invalidPluginAssetPathSegment": "插件資源路徑片段無效:{rawReference}",
"invalidResourcePath": "插件註冊了無效資源路徑:{path}",
"pluginTextAssetIsNotValidUtf": "插件文本資源不是有效 UTF-8:{path}"
},
"pluginPage": "插件頁面",
"page": {
"configurationDescription": "使用插件提供的功能,當前配置爲「{name}」",
"description": "加載已啓用插件的管理頁面",
"unpublished": "該配置或頁面未發佈,可能已停用或切換版本",
"refreshFailed": "頁面目錄刷新失敗,當前顯示上次成功加載的版本:{loadError}",
"loadingPage": "正在加載頁面"
},
"refreshPage": "刷新頁面",
"pluginPageIsUnavailable": "插件頁面不可用",
"returnToPluginManagement": "返回插件管理",
"resources": {
"unavailable": "不可用 · {id}",
"multipleSelectionsAllowed": "{label}(可多選)",
"unlimitedPlaceholder": "不限(可多選)",
"loading": "正在加載…",
"isTemporarilyUnavailable": "暫時無法獲取{label}",
"noMatches": "沒有匹配項",
"no": "暫無{label}",
"createOneInFirst": "請先在{value}中創建"
},
"rollback": {
"rollBackPluginVersion": "回退插件版本",
"description": "恢復對應版本的設置,保持當前啓停狀態",
"targetVersion": "目標版本",
"fallbackInstructions": "回退說明",
"restoreHelp": "恢復目標版本上次啓用時的參數和密鑰,私有數據仍須通過兼容檢查",
"loadingOlderVersions": "正在加載舊版",
"selectRollbackVersion": "請選擇回退目標",
"rollBackToTargetVersion": "回退目標版本",
"empty": "沒有保留恢復設置的舊版,其他版本可在“版本”中切換",
"reload": "重新加載",
"confirmRollback": "確認回退",
"completed": "已回退至 {version},並恢復對應設置"
},
"sourceProxy": {
"noProxyDirectConnection": "不使用代理(直連)",
"disabledSuffix": "(已禁用)",
"catalogUnavailable": "已選代理(目錄暫不可用)",
"label": "下載代理"
},
"status": {
"unableToStart": "無法啓動",
"runFailed": "運行失敗",
"compatibilityReminder": "兼容性提醒",
"deprecatedApi": "接口待升級,當前仍兼容",
"startupUnverified": "可以嘗試啓動,運行結果仍需驗證",
"compatibilityWindow": "舊接口還將兼容至少 {remainingReleases} 個正式版本",
"compatibilityEnding": "兼容窗口已滿,後續正式版本將移除舊接口轉換",
"unsupportedVersionHelp": "配置與數據保留,請安裝可加載的插件版本",
"restartHelp": "啓用配置保留,可在插件詳情中重新啓動",
"upgradeHelp": "請更新插件,或聯繫作者升級接口"
},
"updates": {
"packageRequired": "請選擇插件包以確認版本與兼容性",
"currentlyUsingThisVersion": "當前已使用此版本",
"verifiedUpdate": "發現新版本,插件包已校驗",
"sameVersionDifferentContent": "版本號相同,插件包內容不同",
"noHigherVersionFound": "未發現更高版本",
"pluginUpdate": "插件更新",
"checkingDescription": "正在檢查版本並校驗插件包",
"versionComparison": "版本對比",
"postTag": "發佈標籤",
"updateInspectionInstructions": "更新檢查說明",
"configurationHelp": "按插件包內版本判斷升級,沿用當前設置,配置不兼容時保留當前版本並打開設置",
"trustNotice": "插件可訪問全部網關數據與配置,更新前請確認來源可信",
"thereIsNoTarGzOrTgzPlugin": "此發佈沒有 tar.gz 或 tgz 插件包",
"upgradeTo": "升級到 {version}",
"continueInstallation": "繼續安裝",
"unsupportedSource": "此來源不支持檢查更新,請安裝新版本",
"sourceChanged": "安裝來源已變更,請重新檢查",
"checkForUpdatesFailed": "檢查更新失敗"
},
"versionDetails": "版本詳情",
"toBeInstalled": "待安裝",
"historicalConfiguration": "歷史配置",
"referenceConfiguration": "引用配置",
"versions": {
"detailsLabel": "{version} 版本詳情",
"historicalVersion": "歷史版本"
},
"install": "安裝 {version}",
"deleteVersion": "刪除版本 {version}",
"credentials": {
"selectDownloadCredentials": "選擇下載認證 {name}",
"deleteDownloadCredentials": "刪除下載認證 {name}",
"saveDownloadCredentialsFailed": "下載認證保存失敗",
"sourceCredentialsDeleted": "來源憑據已刪除",
"deleteFailed": "來源憑據刪除失敗"
},
"artifacts": {
"pluginProductHasBeenDeleted": "插件製品已刪除",
"pluginProductDeletionFailed": "插件製品刪除失敗"
},
"instances": {
"saveFailed": "插件配置保存失敗",
"versionMissing": "所選版本已不存在,請重新選擇",
"loadFailed": "啓用配置加載失敗",
"configurationEnablementFailed": "配置啓用失敗",
"switchedCurrentConfiguration": "已切換當前配置",
"pluginSettingsApplied": "插件設置已應用",
"savedDisabled": "設置已保存,插件保持停用",
"pluginDisabled": "插件已停用",
"pluginDeactivationFailed": "插件停用失敗",
"deleted": "配置、密鑰與私有數據已刪除,無法恢復",
"pluginInstanceDeletionFailed": "插件實例刪除失敗"
},
"uninstall": {
"newConfiguration": "出現了新的插件配置,請關閉並重新確認卸載範圍",
"versionChanged": "“{name}”已切換版本,請重新確認卸載範圍",
"removingConfiguration": "正在停用並刪除配置:{name}",
"newVersion": "已刪除確認範圍,但還有新安裝的版本,請關閉並重新確認剩餘內容",
"completed": "插件已卸載,相關數據與來源設置已清理",
"incomplete": "卸載尚未完成,可重試剩餘步驟"
},
"deletingVersion": "正在刪除版本:{version}",
"switchedTo": "已切換至 {version}",
"versionSettingFailedToLoad": "版本設置加載失敗",
"versionSwitchingFailed": "版本切換失敗",
"fallbackVersionLoadingFailed": "回退版本加載失敗",
"pluginVersionRollbackFailed": "插件版本回退失敗",
"fields": {
"requestCompletionAndUsage": "請求完成與用量",
"upstreamWebsocketEvents": "上游 WebSocket 事件",
"requestScheduling": "請求調度",
"modelRouting": "模型路由",
"modelCatalog": "模型目錄",
"retryStrategy": "重試策略",
"requestMiddleware": "請求中間件",
"upstreamAdapter": "上游適配器",
"eventObservation": "事件觀察",
"commandLine": "命令行",
"manageExtensions": "管理擴展",
"maintenanceTasks": "維護任務",
"httpRequest": "HTTP 請求",
"allHttpRequests": "所有 HTTP 請求",
"websocketMessages": "WebSocket 消息",
"allWebsocketMessages": "所有 WebSocket 消息",
"serviceCall": "服務調用",
"allServiceCalls": "所有服務調用",
"requestToStart": "請求開始",
"everyTry": "每次嘗試",
"upstreamCall": "上游調用",
"accountScheduling": "賬號調度",
"retryDecision": "重試決策",
"toBeConfigured": "待配置",
"deactivated": "已停用",
"waitingForItToTakeEffect": "等待生效"
},
"validation": {
"suppliedWithVersion": "隨版本提供",
"localUpload": "本地上傳",
"fixedUrl": "固定 URL",
"releaseList": "發行清單",
"noRemoteUpdateSource": "無遠程更新來源"
},
"onePerLine": "每行一項"
}
}
@@ -0,0 +1,165 @@
{
"proxies": {
"accounts": {
"platformType": "平臺",
"subscription": "訂閱",
"noMatches": "沒有找到匹配的賬號,請嘗試其他名稱或郵箱",
"empty": "暫無關聯賬號",
"linkAccount": "關聯賬號",
"searchAssociatedAccounts": "搜索關聯賬號",
"searchAccountNameOrEmail": "搜索賬號名稱或郵箱",
"removeAction": "從當前代理移除賬號",
"removeAssociatedAccount": "移除關聯賬號",
"remove": "移除",
"removeDescription": "將“{name}”從“{removeProxyName}”移除後,該賬號將改爲直連",
"removed": "賬號已移出當前代理,改爲直連"
},
"actions": {
"test": "測試代理",
"edit": "編輯代理",
"moreActionsFor": "{name} 的更多操作",
"disableProxy": "禁用代理",
"enableProxy": "啓用代理",
"deleteProxy": "刪除代理",
"testInProgress": "代理正在測試,請等待當前測試結束",
"testFailed": "代理測試失敗",
"connectedWithDetails": "{name}:連接成功,{message}",
"timeZoneMismatch": "{name}:連接成功,IPv4 與 IPv6 出口時區不一致",
"connected": "{name}:連接成功",
"fillInProxyConnectionAddress": "請填寫代理連接地址",
"connectedInMs": "連接成功,耗時 {latencyMs} ms",
"locationFailed": "代理連接失敗,未能解析位置",
"exitLocationFilledIn": "已填入出口位置",
"unableToObtainExitLocation": "未獲取到出口位置",
"fieldsRequired": "請填寫代理名稱和連接地址",
"invalidConnectionLimit": "連接上限須爲 0 到 4294967295 之間的整數",
"saved": "代理已保存",
"proxyEnabled": "代理已啓用",
"disabled": "代理已禁用,關聯賬號已改爲直連",
"deleted": "代理已刪除"
},
"batchCreate": {
"proxyList": "代理列表",
"formatDescription": "代理列表格式說明",
"supportedFormats": "支持以下格式",
"hostPortUsernamePassword": "host:port:用戶名:密碼",
"httpUsernamePasswordHostPort": "http://用戶名:密碼{'@'}host:port",
"protocolHelp": "未寫協議時使用下方默認協議,完整 URL 保留各自協議",
"ipv6Help": "IPv6 地址需加方括號,例如",
"onePerLineMaximum": "每行一條 · 最多 {value} 條",
"bulkProxyList": "批量代理列表",
"totalReadyToAdd": "共 {count} 條,{count2} 條可添加",
"needsChanges": ",{count} 條需修改",
"line": "第 {line} 行:{error}",
"additionalIssues": "另有 {count} 條需處理",
"defaultProtocol": "默認協議",
"defaultProtocolLabel": "無協議代理的默認協議",
"namePrefix": "名稱前綴",
"proxy": "代理",
"conflict": "代理已存在或配置衝突,未覆蓋已有記錄",
"stopped": "已停止後續添加"
},
"batchTest": {
"resultsTitle": "批量添加結果",
"processed": "已處理",
"added": "已添加 {created}",
"invalidFormat": "格式錯誤 {invalid}",
"connected": "連接正常 {succeeded}",
"connectionFailed": "連接失敗 {failed}",
"locationPending": "地區待處理 {locationPending}",
"needsAttention": "需處理 {attention}",
"skipped": "未執行 {skipped}",
"scrollListOfProxyResults": "代理結果滾動列表",
"lineNumber": "第 {key} 行",
"addedStatus": "已添加",
"connectionIsNormal": "連接正常",
"stopped": "已停止後續測試",
"proxyMissing": "所選代理已不存在,請刷新列表",
"batchTestCompletedConnected": "批量測試完成,連接正常 {succeeded} 條",
"unsuccessful": "未成功 {count} 條",
"locationsPending": "地區待處理 {locationPending} 條",
"proxiesNoLongerAvailable": "{missing} 條代理已不存在",
"toBeExecuted": "待執行",
"requestFailed": "請求失敗",
"configurationConflict": "配置衝突",
"testingIsBusy": "測試繁忙",
"resultToBeConfirmed": "結果待確認",
"notExecuted": "未執行",
"invalidProxyFormat": "代理格式不正確",
"invalidAddress": "代理主機或端口不合法",
"duplicateOfLine": "與第 {earlier} 行重複",
"formatHelp": "格式不正確,請參考格式說明",
"proxyListCannotExceedKib": "代理列表不能超過 512 KiB",
"addUpToProxiesAtTime": "一次最多添加 {value} 條代理",
"resultUnknown": "未取得確定結果,請刷新列表覈對",
"interrupted": "請求中斷或服務異常,請刷新列表覈對結果",
"skippedAfterFailure": "前序操作異常,未執行"
},
"editor": {
"single": "單條",
"batch": "批量",
"timeZoneMismatch": "IPv4 與 IPv6 出口時區不一致,請手動填寫",
"createTitle": "新增代理",
"connectionHelp": "留空保留當前連接和認證信息,填寫新地址時,請包含所需的用戶名和密碼",
"protocolHelp": "支持 HTTP、HTTPS、SOCKS5 和 SOCKS5H,可在地址中包含用戶名和密碼",
"createDescription": "添加代理,爲賬號配置網絡出口",
"methodLabel": "代理添加方式",
"nameLabel": "代理名稱",
"namePlaceholder": "請輸入代理名稱",
"proxyAddress": "代理地址",
"addressPlaceholder": "輸入代理地址",
"upstreamWsConnectionCap": "上游 WS 連接上限",
"connectionLimitHelp": "使用此代理的賬號共享連接額度",
"noRestrictionsByDefault": "默認不限制",
"customTimeZoneLocation": "自定義時區位置",
"affectedAccounts": "將更新 {count} 個關聯賬號的出口",
"pendingResultsHelp": "待確認項可能已保存,繼續添加前請刷新覈對",
"saveAction": "保存代理",
"waitForCurrentOperationToEnd": "等待當前操作結束",
"stopSubsequentOperations": "停止後續操作",
"testing": "正在測試",
"adding": "正在添加",
"editItemsNotAdded": "修改未添加項",
"testAddedProxies": "測試已添加的 {count} 條",
"testAfterAdding": "添加後測試",
"add": "添加 {count} 條",
"addProxy": "添加代理"
},
"region": {
"connectionFailed": "連接失敗",
"regionalConflict": "地區衝突",
"parsingFailed": "解析失敗",
"exitNotRecognized": "出口未識別",
"ipv4AndIpv6EgressTimeZonesAre": "IPv4 與 IPv6 出口時區不一致",
"exitLocation": "出口地區:{label} · {timezone}",
"detectHelp": "測試代理時解析出口地區",
"customLocation": "自定義位置:{customLabel} · {timezone}",
"custom": "自定義:{customLabel}"
},
"fields": {
"exitIp": "出口 IP",
"latency": "耗時",
"testTime": "測試時間"
},
"page": {
"description": "管理賬號使用的代理,測試連接並查看出口 IP",
"searchLabel": "搜索代理",
"searchPlaceholder": "搜索代理名稱",
"batchTestAction": "批量測試代理",
"batchTest": "批量測試 ({count})",
"noMatches": "沒有找到匹配的代理,請嘗試其他名稱",
"empty": "暫無代理",
"selectCurrentPageProxy": "選擇當前頁代理",
"selectProxy": "選擇代理 {name}",
"credentialsSaved": "代理憑據已保存",
"underTest": "測試中",
"ms": "{message}(耗時 {latencyMs} ms)",
"notTested": "未測試",
"viewAccountsAssociatedWith": "查看 {name} 的 {count} 個關聯賬號",
"disable": "確定禁用“{name}”嗎?",
"disableDescription": "關聯賬號的新請求將改爲直連,代理配置和綁定會保留,重新啓用後恢復使用",
"delete": "確定刪除“{name}”嗎?",
"deleteDescription": "將自動解除關聯賬號,關聯賬號的新請求將改爲直連"
}
}
}

Some files were not shown because too many files have changed in this diff Show More