- | {item.info.email || item.account.name} |
+ {item.info.email || item.account.name} |
{formatPlanLabel(item.info.plan_type) || '—'} |
{item.info.has_refresh_token
diff --git a/src/components/AddRouteModal.tsx b/src/components/AddRouteModal.tsx
index d157ce9..1e9dde0 100644
--- a/src/components/AddRouteModal.tsx
+++ b/src/components/AddRouteModal.tsx
@@ -321,12 +321,12 @@ export function AddRouteModal({ isOpen, accounts, onClose, onSuccess }: AddRoute
{s.model}
)}
-
+
{basename(s.cwd) || '—'}
{s.first_user_text && (
-
+
{truncate(s.first_user_text, 80)}
)}
@@ -386,7 +386,7 @@ export function AddRouteModal({ isOpen, accounts, onClose, onSuccess }: AddRoute
onClick={() => setSelectedAccountId(a.id)}
>
-
+
{a.name}
{badge.label}
diff --git a/src/components/CachePanel.tsx b/src/components/CachePanel.tsx
index cf26abb..6f1c5f8 100644
--- a/src/components/CachePanel.tsx
+++ b/src/components/CachePanel.tsx
@@ -325,7 +325,7 @@ export default function CachePanel({ accounts }: Props) {
{perAccount.map(a => (
- | {a.name} |
+ {a.name} |
{a.requests} |
{formatTokens(a.input)} |
{formatTokens(a.cached)} |
@@ -368,7 +368,7 @@ export default function CachePanel({ accounts }: Props) {
: b.session_key}
- {accountNameById[b.account_id] || b.account_id}
+ {accountNameById[b.account_id] || b.account_id}
|
{b.hit_count} |
{formatTokens(b.total_cached_tokens)} |
diff --git a/src/components/Dashboard.tsx b/src/components/Dashboard.tsx
index e4f5196..cfa9344 100644
--- a/src/components/Dashboard.tsx
+++ b/src/components/Dashboard.tsx
@@ -78,7 +78,7 @@ export function Dashboard({
{/* 问候语 */}
- 你好, {currentAccount?.name.split('@')[0] || '用户'} 👋
+ 你好, {currentAccount?.name.split('@')[0] || '用户'} 👋
@@ -92,8 +92,8 @@ export function Dashboard({
📱
手机锚生效:
- Codex.app 仍以 {anchorAccount.name} 身份在线(手机 bridge 不掉线),
- 代理出口已切到 {currentAccount?.name}。
+ Codex.app 仍以 {anchorAccount.name} 身份在线(手机 bridge 不掉线),
+ 代理出口已切到 {currentAccount?.name}。
@@ -147,7 +147,7 @@ export function Dashboard({
✉
- {currentAccount.name}
+ {currentAccount.name}
{usage?.plan_type && (
{formatPlanLabel(usage.plan_type)}
)}
diff --git a/src/components/ReferralInviteModal.tsx b/src/components/ReferralInviteModal.tsx
index d26bfe7..3cdfd8b 100644
--- a/src/components/ReferralInviteModal.tsx
+++ b/src/components/ReferralInviteModal.tsx
@@ -95,7 +95,7 @@ export function ReferralInviteModal({ id, name, program: initialProgram, onClose
发邀账号
- {name}
+ {name}
{referralProgramLabel(program)}
diff --git a/src/components/RelayImportConfirm.tsx b/src/components/RelayImportConfirm.tsx
index c0f685e..a5d771f 100644
--- a/src/components/RelayImportConfirm.tsx
+++ b/src/components/RelayImportConfirm.tsx
@@ -80,7 +80,7 @@ export function RelayImportConfirm() {
| 名称 |
- {pending.name} |
+ {pending.name} |
| Base URL |
diff --git a/src/components/SessionRoutes.tsx b/src/components/SessionRoutes.tsx
index a70e657..446c499 100644
--- a/src/components/SessionRoutes.tsx
+++ b/src/components/SessionRoutes.tsx
@@ -215,7 +215,7 @@ export function SessionRoutes() {
/>
-
+
{label}
@@ -251,7 +251,7 @@ export function SessionRoutes() {
→
{acc ? (
<>
- {acc.name}
+ {acc.name}
{badge && {badge.label}}
>
) : (
@@ -328,7 +328,7 @@ export function SessionRoutes() {
title="确认删除路由"
message={
<>
- 确认删除路由「{deleteTarget?.label || shortSessionId(deleteTarget?.session_id ?? '')}」?
+ 确认删除路由「{deleteTarget?.label || shortSessionId(deleteTarget?.session_id ?? '')}」?
删除后该 session 将恢复全局自动切号。
diff --git a/src/components/Settings.tsx b/src/components/Settings.tsx
index b5de5cc..1b50be0 100644
--- a/src/components/Settings.tsx
+++ b/src/components/Settings.tsx
@@ -735,7 +735,7 @@ export function Settings({ accounts = [], onSetSessionAnchor }: SettingsProps =
{anchorAccount ? (
<>
- 📱 {anchorAccount.name}
+ 📱 {anchorAccount.name}
{anchorAccount.cached_quota?.plan_type
? formatPlanLabel(anchorAccount.cached_quota.plan_type)
@@ -831,7 +831,7 @@ export function Settings({ accounts = [], onSetSessionAnchor }: SettingsProps =
onClick={() => handleBindAnchor(acc.id)}
disabled={anchorBusy || acc.is_session_anchor}
>
- {acc.name}
+ {acc.name}
{planLabel}
{acc.is_session_anchor && (
✓ 当前绑定
diff --git a/src/components/Skills.tsx b/src/components/Skills.tsx
index 72f9192..61c6b4d 100644
--- a/src/components/Skills.tsx
+++ b/src/components/Skills.tsx
@@ -315,11 +315,11 @@ export function Skills() {
) : filtered.map(skill => (
handleOpenDetail(skill)} style={{ cursor: 'pointer' }}>
- {skill.name}
- {skill.description || '无描述'}
+ {skill.name}
+ {skill.description || '无描述'}
{skill.source === 'github' && skill.repo_owner && (
- {skill.repo_owner}/{skill.repo_name}
+ {skill.repo_owner}/{skill.repo_name}
)}
{skill.source === 'local' && 本地}
@@ -347,10 +347,10 @@ export function Skills() {
{filteredDiscover.map(skill => (
- {skill.name}
- {skill.description || '无描述'}
+ {skill.name}
+ {skill.description || '无描述'}
- {skill.repo_owner}/{skill.repo_name}
+ {skill.repo_owner}/{skill.repo_name}
{skill.installed ? (
@@ -376,7 +376,7 @@ export function Skills() {
{repos.map(repo => (
- {repo.owner}/{repo.name}
+ {repo.owner}/{repo.name}
{repo.branch}
- 即将卸载 {confirmDelete.name},此操作将从所有 CLI 目录移除该 skill。
+ 即将卸载 {confirmDelete.name},此操作将从所有 CLI 目录移除该 skill。
请输入 skill 名称 {confirmDelete.name} 以确认:
@@ -445,8 +445,8 @@ export function Skills() {
e.stopPropagation()}>
- {detailSkill.name}
- {detailSkill.description}
+ {detailSkill.name}
+ {detailSkill.description}
diff --git a/src/components/Stats.tsx b/src/components/Stats.tsx
index d3669d9..e7d568f 100644
--- a/src/components/Stats.tsx
+++ b/src/components/Stats.tsx
@@ -397,7 +397,7 @@ export function Stats() {
{acc.is_banned && 封}
{acc.is_token_invalid && 失效}
{formatPlanLabel(acc.plan_type) || '—'}
- {acc.email}
+ {acc.email}
diff --git a/src/components/TrayPopup.tsx b/src/components/TrayPopup.tsx
index c958464..b821e2e 100644
--- a/src/components/TrayPopup.tsx
+++ b/src/components/TrayPopup.tsx
@@ -186,7 +186,7 @@ export function TrayPopup() {
{/* Account */}
{data?.account && (
- {data.account.name}
+ {data.account.name}
{formatPlanLabel(q?.plan_type) || '-'}
{data.account.is_banned && 封号}
{data.account.is_logged_out && !data.account.is_banned && 需重登}
@@ -199,7 +199,7 @@ export function TrayPopup() {
📱
- 手机锚 {data.anchor.name} · 代理出口 {data.account?.name}
+ 手机锚 {data.anchor.name} · 代理出口 {data.account?.name}
)}
diff --git a/src/i18n/index.ts b/src/i18n/index.ts
new file mode 100644
index 0000000..ca67504
--- /dev/null
+++ b/src/i18n/index.ts
@@ -0,0 +1,32 @@
+import { russianLocale } from './ru';
+import { installUiLocale } from './runtime';
+
+const locales = new Map([
+ ['ru', russianLocale],
+]);
+
+export type AppLocaleCode = 'ru' | 'zh-CN';
+
+function requestedLocale(): string {
+ return (navigator.language || 'zh-CN').toLowerCase();
+}
+
+export function resolveAppLocale(language: string): AppLocaleCode {
+ const normalized = language.toLowerCase();
+ return [...locales.keys()].some(code => normalized.startsWith(code)) ? 'ru' : 'zh-CN';
+}
+
+// Chinese remains the source language and the fallback for unsupported locales.
+export function installAppLocale(systemLocale?: string): AppLocaleCode {
+ const language = systemLocale ?? requestedLocale();
+ const localeCode = resolveAppLocale(language);
+ const locale = localeCode === 'ru' ? russianLocale : undefined;
+ if (locale) {
+ installUiLocale(locale);
+ return localeCode;
+ } else {
+ document.documentElement.lang = 'zh-CN';
+ document.title = 'Codex Switcher';
+ return 'zh-CN';
+ }
+}
diff --git a/src/i18n/ru.ts b/src/i18n/ru.ts
new file mode 100644
index 0000000..5db97d5
--- /dev/null
+++ b/src/i18n/ru.ts
@@ -0,0 +1,1770 @@
+import type { UiLocale } from './runtime';
+
+type Replacement = readonly [source: string, target: string];
+
+const replacements: Replacement[] = [
+ ['Turn-State 被动观测', 'Пассивное наблюдение Turn-State'],
+ ['响应头观测', 'Наблюдения заголовков ответа'],
+ ['292 正常', '292: нормальная форма'],
+ ['312/356 受限形状', '312/356: ограниченная форма'],
+ ['未知/异常', 'Неизвестно / аномалия'],
+ ['仅读取上游响应头,不主动探测、不注入、不重放;长度和时间判断是经验性观测,不代表官方质量指标。', 'Читаются только заголовки ответа сервера, без активных проверок, внедрения или повторной отправки. Оценка длины и времени основана на наблюдениях и не является официальной метрикой качества.'],
+ ['账号 / 模型', 'Аккаунт / модель'],
+ ['形状', 'Форма'],
+ ['时间状态', 'Состояние времени'],
+ ['WS 握手', 'Рукопожатие WS'],
+ ['HTTP 响应', 'Ответ HTTP'],
+ ['代理启动后,收到官方 ChatGPT HTTP/SSE 或 WebSocket 握手响应头才会出现观测。', 'После запуска прокси наблюдения появятся при получении заголовков ответа HTTP/SSE или рукопожатия WebSocket от ChatGPT.'],
+ ['受限', 'Ограничено'],
+ ['格式错误', 'Ошибка формата'],
+ ['未知封装', 'Неизвестный формат упаковки'],
+ ['其他长度', 'Другая длина'],
+ ['OAuth 回调任务锁异常', 'Ошибка блокировки задачи обратного вызова OAuth'],
+ ['OpenAI 授权已超时,请重新发起登录。', 'Время авторизации OpenAI истекло. Начните вход заново.'],
+ ['无法监听 OpenAI 授权回调: {}', 'Не удалось прослушать обратный вызов авторизации OpenAI: {}'],
+ // Messages returned by the Tauri backend. Placeholders are matched at runtime.
+ ['模型列表请求失败: {}', 'Не удалось запросить список моделей: {}'],
+ ['模型列表 JSON 解析失败: {}', 'Не удалось разобрать JSON списка моделей: {}'],
+ ['上游拒绝了模型列表请求', 'Upstream отклонил запрос списка моделей'],
+ ['上游模型列表为空或响应格式不识别', 'Список моделей upstream пуст или имеет неизвестный формат'],
+ ['中转账号不可用', 'Relay-аккаунт недоступен'],
+ ['请先配置此中转的模型 ID', 'Сначала укажите ID модели для этого relay'],
+ ['该账号未配置这个模型', 'Эта модель не настроена для аккаунта'],
+ ['设置文件权限失败: {}', 'Не удалось задать права файла: {}'],
+ ['设置目录权限失败: {}', 'Не удалось задать права каталога: {}'],
+ ['写入文件失败: {}', 'Не удалось записать файл: {}'],
+ ['Google 账号不存在', 'Google-аккаунт не найден'],
+ ['只能选择 Google Antigravity 账号', 'Можно выбрать только аккаунт Google Antigravity'],
+ ['Google 账号不可用,请先重新授权', 'Google-аккаунт недоступен; сначала повторите авторизацию'],
+ ['创建目录失败: {}', 'Не удалось создать каталог: {}'],
+ ['序列化失败: {}', 'Не удалось сериализовать данные: {}'],
+ ['读取 auth.json 失败: {}', 'Не удалось прочитать auth.json: {}'],
+ ['解析 auth.json 失败: {}', 'Не удалось разобрать auth.json: {}'],
+ ['写入临时文件失败: {}', 'Не удалось записать временный файл: {}'],
+ ['重命名文件失败 (Atomic Write): {}', 'Не удалось атомарно переименовать файл: {}'],
+ ['账号不存在: {}', 'Аккаунт не найден: {}'],
+ ['导出失败: {}', 'Не удалось экспортировать: {}'],
+ ['导入失败: {}', 'Не удалось импортировать: {}'],
+ ['Base64 解码失败: {}', 'Не удалось декодировать Base64: {}'],
+ ['base64 解码失败: {}', 'Не удалось декодировать base64: {}'],
+ ['UTF-8 转换失败: {}', 'Не удалось преобразовать в UTF-8: {}'],
+ ['JSON 解析失败: {}', 'Не удалось разобрать JSON: {}'],
+ ['无法定位 Windows 系统目录', 'Не удалось найти системный каталог Windows'],
+ ['无法启动剪贴板工具: {}', 'Не удалось запустить средство буфера обмена: {}'],
+ ['剪贴板输入不可写', 'Буфер обмена недоступен для записи'],
+ ['写入剪贴板失败: {}', 'Не удалось записать в буфер обмена: {}'],
+ ['等待剪贴板工具失败: {}', 'Ошибка ожидания средства буфера обмена: {}'],
+ ['剪贴板工具退出失败: {}', 'Средство буфера обмена завершилось с ошибкой: {}'],
+ ['剪贴板写入超时,请手动复制', 'Истекло время записи в буфер обмена; скопируйте вручную'],
+ ['创建临时文件失败: {}', 'Не удалось создать временный файл: {}'],
+ ['重命名临时文件失败: {}', 'Не удалось переименовать временный файл: {}'],
+ ['邀请奖励或活动条件已变化,请刷新资格后确认', 'Награда или условия акции изменились; обновите сведения и подтвердите повторно'],
+ ['当前没有剩余奖励名额,已阻止发送邀请', 'Свободных бонусных мест нет; отправка приглашения отменена'],
+ ['本次最多可邀请 {cap} 个邮箱', 'За один раз можно пригласить не более {cap} адресов email'],
+ ['邮箱格式不正确', 'Некорректный формат email'],
+ ['发送结果缺少 invites,请先查询邀请记录,勿直接重发', 'В результате отправки нет поля invites; проверьте историю приглашений и не отправляйте повторно вслепую'],
+ ['无法绑定 Antigravity OAuth 回调端口 {CALLBACK_PORT}: {e}', 'Не удалось занять порт обратного вызова Antigravity OAuth {CALLBACK_PORT}: {e}'],
+ ['登录流程状态锁异常', 'Не удалось получить доступ к состоянию входа'],
+ ['Antigravity 登录流程已过期或未启动', 'Процесс входа Antigravity истёк или не был запущен'],
+ ['Google 未返回模型额度,请稍后重试;这不表示额度为 0', 'Google не вернул квоты моделей. Повторите позже; это не означает, что квота равна нулю'],
+ ['zip 解析失败: {}', 'Не удалось разобрать ZIP: {}'],
+ ['zip entry {} 失败: {}', 'Ошибка элемента ZIP {}: {}'],
+ ['{} 解析 JSON 失败: {}', 'Не удалось разобрать JSON в {}: {}'],
+ ['{} 缺 credentials', 'В {} отсутствует поле credentials'],
+ ['无', 'Нет'],
+ ['未找到 IDE {} 的配置', 'Конфигурация IDE {} не найдена'],
+ ['不由自主', 'Нет управления приложением'],
+ ['不允许发送按键', 'Отправка нажатий клавиш запрещена'],
+ ['无法执行 osascript: {}', 'Не удалось выполнить osascript: {}'],
+ ['AppleScript 执行失败: {}', 'Не удалось выполнить AppleScript: {}'],
+ ['store lock 失败', 'Не удалось заблокировать хранилище'],
+ ['client/solo 模式禁止本机 rt 刷新;Server 不可达,跳过本机降级', 'В режиме client/solo локальное обновление RT запрещено; Server недоступен, локальный резервный путь пропущен'],
+ ['chat 入站选中的账号不存在: {}', 'Выбранный для входящего чата аккаунт не найден: {}'],
+ ['chat 入站选中的账号缺 access_token: {}', 'У выбранного для входящего чата аккаунта нет access_token: {}'],
+ ['上游请求失败: {}', 'Запрос к upstream не выполнен: {}'],
+ ['current 已登出', 'Текущий аккаунт вышел из системы'],
+ ['current 没有 refresh_token', 'У текущего аккаунта нет refresh_token'],
+ ['上游 HTTP {}', 'Upstream вернул HTTP {}'],
+ ['读取请求体失败', 'Не удалось прочитать тело запроса'],
+ ['Responses Relay 缺少 API key', 'Для Responses Relay не задан API-ключ'],
+ ['上游连接失败: {}', 'Не удалось подключиться к upstream: {}'],
+ ['响应构建失败', 'Не удалось сформировать ответ'],
+ ['账号已登出/RT 被轮换', 'Аккаунт вышел из системы или RT был заменён'],
+ ['缺 refresh_token 无法刷新', 'Обновление невозможно: отсутствует refresh_token'],
+ ['瞬时刷新失败: {}', 'Временный сбой обновления: {}'],
+ ['5xx 透传', 'Ответ 5xx передан без изменений'],
+ ['4xx 透传失败', 'Не удалось передать ответ 4xx'],
+ ['所有账号额度已耗尽,最早恢复:{}', 'Квоты всех аккаунтов исчерпаны. Ближайшее восстановление: {}'],
+ ['所有账号额度已耗尽', 'Квоты всех аккаунтов исчерпаны'],
+ ['Server 不可达: {}', 'Server недоступен: {}'],
+ ['无法从 {} 构造 Server proxy URL', 'Не удалось сформировать URL прокси Server из {}'],
+ ['构建 no_proxy client 失败: {}', 'Не удалось создать клиент no_proxy: {}'],
+ ['转发到 Server 失败: {e:?}', 'Не удалось перенаправить запрос на Server: {e:?}'],
+ ['silent_retry: 读首 chunk 失败: {}', 'silent_retry: не удалось прочитать первый фрагмент: {}'],
+ ['未配置 remote_shared_secret', 'Не задан remote_shared_secret'],
+ ['转发请求失败: {}', 'Не удалось перенаправить запрос: {}'],
+ ['流构建失败', 'Не удалось сформировать поток'],
+ ['锁失败', 'Не удалось получить блокировку'],
+ ['WebSocket 请求构建失败: {}', 'Не удалось сформировать запрос WebSocket: {}'],
+ ['刷新后 WebSocket 仍连接失败: {}', 'После обновления подключение WebSocket по-прежнему не устанавливается: {}'],
+ ['101 构建失败', 'Не удалось сформировать ответ 101'],
+ ['translator 请求处理失败: {}', 'Translator не смог обработать запрос: {}'],
+ ['Relay base_url 未配置', 'Для Relay не задан base_url'],
+ ['Relay base_url 解析失败', 'Не удалось разобрать base_url Relay'],
+ ['relay 上游连接失败: {}', 'Не удалось подключиться к upstream relay: {}'],
+ ['relay 上游 {}: {}', 'Upstream relay вернул {}: {}'],
+ ['sync 响应翻译失败: {}', 'Не удалось преобразовать синхронный ответ: {}'],
+ ['relay SSE 上游错误: {}', 'Ошибка SSE upstream relay: {}'],
+ ['StepFun /models 请求失败: {}', 'Запрос StepFun /models не выполнен: {}'],
+ ['上游响应构建失败', 'Не удалось сформировать ответ upstream'],
+ ['网络请求失败: {}', 'Сетевой запрос не выполнен: {}'],
+ ['wham/usage 请求失败', 'Запрос wham/usage не выполнен'],
+ ['刷新后重试失败: {}', 'Повторный запрос после обновления не выполнен: {}'],
+ ['刷新后重试失败', 'Повторный запрос после обновления не выполнен'],
+ ['ACCOUNT_LOGGED_OUT:您已登出或登录了其他账号,请重新登录', 'ACCOUNT_LOGGED_OUT: выполнен выход или вход в другой аккаунт; войдите заново'],
+ ['ACCOUNT_BANNED:该账号已被封禁', 'ACCOUNT_BANNED: аккаунт заблокирован'],
+ ['当前激活账号访问配额接口返回 401/403;已禁用本地 refresh_token 刷新,请稍后重试或在 Codex 中触发一次请求', 'Запрос квоты активного аккаунта вернул 401/403. Локальное обновление refresh_token отключено; повторите позже или выполните запрос в Codex'],
+ ['TOKEN_INVALID:授权已失效,请删除该账号后重新登录', 'TOKEN_INVALID: авторизация недействительна; удалите аккаунт и войдите заново'],
+ ['读取响应失败: {}', 'Не удалось прочитать ответ: {}'],
+ ['解析 JSON 失败: {}', 'Не удалось разобрать JSON: {}'],
+ ['ACCOUNT_BANNED:该账号已被封禁(workspace 已停用)', 'ACCOUNT_BANNED: аккаунт заблокирован (workspace отключён)'],
+ ['{}H 限额', 'Лимит {}ч'],
+ ['{}天后重置', 'Сброс через {} дн.'],
+ ['{}小时{}分钟后重置', 'Сброс через {} ч {} мин'],
+ ['{}分钟后重置', 'Сброс через {} мин'],
+ ['usage 请求失败: {}', 'Запрос usage не выполнен: {}'],
+ ['usage JSON 解析失败: {}', 'Не удалось разобрать JSON usage: {}'],
+ ['上游响应缺 remaining/balance 字段', 'В ответе upstream нет поля remaining или balance'],
+ ['subscription 请求失败: {}', 'Запрос subscription не выполнен: {}'],
+ ['subscription JSON 解析失败: {}', 'Не удалось разобрать JSON subscription: {}'],
+ ['subscription 缺 soft_limit_usd 字段', 'В ответе subscription нет поля soft_limit_usd'],
+ ['无法从 base_url 解析 origin: {}', 'Не удалось получить origin из base_url: {}'],
+ ['MiMo Cookie 缺少 api-platform_serviceToken 或 userId', 'В Cookie MiMo отсутствует api-platform_serviceToken или userId'],
+ ['MiMo usage 响应缺 monthUsage.items', 'В ответе MiMo usage нет monthUsage.items'],
+ ['MiMo usage 响应缺 percent/used/limit', 'В ответе MiMo usage нет percent, used или limit'],
+ ['StepFun 额度查询需要 platform.stepfun.com 的 Oasis-Token', 'Для проверки квоты StepFun требуется Oasis-Token с platform.stepfun.com'],
+ ['StepFun 额度请求失败: {}', 'Запрос квоты StepFun не выполнен: {}'],
+ ['StepFun 额度 JSON 解析失败: {}', 'Не удалось разобрать JSON квоты StepFun: {}'],
+ ['上游拒绝了额度查询', 'Upstream отклонил запрос квоты'],
+ ['订阅 Credit', 'Кредит подписки'],
+ ['加油包 Credit', 'Дополнительный кредит'],
+ ['响应中没有可识别的 Step Plan 额度字段', 'В ответе нет распознаваемых полей квоты Step Plan'],
+ ['StepFun 额度解析失败: {}', 'Не удалось разобрать квоту StepFun: {}'],
+ ['MiMo usage 请求失败: {}', 'Запрос MiMo usage не выполнен: {}'],
+ ['MiMo 登录态已失效,请重新登录后复制 Cookie', 'Сеанс MiMo истёк; войдите заново и скопируйте Cookie'],
+ ['MiMo Cookie 无效或权限不足', 'Cookie MiMo недействителен или не имеет необходимых прав'],
+ ['MiMo usage JSON 解析失败: {}', 'Не удалось разобрать JSON MiMo usage: {}'],
+ ['至少需要 1 个邀请邮箱', 'Укажите хотя бы один email для приглашения'],
+ ['邀请 {} 获得', 'Получено за приглашение {}'],
+ ['Codex 赠送', 'Подарок Codex'],
+ ['未知来源', 'Источник неизвестен'],
+ ['token 失效(401),请刷新或重新登录', 'Токен недействителен (401); обновите его или войдите заново'],
+ ['需要验证(403)', 'Требуется подтверждение (403)'],
+ ['请求过于频繁(429),稍后再试', 'Слишком много запросов (429); повторите позже'],
+ ['上游返回 HTTP {}', 'Upstream вернул HTTP {}'],
+ ['上游返回非 JSON', 'Upstream вернул ответ не в формате JSON'],
+ ['上游未返回有效的重置银行明细,当前次数未知(不代表已清空)', 'Upstream не вернул корректные сведения о доступных сбросах. Их число неизвестно; это не означает, что сбросов не осталось'],
+ ['已重置 {} 个限额窗口', 'Сброшено окон лимита: {}'],
+ ['当前没有可重置的限额(额度还没用到上限)', 'Сейчас нечего сбрасывать: квота ещё не исчерпана'],
+ ['上游返回:{}', 'Ответ upstream: {}'],
+ ['配额已耗尽(usage_limit_reached)', 'Квота исчерпана (usage_limit_reached)'],
+ ['token 失效(401)', 'Токен недействителен (401)'],
+ ['需要验证或提交保证书(403)', 'Требуется подтверждение или гарантийное заявление (403)'],
+ ['配额已耗尽(429)', 'Квота исчерпана (429)'],
+ ['Server 不可达(fallback={})', 'Server недоступен (резервный адрес: {})'],
+ ['Server 不可达(primary={})', 'Server недоступен (основной адрес: {})'],
+ ['Server 不可达(primary={}, fallback={})', 'Server недоступен (основной адрес: {}, резервный: {})'],
+ ['Server Google token 租约失败: {error}', 'Не удалось получить аренду Google-токена у Server: {error}'],
+ ['Server Google token 租约失败', 'Не удалось получить аренду Google-токена у Server'],
+ ['构建 HTTP client 失败: {}', 'Не удалось создать HTTP-клиент: {}'],
+ ['连接 Server 失败: {}', 'Не удалось подключиться к Server: {}'],
+ ['Server /health 返回 {}', 'Server /health вернул {}'],
+ ['解析 /health 响应失败: {}', 'Не удалось разобрать ответ /health: {}'],
+ ['连接失败: {}', 'Не удалось подключиться: {}'],
+ ['共享密钥不正确', 'Неверный общий ключ'],
+ ['Server /accounts 返回 {}', 'Server /accounts вернул {}'],
+ ['请求失败: {}', 'Запрос не выполнен: {}'],
+ ['Server 返回 {}', 'Server вернул {}'],
+ ['响应缺少 accounts 字段', 'В ответе нет поля accounts'],
+ ['反序列化账号列表失败: {}', 'Не удалось прочитать список аккаунтов: {}'],
+ ['创建 SSOT 目录失败: {}', 'Не удалось создать каталог SSOT: {}'],
+ ['读取目录失败: {}', 'Не удалось прочитать каталог: {}'],
+ ['移除旧 Antigravity skills 链接失败: {}', 'Не удалось удалить старую ссылку навыков Antigravity: {}'],
+ ['移除旧 Antigravity skills 目录失败: {}', 'Не удалось удалить старый каталог навыков Antigravity: {}'],
+ ['移除旧 Antigravity skill 失败: {}', 'Не удалось удалить старый навык Antigravity: {}'],
+ ['移除旧 Antigravity skills manifest 失败: {}', 'Не удалось удалить старый манифест навыков Antigravity: {}'],
+ ['Antigravity skills 目录不可用', 'Каталог навыков Antigravity недоступен'],
+ ['移除 Antigravity skills symlink 失败: {}', 'Не удалось удалить символическую ссылку навыков Antigravity: {}'],
+ ['Antigravity skills 路径不是目录: {:?}', 'Путь навыков Antigravity не является каталогом: {:?}'],
+ ['创建 Antigravity skills 目录失败: {}', 'Не удалось создать каталог навыков Antigravity: {}'],
+ ['移除过期 Antigravity skill {} 失败: {}', 'Не удалось удалить устаревший навык Antigravity {}: {}'],
+ ['覆盖 Antigravity skill {} 失败: {}', 'Не удалось заменить навык Antigravity {}: {}'],
+ ['生成 Antigravity skills manifest 失败: {}', 'Не удалось создать манифест навыков Antigravity: {}'],
+ ['写入 Antigravity skills manifest 失败: {}', 'Не удалось записать манифест навыков Antigravity: {}'],
+ ['移除 Antigravity skill 失败: {}', 'Не удалось удалить навык Antigravity: {}'],
+ ['移除 Antigravity skills manifest 失败: {}', 'Не удалось удалить манифест навыков Antigravity: {}'],
+ ['创建 symlink 失败: {}', 'Не удалось создать символическую ссылку: {}'],
+ ['读取条目失败: {}', 'Не удалось прочитать элемент: {}'],
+ ['复制文件失败: {}', 'Не удалось скопировать файл: {}'],
+ ['备份文件失败: {}', 'Не удалось создать резервную копию файла: {}'],
+ ['写入失败: {}', 'Не удалось записать: {}'],
+ ['未知 app: {}', 'Неизвестное приложение: {}'],
+ ['下载失败: {}', 'Не удалось скачать: {}'],
+ ['下载失败: HTTP {}', 'Не удалось скачать: HTTP {}'],
+ ['读取失败: {}', 'Не удалось прочитать: {}'],
+ ['在仓库中未找到 skill: {}', 'Навык не найден в репозитории: {}'],
+ ['skill 不存在: {}', 'Навык не найден: {}'],
+ ['打开 ZIP 失败: {}', 'Не удалось открыть ZIP: {}'],
+ ['读取 ZIP 条目失败: {}', 'Не удалось прочитать элемент ZIP: {}'],
+ ['创建文件失败: {}', 'Не удалось создать файл: {}'],
+ ['skill 目录不存在: {}', 'Каталог навыка не найден: {}'],
+ ['读取目录失败 {:?}: {}', 'Не удалось прочитать каталог {:?}: {}'],
+ ['添加目录失败: {}', 'Не удалось добавить каталог: {}'],
+ ['开始文件失败: {}', 'Не удалось начать запись файла: {}'],
+ ['打开文件失败 {:?}: {}', 'Не удалось открыть файл {:?}: {}'],
+ ['读取文件失败: {}', 'Не удалось прочитать файл: {}'],
+ ['写入 zip 失败: {}', 'Не удалось записать ZIP: {}'],
+ ['finish zip 失败: {}', 'Не удалось завершить создание ZIP: {}'],
+ ['非法 skill 名: {}', 'Недопустимое имя навыка: {}'],
+ ['创建 SSOT 失败: {}', 'Не удалось создать SSOT: {}'],
+ ['创建 staging 失败: {}', 'Не удалось создать временный каталог импорта: {}'],
+ ['打开 zip 失败: {}', 'Не удалось открыть ZIP: {}'],
+ ['读取 zip 条目失败: {}', 'Не удалось прочитать элемент ZIP: {}'],
+ ['zip 条目名非法: {}', 'Недопустимое имя элемента ZIP: {}'],
+ ['zip 条目缺少顶层目录', 'В элементе ZIP отсутствует корневой каталог'],
+ ['zip 顶层目录 {:?} 与期望 {} 不一致', 'Корневой каталог ZIP {:?} не совпадает с ожидаемым {}'],
+ ['创建父目录失败: {}', 'Не удалось создать родительский каталог: {}'],
+ ['创建文件失败 {:?}: {}', 'Не удалось создать файл {:?}: {}'],
+ ['读取 zip 内容失败: {}', 'Не удалось прочитать содержимое ZIP: {}'],
+ ['备份原目录失败: {}', 'Не удалось создать резервную копию исходного каталога: {}'],
+ ['替换 skill 失败: {}', 'Не удалось заменить навык: {}'],
+ ['sentinel/req 请求失败: {e}', 'Запрос sentinel/req не выполнен: {e}'],
+ ['sentinel/req 读取响应失败: {e}', 'Не удалось прочитать ответ sentinel/req: {e}'],
+ ['sentinel/req JSON 解析失败: {e}', 'Не удалось разобрать JSON sentinel/req: {e}'],
+ ['构建 HTTP client 失败: {e}', 'Не удалось создать HTTP-клиент: {e}'],
+ ['/oauth/authorize 请求失败: {e}', 'Запрос /oauth/authorize не выполнен: {e}'],
+ ['authorize/continue 失败: {e}', 'Запрос authorize/continue не выполнен: {e}'],
+ ['authorize/continue 读响应失败: {e}', 'Не удалось прочитать ответ authorize/continue: {e}'],
+ ['send-otp 失败: {e}', 'Не удалось отправить OTP: {e}'],
+ ['send-otp 非 200: {status} body={}', 'send-otp вернул статус {status}; тело ответа: {}'],
+ ['email-otp/validate 失败: {e}', 'Не удалось проверить OTP email: {e}'],
+ ['session_dump 失败: {e}', 'Не удалось получить session_dump: {e}'],
+ ['workspace/select 失败: {e}', 'Не удалось выбрать workspace: {e}'],
+ ['无法获取 continue_url,OTP 校验/workspace 选择都没给出,无法继续', 'Не получен continue_url: ни проверка OTP, ни выбор workspace не дали адреса для продолжения'],
+ ['follow {url} 失败: {e}', 'Не удалось перейти по {url}: {e}'],
+ ['follow_until_callback 超过 15 跳', 'Превышен лимит из 15 переходов до callback'],
+ ['URL 解析失败: {e}', 'Не удалось разобрать URL: {e}'],
+ ['URL 里没有 code 参数: {url}', 'В URL нет параметра code: {url}'],
+ ['请求令牌失败: {}', 'Не удалось запросить токен: {}'],
+ ['OpenAI 返回错误: {}', 'OpenAI вернул ошибку: {}'],
+ ['解析令牌响应失败: {}', 'Не удалось разобрать ответ с токеном: {}'],
+ ['store 锁中毒', 'Блокировка хранилища повреждена'],
+ ['刷新令牌失败: {}', 'Не удалось обновить токен: {}'],
+ ['刷新令牌被拒绝: {}', 'Обновление токена отклонено: {}'],
+ ['解析刷新响应失败: {}', 'Не удалось разобрать ответ обновления: {}'],
+ ['OTP 等待超时', 'Истекло время ожидания OTP'],
+ ['nissanserena GET 失败: {e}', 'Запрос nissanserena GET не выполнен: {e}'],
+ ['nissanserena 读响应失败: {e}', 'Не удалось прочитать ответ nissanserena: {e}'],
+ ['回调链接不能为空', 'Ссылка обратного вызова не может быть пустой'],
+ ['未能从输入中解析出 code 参数', 'Не удалось извлечь параметр code из введённого значения'],
+ ['state 校验不通过:这个回调链接不属于本次登录流程', 'Проверка state не пройдена: ссылка обратного вызова не относится к текущему процессу входа'],
+ ['登录流程已过期或未启动,请先点击『立即登录 OpenAI』', 'Процесс входа истёк или не был запущен. Сначала нажмите «Войти в OpenAI сейчас»'],
+ ['派发 oauth-callback-received 失败: {}', 'Не удалось отправить событие oauth-callback-received: {}'],
+ ['无法启动 pbcopy: {}', 'Не удалось запустить pbcopy: {}'],
+ ['pbcopy stdin 不可写', 'Стандартный ввод pbcopy недоступен для записи'],
+ ['写入 pbcopy 失败: {}', 'Не удалось записать в pbcopy: {}'],
+ ['等待 pbcopy 退出失败: {}', 'Ошибка ожидания завершения pbcopy: {}'],
+ ['pbcopy 返回非零: {:?}', 'pbcopy завершился с ненулевым кодом: {:?}'],
+ ['锁被污染', 'Блокировка повреждена'],
+ ['登录流程已过期或未启动', 'Процесс входа истёк или не был запущен'],
+ ['锁获取失败: {}', 'Не удалось получить блокировку: {}'],
+ ['Google ST 获取失败', 'Не удалось получить Google ST'],
+ ['Google ST 缺失', 'Отсутствует Google ST'],
+ ['Google project_id 缺失', 'Отсутствует Google project_id'],
+ ['账号已被删除', 'Аккаунт удалён'],
+ ['读取 OAuth body 失败: {error}', 'Не удалось прочитать тело OAuth: {error}'],
+ ['OAuth JSON 解析失败: {error}', 'Не удалось разобрать JSON OAuth: {error}'],
+ ['读取 body 失败: {}', 'Не удалось прочитать тело запроса: {}'],
+ ['保存失败: {}', 'Не удалось сохранить: {}'],
+ ['锁获取失败', 'Не удалось получить блокировку'],
+ ['序列化响应失败: {}', 'Не удалось сериализовать ответ: {}'],
+ ['刷新 token 失败: {}', 'Не удалось обновить токен: {}'],
+ ['无 access_token 且无 refresh_token', 'Отсутствуют и access_token, и refresh_token'],
+ ['TOKEN_INVALID:刷新 token 失败: {}', 'TOKEN_INVALID: не удалось обновить токен: {}'],
+ ['switch_to 失败: {}', 'Не удалось выполнить switch_to: {}'],
+ ['加载图标失败: {}', 'Не удалось загрузить значок: {}'],
+ ['安全确认已过期,请重新点击修复', 'Срок подтверждения истёк; снова нажмите «Исправить»'],
+ ['安全确认无效,请重新点击修复', 'Подтверждение недействительно; снова нажмите «Исправить»'],
+ ['缺少安全确认,请重新点击修复', 'Отсутствует подтверждение; снова нажмите «Исправить»'],
+ ['当前 auth.json 缺少 refresh_token,无法自动续期,请重新登录', 'В текущем auth.json нет refresh_token, поэтому автоматическое продление невозможно. Войдите заново'],
+ ['仅 ChatGPT OAuth 订阅账号支持周期保鲜', 'Продление периода поддерживается только для аккаунтов с подпиской ChatGPT OAuth'],
+ ['base_url 必须以 http:// 或 https:// 开头', 'base_url должен начинаться с http:// или https://'],
+ ['api_key 不能为空', 'api_key не может быть пустым'],
+ ['name 不能为空', 'Имя не может быть пустым'],
+ ['中转站账号缺 base_url', 'У relay-аккаунта отсутствует base_url'],
+ ['中转站账号缺 api_key', 'У relay-аккаунта отсутствует api_key'],
+ ['账号在刷新模型时被删除', 'Аккаунт был удалён во время обновления моделей'],
+ ['账号在刷新模型时发生变化', 'Аккаунт изменился во время обновления моделей'],
+ ['账号 {} 不存在', 'Аккаунт {} не найден'],
+ ['自动探测未命中:上游不支持 /v1/dashboard/billing 或 /v1/usage(可手动选 usage 策略,或保持「不拉取」)', 'Автоопределение не сработало: upstream не поддерживает /v1/dashboard/billing или /v1/usage. Выберите стратегию usage вручную либо оставьте «Не запрашивать»'],
+ ['MiMo 配额查询需要登录 platform.xiaomimimo.com 后复制 Cookie header', 'Для проверки квоты MiMo войдите на platform.xiaomimimo.com и скопируйте заголовок Cookie'],
+ ['StepFun 额度查询需要登录 platform.stepfun.com 后复制 Oasis-Token', 'Для проверки квоты StepFun войдите на platform.stepfun.com и скопируйте Oasis-Token'],
+ ['未支持的 usage_preset: {}', 'Неподдерживаемый usage_preset: {}'],
+ ['usage 策略未确定', 'Стратегия usage не определена'],
+ ['OAuth 未返回 refresh_token,无法自动续期', 'OAuth не вернул refresh_token; автоматическое продление невозможно'],
+ ['无法从授权响应中解析用户信息 (Missing ID Token)', 'Не удалось получить данные пользователя из ответа авторизации: отсутствует ID Token'],
+ ['没有当前激活账号', 'Нет активного аккаунта'],
+ ['已覆盖 ~/.codex/auth.json', 'Файл ~/.codex/auth.json перезаписан'],
+ ['OpenAI OAuth 登录', 'Вход через OpenAI OAuth'],
+ ['该账号不是 Google Antigravity 账号', 'Этот аккаунт не относится к Google Antigravity'],
+ ['Antigravity 账号由模型路由自动选择,不切换 Codex 当前身份', 'Аккаунты Antigravity выбираются маршрутизацией моделей автоматически и не меняют текущий аккаунт Codex'],
+ ['账号缺少 access_token', 'У аккаунта отсутствует access_token'],
+ ['该账号正在被其他流程刷新,请稍后重试', 'Аккаунт обновляется другим процессом; повторите позже'],
+ ['仅 solo 模式支持同号操作', 'Операция синхронизации аккаунта поддерживается только в режиме solo'],
+ ['没有可用账号', 'Нет доступных аккаунтов'],
+ ['遍历完所有账号,未发现可用配额的账号', 'Проверены все аккаунты; аккаунтов с доступной квотой не найдено'],
+ ['PROVIDER_ACCOUNT:该 Provider 账号不支持 OpenAI usage 查询', 'PROVIDER_ACCOUNT: этот аккаунт провайдера не поддерживает запрос OpenAI usage'],
+ ['TOKEN_INVALID:client/solo 模式禁止本机 rt 刷新;请确认账号已同步到 Server', 'TOKEN_INVALID: в режиме client/solo локальное обновление RT запрещено; проверьте синхронизацию аккаунта с Server'],
+ ['TOKEN_INVALID:无 access_token 且无 refresh_token', 'TOKEN_INVALID: отсутствуют и access_token, и refresh_token'],
+ ['邀请邮箱过多:{} 个,最多 50 个', 'Слишком много адресов для приглашения: {}; допускается не более 50'],
+ ['PROVIDER_ACCOUNT:该 Provider 账号不支持 Codex 邀请', 'PROVIDER_ACCOUNT: этот аккаунт провайдера не поддерживает приглашения Codex'],
+ ['你好', 'Здравствуйте'],
+ ['UNSUPPORTED_ACCOUNT:仅 ChatGPT OAuth 订阅账号支持 Codex 唤醒', 'UNSUPPORTED_ACCOUNT: запуск Codex поддерживается только для аккаунтов с подпиской ChatGPT OAuth'],
+ ['PROVIDER_ACCOUNT:该 Provider 账号不支持 codex 终端', 'PROVIDER_ACCOUNT: этот аккаунт провайдера не поддерживает терминал Codex'],
+ ['账号 auth_json 结构异常', 'Некорректная структура auth_json аккаунта'],
+ ['账号缺少 codex tokens,无法启动', 'У аккаунта нет токенов Codex; запуск невозможен'],
+ ['创建 CODEX_HOME 失败: {}', 'Не удалось создать CODEX_HOME: {}'],
+ ['写 auth.json 失败: {}', 'Не удалось записать auth.json: {}'],
+ ['写 config.toml 失败: {}', 'Не удалось записать config.toml: {}'],
+ ['打开 Terminal 失败: {}', 'Не удалось открыть терминал: {}'],
+ ['已为 {} 打开 codex 终端', 'Терминал Codex открыт для {}'],
+ ['同步失败:账号不存在或 User ID 不匹配', 'Синхронизация не выполнена: аккаунт не найден или User ID не совпадает'],
+ ['PROVIDER_ACCOUNT:该 Provider 账号不支持 OpenAI usage', 'PROVIDER_ACCOUNT: этот аккаунт провайдера не поддерживает OpenAI usage'],
+ ['当前激活账号与 ~/.codex/auth.json 身份不匹配,已拒绝覆盖,请先在 Codex 中切回同一账号', 'Активный аккаунт не совпадает с аккаунтом в ~/.codex/auth.json. Перезапись отклонена; сначала переключите Codex на тот же аккаунт'],
+ ['session route 不存在: {}', 'Маршрут сессии не найден: {}'],
+ ['执行失败: {}', 'Не удалось выполнить: {}'],
+ ['已终止 {} 个 codex 进程', 'Завершено процессов Codex: {}'],
+ ['读取 {} 失败: {}', 'Не удалось прочитать {}: {}'],
+ ['写入 {} 失败: {}', 'Не удалось записать {}: {}'],
+ ['config.toml(失败: {})', 'config.toml (ошибка: {})'],
+ ['创建 config.toml 失败: {}', 'Не удалось создать config.toml: {}'],
+ ['读取 config.toml 失败: {}', 'Не удалось прочитать config.toml: {}'],
+ ['写入 config.toml 失败: {}', 'Не удалось записать config.toml: {}'],
+ ['~/.codex/config.toml 不存在', 'Файл ~/.codex/config.toml не найден'],
+ ['Fast 模式已开启(2x 额度消耗,更快推理)。重启 Codex 生效。', 'Режим Fast включён: ответы быстрее, расход квоты удвоен. Перезапустите Codex для применения'],
+ ['Fast 模式已关闭。重启 Codex 生效。', 'Режим Fast отключён. Перезапустите Codex для применения'],
+ ['[features] goals = true 已写入。重启 Codex 生效。', 'Параметр [features] goals = true записан. Перезапустите Codex для применения'],
+ ['[features] goals 已关闭。重启 Codex 生效。', 'Функция [features] goals отключена. Перезапустите Codex для применения'],
+ ['本地未找到账号 {}', 'Локальный аккаунт {} не найден'],
+ ['zip task 崩溃: {}', 'Задача ZIP аварийно завершилась: {}'],
+ ['已停止(当前模式 {})', 'Остановлено (текущий режим: {})'],
+ ['已启动 http://{}:{}', 'Запущено: http://{}:{}'],
+
+
+ // Dynamic fragments and complete mixed-language labels.
+ ['分钟 后重置', 'мин до сброса'],
+ ['后台保活已停用(', 'Фоновое продление отключено ('],
+ [',需重新登录)@', ', требуется повторный вход) @'],
+ ['后台保活临时失败(', 'Временный сбой фонового продления ('],
+ ['代理已自动切号 →', 'Прокси автоматически переключил аккаунт →'],
+ ['检测到封号:', 'Обнаружена блокировка аккаунта:'],
+ [',已自动切换', ', выполнено автоматическое переключение'],
+ ['(早期数据·无 account)', '(старые данные, без аккаунта)'],
+ ['+ 添加', '+ Добавить'],
+ ['没有匹配「', 'Нет правил, соответствующих «'],
+ ['已复制 ✓', 'Скопировано ✓'],
+ ['确认删除路由「', 'Удалить маршрут «'],
+ ['来源:', 'Источник:'],
+ ['⚠️ 链接里携带的', '⚠️ Переданное в ссылке значение '],
+ ['未在内置白名单中,已忽略。账号仍可正常使用, 但额度查询不会自动进行。导入后可在账号详情中手动选 usage preset。', 'не входит во встроенный список разрешённых значений и было проигнорировано. Аккаунт останется доступен, но квота не будет проверяться автоматически. После импорта стратегию проверки квоты можно выбрать в параметрах аккаунта.'],
+ ['添加路由', 'Добавить маршрут'],
+ ['同步到 Server 失败:', 'Не удалось синхронизировать с Server:'],
+ ['已安装 (', 'Установлено ('],
+ [',此操作将从所有 CLI 目录移除该 skill。', ', навык будет удалён из всех каталогов CLI.'],
+ ['失败:', 'Ошибка: '],
+ [',远端账号数', ', аккаунтов на Server: '],
+ ['✅ 已设为手机锚', '✅ Мобильная привязка установлена'],
+ ['❌ 绑定失败:', '❌ Не удалось установить привязку: '],
+ ['✅ 已解除手机锚绑定', '✅ Мобильная привязка снята'],
+ ['❌ 解除失败:', '❌ Не удалось снять привязку: '],
+ ['这将尝试移除 Codex App 的安全隔离属性。 系统可能会弹窗要求输入密码以获得权限。是否继续?', 'Будет выполнена попытка удалить quarantine-атрибут Codex App. Система может запросить пароль администратора. Продолжить?'],
+ ['off=独立;server=Server 侧提供 API;client=本机,rt 旋转走 Server。 老 solo 模式已合并到 client(自动迁移:solo → client + 本机直连上游 + 本机管 current)。', 'off — автономная работа; server — предоставление API на стороне Server; client — работа на этом компьютере с обновлением RT через Server. Прежний режим solo объединён с client и автоматически переносится в client с локальным подключением к upstream и локальным управлением current.'],
+ ['off(关闭)', 'off (выключено)'],
+ ['(未设置)', '(не задано)'],
+ ['优先尝试,建议填局域网 IP,如 http://192.168.2.14:18081', 'Используется первым. Рекомендуется адрес в локальной сети, например http://192.168.2.14:18081'],
+ ['主不通时自动切换,建议填 ZeroTier IP,如 http://172.26.96.198:18081', 'Используется автоматически, если основной адрес недоступен. Рекомендуется адрес ZeroTier, например http://172.26.96.198:18081'],
+ ['磁盘 ~/.codex/auth.json 永远跟随此号,Codex.app 手机远程连接绑定此号; 切到其他号时 disk 不动、proxy 出口照切(手机 bridge 不掉线)。 仅 ChatGPT 订阅号可绑定。', 'Файл ~/.codex/auth.json всегда остаётся привязан к этому аккаунту, как и мобильное удалённое подключение Codex.app. При переключении других аккаунтов файл на диске не меняется, а выход прокси переключается без разрыва мобильного подключения. Привязать можно только аккаунт с подпиской ChatGPT.'],
+ ['· 代理出口', '· выход прокси'],
+ ['Vs 上月 $', 'К прошлому месяцу: $'],
+ ['身份在线(手机 bridge 不掉线), 代理出口已切到', 'остаётся активным для мобильного подключения, а выход прокси переключён на '],
+ ['(代理正在注入当前激活号的 token,', '(прокси подставляет токен активного аккаунта, '],
+ ['; 关闭代理后 codex 会读到这个号)', '; после отключения прокси Codex прочитает этот аккаунт)'],
+ ['⚠️ 失效', '⚠️ Недействителен'],
+ ['💰 额度', '💰 Квота'],
+ ['代理已启动', 'Прокси запущен'],
+ ['代理已停止', 'Прокси остановлен'],
+ ['(新终端窗口生效)', '(вступит в силу в новом окне терминала)'],
+ ['auto:代理开启时自动走热切(不写 auth.json,不杀进程,仅刷 store.current)。 代理关闭时回退到冷切。cold:无论如何都冷切。', 'auto: при включённом прокси используется горячее переключение без записи auth.json и завершения процессов; обновляется только store.current. При выключенном прокси используется холодное переключение. cold: всегда использовать холодное переключение.'],
+ ['。 同邮箱已存在的账号会跳过,不覆盖现有 token。', '. Аккаунты с уже существующим email будут пропущены, имеющиеся токены не перезаписываются.'],
+ ['(同名)', '(с тем же именем)'],
+ ['新增账号详情(', 'Сведения о новых аккаунтах ('],
+ ['⚠ 仅 RT,首次请求自动 refresh', '⚠ Только RT; при первом запросе токен обновится автоматически'],
+ ['), 绕过 Codex 手机验证。支持单个对象、对象数组、或者嵌套容器,会自动递归识别。', '), что позволяет пройти проверку телефона Codex. Поддерживаются отдельный объект, массив объектов и вложенные контейнеры; формат определяется рекурсивно.'],
+ ['导入账号详情(', 'Сведения об импортированных аккаунтах ('],
+ ['(id_token 合成)', '(id_token сформирован автоматически)'],
+ ['失败项(', 'Ошибки ('],
+ ['glm_zhipu (GLM 自家 quota 接口)', 'glm_zhipu (собственный API квот GLM)'],
+ ['kimi_coding (Kimi 编程套餐 5H / 7D)', 'kimi_coding (тариф Kimi Coding, 5ч / 7д)'],
+ ['mimo_token_plan (MiMo 控制台 Cookie)', 'mimo_token_plan (Cookie из консоли MiMo)'],
+ ['stepfun_plan (StepFun 控制台 Oasis-Token)', 'stepfun_plan (Oasis-Token из консоли StepFun)'],
+ ['Oasis-Token=...(或直接粘贴 token)', 'Oasis-Token=... (или вставьте сам токен)'],
+ ['将从本地官方 Codex 的登录状态 (`auth.json`) 中提取认证信息。', 'Данные авторизации будут извлечены из локального файла входа официального Codex (`auth.json`).'],
+ ['deep link 添加。', 'добавление по ссылке приложения.'],
+ ['(自定义 base URL)', '(собственный базовый URL)'],
+ ['kimi_coding · Kimi 编程套餐 5H / 7D', 'kimi_coding · тариф Kimi Coding, 5ч / 7д'],
+ ['mimo_token_plan · 需 Cookie', 'mimo_token_plan · требуется Cookie'],
+ ['stepfun_plan · Step Plan 控制台 Token', 'stepfun_plan · токен из консоли Step Plan'],
+ ['· 已过期', '· истёк'],
+ ['· 今天', '· сегодня'],
+ ['账号还有', 'До окончания аккаунта осталось '],
+ [',点击修改', ', нажмите для изменения'],
+ ['(消耗了到期', '(использован кредит со сроком до '],
+ ['的那条)', ')'],
+ ['[AutoRefresh] 触发', '[AutoRefresh] запущено для '],
+ ['个账号 reset 后自动刷新:', ' аккаунтов после сброса:'],
+ [',已刷新额度', ', квота обновлена'],
+ ['推送 Server 成功(', 'успешно отправлен на Server ('],
+ ['Google 切号失败:', 'Не удалось переключить Google-аккаунт: '],
+ ['设为其模型的当前账号(Codex / Google 不变)', 'назначен текущим аккаунтом для своих моделей (Codex и Google не изменены)'],
+ ['登录已失效:refresh_token 已过期或被撤销,请重新登录', 'Сеанс входа недействителен: refresh_token истёк или был отозван. Войдите заново'],
+ ['刷新失败:', 'Не удалось обновить: '],
+ ['📱 手机锚', '📱 Мобильная привязка'],
+ ['🔄 次数未知', '🔄 Число сбросов неизвестно'],
+ ['⚡ 当前已被限流(额度桶为 0)——现在用一次主动重置回收最大,点击查看明细', '⚡ Сейчас действует ограничение: окно квоты равно нулю. Активный сброс даст максимальный эффект; нажмите, чтобы посмотреть сведения.'],
+ ['🚀 启动 codex', '🚀 Запустить Codex'],
+ ['周期保鲜最近错误:', 'Последняя ошибка продления периода: '],
+ ['🌿 周期保鲜 ·', '🌿 Продление периода ·'],
+ ['🌿 保鲜已关 ·', '🌿 Продление отключено ·'],
+ ['最近尝试:', 'Последняя попытка: '],
+ ['最近成功:', 'Последнее успешное выполнение: '],
+ ['最近结果:', 'Последний результат: '],
+ ['主动重置 ·', 'Активный сброс ·'],
+ ['拉取明细失败:', 'Не удалось загрузить сведения: '],
+ [',区别仅到期时间;', ', различается только срок действия; '],
+ [',也可粘贴包含它的 Cookie header。', '; также можно вставить заголовок Cookie, который его содержит.'],
+ [':每次切号前后强制抓 quota 写 `~/.codex-switcher/quota-snapshots.jsonl`。同一窗口内任意两次快照的 Δused_pct 配合期间代理 tokens → 推出该 Plan 总容量(capacity = Δtokens / Δpct × 100)。', ': до и после каждого переключения снимок квоты принудительно записывается в `~/.codex-switcher/quota-snapshots.jsonl`. Любые два снимка одного окна вместе с числом токенов прокси за этот период позволяют оценить общую ёмкость тарифа: capacity = Δtokens / Δpct × 100.'],
+ ['5h 周期(', 'Периоды 5ч ('],
+ ['周周期(', 'Недельные периоды ('],
+ ['每格显示「', 'В каждой ячейке показано «'],
+ ['= `实测累加 ÷ snapshot used_pct × 100`,用快照里 used_pct 最大那个算(量化误差最小)。`?%` 标记的 used_pct 偏小,估算误差大。', '= `фактическая сумма ÷ snapshot used_pct × 100`; расчёт выполняется по снимку с наибольшим used_pct, чтобы снизить ошибку округления. Метка `?%` означает, что used_pct мал и оценка менее точна.'],
+ ['🔴 = 窗口内触发过限额切号 —— 此时实测累加 ≈ Plan 实际窗口配额。', '🔴 = в этом окне было переключение из-за лимита; фактическая сумма примерно равна реальной квоте окна тарифа.'],
+ ['点开账号看历史周期,点开周期看 session 明细。', 'Раскройте аккаунт, чтобы посмотреть историю периодов, затем раскройте период для просмотра сессий.'],
+ ['切号日志 (', 'Журнал переключений ('],
+ ['后台任务日志 (', 'Журнал фоновых задач ('],
+ ['% · 窗口', '% · окно '],
+ ['Token Plan 订阅(tp-key;配额用控制台 Cookie)', 'Подписка Token Plan (tp-key; квота проверяется по Cookie из консоли)'],
+ ['手动填 base_url;余额自动探测', 'Укажите base_url вручную; баланс определяется автоматически'],
+
+ // Fragments rendered as separate React text nodes.
+ ['模型', 'Модель'],
+ ['最后更新:', 'Последнее обновление: '],
+ ['奖励', 'Награда'],
+ ['目标账号异常:', 'Ошибка целевого аккаунта: '],
+ ['还没有路由规则。点', 'Правил маршрутизации пока нет. Нажмите '],
+ ['」的规则。', '».'],
+ ['未知账号(已删除? id:', 'Неизвестный аккаунт (возможно, удалён; id:'],
+ ['当前活跃会话', 'Текущая активная сессия'],
+ ['授权链接', 'Ссылка авторизации'],
+ ['以确认:', 'для подтверждения:'],
+ ['生成', 'Создать'],
+ ['心跳时自动把本机 current 对齐到 Server 的 current。 Server 不可达会静默跳过,保持本机现状。', 'При проверке связи локальный current автоматически синхронизируется с current на Server. Если Server недоступен, синхронизация молча пропускается и локальное состояние сохраняется.'],
+ ['上游模型额度:', 'Квоты моделей upstream: '],
+ [';窗口明细未获取', '; сведения об окнах не получены'],
+ ['代理已自动切换到账号:', 'Прокси автоматически переключился на аккаунт:'],
+ ['写入', 'Записать '],
+ ['goals = true 到 ~/.codex/config.toml。', 'goals = true в ~/.codex/config.toml.'],
+ ['(codex_credentials zip / 单 .json)、', ' (архив codex_credentials или отдельный .json), '],
+ ['个账号', ' аккаунтов'],
+ ['失效(约 30 天)后账号会变成不可用, 需要重新粘贴一次新 session。Plus 账号能正常调用模型,Free 账号即使导入也无 API 权限。', 'истекает примерно через 30 дней, после чего аккаунт становится недоступен и потребуется вставить новую сессию. Аккаунты Plus могут обращаться к моделям; у Free-аккаунтов нет доступа к API даже после импорта.'],
+ [')粘贴到下方:', ') и вставьте ниже:'],
+ ['选一个', 'Выберите сервис'],
+ [',base URL 自动填好,下一步只用粘 API Key。\n 需要在多家 Coding Plan 之间切换额度的话,可以把同一个服务添加多次(用账号名区分)。\n 也支持', ': базовый URL заполнится автоматически, на следующем шаге останется вставить API-ключ. Чтобы переключать квоты между несколькими Coding Plan, добавьте один сервис несколько раз под разными именами аккаунтов. Также поддерживается '],
+ ['切换服务', 'Сменить сервис'],
+ ['前缀', 'Префикс'],
+ ['API 地址(可修改)', 'Адрес API (можно изменить)'],
+ ['默认模型 ID(可修改)', 'ID модели по умолчанию (можно изменить)'],
+ ['余额查询', 'Проверка баланса'],
+ ['额度凭证', 'Данные для проверки квоты'],
+ ['填写凭据', 'Укажите данные доступа'],
+ ['← 返回选择', '← Вернуться к выбору'],
+ ['设为这些模型的当前号:', 'Сделать текущим для моделей: '],
+ ['(不影响 Codex / Google)', ' (не влияет на Codex / Google)'],
+ ['(通常最早到期优先,客户端无法指定)。', ' (обычно сначала используется кредит с ближайшим сроком; клиент не может выбрать его вручную).'],
+ ['消耗 1 次会把当前已耗尽的 5H / 周限额窗口立刻清零,此操作不可撤销。若额度还没用到上限,上游会返回「无可重置」且', 'Одна попытка сразу сбросит исчерпанное окно лимита 5ч или недели. Действие необратимо. Если квота ещё не исчерпана, upstream вернёт «сбрасывать нечего» и '],
+ ['。登录', '. После входа '],
+ ['人', ' чел.'],
+ ['请检查邮箱格式和本次可发送人数(最多', 'Проверьте формат email и доступное число получателей (не более '],
+ ['个)。', ' email).'],
+ ['上游已创建', 'Upstream создал '],
+ ['条邀请', ' приглашений'],
+ ['本次奖励:', 'Награда за эту отправку: '],
+ ['未成功:', 'Не отправлено: '],
+ ['日', 'День'],
+ ['周', 'Неделя'],
+ ['月', 'Месяц'],
+ ['是去掉异常值后最稳的估计。Δpct<3% 的样本被丢弃(used_pct 是整数,量化误差会失真)。', 'даёт наиболее устойчивую оценку после удаления выбросов. Образцы с Δpct<3% отбрасываются: used_pct является целым числом, поэтому ошибка квантования искажает результат.'],
+ ['= token-history.jsonl 在该窗口内的精确求和(不平均、不打折,无论中间切号几次)。', '= точная сумма из token-history.jsonl за это окно: без усреднения и скидок, независимо от числа переключений аккаунта.'],
+ ['条)', ' зап.)'],
+ ['无数据', 'Нет данных'],
+ ['首次 → 末次', 'Первое → последнее'],
+ ['直接切换将', 'Прямое переключение '],
+ ['覆盖', 'перезапишет'],
+ ['官方插件中的当前登录状态,且无法找回这些未同步的更新。', 'текущее состояние входа официального плагина; восстановить несинхронизированные обновления будет невозможно.'],
+
+ // Relay provider names and descriptions shown in the account dialogs.
+ ['月之暗面(Kimi)', 'Moonshot AI (Kimi)'],
+ ['编程套餐:5H / 7D 额度;使用 Kimi Code Key,模型按会员权限选择', 'Тариф для разработки: квоты 5ч / 7д; используется Kimi Code Key, модели зависят от подписки'],
+ ['智谱', 'Zhipu AI'],
+ ['开放平台 API;OpenAI 兼容,支持模型映射', 'API открытой платформы; совместим с OpenAI, поддерживает сопоставление моделей'],
+ ['GLM Coding Plan(codex /v1/responses ↔ /chat/completions 翻译,内置)', 'GLM Coding Plan (встроенный перевод codex /v1/responses ↔ /chat/completions)'],
+ ['小米', 'Xiaomi'],
+ ['MiMo 按量付费(sk-key;非 Token Plan,无配额限制按用量计费)', 'MiMo с оплатой по потреблению (sk-key; не Token Plan, оплата по фактическому использованию без квоты)'],
+ ['PinCC / PackyCode / AICodeMirror / 自建 CLIProxyAPI 等;余额自动探测', 'PinCC, PackyCode, AICodeMirror, собственный CLIProxyAPI и другие; баланс определяется автоматически'],
+ ['原生 Responses API;支持官网或自有中转,API 地址和模型 ID 均可修改', 'Нативный Responses API; поддерживает официальный или собственный relay, адрес API и ID модели можно изменить'],
+ ['开放平台 API,原生 Responses;使用平台 API Key,非 Kimi Code 订阅密钥', 'API открытой платформы с нативным Responses; используется API-ключ платформы, а не ключ подписки Kimi Code'],
+ ['按量付费 / 订阅服务;OpenAI Chat 兼容', 'Оплата по потреблению или подписка; совместим с OpenAI Chat'],
+ ['阿里云', 'Alibaba Cloud'],
+ ['百炼开放平台;OpenAI 兼容模式', 'Открытая платформа Bailian; режим совместимости с OpenAI'],
+ ['通义', 'Qwen'],
+ ['字节跳动', 'ByteDance'],
+ ['火山方舟 (Coding Plan / Agent Plan / 按量付费);model 字段需用户填实际 endpoint id', 'Volcano Engine Ark (Coding Plan, Agent Plan или оплата по потреблению); в поле model укажите фактический ID endpoint'],
+ ['火', 'V'],
+ ['腾讯', 'Tencent'],
+ ['腾讯混元 (Token Plan / TokenHub 按量);OpenAI Chat 兼容', 'Tencent Hunyuan (Token Plan или TokenHub с оплатой по потреблению); совместим с OpenAI Chat'],
+ ['混', 'H'],
+ ['百度', 'Baidu'],
+ ['百度千帆 / 文心一言 ERNIE(按量付费 / 中国订阅)', 'Baidu Qianfan / ERNIE (оплата по потреблению или подписка для Китая)'],
+ ['千', 'B'],
+ ['优刻得(UCloud)', 'UCloud'],
+ ['UCloud Modelverse (Coding Plan + 按量付费 国内/海外);多模型聚合', 'UCloud Modelverse (Coding Plan и оплата по потреблению в Китае или за его пределами); агрегатор моделей'],
+ ['Fireworks AI 海外高速推理(按量 / Fire Pass 国际订阅);OpenAI Chat 兼容', 'Fireworks AI: высокоскоростной инференс за пределами Китая (оплата по потреблению или международная подписка Fire Pass); совместим с OpenAI Chat'],
+ ['阶跃星辰 Step Plan', 'StepFun Step Plan'],
+ ['Step Plan 订阅;模型直接读取 /models,额度可用控制台 Oasis-Token 查询', 'Подписка Step Plan; модели загружаются из /models, квоту можно проверить по Oasis-Token из консоли'],
+ ['阶跃星辰', 'StepFun'],
+ ['阶跃星辰 step 系列 (按量付费 / 中国订阅 / 国际订阅)', 'Серия StepFun Step (оплата по потреблению, подписка для Китая или международная подписка)'],
+ ['多模型聚合 API;可配置厂商模型 ID', 'API-агрегатор моделей; можно настроить ID модели провайдера'],
+ ['Aiberm 全球聚合 API(OpenAI/Anthropic 双协议,模型按 token group 动态)', 'Глобальный API-агрегатор Aiberm (протоколы OpenAI и Anthropic; модели зависят от группы токена)'],
+ ['神马中转 API 全球按量付费聚合(OpenAI/Anthropic 双协议)', 'Глобальный relay API Shenma с оплатой по потреблению (протоколы OpenAI и Anthropic)'],
+ ['神', 'S'],
+ ['魔搭(阿里云)', 'ModelScope (Alibaba Cloud)'],
+ ['阿里魔搭 ModelScope 按量付费;OpenAI Chat 兼容(Qwen 系列为主)', 'Alibaba ModelScope с оплатой по потреблению; совместим с OpenAI Chat (преимущественно модели Qwen)'],
+ ['魔', 'M'],
+ ['Ollama 本地推理(localhost:11434,需先 ollama pull 模型);API Key 任意填一个非空字符串即可', 'Локальный инференс Ollama (localhost:11434; сначала выполните ollama pull для модели); в качестве API-ключа подойдёт любая непустая строка'],
+
+ // English commands that have clear Russian UI equivalents.
+ ['● Proxy ON', '● Прокси включён'],
+ ['● Proxy OFF', '● Прокси выключен'],
+ ['📋 Dashboard', '📋 Открыть панель'],
+ ['↻ Refresh', '↻ Обновить'],
+ ['Base URL', 'Базовый URL'],
+ ['Base URL *', 'Базовый URL *'],
+ ['API Key', 'API-ключ'],
+ ['API Key (sk-... / tp-...) *', 'API-ключ (sk-... / tp-...) *'],
+ ['deep link', 'ссылка приложения'],
+ ['deep link。', 'ссылка приложения.'],
+ ['Plan', 'Тариф'],
+ ['Email / Plan', 'Email / тариф'],
+ ['Session', 'Сессия'],
+ ['Token', 'Токены'],
+ ['检查同步状态失败:', 'Не удалось проверить состояние синхронизации:'],
+ ['[Frontend] 收到后台刷新通知,重新加载账号列表', '[Frontend] Получено уведомление об обновлении; список аккаунтов загружается заново'],
+ ['[Frontend] 收到设置更新通知,重新加载设置', '[Frontend] Получено уведомление об изменении; настройки загружаются заново'],
+ ['同步 IDE 状态失败:', 'Не удалось синхронизировать состояние IDE:'],
+ ['加载设置失败:', 'Не удалось загрузить настройки:'],
+ ['加载代理状态失败:', 'Не удалось загрузить состояние прокси:'],
+ ['次', ' раз'],
+ ['glm_zhipu · GLM 自家 quota', 'glm_zhipu · собственная квота GLM'],
+ ['是去掉异常值后最稳的估计。Δpct<3% 的样本被丢弃(used_pct 是整数,量化误差会失真)。', 'даёт наиболее устойчивую оценку после удаления выбросов. Образцы с Δpct<3% отбрасываются: used_pct является целым числом, поэтому ошибка квантования искажает результат.'],
+ ['心跳时自动把本机 current 对齐到 Server 的 current。', 'При проверке связи локальный current автоматически синхронизируется с current на Server.'],
+ ['Server 不可达会静默跳过,保持本机现状。', 'Если Server недоступен, синхронизация молча пропускается и локальное состояние сохраняется.'],
+ ['失效(约 30 天)后账号会变成不可用,', 'истекает примерно через 30 дней, после чего аккаунт становится недоступен; '],
+ ['需要重新粘贴一次新 session。', 'потребуется вставить новую сессию. '],
+ ['秒 后重置', 'с до сброса'],
+ ['⚠️ 登录状态冲突警告', '⚠️ Конфликт состояния входа'],
+ ['检测到官方 Codex 插件中存在未同步的 Token 更新。', 'В официальном Codex обнаружены несинхронизированные обновления токена.'],
+ ['当前的账号状态与官方文件不一致:', 'Текущее состояние аккаунта не совпадает с официальным файлом:'],
+ ['直接切换将覆盖官方插件中的当前登录状态,且无法找回这些未同步的更新。', 'Прямое переключение перезапишет текущий вход официального плагина; эти несинхронизированные обновления нельзя будет восстановить.'],
+ ['确认覆盖并切换', 'Перезаписать и переключить'],
+ ['以 IDE 为准 (同步状态)', 'Взять состояние из IDE'],
+ ['导出成功!', 'Экспорт выполнен.'],
+ ['导出失败:', 'Экспорт не выполнен:'],
+ ['加载中...', 'Загрузка...'],
+ ['加载中…', 'Загрузка...'],
+ ['代理运行中', 'Прокси запущен'],
+ ['代理未启动', 'Прокси остановлен'],
+ ['仪表盘', 'Панель'],
+ ['账号管理', 'Аккаунты'],
+ ['代理控制', 'Управление прокси'],
+ ['本地代理服务器', 'Локальный прокси-сервер'],
+ ['路由', 'Маршруты'],
+ ['统计', 'Статистика'],
+ ['缓存', 'Кэш'],
+ ['设置', 'Настройки'],
+ ['+ 登录账号', '+ Войти в аккаунт'],
+ ['+ 添加中转', '+ Добавить relay'],
+ ['+ 添加路由', '+ Добавить маршрут'],
+ ['从 IDE 自动导入', 'Автоимпорт из IDE'],
+ ['同步状态失败:', 'Не удалось синхронизировать состояние:'],
+ ['切换检查失败:', 'Не удалось проверить переключение:'],
+ ['保守切换也失败了:', 'Резервное переключение тоже не удалось:'],
+ ['确认切换失败:', 'Не удалось подтвердить переключение:'],
+ ['覆盖 ~/.codex/auth.json 失败:', 'Не удалось перезаписать ~/.codex/auth.json:'],
+ ['后台保活已停用', 'Фоновое продление отключено'],
+ ['后台保活临时失败', 'Временный сбой фонового продления'],
+ ['代理已自动切号', 'Прокси автоматически переключил аккаунт. '],
+ ['检测到封号', 'Обнаружена блокировка аккаунта'],
+ ['已自动切换', 'Переключение выполнено автоматически'],
+ ['当前账号', 'Текущий аккаунт'],
+ ['取消', 'Отмена'],
+ ['关闭', 'Закрыть'],
+ ['确认', 'Подтвердить'],
+ ['保存', 'Сохранить'],
+ ['删除', 'Удалить'],
+ ['刷新', 'Обновить'],
+ ['切换', 'Переключить'],
+ ['导入', 'Импорт'],
+ ['导出', 'Экспорт'],
+ ['添加', 'Добавить'],
+ ['移除', 'Убрать'],
+ ['清空', 'Очистить'],
+ ['复制', 'Скопировать'],
+ ['已复制', 'Скопировано'],
+ ['保存并刷新', 'Сохранить и обновить'],
+ ['测试连接', 'Проверить соединение'],
+ ['重启 HTTP 服务', 'Перезапустить HTTP-сервис'],
+ ['写入环境变量', 'Записать переменные окружения'],
+ ['环境变量', 'Переменные окружения'],
+ ['手动启动', 'Ручной запуск'],
+ ['复制命令到终端运行', 'Скопируйте команду и выполните в терминале'],
+ ['局域网客户端', 'Клиент в локальной сети'],
+ ['局域网可用', 'Доступно в LAN'],
+ ['允许局域网访问', 'Разрешить доступ из LAN'],
+ ['全局代理(CLI + App 全覆盖)', 'Глобальный прокси (CLI + приложение)'],
+ ['同时写入 ~/.zshrc、launchctl 和 ~/.codex/config.toml,终端 CLI 和 Codex App 均走代理', 'Записывает настройки в ~/.zshrc, launchctl и ~/.codex/config.toml; терминальный CLI и Codex App будут идти через прокси'],
+ ['定时额度刷新', 'Плановое обновление квот'],
+ ['自动刷新账号额度', 'Автоматически обновлять квоты аккаунтов'],
+ ['刷新间隔(分钟/账号)', 'Интервал обновления (минут на аккаунт)'],
+ ['每个账号之间的刷新间隔', 'Пауза между обновлением отдельных аккаунтов'],
+ ['每轮刷新账号数', 'Аккаунтов за цикл'],
+ ['每轮循环刷新多少个账号', 'Сколько аккаунтов обновлять за один цикл'],
+ ['切号通知', 'Уведомления о переключении'],
+ ['macOS 系统通知', 'Системные уведомления macOS'],
+ ['切号时在屏幕右上角弹出系统通知', 'Показывать системное уведомление при переключении аккаунта'],
+ ['对话内注入通知(实验性)', 'Вставлять уведомление в диалог (экспериментально)'],
+ ['切号后在 Codex 对话中插入一条切号提示消息。可能影响对话状态。', 'После переключения вставляет сообщение в диалог Codex. Может повлиять на состояние диалога.'],
+ ['Codex 配置', 'Настройки Codex'],
+ ['Fast 模式', 'Режим Fast'],
+ ['更快推理速度,但消耗 2x 额度。', 'Более быстрые ответы, но расход квоты в 2 раза выше.'],
+ ['更快推理速度,但消耗 2x 额度。当前:已开启', 'Более быстрые ответы, но расход квоты в 2 раза выше. Сейчас включено'],
+ ['更快推理速度,但消耗 2x 额度。当前:已关闭', 'Более быстрые ответы, но расход квоты в 2 раза выше. Сейчас выключено'],
+ ['当前:已开启', ' Сейчас включено'],
+ ['当前:已关闭', ' Сейчас выключено'],
+ ['关闭 Fast', 'Отключить Fast'],
+ ['开启 Fast', 'Включить Fast'],
+ ['Goals 实验特性', 'Экспериментальная функция Goals'],
+ ['写入 [features] goals = true 到 ~/.codex/config.toml。', 'Записывает [features] goals = true в ~/.codex/config.toml.'],
+ ['写入 [features] goals = true 到 ~/.codex/config.toml。当前:已开启', 'Записывает [features] goals = true в ~/.codex/config.toml. Сейчас включено'],
+ ['写入 [features] goals = true 到 ~/.codex/config.toml。当前:已关闭', 'Записывает [features] goals = true в ~/.codex/config.toml. Сейчас выключено'],
+ ['写入 [features] goals = true 到 ~/.codex/config.toml', 'Записывает [features] goals = true в ~/.codex/config.toml'],
+ ['关闭 Goals', 'Отключить Goals'],
+ ['开启 Goals', 'Включить Goals'],
+ ['进程管理', 'Управление процессами'],
+ ['终止所有 Codex 进程', 'Завершить все процессы Codex'],
+ ['强制终止所有运行中的 codex 进程,用于切换代理模式后重启或排错', 'Принудительно завершает запущенные процессы codex для перезапуска после смены режима прокси или диагностики'],
+ ['终止中...', 'Завершение...'],
+ ['终止进程', 'Завершить процессы'],
+ ['智能切号策略', 'Стратегия автопереключения'],
+ ['5h 配额预防性切号阈值', 'Порог раннего переключения для квоты 5ч'],
+ ['剩余配额低于此百分比时提前切号(0 = 仅 429 触发,推荐 10)', 'Переключаться заранее, когда остаток ниже этого процента (0 = только при 429, рекомендуется 10)'],
+ ['周配额预防性切号阈值', 'Порог раннего переключения для недельной квоты'],
+ ['剩余周配额低于此百分比时提前切号(0 = 仅 429 触发,推荐 5)', 'Переключаться заранее, когда недельный остаток ниже этого процента (0 = только при 429, рекомендуется 5)'],
+ ['Free 账号保护线', 'Защитный порог Free-аккаунтов'],
+ ['Free 账号剩余配额低于此百分比时强制切号(0 = 不特殊处理,推荐 35)', 'Принудительно переключаться с Free-аккаунта ниже этого остатка (0 = без особой обработки, рекомендуется 35)'],
+ ['智能切号允许 FREE 账号', 'Разрешить Free-аккаунты для автопереключения'],
+ ['点击“切换下一个账号”时,是否允许自动寻找并切到 FREE 账号(默认优先付费账号)', 'Разрешать ли переход на Free-аккаунт при выборе следующего аккаунта (по умолчанию приоритет у платных)'],
+ ['SSE Bootstrap 嗅探窗口', 'Окно анализа SSE bootstrap'],
+ ['字节上限', 'Лимит байт'],
+ ['时间上限', 'Лимит времени'],
+ ['读到这么多字节还没见到内容事件就放行 codex(默认 32768,越大越能逮住慢上游的限额事件)', 'Если до этого объёма байт не найдено событие с содержимым, запрос пропускается в codex (по умолчанию 32768; большее значение лучше ловит медленные события лимита)'],
+ ['等首个内容事件最长等多久(默认 8000ms)。配合 SSE keep-alive 心跳,拉到 30000 也不会让 codex 那头超时。', 'Максимальное ожидание первого события с содержимым (по умолчанию 8000 мс). С SSE keep-alive можно увеличить до 30000 без тайм-аута на стороне codex.'],
+ ['界面外观', 'Внешний вид'],
+ ['界面配色', 'Цветовая схема'],
+ ['主界面颜色的色调风格', 'Цветовой стиль основного окна'],
+ ['经典蓝', 'Классический синий'],
+ ['玛瑙绿', 'Агатовый зелёный'],
+ ['暗黑护眼', 'Тёмная тема'],
+ ['关于', 'О программе'],
+ ['多账号智能切换 + 本地代理 + 用量统计', 'Умное переключение аккаунтов, локальный прокси и статистика использования'],
+ ['你好,', 'Здравствуйте,'],
+ ['用户', 'пользователь'],
+ ['手机锚生效:', 'Мобильная привязка активна:'],
+ ['手机锚', 'Мобильная привязка'],
+ ['Codex.app 仍以', 'Codex.app остаётся онлайн как'],
+ ['身份在线(手机 bridge 不掉线),', 'через bridge телефона без разрыва,'],
+ ['代理出口已切到', 'выход прокси переключён на'],
+ ['磁盘 auth.json 落后:', 'auth.json на диске отстаёт: '],
+ ['登录状态不一致:', 'Состояние входа не совпадает: '],
+ ['停在', 'Остался на '],
+ ['未知账号', 'Неизвестный аккаунт'],
+ ['代理正在注入当前激活号的 token,', 'прокси подставляет токен активного аккаунта, '],
+ ['不影响 codex 工作', 'это не мешает работе codex'],
+ ['关闭代理后 codex 会读到这个号', 'после отключения прокси codex прочитает этот аккаунт'],
+ ['检测到 IDE 正在使用', 'Обнаружено, что IDE использует'],
+ ['同步磁盘', 'Синхронизировать диск'],
+ ['修正激活状态', 'Исправить активное состояние'],
+ ['立即导入该账号', 'Сразу импортировать этот аккаунт'],
+ ['授权已失效,请删除后重新登录', 'Авторизация истекла; удалите аккаунт и войдите заново'],
+ ['失效', 'Недействителен'],
+ ['与 ~/.codex/auth.json 身份不匹配', 'Не совпадает с идентификатором в ~/.codex/auth.json'],
+ ['IDE 当前用:', 'IDE сейчас использует:'],
+ ['用此账号覆盖 IDE', 'Перезаписать IDE этим аккаунтом'],
+ ['改用 IDE 当前', 'Взять текущий из IDE'],
+ ['导入 IDE 当前', 'Импортировать текущий из IDE'],
+ ['切换账号', 'Переключить аккаунт'],
+ ['暂无账号', 'Аккаунтов нет'],
+ ['最佳账号推荐', 'Рекомендуемый аккаунт'],
+ ['推荐账号', 'Рекомендация'],
+ ['暂无推荐', 'Рекомендаций нет'],
+ ['一键切换最佳', 'Переключиться на лучший'],
+ ['查看所有账号', 'Все аккаунты'],
+ ['导出账号数据', 'Экспорт аккаунтов'],
+ ['账号总数', 'Всего аккаунтов'],
+ ['账号信息', 'Данные аккаунта'],
+ ['账号名称', 'Имя аккаунта'],
+ ['搜索邮箱...', 'Поиск по email...'],
+ ['关闭自动重载 IDE', 'Отключить автообновление IDE'],
+ ['开启自动重载 IDE', 'Включить автообновление IDE'],
+ ['刷新所有账号配额', 'Обновить квоты всех аккаунтов'],
+ ['共 ', 'Всего '],
+ ['点击复制账号', 'Скопировать аккаунт'],
+ ['该账号已被 OpenAI 封禁', 'Этот аккаунт заблокирован OpenAI'],
+ ['封号', 'Заблокирован'],
+ ['登录已失效,可能是 refresh_token 过期、被撤销或会话在其他设备结束', 'Вход истёк: возможно, refresh_token устарел, отозван или сессия завершена на другом устройстве'],
+ ['需重新登录', 'Нужно войти заново'],
+ ['该账号 Token 已过期或失效', 'Токен аккаунта истёк или недействителен'],
+ ['过期', 'Истёк'],
+ ['主动重置次数(剩余 0 次,无法重置)', 'Активные сбросы: осталось 0, сброс недоступен'],
+ ['主动重置次数', 'Активные сбросы'],
+ ['重置中', 'Сброс...'],
+ ['该账号当前没有可用的主动重置次数。', 'У этого аккаунта нет доступных активных сбросов.'],
+ ['消耗 1 次会把当前已耗尽的 5H / 周限额窗口立刻清零,此操作不可撤销。若额度还没用到上限,上游会返回「无可重置」且不扣次数。', 'Один сброс сразу обнулит исчерпанное окно 5ч/неделя. Действие необратимо. Если лимит ещё не исчерпан, upstream вернёт «сбрасывать нечего» и попытка не будет списана.'],
+ ['仍可直接消耗 1 次', 'Можно списать 1 попытку напрямую'],
+ ['消耗哪条由服务端决定', 'Какое окно сбросить, решает сервер'],
+ ['将被消耗', 'Будет списано'],
+ ['立即重置', 'Сбросить сейчас'],
+ ['已重置', 'Сброшено'],
+ ['当前没有可重置的限额', 'Сейчас нет лимита для сброса'],
+ ['没有可用的主动重置次数了', 'Активных сбросов больше нет'],
+ ['该重置请求已经兑现过了', 'Этот запрос сброса уже использован'],
+ ['请求过于频繁', 'Слишком частые запросы'],
+ ['Token 已失效,需要重新登录', 'Токен недействителен, нужен повторный вход'],
+ ['账号已被封禁', 'Аккаунт заблокирован'],
+ ['账号已到期', 'Срок аккаунта истёк'],
+ ['账号今天到期,点击修改', 'Аккаунт истекает сегодня, нажмите для изменения'],
+ ['点击设置账号到期日', 'Нажмите, чтобы задать срок аккаунта'],
+ ['日期格式异常,点击修正', 'Некорректный формат даты, нажмите для исправления'],
+ ['日期内容异常,点击修正', 'Некорректная дата, нажмите для исправления'],
+ ['近 7 天', 'Ближайшие 7 дней'],
+ ['清除日期', 'Очистить дату'],
+ ['账号到期日', 'Дата окончания аккаунта'],
+ ['到期日期', 'Дата окончания'],
+ ['编辑备注', 'Изменить заметку'],
+ ['发送 Codex 邀请', 'Отправить приглашение Codex'],
+ ['发送邀请', 'Отправить приглашение'],
+ ['发送中…', 'Отправка...'],
+ ['请输入 skill 名称', 'Введите имя навыка'],
+ ['请至少填写 1 个邀请邮箱', 'Укажите хотя бы один email для приглашения'],
+ ['当前套餐不支持发邀请(free 号没有邀请权限)', 'Текущий тариф не поддерживает приглашения (у Free-аккаунтов нет такого права)'],
+ ['已发送,邮件已投递到对方邮箱。', 'Отправлено, письмо доставлено на указанный email.'],
+ ['邀请未成功', 'Приглашение не отправлено'],
+ ['该邮箱无法被邀请(通常是已注册过 ChatGPT 的老用户,推荐奖励只对新邮箱有效)', 'Этот email нельзя пригласить: обычно это уже зарегистрированный ChatGPT-пользователь, бонус действует только для новых email'],
+ ['已经给该邮箱发过邀请了(同一邮箱不能重复邀请)', 'На этот email уже отправляли приглашение; повторить нельзя'],
+ ['邀请链接', 'Ссылка приглашения'],
+ ['有效;同一邮箱只能邀一次。', 'действительно; один email можно пригласить только один раз.'],
+ ['邮箱列表(每行一个)', 'Список email, по одному в строке'],
+ ['邮箱 OTP 批量自动授权', 'Пакетная OTP-авторизация email'],
+ ['每个邮箱 OTP 超时(秒)', 'Тайм-аут OTP на email (сек)'],
+ ['开始批量授权', 'Начать пакетную авторизацию'],
+ ['授权中…', 'Авторизация...'],
+ ['重试失败', 'Повторить неудачные'],
+ ['官方 OAuth 授权', 'Официальная OAuth-авторизация'],
+ ['OpenAI 登录 (推荐)', 'Вход OpenAI (рекомендуется)'],
+ ['直接通过 OpenAI 官方渠道登录。支持令牌自动续期,多账号切换更稳定,无需再手动更新 `auth.json`。', 'Вход через официальный канал OpenAI. Поддерживает автообновление токена, стабильнее для нескольких аккаунтов и не требует ручного обновления `auth.json`.'],
+ ['授权将在你系统的默认浏览器中完成,安全可信。', 'Авторизация откроется в браузере по умолчанию.'],
+ ['复制授权链接(指定浏览器登录)', 'Скопировать ссылку авторизации'],
+ ['浏览器没跳回来?手动粘贴回调链接', 'Браузер не вернулся в приложение? Вставьте callback-ссылку вручную'],
+ ['从浏览器地址栏复制完整 URL(包含', 'Скопируйте полный URL из адресной строки браузера, включая'],
+ ['将从本地官方 Codex 的登录状态', 'Будут извлечены данные входа из локального официального Codex'],
+ ['中提取认证信息。', ''],
+ ['从官方导入', 'Импорт из официального Codex'],
+ ['批量导入文件', 'Пакетный импорт файлов'],
+ ['自动识别格式,可一次选多个文件:', 'Формат распознаётся автоматически, можно выбрать несколько файлов:'],
+ ['codex-switcher 原生 accounts.json', 'родной accounts.json codex-switcher'],
+ ['chatgpt.com 网页登录的 session JSON', 'session JSON из веб-входа chatgpt.com'],
+ ['Web session 没有', 'В Web session нет'],
+ ['绕过 Codex 手机验证。支持单个对象、对象数组、或者嵌套容器,会自动递归识别。', 'обходит телефонную проверку Codex. Поддерживаются одиночный объект, массив объектов и вложенные контейнеры; распознавание рекурсивное.'],
+ ['解析', 'Распознано'],
+ ['新增账号详情', 'Детали новых аккаунтов'],
+ ['导入账号详情', 'Детали импортированных аккаунтов'],
+ ['失败项', 'Ошибки'],
+ ['失败', 'Ошибка'],
+ ['新增', 'Добавлено'],
+ ['同名', 'с тем же именем'],
+ ['同邮箱已存在的账号会跳过,不覆盖现有 token。', 'Аккаунты с уже существующим email пропускаются, существующие токены не перезаписываются.'],
+ ['添加中转 (Coding Plan / 通用 Responses 中转)', 'Добавить relay (Coding Plan / универсальный Responses relay)'],
+ ['选择中转服务', 'Выберите relay-сервис'],
+ ['选预设 · 填 Key', 'Выберите пресет и вставьте ключ'],
+ ['选完进入下一步,base URL 已自动填好', 'После выбора переходите дальше; base URL заполнится автоматически'],
+ ['选择目标账号', 'Выберите целевой аккаунт'],
+ ['选择会话', 'Выберите сессию'],
+ ['从最近会话挑选', 'Выбрать из недавних сессий'],
+ ['手动输入 ID', 'Ввести ID вручную'],
+ ['绑定当前活跃会话', 'Привязать текущую активную сессию'],
+ ['加载最近会话…', 'Загрузка недавних сессий...'],
+ ['最近没有活跃会话', 'Недавних активных сессий нет'],
+ ['粘贴 session_id(UUID 格式,36 字符)', 'Вставьте session_id (UUID, 36 символов)'],
+ ['看起来不像 UUID。请检查长度是否为 36 字符、包含 4 个连字符。', 'Это не похоже на UUID. Проверьте длину 36 символов и 4 дефиса.'],
+ ['把会话钉到账号', 'Закрепить сессию за аккаунтом'],
+ ['指定 codex 会话强制使用某个账号,绕过全局自动切号。', 'Заставляет указанную сессию codex использовать выбранный аккаунт, обходя глобальное автопереключение.'],
+ ['当前绑定账号', 'Текущая привязка'],
+ ['✓ 当前绑定', '✓ Текущая привязка'],
+ ['条规则,启用', 'правил, включено'],
+ ['还没有路由规则。', 'Правил маршрутизации пока нет.'],
+ ['没有匹配的最近会话。试试调整搜索词或切换到「手动输入 ID」。', 'Подходящих недавних сессий нет. Измените поиск или переключитесь на ручной ввод ID.'],
+ ['没有匹配', 'Нет совпадений'],
+ ['删除后该 session 将恢复全局自动切号。', 'После удаления эта session вернётся к глобальному автопереключению.'],
+ ['确认删除路由', 'Удалить маршрут?'],
+ ['目标账号已被删除', 'Целевой аккаунт удалён'],
+ ['Skills', 'Навыки'],
+ ['Skill', 'Навык'],
+ ['skill', 'навык'],
+ ['Usage Monitor', 'Монитор квот'],
+ ['Proxy ON', 'Прокси включён'],
+ ['Proxy OFF', 'Прокси выключен'],
+ ['SESSION', 'СЕССИЯ'],
+ ['WEEKLY', 'НЕДЕЛЯ'],
+ ['COST USAGE', 'РАСХОДЫ'],
+ ['TOKEN USAGE', 'ТОКЕНЫ'],
+ ['Remaining', 'Осталось'],
+ ['Spent', 'Потрачено'],
+ ['Tokens', 'Токены'],
+ ['HEALTHY', 'НОРМА'],
+ ['WARNING', 'ВНИМАНИЕ'],
+ ['CRITICAL', 'КРИТИЧНО'],
+ ['Resets in', 'Сброс через'],
+ ['In', 'Вход'],
+ ['Out', 'Выход'],
+ ['Vs 上月', 'К прошлому месяцу'],
+ ['手机锚 = 当前号', 'Мобильная привязка = текущий аккаунт'],
+ ['代理出口 ', 'выход прокси '],
+ ['需重登', 'Нужен вход'],
+ ['Google 当前', 'Текущий Google'],
+ ['模型 当前', 'Текущая модель'],
+ ['部分模型当前', 'Часть моделей текущие'],
+ ['Kimi 当前', 'Текущий Kimi'],
+ ['DeepSeek 当前', 'Текущий DeepSeek'],
+ ['当前模型:', 'Текущие модели: '],
+ ['Token 配额', 'Квота токенов'],
+ ['Spark 周', 'Spark нед.'],
+ ['三方', 'Сторонние'],
+ ['未获取数据', 'Данные не получены'],
+ ['次数未知', 'Сбросы неизвестны'],
+ ['上游未返回重置次数,不代表次数已清空。点击查询银行明细。', 'Upstream не вернул число сбросов; это не значит, что они закончились. Нажмите, чтобы проверить детали.'],
+ ['当前已被限流(额度桶为 0)——现在用一次主动重置回收最大,点击查看明细', 'Сейчас действует лимит (окно квоты равно 0) - активный сброс даст максимальный эффект. Нажмите, чтобы посмотреть детали.'],
+ ['点击查看所有主动重置次数(含各自到期时间),再消耗一次重置限额窗口', 'Показать все активные сбросы и сроки их действия, затем списать один сброс окна лимита'],
+ ['登录账号 (OpenAI / Google / 导入)', 'Войти в аккаунт (OpenAI / Google / импорт)'],
+ ['刷新 Codex 当前账号额度', 'Обновить квоту текущего аккаунта Codex'],
+ ['刷新当前列表额度', 'Обновить квоты текущего списка'],
+ ['ACCOUNT INVITE', 'ПРИГЛАШЕНИЕ'],
+ ['OFFER', 'ПРЕДЛОЖЕНИЕ'],
+ ['RECIPIENTS', 'ПОЛУЧАТЕЛИ'],
+ ['RESULT', 'РЕЗУЛЬТАТ'],
+ ['HISTORY', 'ИСТОРИЯ'],
+ ['Session 导入', 'Импорт Session'],
+ ['选择文件并导入', 'Выбрать файлы и импортировать'],
+ ['解析并导入', 'Распознать и импортировать'],
+ ['导入中…', 'Импорт...'],
+ ['跳过', 'Пропущено'],
+ ['仅 RT,首次请求自动 refresh', 'только RT, при первом запросе будет auto-refresh'],
+ ['✓ ready', '✓ готово'],
+ ['含 refresh_token', 'есть refresh_token'],
+ ['无 refresh_token,到期后需重新导入', 'нет refresh_token, после истечения нужно импортировать заново'],
+ ['id_token 合成', 'id_token создан автоматически'],
+ ['注意:', 'Внимание:'],
+ ['Plus 账号能正常调用模型,Free 账号即使导入也无 API 权限。', 'Plus-аккаунты смогут вызывать модели; у Free-аккаунтов API-доступа нет даже после импорта.'],
+ ['粘贴', 'Вставьте'],
+ ['网页登录的 session JSON', 'session JSON из веб-входа'],
+ ['连接 Google 账号', 'Подключить Google-аккаунт'],
+ ['等待浏览器授权…', 'Ожидание авторизации в браузере...'],
+ ['授权后 Gemini 模型通过 Codex Switcher 原生路由;不会修改 Codex 的 OpenAI 登录身份。', 'После авторизации модели Gemini пойдут через родную маршрутизацию Codex Switcher; OpenAI-вход Codex изменён не будет.'],
+ ['不打开默认浏览器,把 Google 授权链接复制到剪贴板', 'Не открывать браузер по умолчанию, а скопировать ссылку Google-авторизации в буфер'],
+ ['导入中转站账号', 'Импорт relay-аккаунта'],
+ ['链接里携带的', 'В ссылке передан'],
+ ['未在内置白名单中,已忽略。账号仍可正常使用,', 'не входит во встроенный белый список и был проигнорирован. Аккаунт можно использовать,'],
+ ['但额度查询不会自动进行。导入后可在账号详情中手动选 usage preset。', 'но квоты не будут обновляться автоматически. После импорта можно вручную выбрать usage preset в деталях аккаунта.'],
+ ['导入失败:', 'Импорт не выполнен:'],
+ ['导入中转站', 'Импортировать relay'],
+ ['预设', 'Пресет'],
+ ['选预设自动填 base_url,贴 API Key 即可。也支持', 'Выберите пресет, base_url заполнится автоматически, затем вставьте API Key. Также поддерживается'],
+ ['余额查询策略', 'Стратегия проверки баланса'],
+ ['不拉取', 'Не запрашивать'],
+ ['登录 platform.stepfun.com 后复制 Oasis-Token,也可粘贴 Cookie header', 'Войдите на platform.stepfun.com и скопируйте Oasis-Token; можно вставить и Cookie header'],
+ ['登录 platform.xiaomimimo.com 后,从 Network 复制 Cookie header', 'Войдите на platform.xiaomimimo.com и скопируйте Cookie header из Network'],
+ ['该凭证只用于查询 Step Plan 额度,不会参与模型请求;实际调用仍使用上面的 Step API Key。', 'Эти данные нужны только для проверки квоты Step Plan и не участвуют в запросах к моделям; реальные вызовы используют Step API Key выше.'],
+ ['这里的 Cookie 只用于查询 Token Plan 用量,不会参与模型请求。实际调用仍使用上面的 tp-key。', 'Этот Cookie нужен только для проверки расхода Token Plan и не участвует в запросах к моделям; реальные вызовы используют tp-key выше.'],
+ ['上游协议', 'Протокол upstream'],
+ ['中转站讲什么 wire format', 'какой wire format понимает relay'],
+ ['模型兜底', 'Резервная модель'],
+ ['客户端发的 model 没命中映射时,统一替换成这个', 'если model от клиента не найден в карте, заменить на это значение'],
+ ['模型映射表', 'Таблица сопоставления моделей'],
+ ['每行', 'Каждая строка'],
+ ['客户端model=中转站model', 'client_model=relay_model'],
+ ['如 glm-5.1(留空 = 透传不替换)', 'например glm-5.1 (пусто = передавать без замены)'],
+ ['修改 StepFun 额度凭证', 'Изменить данные проверки квоты StepFun'],
+ ['修改 MiMo 配额 Cookie', 'Изменить Cookie проверки квоты MiMo'],
+ ['账号:', 'Аккаунт: '],
+ ['后复制', 'и скопируйте'],
+ ['后,从 Network 请求里复制', 'и скопируйте из запроса Network'],
+ ['也可粘贴包含它的 Cookie header。', 'также можно вставить Cookie header, где он содержится.'],
+ ['仓库', 'Репозитории'],
+ ['发现', 'Поиск'],
+ ['已安装', 'Установлено'],
+ ['未链接', 'Не подключено'],
+ ['已链接', 'Подключено'],
+ ['暂无已安装的 skill', 'Установленных навыков пока нет'],
+ ['无描述', 'Без описания'],
+ ['正在扫描 GitHub 仓库...', 'Сканирование GitHub-репозиториев...'],
+ ['点击"刷新"从仓库发现 skill', 'Нажмите «Обновить», чтобы найти навыки в репозиториях'],
+ ['确认卸载', 'Подтвердите удаление'],
+ ['即将卸载', 'Будет удалён'],
+ ['此操作将从所有 CLI 目录移除该 skill。', 'Это удалит навык из всех CLI-каталогов.'],
+ ['以确认:', 'для подтверждения:'],
+ ['卸载', 'Удалить'],
+ ['发现失败:', 'Поиск не выполнен:'],
+ ['安装失败:', 'Установка не выполнена:'],
+ ['卸载失败:', 'Удаление не выполнено:'],
+ ['无法读取 SKILL.md', 'Не удалось прочитать SKILL.md'],
+ ['操作失败:', 'Операция не выполнена:'],
+ ['同步完成', 'Синхронизация завершена'],
+ ['同步失败:', 'Синхронизация не выполнена:'],
+ ['同步中...', 'Синхронизация...'],
+ ['同步到 Server', 'Синхронизировать на Server'],
+ ['将本机 SSOT 下所有 skill 推送到 Server(按黑名单跳过)', 'Отправить все навыки из локального SSOT на Server с учетом чёрного списка'],
+ ['全量同步', 'Полная синхронизация'],
+ ['搜索 skill...', 'Поиск навыка...'],
+ ['推送', 'Отправлено'],
+ ['已断开链接', 'отключено от Skills'],
+ ['已链接到 Skills', 'подключено к Skills'],
+ ['已卸载', 'Удалено'],
+ ['自动导入', 'Автоимпорт'],
+ ['个新 skill', 'новых навыков'],
+ [' 个 skill', ' навыков'],
+ ['已添加', 'Добавлено'],
+ ['套餐待同步', 'Тариф ожидает синхронизации'],
+ ['到期,点击修改', 'истекает, нажмите для изменения'],
+ ['今天到期', 'истекает сегодня'],
+ ['今天', 'сегодня'],
+ ['还有 ', 'осталось '],
+ [' 天到期,点击修改', ' дн. до окончания, нажмите для изменения'],
+ ['到期日 ', 'Дата окончания '],
+ ['点击修改', 'нажмите для изменения'],
+ ['本地已保存,但同步 Server 失败:', 'Локально сохранено, но синхронизация с Server не выполнена:'],
+ ['已打开 codex 终端', 'терминал codex открыт'],
+ ['启动失败:', 'Не удалось запустить:'],
+ ['重置失败:', 'Сброс не выполнен:'],
+ ['消耗了到期', 'списан сброс со сроком до'],
+ ['的那条', ''],
+ ['触发 ', 'Запущено '],
+ ['个账号 reset 后自动刷新', 'аккаунтов для автообновления после reset'],
+ ['刷新失败:', 'Обновление не выполнено:'],
+ ['天 ', ' дн. '],
+ ['时 ', ' ч '],
+ ['分', ' мин'],
+ ['重试中', 'Повтор...'],
+ ['合并到同邮箱旧账号', 'объединён со старым аккаунтом с тем же email'],
+ ['更新', 'Обновлено'],
+ ['已刷新额度', 'квота обновлена'],
+ ['推送 Server 成功', 'успешно отправлен на Server'],
+ ['推送失败:', 'Отправка не выполнена:'],
+ ['Google 当前账号已切换为', 'Текущий Google-аккаунт переключён на'],
+ ['Google 切号失败:', 'Не удалось переключить Google-аккаунт:'],
+ ['已将 ', 'Назначен '],
+ ['设为其模型的当前账号', 'текущим аккаунтом для его моделей'],
+ ['Codex / Google 不变', 'Codex / Google не меняются'],
+ ['模型切号失败:', 'Не удалось переключить модель:'],
+ ['登录已失效:', 'Вход истёк:'],
+ ['已过期或被撤销', 'истёк или был отозван'],
+ ['请重新登录', 'войдите заново'],
+ ['刷新令牌', 'Обновить токен'],
+ ['保存额度凭证失败:', 'Не удалось сохранить данные проверки квоты:'],
+ ['点击修改额度查询凭证', 'Изменить данные проверки квоты'],
+ ['额度余额 ', 'Баланс квоты '],
+ ['来自 /wham/usage 的 credits.balance', 'Значение credits.balance из /wham/usage'],
+ ['请刷新该账号额度以查询 credits.balance', 'Обновите квоту аккаунта, чтобы получить credits.balance'],
+ ['IDE 自动重载仅支持 macOS,请手动重载 IDE', 'Автообновление IDE доступно только на macOS; перезагрузите IDE вручную'],
+ ['配额状态', 'Состояние квот'],
+ ['同步/保活', 'Синхронизация/продление'],
+ ['操作', 'Действия'],
+ ['点击打开 ', 'Открыть '],
+ ['刷新模型额度', 'Обновить квоты моделей'],
+ ['切换 Google 当前账号(不影响 Codex 当前账号)', 'Переключить текущий Google-аккаунт (не влияет на текущий аккаунт Codex)'],
+ ['邀请同事使用 ChatGPT 桌面版', 'Пригласить коллегу в ChatGPT Desktop'],
+ ['邀请朋友使用 ChatGPT 桌面版', 'Пригласить друга в ChatGPT Desktop'],
+ ['确定要永久删除账号', 'Точно удалить аккаунт навсегда'],
+ ['吗?', '?'],
+ ['此操作不可恢复,删除后有关该账号的本地授权信息将被清除。', 'Действие необратимо: локальные данные авторизации этого аккаунта будут удалены.'],
+ ['ChatGPT / Codex 目前没有提供可靠的订阅到期日接口,因此这里由你手工维护。它不会修改登录 Token、不会当作额度重置时间,也不会触发自动切号。留空保存可清除日期。',
+ 'ChatGPT / Codex сейчас не предоставляет надёжный API даты окончания подписки, поэтому дата ведётся вручную. Она не меняет токен входа, не считается временем сброса квоты и не запускает автопереключение. Сохраните пустое поле, чтобы очистить дату.'],
+ ['保存中…', 'Сохранение...'],
+ ['系统默认自动管理全部订阅号,并以 /wham/usage 返回的 primary_window 实际时长判断 5H 或 7D,不绑定套餐名称。首次遇到无法确认是否激活的 100% 窗口时只发一次极小请求;之后按固定 reset_at 到点触发。这里可以单独关闭该账号,client/solo 模式由 Server 单端执行。',
+ 'По умолчанию система автоматически ведёт все подписочные аккаунты и определяет окно 5ч или 7д по фактической длительности primary_window из /wham/usage, без привязки к названию тарифа. При первом неопределённом окне 100% отправляется один минимальный запрос; дальше запуск идёт по reset_at. Здесь можно отключить это для отдельного аккаунта; в client/solo режиме задачу выполняет только Server.'],
+ ['当前可用次数无法确认,不代表已清空。请稍后重试查询。', 'Текущее число доступных сбросов не удалось подтвердить; это не значит, что они закончились. Повторите проверку позже.'],
+ ['次,按到期时间排序(最早在前)。所有次数', 'шт., отсортированы по сроку действия (самые ранние сверху). Все сбросы '],
+ ['等价', 'равнозначны'],
+ ['区别仅到期时间;', 'отличается только срок действия;'],
+ ['剩 ', 'осталось '],
+ ['不扣次数', 'не списывать сброс'],
+ ['重新查询', 'Проверить заново'],
+ ['正在重置…', 'Сброс...'],
+ ['或直接粘贴 token', 'или вставьте token напрямую'],
+ ['四段RT', 'RT в 4 частях'],
+ ['默认 / 上游懂 codex /v1/responses', 'по умолчанию / upstream понимает codex /v1/responses'],
+ ['StepFun 额度查询需要粘贴 platform.stepfun.com 的 Oasis-Token;如果暂时不查配额,请把余额查询策略改成“不拉取”。',
+ 'Для проверки квоты StepFun нужен Oasis-Token с platform.stepfun.com. Если квоты пока не нужны, переключите стратегию проверки баланса на «Не запрашивать».'],
+ ['MiMo 配额查询需要粘贴 platform.xiaomimimo.com 的 Cookie;如果暂时不查配额,请把余额查询策略改成“不拉取”。',
+ 'Для проверки квоты MiMo нужен Cookie с platform.xiaomimimo.com. Если квоты пока не нужны, переключите стратегию проверки баланса на «Не запрашивать».'],
+ ['已获取授权码,正在交换令牌...', 'Код авторизации получен, обмен токена...'],
+ ['授权成功!账号已添加。', 'Авторизация успешна, аккаунт добавлен.'],
+ ['已获取 Google 授权码,正在验证账号和项目...', 'Код авторизации Google получен, проверка аккаунта и проекта...'],
+ ['Google Antigravity 账号已添加。', 'Аккаунт Google Antigravity добавлен.'],
+ ['请输入账号名称', 'Введите имя аккаунта'],
+ ['正在启动官方浏览器授权...', 'Запуск официальной авторизации в браузере...'],
+ ['请在打开的浏览器窗口中完成 OpenAI 授权...', 'Завершите авторизацию OpenAI в открывшемся браузере...'],
+ ['授权链接已复制,请粘贴到目标浏览器完成授权,回调会自动回到本应用...', 'Ссылка авторизации скопирована. Вставьте её в нужный браузер; callback вернётся в приложение автоматически...'],
+ ['自动复制失败。请在下方选择完整链接手动复制,或重试复制。', 'Автокопирование не удалось. Выделите полную ссылку ниже вручную или повторите копирование.'],
+ ['正在生成授权链接...', 'Создание ссылки авторизации...'],
+ ['正在启动 Google Antigravity 授权...', 'Запуск авторизации Google Antigravity...'],
+ ['请在浏览器中完成 Google 授权...', 'Завершите авторизацию Google в браузере...'],
+ ['账号导入文件', 'Файлы импорта аккаунтов'],
+ ['所有文件', 'Все файлы'],
+ ['请粘贴 ChatGPT session JSON', 'Вставьте ChatGPT session JSON'],
+ ['已提交回调链接,正在交换令牌...', 'Callback-ссылка отправлена, обмен токена...'],
+ ['添加账号', 'Добавить аккаунт'],
+ ['带 ', 'с '],
+ ['处理中...', 'Обработка...'],
+ ['导入当前账号', 'Импортировать текущий аккаунт'],
+ ['立即登录 OpenAI', 'Войти в OpenAI сейчас'],
+ ['提交中...', 'Отправка...'],
+ ['开始授权', 'Начать авторизацию'],
+ ['GLM 自家 quota 接口', 'родной quota API GLM'],
+ ['Kimi 编程套餐 5H / 7D', 'Kimi Coding Plan 5ч / 7д'],
+ ['MiMo 控制台 Cookie', 'Cookie консоли MiMo'],
+ ['StepFun 控制台 Oasis-Token', 'Oasis-Token консоли StepFun'],
+ ['StepFun 额度凭证', 'Данные проверки квоты StepFun'],
+ ['基于 new-api / CLIProxyAPI / sub2api 的第三方中转,原生 /v1/responses', 'Сторонний relay на базе new-api / CLIProxyAPI / sub2api, родной /v1/responses'],
+ ['厂商编程订阅,按服务支持选择 Responses 或 Chat Completions', 'Поставщик coding-подписки; выберите Responses или Chat Completions по поддержке сервиса'],
+ ['厂商按量付费 API(DeepSeek / Kimi / 通义 / OpenRouter 等)', 'API поставщика с оплатой по расходу (DeepSeek / Kimi / Tongyi / OpenRouter и др.)'],
+ ['手动填 base_url', 'Заполнить base_url вручную'],
+ ['保存后直接读取 StepFun /models 返回的原生 step-* 模型,在 Codex 模型列表中选择。', 'После сохранения будут прочитаны родные step-* модели из StepFun /models, их можно выбрать в списке моделей Codex.'],
+ ['保存后可在 Codex 中选择此中转的模型,无需切换 ChatGPT 账号。', 'После сохранения модели этого relay можно выбирать в Codex без переключения ChatGPT-аккаунта.'],
+ ['预设仅提供默认地址;使用自有中转时,请填写该中转的 API 地址和对应 Key。', 'Пресет задаёт только адрес по умолчанию; для собственного relay укажите его API-адрес и ключ.'],
+ ['填写此 API 实际支持的模型 ID', 'Укажите ID модели, которую реально поддерживает этот API'],
+ ['会显示在 Codex 模型列表;高级设置可添加其他模型。', 'Будет показана в списке моделей Codex; другие модели можно добавить в расширенных настройках.'],
+ ['需 Cookie', 'нужен Cookie'],
+ ['Step Plan 控制台 Token', 'Token консоли Step Plan'],
+ ['从 platform.stepfun.com Cookie 复制 Oasis-Token,或直接粘贴 token', 'Скопируйте Oasis-Token из Cookie на platform.stepfun.com или вставьте token напрямую'],
+ ['模型来源', 'Источник моделей'],
+ ['高级设置(模型兜底 / 映射表)', 'Расширенные настройки (резервная модель / таблица сопоставления)'],
+ ['Step Plan 不使用模型映射;模型列表由官方 API 返回,保存后刷新 Codex 模型列表即可。', 'Step Plan не использует сопоставление моделей; список возвращает официальный API, после сохранения обновите список моделей Codex.'],
+ ['客户端发的 model 未命中映射时统一替换', 'Единая замена, если model от клиента не найдена в сопоставлении'],
+ ['API Key 不能为空', 'API Key не может быть пустым'],
+ ['StepFun 额度查询需要粘贴 platform.stepfun.com 的 Oasis-Token;不查配额请把策略改成「不拉取」。', 'Для проверки квоты StepFun нужен Oasis-Token с platform.stepfun.com; если квоты не нужны, выберите стратегию «Не запрашивать».'],
+ ['MiMo 配额查询需要粘贴 platform.xiaomimimo.com 的 Cookie;不查配额请把策略改成「不拉取」。', 'Для проверки квоты MiMo нужен Cookie с platform.xiaomimimo.com; если квоты не нужны, выберите стратегию «Не запрашивать».'],
+ ['账号于 ', 'Аккаунт истекает '],
+ ['本地已保存,但同步 Server 失败:', 'Локально сохранено, но синхронизация с Server не выполнена: '],
+ ['启动失败:', 'Не удалось запустить: '],
+ ['重置失败:', 'Сброс не выполнен: '],
+ ['切号失败:', 'Не удалось переключить аккаунт: '],
+ ['模型切号失败:', 'Не удалось переключить модель: '],
+ ['登录已失效:', 'Вход истёк: '],
+ ['导入中...', 'Импорт...'],
+ ['注意:', 'Внимание:'],
+ ['(带', ' (с '],
+ ['添加中转', 'Добавить relay'],
+ ['余额 ', 'Баланс '],
+ ['✓ 已选', '✓ Выбрано'],
+ ['一键使用 →', 'Использовать →'],
+ ['没有账号。先去「账号管理」添加。', 'Аккаунтов нет. Сначала добавьте их в разделе «Аккаунты».'],
+ ['例如:GLM 跑文档', 'Например: GLM для документов'],
+ ['在路由列表里显示这个名字,方便识别。', 'Это имя будет показано в списке маршрутов, чтобы его было проще узнать.'],
+ ['准备就绪 — 点「添加路由」', 'Готово — нажмите «Добавить маршрут»'],
+ ['选好会话和账号即可添加', 'Выберите сессию и аккаунт, затем добавьте маршрут'],
+ ['重置未知', 'Сброс неизвестен'],
+ ['待刷新', 'Нужно обновить'],
+ ['上游未提供重置时间', 'Upstream не передал время сброса'],
+ ['重置时间:', 'Время сброса: '],
+ ['7D 额度已耗尽,请展开查看', 'Квота 7D исчерпана, раскройте подробности'],
+ ['7D耗尽', '7д исчерпано'],
+ ['暂无模型额度,点击刷新', 'Квот моделей пока нет, нажмите обновить'],
+ ['收起全部模型', 'Свернуть все модели'],
+ ['查看全部模型', 'Показать все модели'],
+ ['全部模型额度', 'Квоты всех моделей'],
+ ['剩余额度 · 重置倒计时', 'Остаток квоты · обратный отсчёт до сброса'],
+ ['默认优先显示 5H;5H 与 7D 同时生效,同组模型共享额度。未获取的窗口显示未知。', 'По умолчанию сначала показано 5ч; 5ч и 7д действуют одновременно, модели одной группы делят квоту. Не полученные окна отображаются как неизвестные.'],
+ ['模型额度列表', 'Список квот моделей'],
+ ['早期数据·无 account', 'старые данные · без account'],
+ ['正在切换...', 'Переключение...'],
+ ['新账号', 'Новый аккаунт'],
+ ['复制中…', 'Копирование...'],
+ ['复制此链接', 'Скопировать эту ссылку'],
+ ['端口已更新(重启代理后生效)', 'Порт обновлён (вступит в силу после перезапуска прокси)'],
+ ['保存失败:', 'Не удалось сохранить:'],
+ ['新终端窗口生效', 'вступит в силу в новом окне терминала'],
+ ['启动代理', 'Запустить прокси'],
+ ['关闭代理', 'Остановить прокси'],
+ ['复制命令到 PowerShell 运行', 'Скопировать команду для запуска в PowerShell'],
+ ['client 模式:本机不跑 oauth,改为从 Server /quotas 自动同步 cached_quota(约 5 分钟一轮)', 'Режим client: локальный oauth не запускается; cached_quota автоматически синхронизируется из Server /quotas примерно раз в 5 минут'],
+ ['按最后更新时间排序,自动循环刷新所有账号的配额数据', 'Сортировать по времени последнего обновления и циклически обновлять квоты всех аккаунтов'],
+ ['邀请同事加入工作区,奖励按官方活动规则发放', 'Пригласите коллегу в workspace; бонус начисляется по официальным правилам акции'],
+ ['邀请朋友加入,奖励按官方活动规则发放', 'Пригласите друга; бонус начисляется по официальным правилам акции'],
+ ['关闭邀请窗口', 'Закрыть окно приглашения'],
+ ['发邀账号', 'Аккаунт отправителя'],
+ ['当前活动', 'Текущая акция'],
+ ['活动范围', 'Область акции'],
+ ['个人账号', 'Личный аккаунт'],
+ ['工作区', 'Workspace'],
+ ['查询中…', 'Проверка...'],
+ ['刷新资格', 'Обновить право на приглашения'],
+ ['正在查询活动资格…', 'Проверка права на участие...'],
+ ['每位符合条件的邀请奖励', 'Бонус за каждого подходящего приглашённого'],
+ ['当前账号暂未开放', 'Для текущего аккаунта пока недоступно'],
+ ['当前账号暂未开放此邀请活动。', 'Для текущего аккаунта эта акция приглашений пока недоступна.'],
+ ['可发送邮箱', 'Можно отправить email'],
+ ['未提供', 'Не предоставлено'],
+ ['接口未提供实际奖励金额,不能根据活动编号推断为 500 或 1000。', 'API не передал фактический размер бонуса; нельзя выводить 500 или 1000 только по номеру акции.'],
+ ['接口未提供实际奖励金额,不能根据活动编号推断奖励数额。', 'API не передал фактический размер бонуса; нельзя выводить сумму по номеру акции.'],
+ ['活动奖励不等于当前余额;对方接受邀请并完成官方要求后才会到账。', 'Бонус акции не равен текущему балансу; он поступит только после принятия приглашения и выполнения официальных условий.'],
+ ['当前奖励名额为 0,已禁止发送邀请。', 'Доступных бонусных мест 0, отправка приглашений отключена.'],
+ ['填写受邀邮箱', 'Введите email получателей'],
+ ['奖励名额已用完', 'Бонусные места закончились'],
+ ['最多发送 ', 'Можно отправить максимум '],
+ ['受邀邮箱', 'Email получателей'],
+ ['每行一个邮箱,也可用逗号或分号分隔', 'Один email на строку; можно разделять запятыми или точками с запятой'],
+ ['我已确认收件人及奖励条件,发送邀请不代表奖励已到账。', 'Я проверил получателей и условия бонуса; отправка приглашения не означает, что бонус уже начислен.'],
+ ['发送结果', 'Результат отправки'],
+ ['邀请记录已创建', 'Запись приглашения создана'],
+ ['未返回已创建的邀请,请查询记录确认。', 'Созданное приглашение не вернулось в ответе; проверьте историю.'],
+ ['本次提交已结束。需要再次邀请时,请先核对记录,再重新打开此窗口。', 'Эта отправка завершена. Для нового приглашения сначала проверьте историю, затем откройте окно снова.'],
+ ['邀请记录', 'История приглашений'],
+ ['查询近 90 天', 'Проверить последние 90 дней'],
+ ['近 90 天没有邀请记录。', 'За последние 90 дней приглашений нет.'],
+ ['上游未提供状态', 'Upstream не передал статус'],
+ ['加载更多', 'Загрузить ещё'],
+ ['奖励到账以官方记录为准', 'Начисление бонуса определяется официальной историей'],
+ ['邀请额度', 'Квота приглашений'],
+ ['刷新邀请额度', 'Обновить квоту приглашений'],
+ ['正在查询邀请资格…', 'Проверка права на приглашения...'],
+ ['每位奖励', 'Бонус за человека'],
+ ['上次数据已过期,请刷新额度', 'Предыдущие данные устарели, обновите квоту'],
+ ['剩余 ', 'Осталось '],
+ ['加载路由规则…', 'Загрузка правил маршрутизации...'],
+ ['删除路由', 'Удалить маршрут'],
+ ['点击复制完整 session_id', 'Скопировать полный session_id'],
+ ['✅ 设置已保存', '✅ Настройки сохранены'],
+ ['❌ 保存失败:', '❌ Не удалось сохранить:'],
+ ['生成失败:', 'Не удалось создать: '],
+ ['已切换到 ', 'Переключено на '],
+ ['已与 Server 一致,无需切换', 'Уже совпадает с Server, переключение не требуется'],
+ ['使用 ', 'Используется '],
+ ['远端账号数 ', 'аккаунтов на удалённой стороне: '],
+ ['推送全部账号到 Server', 'Отправить все аккаунты на Server'],
+ ['已上传 ', 'Загружено '],
+ ['从 Server 拉取全部账号', 'Загрузить все аккаунты с Server'],
+ ['已合并 ', 'Объединено '],
+ ['从 Server 同步所有 token', 'Синхронизировать все token с Server'],
+ ['已写 auth.json', 'auth.json записан'],
+ ['✅ 修复成功!\n\n现在请尝试重新打开 Codex App。', '✅ Исправлено.\n\nТеперь попробуйте снова открыть Codex App.'],
+ ['保存中...', 'Сохранение...'],
+ ['保存设置', 'Сохранить настройки'],
+ ['client 模式:保活由 Server 负责,本机已强制关闭(避免双路刷新撞飞 refresh_token)', 'Режим client: продление выполняет Server, локально оно принудительно отключено, чтобы два процесса не испортили refresh_token'],
+ ['Server 负责', 'Отвечает Server'],
+ ['已开启', 'Включено'],
+ ['已关闭', 'Отключено'],
+ ['执行中...', 'Выполнение...'],
+ ['立即重启', 'Перезапустить сейчас'],
+ ['更换', 'Заменить'],
+ ['选择绑定账号', 'Выбрать привязанный аккаунт'],
+ ['隔离属性修复仅适用于 macOS', 'Исправление quarantine-атрибута доступно только на macOS'],
+ ['修复中...', 'Исправление...'],
+ ['立即修复', 'Исправить сейчас'],
+ ['当前没有 ChatGPT 订阅号', 'Сейчас нет ChatGPT-аккаунтов с подпиской'],
+ ['没有匹配的账号', 'Подходящих аккаунтов нет'],
+ ['扫描中...', 'Сканирование...'],
+ ['个人活动', 'Личная акция'],
+ ['工作区活动', 'Акция workspace'],
+ ['个使用额度', 'кредитов использования'],
+ ['个工作区额度', 'кредитов workspace'],
+ ['次限额重置', 'сбросов лимита'],
+ ['活动未提供奖励数额', 'Акция не передала размер бонуса'],
+ ['发送上限', 'Лимит отправки'],
+ ['奖励名额', 'Бонусных мест'],
+ ['250 个使用额度', '250 кредитов использования'],
+ ['可以 отправить email', 'Можно отправить email'],
+ ['Codex CLI 通过代理连接 OpenAI,支持无中断自动切号和 429 智能重试',
+ 'Codex CLI подключается к OpenAI через прокси; поддерживает переключение аккаунтов без обрыва и умный повтор при 429'],
+ ['auto:代理开启时自动走热切(不写 auth.json,不杀进程,仅刷 store.current)。代理关闭时回退到冷切。cold:无论如何都冷切。',
+ 'auto: при включённом прокси используется горячее переключение (без записи auth.json, без завершения процессов, обновляется только store.current). При выключенном прокси используется холодное переключение. cold: всегда холодное переключение.'],
+ ['代理开启时自动走热切', 'при включённом прокси используется горячее переключение'],
+ ['不写 auth.json,不杀进程,仅刷 store.current', 'без записи auth.json, без завершения процессов, обновляется только store.current'],
+ ['代理关闭时回退到冷切', 'при выключенном прокси используется холодное переключение'],
+ ['无论如何都冷切', 'всегда холодное переключение'],
+ ['开启(默认):current 是中转 / Coding Plan / 三方 API 时,遇到 401/429/quota 自动切到健康的订阅号,避免请求卡死。关闭后这类号出错会把错误透传给客户端,不偷换。',
+ 'Включено по умолчанию: если current это relay / Coding Plan / сторонний API, при 401/429/quota приложение автоматически переключится на исправный подписной аккаунт, чтобы запрос не завис. Если выключить, такие ошибки будут передаваться клиенту без скрытой подмены аккаунта.'],
+ ['关闭(默认):用订阅号时自动切号 / affinity 不会路由到中转 / Coding Plan / 三方 API,避免偷扣余额。开启后这类号跟订阅号同等参与轮询(量大但要确认你愿意花对应套餐的额度)。',
+ 'Выключено по умолчанию: при работе с подписным аккаунтом автопереключение и affinity не будут маршрутизировать запросы в relay / Coding Plan / сторонний API, чтобы случайно не списывать баланс. Если включить, эти аккаунты участвуют в выборе наравне с подписками; используйте только если готовы тратить их квоту.'],
+ ['开启后 HTTP 也跟 WebSocket 同路,本机直接打上游,不再经 Server 转发;access_token 仍从 Server 拉。适合 Server 出口不稳但本机出口稳的场景。',
+ 'После включения HTTP пойдёт тем же путём, что и WebSocket: этот компьютер обращается к upstream напрямую, без пересылки через Server; access_token всё равно берётся с Server. Полезно, если выход Server нестабилен, а локальный выход стабилен.'],
+ ['开启后本机自己决定 current(不被 Server `/current` 反向同步覆盖),`~/.codex/auth.json` 也由本机自己写。等价于旧 solo 模式(已并入 client)。',
+ 'После включения этот компьютер сам выбирает current (Server `/current` не перезаписывает его обратной синхронизацией), и сам пишет `~/.codex/auth.json`. Это эквивалент старого solo-режима, теперь встроенного в client.'],
+ ['off=独立;server=Server 侧提供 API;client=本机,rt 旋转走 Server。',
+ 'off = автономно; server = эта сторона предоставляет API; client = этот компьютер, ротация RT идёт через Server.'],
+ ['老 solo 模式已合并到 client(自动迁移:solo → client + 本机直连上游 + 本机管 current)。',
+ 'Старый solo-режим объединён с client (автомиграция: solo -> client + локальный прямой upstream + локальное управление current).'],
+ ['磁盘 ~/.codex/auth.json 永远跟随此号,Codex.app 手机远程连接绑定此号;切到其他号时 disk 不动、proxy 出口照切(手机 bridge 不掉线)。仅 ChatGPT 订阅号可绑定。',
+ '~/.codex/auth.json на диске всегда следует этому аккаунту, мобильное удалённое подключение Codex.app привязано к нему. При переходе на другие аккаунты disk не меняется, меняется только выход proxy (мобильный bridge не отваливается). Привязать можно только подписной аккаунт ChatGPT.'],
+ ['磁盘 ~/.codex/auth.json 永远跟随此号,Codex.app 手机远程连接绑定此号;',
+ '~/.codex/auth.json на диске всегда следует этому аккаунту, мобильное удалённое подключение Codex.app привязано к нему; '],
+ ['切到其他号时 disk 不动、proxy 出口照切(手机 bridge 不掉线)。', 'при переходе на другие аккаунты disk не меняется, меняется только выход proxy (мобильный bridge не отваливается).'],
+ ['仅 ChatGPT 订阅号可绑定。', 'Привязать можно только подписной аккаунт ChatGPT.'],
+ ['原理', 'Принцип'],
+ ['每次切号前后强制抓 quota 写', 'перед и после каждого переключения принудительно снимается quota и пишется в'],
+ ['同一窗口内任意两次快照的', 'любые два снимка в одном окне дают'],
+ ['任何两次快照的', 'любые два снимка дают'],
+ ['配合期间代理 tokens', 'вместе с proxy tokens за период'],
+ ['推出该 Plan 总容量', 'оценку общей ёмкости Plan'],
+ ['推出 Plan 总容量', 'оценку общей ёмкости Plan'],
+ ['中位', 'Медиана'],
+ ['是去掉异常值后最稳的估计', ' - самая устойчивая оценка после удаления выбросов'],
+ ['是去掉异常值后的稳定估计', ' - устойчивая оценка после удаления выбросов'],
+ ['Δpct<3% 的样本被丢弃', 'Сэмплы с Δpct < 3% отбрасываются'],
+ ['样本被丢弃', 'семплы отбрасываются'],
+ ['used_pct 是整数', 'used_pct целочисленный'],
+ ['量化误差会失真', 'ошибка квантования искажает результат'],
+ ['样本会随每次切号自动累积', 'семплы автоматически накапливаются при каждом переключении'],
+ ['样本数低于', 'если семплов меньше'],
+ ['时估计仍有偏差,多用几小时即可', 'оценка ещё может быть смещена; дайте системе поработать несколько часов'],
+ ['每号 Token 历史(精确累加 + 估算上限)', 'История токенов по аккаунтам (точная сумма + оценка лимита)'],
+ ['邮箱 / Plan', 'Email / Plan'],
+ ['当前 5h', 'Текущие 5ч'],
+ ['上次 5h', 'Прошлые 5ч'],
+ ['当前 周', 'Текущая неделя'],
+ ['上次 周', 'Прошлая неделя'],
+ ['每格显示', 'В каждой ячейке показано'],
+ ['实测累加 / 估算上限', 'фактическая сумма / оценка лимита'],
+ ['实测累加', 'Фактическая сумма'],
+ ['在该窗口内的精确求和', 'точная сумма в этом окне'],
+ ['不平均,不打折,无论中间切号几次', 'без усреднения и скидок, независимо от числа переключений внутри'],
+ ['估算上限', 'Оценка лимита'],
+ ['用快照里 used_pct 最大的那个算', 'считается по снимку с максимальным used_pct'],
+ ['用快照里 used_pct 最大那个算', 'считается по снимку с максимальным used_pct'],
+ ['量化误差最小', 'минимальная ошибка квантования'],
+ ['标记的 used_pct 偏小,估算误差大', 'помеченный used_pct маловат, оценка менее точная'],
+ ['窗口内触发过限额切号', 'в окне было переключение из-за лимита'],
+ ['此时实测累加', 'в этом случае фактическая сумма'],
+ ['实际窗口配额', 'фактической квоте окна'],
+ ['点开账号看历史周期,点开周期看 session 明细', 'раскройте аккаунт для истории циклов, затем цикл для деталей session'],
+ ['最近', 'недавно'],
+ ['Token 趋势', 'Динамика токенов'],
+ ['费用趋势', 'Динамика расходов'],
+ ['切号日志', 'Журнал переключений'],
+ ['切换路径', 'Путь переключения'],
+ ['使用时长', 'Время использования'],
+ ['暂无切号记录', 'Записей переключения пока нет'],
+ ['Панель Prompt Cache', 'Панель Prompt Cache'],
+ ['隐藏旧数据', 'Скрыть старые данные'],
+ ['早期版本没记 account_id 的历史条目', 'Исторические записи старых версий без account_id'],
+ ['近 24 小时', 'Последние 24 часа'],
+ ['近 30 天', 'Последние 30 дней'],
+ ['节省', 'Сэкономлено'],
+ ['总花费', 'Итоговый расход'],
+ ['次请求', 'запросов'],
+ ['按模型 token 分布', 'Распределение токенов по моделям'],
+ ['Кэшированный вход', 'Кэшированный вход'],
+ ['Некэшированный вход', 'Некэшированный вход'],
+ ['Выход', 'Выход'],
+ ['本字段是这次新增的,旧条目里没有,不能事后追溯', 'Это поле появилось недавно; в старых записях его нет, восстановить задним числом нельзя'],
+ ['累计 cached tokens', 'Всего кэшированных токенов'],
+ ['健康', 'Исправен'],
+ ['失效或封号', 'Недействителен или заблокирован'],
+ ['创建于', 'Создано'],
+ ['命中', 'Срабатываний'],
+ ['从未', 'Никогда'],
+ ['刚刚', 'Только что'],
+ ['分钟前', 'мин назад'],
+ ['小时前', 'ч назад'],
+ ['昨天', 'Вчера'],
+ ['天前', 'дн назад'],
+ ['中转服务', 'Relay-сервис'],
+ ['选择预设', 'Выберите пресет'],
+ ['账号名称 *', 'Имя аккаунта *'],
+ ['例如:unity2-工作', 'Например: unity2-work'],
+ ['例如:工作 · GLM Coding', 'Например: Работа · GLM Coding'],
+ ['例如:工作账号、个人账号', 'Например: рабочий аккаунт, личный аккаунт'],
+ ['可选的备注信息...', 'Необязательная заметка...'],
+ ['主页', 'Сайт'],
+ ['名称', 'Название'],
+ ['备注(可选)', 'Заметка (необязательно)'],
+ ['默认自动探测', 'Автоопределение по умолчанию'],
+ ['自动探测(推荐 · new-api / sub2api 都能识别)', 'Автоопределение (рекомендуется, распознаёт new-api / sub2api)'],
+ ['responses(默认 / Unity2、ChatGPT、OpenAI key)', 'responses (по умолчанию / Unity2, ChatGPT, OpenAI key)'],
+ ['chat_completions(GLM/MiMo Coding Plan / 通用 OpenAI Chat)', 'chat_completions (GLM/MiMo Coding Plan / универсальный OpenAI Chat)'],
+ ['留空 = 透传不替换', 'пусто = передавать без замены'],
+ ['每行 客户端model=中转站model', 'По одной строке: client_model=relay_model'],
+ ['添加中…', 'Добавление...'],
+ ['Base URL 已自动填好', 'Base URL заполнен автоматически'],
+ ['通用中转', 'Универсальный relay'],
+ ['三方模型', 'Сторонние модели'],
+ ['自定义', 'Пользовательский'],
+ ['厂商自家订阅', 'Подписка провайдера'],
+ ['厂商按量付费 API', 'API с оплатой по расходу'],
+ ['中转 / Plan / 三方 出问题时切回订阅号', 'При сбое relay / Plan / стороннего API вернуться на подписной аккаунт'],
+ ['自动选号可挑中 中转 / Plan / 三方', 'Автовыбор может выбирать relay / Plan / сторонний API'],
+ ['智谱 GLM', 'Zhipu GLM'],
+ ['通用 Responses 中转(new-api / CLIProxyAPI / sub2api)', 'Универсальный Responses relay (new-api / CLIProxyAPI / sub2api)'],
+ ['自定义中转站', 'Пользовательский relay'],
+ ['阿里 DashScope (通义千问)', 'Alibaba DashScope (Qwen)'],
+ ['火山方舟 (ByteDance Doubao)', 'Volcano Ark (ByteDance Doubao)'],
+ ['腾讯混元', 'Tencent Hunyuan'],
+ ['百度千帆 (ERNIE)', 'Baidu Qianfan (ERNIE)'],
+ ['优云智算 UCloud Modelverse', 'UCloud Modelverse'],
+ ['阶跃星辰 Stepfun', 'Stepfun'],
+ ['神马中转 API (Whatai)', 'Whatai relay API'],
+ ['魔搭 ModelScope', 'ModelScope'],
+ ['Ollama 本地推理', 'Локальный Ollama'],
+ ['按量付费', 'оплата по расходу'],
+ ['中国订阅', 'китайская подписка'],
+ ['国际订阅', 'международная подписка'],
+ ['余额自动探测', 'автоопределение баланса'],
+ ['OpenAI 兼容', 'OpenAI-совместимый'],
+ ['OpenAI Chat 兼容', 'совместим с OpenAI Chat'],
+ ['配额用控制台 Cookie', 'квота через Cookie консоли'],
+ ['MiMo 配额 Cookie', 'Cookie квоты MiMo'],
+ ['从 platform.xiaomimimo.com Network 复制 Cookie header', 'Скопируйте Cookie header из Network на platform.xiaomimimo.com'],
+ ['Prompt Cache 面板', 'Панель кэша промптов'],
+ ['还没有任何 session 命中过 cache', 'Ни одна сессия пока не использовала кэш'],
+ ['活跃 session 绑定', 'Активные привязки сессий'],
+ ['活跃 Session 绑定(evidence-based stickiness)', 'Активные привязки сессий (по подтверждённым попаданиям)'],
+ ['命中率(按小时)', 'Доля попаданий по часам'],
+ ['按模型 token 分布(cached vs uncached vs output)', 'Распределение токенов по моделям (кэшированный вход / некэшированный вход / выход)'],
+ ['vs 全价 input', 'к полной цене input'],
+ ['请求数', 'Запросов'],
+ ['命中率', 'Доля попаданий'],
+ ['全部项目', 'Все элементы'],
+ ['近 90 天', 'Последние 90 дней'],
+ ['Token 总量', 'Всего token'],
+ ['总费用', 'Итоговая стоимость'],
+ ['切号次数', 'Переключений'],
+ ['使用账号数', 'Использовано аккаунтов'],
+ ['Plan 配额上限估算(Δpct 反推,不依赖账号打满)', 'Оценка лимита Plan по Δpct без полного расхода аккаунта'],
+ ['5h 样本', 'Сэмплы 5ч'],
+ ['5h 中位', 'Медиана 5ч'],
+ ['5h 平均', 'Среднее 5ч'],
+ ['5h min–max', 'Мин-макс 5ч'],
+ ['5h min-max', 'Мин-макс 5ч'],
+ ['5H MIN-MAX', 'Мин-макс 5ч'],
+ ['5h MIN-MAX', 'Мин-макс 5ч'],
+ ['MIN-MAX 周', 'Мин-макс недели'],
+ ['周 样本', 'Сэмплы недели'],
+ ['周 中位', 'Медиана недели'],
+ ['周 平均', 'Среднее недели'],
+ ['周 min–max', 'Мин-макс недели'],
+ ['样本会随每次切号自动累积;样本数低于 ~5 时估计仍有偏差,多用几小时即可。', 'Сэмплы автоматически копятся при переключениях; при числе меньше ~5 оценка может быть неточной, дайте системе поработать несколько часов.'],
+ ['5h 周期', 'Периоды 5ч'],
+ ['周周期', 'Недельные периоды'],
+ ['每格显示「实测累加 / 估算上限」。', 'В каждой ячейке показано «фактическая сумма / оценка лимита».'],
+ ['窗口', 'Окно'],
+ ['轮数', 'Раундов'],
+ ['session 数', 'Session'],
+ ['状态', 'Статус'],
+ ['进行中', 'Идёт'],
+ ['正常', 'Норма'],
+ ['暂无数据', 'Данных нет'],
+ ['后台任务日志', 'Журнал фоновых задач'],
+ ['时间', 'Время'],
+ ['原因', 'Причина'],
+ ['目标账号', 'Целевой аккаунт'],
+ ['任务类型', 'Тип задачи'],
+ ['刷新后额度', 'Квота после обновления'],
+ ['成功', 'Успешно'],
+ ['手动', 'Вручную'],
+ ['自动刷新', 'Автообновление'],
+ ['后台保活', 'Фоновое продление'],
+ ['限额', 'Лимит'],
+ ['配额充足', 'Квоты достаточно'],
+ ['配额偏低', 'Квота низкая'],
+ ['加载统计数据失败:', 'Не удалось загрузить статистику:'],
+ ['Remote Mode(局域网同步)', 'Удалённый режим (синхронизация в LAN)'],
+ ['工作模式', 'Режим работы'],
+ ['仅本机', 'Только этот компьютер'],
+ ['client(本机)', 'client (этот компьютер)'],
+ ['server(Server 侧)', 'server (на стороне Server)'],
+ ['solo(本机接管保活)', 'solo (локальное продление)'],
+ ['Server API 地址(主)', 'Адрес Server API (основной)'],
+ ['Server API 地址(回退)', 'Адрес Server API (резервный)'],
+ ['优先尝试,建议填局域网 IP,如 http:', 'Пробуется первым; лучше указать LAN IP, например http:'],
+ ['主不通时自动切换,建议填 ZeroTier IP,如 http:', 'Если основной недоступен, используется этот; лучше ZeroTier IP, например http:'],
+ ['共享密钥', 'Общий секрет'],
+ ['必须与 Server 端一致', 'Должен совпадать с Server'],
+ ['已生成新密钥,记得保存设置', 'Новый секрет создан, не забудьте сохранить настройки'],
+ ['监听地址', 'Адрес прослушивания'],
+ ['监听端口', 'Порт прослушивания'],
+ ['Server 侧 HTTP API 端口(默认 18081)', 'Порт HTTP API на стороне Server (по умолчанию 18081)'],
+ ['0.0.0.0 监听所有网卡;建议仅暴露给 ZeroTier 网段', '0.0.0.0 слушает все интерфейсы; лучше открывать только для ZeroTier-сети'],
+ ['客户端访问需携带 X-Auth-Token;留空则拒绝所有请求', 'Клиент должен передавать X-Auth-Token; пустое значение запрещает все запросы'],
+ ['测试连通性 / 推送本机账号 / 从 Server 合并', 'Проверить связь / отправить локальные аккаунты / слить с Server'],
+ ['推送全部', 'Отправить всё'],
+ ['拉取合并', 'Получить и слить'],
+ ['同步所有 token', 'Синхронизировать все token'],
+ ['自动同号', 'Автосовпадение аккаунта'],
+ ['本机管 current 指针', 'Этот компьютер управляет указателем current'],
+ ['当前账号只做权威回流;非活跃账号按独占策略保活刷新(保存后生效)', 'Текущий аккаунт только возвращается как authoritative; неактивные аккаунты продлеваются по эксклюзивной стратегии (после сохранения)'],
+ ['手工拉取 Server 当前账号并热切过去(自动同号关了也可用)', 'Вручную получить текущий аккаунт Server и горячо переключиться на него (работает даже при выключенном автосовпадении)'],
+ ['立即同号', 'Синхронизировать current'],
+ ['后台保活与同步', 'Фоновое продление и синхронизация'],
+ ['非活跃保活阈值(天)', 'Порог неактивного продления (дни)'],
+ ['当账号 last_refresh 超过该阈值时,调度器才会尝试保活刷新', 'Планировщик будет пытаться продлить аккаунт, когда last_refresh старше этого порога'],
+ ['调度间隔(分钟)', 'Интервал планировщика (мин)'],
+ ['自动重载 IDE', 'Автоперезагрузка IDE'],
+ ['切换账号后自动重载 IDE 以应用新的 Token', 'Автоматически перезагружать IDE после переключения аккаунта, чтобы применить новый токен'],
+ ['仅重载选中的 IDE', 'Перезагружать только выбранные IDE'],
+ ['使用杀进程重启', 'Перезапуск через завершение процессов'],
+ ['使用 pkill 方式重启(Windsurf 推荐,无需权限)', 'Перезапуск через pkill (рекомендуется для Windsurf, без прав администратора)'],
+ ['修复 Codex App 闪退', 'Исправить сбой запуска Codex App'],
+ ['移除 macOS 安全隔离属性 (需要管理员权限)', 'Удалить macOS quarantine-атрибут (нужны права администратора)'],
+ ['这将尝试移除 Codex App 的安全隔离属性。', 'Будет выполнена попытка удалить quarantine-атрибут Codex App.'],
+ ['系统可能会弹窗要求输入密码以获得权限。是否继续?', 'Система может запросить пароль для получения прав. Продолжить?'],
+ ['❌ 修复失败:', '❌ Исправление не удалось:'],
+ ['安装', 'Установить'],
+ ['仓库已存在', 'Репозиторий уже существует'],
+ ['读取失败:', 'Не удалось прочитать:'],
+ ['5H 限额', 'Лимит 5ч'],
+ ['24H 限额', 'Лимит 24H'],
+ ['周限额', 'Недельный лимит'],
+ ['周配额', 'Недельная квота'],
+ ['5h 配额', 'Квота 5ч'],
+ ['加载用量...', 'Загрузка usage...'],
+ ['即将重置', 'Скоро сброс'],
+ ['后重置', 'до сброса'],
+ ['小时', 'ч'],
+ ['分钟', 'мин'],
+ ['秒', 'с'],
+ ['未知', 'Неизвестно'],
+ ['中转账号请用「中转余额刷新」', 'Для relay-аккаунта используйте «обновление баланса relay»'],
+ ['未设置当前账号', 'Текущий аккаунт не выбран'],
+ ['网络请求失败,检查代理/网络', 'Сетевой запрос не удался, проверьте прокси/сеть'],
+ ['刷新失败:网络或服务暂时异常,未判定账号失效', 'Обновление не удалось: временный сбой сети или сервиса, аккаунт не помечен недействительным'],
+ ['请求超时(OpenAI 端慢/被节流)', 'Тайм-аут запроса (OpenAI медлит или ограничивает)'],
+ ['refresh_token 刷新失败', 'Не удалось обновить refresh_token'],
+ ['网络请求失败', 'Сетевой запрос не удался'],
+ ['已设为手机锚', 'Мобильная привязка включена'],
+ ['已解除手机锚绑定', 'Мобильная привязка снята'],
+ ['选择手机锚账号', 'Выберите аккаунт мобильной привязки'],
+ ['手机锚:磁盘 ~/.codex/auth.json 永远跟随此号,Codex.app 手机远程连接绑定此号;切到其他号时 disk 不动、proxy 出口照切', 'Мобильная привязка: ~/.codex/auth.json на диске всегда следует этому аккаунту; телефонное подключение Codex.app привязано к нему. При переходе на другие аккаунты диск не меняется, меняется только выход прокси'],
+ ['仅 ChatGPT 订阅号可绑定(Codex.app 远程连接需要 chatgpt_account_id 鉴权)', 'Привязать можно только подписной аккаунт ChatGPT, потому что удалённое подключение Codex.app требует chatgpt_account_id'],
+ ['周期保鲜', 'Продление периода'],
+ ['保鲜已关', 'Продление выключено'],
+ ['最近尝试', 'Последняя попытка'],
+ ['最近成功', 'Последний успех'],
+ ['最近结果', 'Последний результат'],
+ ['按 primary_window 实际时长自动识别', 'Автоопределение по фактической длительности primary_window'],
+ ['接口返回 · 5 小时窗口', 'API вернул окно 5 часов'],
+ ['接口返回 · 7 天窗口', 'API вернул окно 7 дней'],
+ ['正在拉取重置次数明细…', 'Загрузка деталей активных сбросов...'],
+ ['拉取明细失败', 'Не удалось загрузить детали'],
+ ['Input', 'Вход'],
+ ['Cached', 'Кэшировано'],
+ ['Output', 'Выход'],
+ ['Session Key', 'Ключ сессии'],
+ ['Cached input', 'Кэшированный вход'],
+ ['Uncached input', 'Некэшированный вход'],
+ ['cached / input', 'кэшировано / вход'],
+ ['owner', 'владелец'],
+ ['repo', 'репозиторий'],
+ ['branch', 'ветка'],
+ ['evidence-based', 'по подтверждённым попаданиям'],
+ ['evidence-based stickiness', 'привязка по подтверждённым попаданиям'],
+ ['Email', 'Email'],
+ ['Free', 'Free'],
+ ['Plus', 'Plus'],
+ ['Team', 'Team'],
+ ['后台服务', 'Фоновые службы'],
+ ['HTTP 也走本机直连上游', 'HTTP тоже идёт напрямую к upstream с этого компьютера'],
+ ['IDE 重载', 'Перезагрузка IDE'],
+ ['主力 IDE', 'Основная IDE'],
+ ['绑定地址', 'Адрес привязки'],
+ ['修改端口/绑定/密钥后点此应用(保存设置后)', 'Нажмите после изменения порта, привязки или секрета (после сохранения настроек)'],
+ ['同步操作', 'Операции синхронизации'],
+ ['Codex.app 手机锚绑定', 'Телефонная привязка Codex.app'],
+ ['故障修复', 'Устранение неполадок'],
+ ['代理服务', 'Прокси-сервис'],
+ ['代理端口', 'Порт прокси'],
+ ['开启后监听 `0.0.0.0`,同一局域网内的 Windows 可直接连接这台机器的代理', 'После включения слушает `0.0.0.0`; Windows в той же LAN сможет подключаться к прокси на этом компьютере'],
+ ['切号模式', 'Режим переключения аккаунтов'],
+ ['auto(代理开=热切)', 'auto (прокси включен = горячее переключение)'],
+ ['cold(强制冷切)', 'cold (принудительное холодное переключение)'],
+ ['Windows 机器可把 `OPENAI_BASE_URL` 指向下面这个地址', 'На Windows укажите `OPENAI_BASE_URL` на этот адрес'],
+ ['5H', '5ч'],
+ ['5h', '5ч'],
+ ['7D', '7д'],
+ ['7d', '7д'],
+ ['Spark 5H', 'Spark 5ч'],
+ ['登录账号 (OpenAI / OTP / 导入)', 'Войти в аккаунт (OpenAI / OTP / импорт)'],
+ ['用该账号开一个真 codex 终端(隔离 + 直连),可发一句"你好"触发 referral 兑现', 'Открыть настоящий терминал codex для этого аккаунта (изоляция + прямое соединение); можно отправить короткое сообщение, чтобы активировать referral.'],
+ ['推送到 Server', 'Отправить на Server'],
+ ['确认删除账号', 'Удалить аккаунт?'],
+ ['彻底删除', 'Удалить окончательно'],
+ ['不打开默认浏览器,把授权链接复制到剪贴板,由你粘贴到目标浏览器', 'Не открывать браузер по умолчанию; скопировать ссылку авторизации в буфер, чтобы вставить её в нужный браузер'],
+ ['刷新额度', 'Обновить квоту'],
+ ['授权成功', 'Авторизация успешна'],
+ ['OAuth 授权成功', 'OAuth-авторизация успешна'],
+ ['无法获取用户目录', 'Не удалось получить домашний каталог пользователя'],
+ ['设置文件权限失败', 'Не удалось задать права файла'],
+ ['设置目录权限失败', 'Не удалось задать права каталога'],
+ ['写入文件失败', 'Не удалось записать файл'],
+ ['创建目录失败', 'Не удалось создать каталог'],
+ ['创建临时文件失败', 'Не удалось создать временный файл'],
+ ['写入临时文件失败', 'Не удалось записать временный файл'],
+ ['重命名临时文件失败', 'Не удалось переименовать временный файл'],
+ ['重命名文件失败 (Atomic Write)', 'Не удалось переименовать файл (atomic write)'],
+ ['读取 auth.json 失败', 'Не удалось прочитать auth.json'],
+ ['解析 auth.json 失败', 'Не удалось разобрать auth.json'],
+ ['未找到 Codex auth.json,请先登录 Codex', 'Codex auth.json не найден, сначала войдите в Codex'],
+ ['账号不存在', 'Аккаунт не найден'],
+ ['当前账号不存在', 'Текущий аккаунт не найден'],
+ ['没有激活的账号', 'Нет активного аккаунта'],
+ ['当前账号缺少 access_token', 'У текущего аккаунта нет access_token'],
+ ['session 绑定账号不存在', 'Привязанный к session аккаунт не найден'],
+ ['session 绑定账号缺 access_token', 'У привязанного к session аккаунта нет access_token'],
+ ['账号到期日格式必须是 YYYY-MM-DD', 'Дата окончания аккаунта должна быть в формате YYYY-MM-DD'],
+ ['不是中转站账号', 'Это не relay-аккаунт'],
+ ['无效的 Token 格式', 'Недопустимый формат токена'],
+ ['Base64 解码失败', 'Не удалось декодировать Base64'],
+ ['UTF-8 转换失败', 'Не удалось преобразовать UTF-8'],
+ ['JSON 解析失败', 'Не удалось разобрать JSON'],
+ ['文件不是 UTF-8 文本', 'Файл не является UTF-8 текстом'],
+ ['无法识别的 JSON 结构', 'Не удалось распознать структуру JSON'],
+ ['无法识别的文件格式', 'Не удалось распознать формат файла'],
+ ['zip 解析失败', 'Не удалось разобрать zip'],
+ ['缺 email', 'Нет email'],
+ ['缺 access_token', 'Нет access_token'],
+ ['缺 refresh_token', 'Нет refresh_token'],
+ ['无 accounts 数组', 'Нет массива accounts'],
+ ['缺 credentials', 'Нет credentials'],
+ ['native: 缺 accounts 对象', 'native: нет объекта accounts'],
+ ['session JSON 不能为空', 'session JSON не должен быть пустым'],
+ ['未找到包含 accessToken 的 session 对象', 'Не найден session-объект с accessToken'],
+ ['缺少 accessToken', 'Нет accessToken'],
+ ['执行失败', 'Не удалось выполнить'],
+ ['未找到运行中的 codex 进程', 'Запущенные процессы codex не найдены'],
+ ['未配置 Server 地址', 'Адрес Server не настроен'],
+ ['未配置共享密钥', 'Общий секрет не настроен'],
+ ['共享密钥为空,请先生成', 'Общий секрет пуст, сначала сгенерируйте его'],
+ ['磁盘账号不在管理列表中,请先导入', 'Аккаунта с диска нет в списке управления, сначала импортируйте его'],
+ ['手机锚只能设在 ChatGPT 订阅号上', 'Телефонный якорь можно включать только для аккаунта с подпиской ChatGPT'],
+ ['拒绝同步:身份不匹配', 'Синхронизация отклонена: идентичность не совпадает'],
+ ['拒绝同步:账号名与 token 邮箱不一致', 'Синхронизация отклонена: имя аккаунта не совпадает с email в токене'],
+ ['刷新令牌被拒绝', 'Refresh token отклонён'],
+ ['刷新令牌失败', 'Не удалось обновить refresh token'],
+ ['发现失败', 'Поиск не удался'],
+ ['安装失败', 'Установка не удалась'],
+ ['卸载失败', 'Удаление не удалось'],
+ ['操作失败', 'Операция не удалась'],
+ ['同步失败', 'Синхронизация не удалась'],
+ ['✓ 含 refresh_token', '✓ есть refresh_token'],
+ ['⚠ 无 refresh_token,到期后需重新导入', '⚠ нет refresh_token, после истечения нужно импортировать заново'],
+ ['每行一个,自动识别 provider', 'По одному на строку, provider определяется автоматически'],
+ ['运行中', 'Выполняется'],
+ ['等待中', 'Ожидает'],
+ ['Base URL 必须以 http:// 或 https:// 开头', 'Base URL должен начинаться с http:// или https://'],
+ ['API Key 看起来太短', 'API Key выглядит слишком коротким'],
+ ['账号名不能为空', 'Имя аккаунта не должно быть пустым'],
+ ['已封号', 'Заблокирован'],
+ ['Token 失效', 'Токен недействителен'],
+ ['日期异常', 'Некорректная дата'],
+ ['已过期', 'Истёк'],
+ ['天到期', 'дн до окончания'],
+ ['启动中…', 'Запуск...'],
+ ['启动 codex', 'Запустить codex'],
+ ['周期保鲜最近错误', 'Последняя ошибка продления периода'],
+ ['周期保鲜会在额度窗口到点后自动发一次最小 Codex 请求', 'После сброса окна квоты продление периода автоматически отправит минимальный запрос Codex'],
+ ['主动重置', 'Активный сброс'],
+ ['保活:', 'Продление:'],
+ ['刷新:', 'Обновление:'],
+ ['到期:', 'Окончание:'],
+ ['已选', 'Выбрано'],
+ ['按账号', 'По аккаунтам'],
+ ['绑定账号', 'Привязанный аккаунт'],
+ ['命中次数', 'Попаданий'],
+ ['年龄', 'Возраст'],
+ ['花费', 'Расход'],
+ ['搜索 label / session_id / 账号…', 'Поиск label / session_id / аккаунта...'],
+ ['搜索 cwd / 首条消息…', 'Поиск cwd / первого сообщения...'],
+ ['搜索账号…', 'Поиск аккаунта...'],
+ ['搜索邮箱 / 订阅类型 (如 team / pro / free)…', 'Поиск email / типа подписки (например team / pro / free)...'],
+ ['模型分布', 'Распределение моделей'],
+ ['切号原因', 'Причины переключений'],
+ ['费用', 'Стоимость'],
+ ['上次', 'Прошлое'],
+ ['当前', 'Текущий'],
+ ['周期', 'Период'],
+ ['订阅', 'Подписка'],
+ ['代理', 'Прокси'],
+ ['账号', 'Аккаунт'],
+ ['额度', 'Квота'],
+ ['配额', 'Квота'],
+ ['中转', 'Relay'],
+ ['保活', 'Продление'],
+ ['绑定', 'Привязка'],
+ ['解除', 'Снять'],
+ ['重试', 'Повтор'],
+ ['错误', 'Ошибка'],
+ ['开启', 'Включить'],
+ ['启用', 'Включено'],
+ ['禁用', 'Отключено'],
+ ['已启用', 'Включено'],
+ ['已禁用', 'Отключено'],
+ ['已停止', 'Остановлено'],
+ ['已启动', 'Запущено'],
+ ['未设置', 'Не задано'],
+ ['未绑定', 'Не привязано'],
+ ['自动', 'Авто'],
+ ['本地', 'Локально'],
+ ['远程', 'Удалённо'],
+ ['全量', 'Полный'],
+ ['备注', 'Заметка'],
+ ['说明', 'Описание'],
+ ['来源', 'Источник'],
+ ['到期', 'Истекает'],
+ ['邮箱', 'Email'],
+ ['日期', 'Дата'],
+ ['当前号', 'текущий аккаунт'],
+ ['封', 'Блок'],
+ ['条', 'зап.'],
+ ['个', 'шт.'],
+ [',', ', '],
+ ['。', '. '],
+ [':', ': '],
+ ['(', ' ('],
+ [')', ')'],
+ ['、', ', '],
+ [';', '; '],
+ ['「', '«'],
+ ['」', '»'],
+ ['【', '['],
+ ['】', ']'],
+];
+
+const sortedReplacements = [...replacements].sort((a, b) => b[0].length - a[0].length);
+const exactReplacements = new Map(replacements);
+const cjkRe = /[\u4e00-\u9fff]/;
+const normalizeWhitespace = (value: string) => value.replace(/\s+/g, ' ').trim();
+const normalizedExactReplacements = new Map(
+ replacements.map(([source, target]) => [normalizeWhitespace(source), target]),
+);
+const placeholderRe = /\{[^{}]*\}/g;
+const escapeRegExp = (value: string) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+const dynamicReplacements = replacements
+ .filter(([source]) => /\{[^{}]*\}/.test(source))
+ .sort((a, b) => b[0].length - a[0].length)
+ .map(([source, target]) => {
+ placeholderRe.lastIndex = 0;
+ const parts = normalizeWhitespace(source).split(placeholderRe).map(escapeRegExp);
+ placeholderRe.lastIndex = 0;
+ return { pattern: new RegExp(`^${parts.join('(.*?)')}$`, 'u'), target };
+ });
+const partialReplacements = sortedReplacements.filter(([source]) => (
+ cjkRe.test(source) || /[():「」【】、,。;]/.test(source)
+));
+export function translateRu(value: string): string {
+ if (!value) {
+ return value;
+ }
+ const leading = value.match(/^\s*/)?.[0] ?? '';
+ const trailing = value.match(/\s*$/)?.[0] ?? '';
+ const core = value.trim();
+ const exact = exactReplacements.get(core);
+ if (exact) {
+ return `${leading}${exact}${trailing}`;
+ }
+ const normalizedExact = normalizedExactReplacements.get(normalizeWhitespace(core));
+ if (normalizedExact) {
+ return `${leading}${normalizedExact}${trailing}`;
+ }
+ const normalizedCore = normalizeWhitespace(core);
+ for (const replacement of dynamicReplacements) {
+ const match = replacement.pattern.exec(normalizedCore);
+ if (!match) continue;
+ let capture = 1;
+ const translated = replacement.target.replace(placeholderRe, () => match[capture++] ?? '');
+ return `${leading}${translated}${trailing}`;
+ }
+ if (!cjkRe.test(value)) {
+ return value;
+ }
+
+ let out = value;
+ for (const [source, target] of partialReplacements) {
+ if (out.includes(source)) {
+ out = out.split(source).join(target);
+ }
+ }
+ out = out
+ .replace(/(\d+)\s*天后重置/g, '$1 дн до сброса')
+ .replace(/(\d+)\s*小时(\d+)\s*分钟后重置/g, '$1 ч $2 мин до сброса')
+ .replace(/(\d+)\s*分钟后重置/g, '$1 мин до сброса')
+ .replace(/(\d+)\s*天\s*(\d+)\s*小时\s*(\d+)\s*分钟\s*后重置/g, '$1 дн $2 ч $3 мин до сброса')
+ .replace(/(\d+)\s*小时\s*(\d+)\s*分钟\s*(\d+)\s*秒\s*后重置/g, '$1 ч $2 мин $3 с до сброса')
+ .replace(/(\d+)\s*分钟\s*(\d+)\s*秒\s*后重置/g, '$1 мин $2 с до сброса')
+ .replace(/(\d+)\s*秒\s*后重置/g, '$1 с до сброса')
+ .replace(/(\d+)\s*天到期/g, '$1 дн до окончания')
+ .replace(/(\d+)\s*天前/g, '$1 дн назад')
+ .replace(/(\d+)\s*小时前/g, '$1 ч назад')
+ .replace(/(\d+)\s*分钟前/g, '$1 мин назад')
+ .replace(/(\d+)\s*个使用额度/g, '$1 кредитов использования')
+ .replace(/(\d+)\s*个工作区额度/g, '$1 кредитов workspace')
+ .replace(/(\d+)\s*次限额重置/g, '$1 сбросов лимита')
+ .replace(/(\d+)\s*个账号/g, '$1 аккаунтов')
+ .replace(/(\d+)\s*人/g, '$1 чел.')
+ .replace(/(\d+)\s*条/g, '$1 зап.')
+ .replace(/(\d+)\s*小\s*ч/g, '$1 ч')
+ .replace(/(\d+)\s*天/g, '$1 дн')
+ .replace(/(\d+)\s*小时/g, '$1 ч')
+ .replace(/(\d+)\s*分钟/g, '$1 мин')
+ .replace(/(\d+)\s*秒/g, '$1 с')
+ .replace(/(\d+)\s*时/g, '$1 ч')
+ .replace(/(\d+)\s*分/g, '$1 мин')
+ .replace(/(\d+)\s*ч/g, '$1 ч')
+ .replace(/(\d+)\s*мин/g, '$1 мин')
+ .replace(/(\d+)\s*с\b/g, '$1 с');
+ return out;
+}
+
+export const russianLocale: UiLocale = {
+ code: 'ru',
+ title: 'Codex Switcher',
+ translate: translateRu,
+};
+
+export function countRussianReplacements(): number {
+ return replacements.length;
+}
diff --git a/src/i18n/runtime.ts b/src/i18n/runtime.ts
new file mode 100644
index 0000000..e4a89a4
--- /dev/null
+++ b/src/i18n/runtime.ts
@@ -0,0 +1,112 @@
+export interface UiLocale {
+ code: string;
+ title: string;
+ translate(value: string): string;
+}
+
+const translatedMark = 'data-ui-locale';
+const untranslatedSelector = 'script, style, textarea, input, code, pre, [translate="no"], [data-i18n-ignore]';
+
+function translateTextNode(node: Text, locale: UiLocale) {
+ const parent = node.parentElement;
+ if (!parent || parent.closest(untranslatedSelector)) return;
+ const translated = locale.translate(node.data);
+ if (translated !== node.data) node.data = translated;
+}
+
+function translateElementAttributes(element: Element, locale: UiLocale) {
+ if (element.closest('[translate="no"], [data-i18n-ignore]')) return;
+ for (const attr of ['title', 'placeholder', 'aria-label', 'alt']) {
+ const value = element.getAttribute(attr);
+ if (!value) continue;
+ const translated = locale.translate(value);
+ if (translated !== value) element.setAttribute(attr, translated);
+ }
+}
+
+function translateTree(root: ParentNode, locale: UiLocale) {
+ const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
+ let node = walker.nextNode();
+ while (node) {
+ translateTextNode(node as Text, locale);
+ node = walker.nextNode();
+ }
+ if (root instanceof Element) translateElementAttributes(root, locale);
+ root.querySelectorAll?.('[title], [placeholder], [aria-label], [alt]')
+ .forEach(element => translateElementAttributes(element, locale));
+}
+
+function wrapDialogs(locale: UiLocale) {
+ const originalAlert = window.alert.bind(window);
+ const originalConfirm = window.confirm.bind(window);
+ const originalPrompt = window.prompt.bind(window);
+ window.alert = (message?: unknown) => originalAlert(locale.translate(String(message ?? '')));
+ window.confirm = (message?: string) => originalConfirm(locale.translate(String(message ?? '')));
+ window.prompt = (message?: string, defaultValue?: string) => (
+ originalPrompt(locale.translate(String(message ?? '')), defaultValue)
+ );
+}
+
+function wrapNotification(locale: UiLocale) {
+ if (!('Notification' in window)) return;
+ const OriginalNotification = window.Notification;
+ const LocalizedNotification = function Notification(title: string, options?: NotificationOptions) {
+ const localizedOptions = options
+ ? { ...options, body: options.body ? locale.translate(options.body) : options.body }
+ : options;
+ return new OriginalNotification(locale.translate(title), localizedOptions);
+ } as unknown as typeof Notification;
+ Object.setPrototypeOf(LocalizedNotification, OriginalNotification);
+ LocalizedNotification.prototype = OriginalNotification.prototype;
+ try {
+ window.Notification = LocalizedNotification;
+ } catch {
+ // Some WebView builds expose Notification as read-only.
+ }
+}
+
+export function installUiLocale(locale: UiLocale) {
+ document.documentElement.lang = locale.code;
+ document.title = locale.title;
+
+ const bootStyle = document.createElement('style');
+ bootStyle.id = 'ui-locale-boot';
+ bootStyle.textContent = `body:not([${translatedMark}="ready"]) { visibility: hidden; }`;
+ document.head.appendChild(bootStyle);
+
+ wrapDialogs(locale);
+ wrapNotification(locale);
+
+ const observer = new MutationObserver((mutations) => {
+ for (const mutation of mutations) {
+ if (mutation.type === 'characterData' && mutation.target.nodeType === Node.TEXT_NODE) {
+ translateTextNode(mutation.target as Text, locale);
+ continue;
+ }
+ for (const node of mutation.addedNodes) {
+ if (node.nodeType === Node.TEXT_NODE) {
+ translateTextNode(node as Text, locale);
+ } else if (node.nodeType === Node.ELEMENT_NODE) {
+ translateTree(node as Element, locale);
+ }
+ }
+ if (mutation.type === 'attributes' && mutation.target instanceof Element) {
+ translateElementAttributes(mutation.target, locale);
+ }
+ }
+ });
+
+ observer.observe(document.documentElement, {
+ childList: true,
+ subtree: true,
+ characterData: true,
+ attributes: true,
+ attributeFilter: ['title', 'placeholder', 'aria-label', 'alt'],
+ });
+
+ queueMicrotask(() => {
+ translateTree(document.body, locale);
+ document.body.setAttribute(translatedMark, 'ready');
+ bootStyle.remove();
+ });
+}
diff --git a/src/main.tsx b/src/main.tsx
index fc750ba..1b12d5b 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -3,11 +3,23 @@ import ReactDOM from "react-dom/client";
import App from "./App";
import { TrayPopup } from "./components/TrayPopup";
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
+import { invoke } from "@tauri-apps/api/core";
+import { installAppLocale } from "./i18n";
const label = getCurrentWebviewWindow().label;
-ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
-
- {label === "tray-popup" ? : }
- ,
-);
+async function startApp() {
+ const systemLocale = await invoke ("get_system_locale").catch(() => null);
+ const appLocale = installAppLocale(systemLocale ?? undefined);
+ await invoke("set_app_locale", { locale: appLocale }).catch((error) => {
+ console.error("Failed to synchronize the application locale", error);
+ });
+
+ ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
+
+ {label === "tray-popup" ? : }
+ ,
+ );
+}
+
+void startApp();
|