Compare commits

...

42 Commits

Author SHA1 Message Date
Supra4E8C
3468fd8373 feat(app.js, styles): enhance connection state handling and update editor dimensions
- Added a new property to track the last connection state in CLIProxyManager.
- Updated the config editor availability logic to reflect changes in connection state.
- Increased minimum height for various editor components in styles to improve usability.
- Introduced responsive styles for smaller screens to ensure proper display of editor elements.
2025-11-10 18:07:31 +08:00
Supra4E8C
4f15c3f5c5 feat(app.js, i18n): enforce required base URL for Codex API configuration
- Updated the Codex API configuration modals to mark the Base URL field as required.
- Added validation to ensure the Base URL is provided before submission, with appropriate error notifications.
- Updated internationalization strings to reflect the change in the Base URL label from "Optional" to "Required" in both English and Chinese.
2025-11-10 12:16:46 +08:00
hkfires
72cd117aab fix(logs): exclude all /v0/management/ API entries from viewer 2025-11-10 10:40:28 +08:00
hkfires
5d62cd91f2 perf(cli): prefetch /usage, derive keyStats, reuse across renders 2025-11-10 10:32:57 +08:00
Supra4E8C
6837100dec feat(app.js, i18n, styles): implement custom headers functionality in API key management
- Added the ability to input custom HTTP headers for API keys in the CLIProxyManager.
- Introduced new methods for adding, populating, collecting, and applying custom headers.
- Updated the UI to include input fields for custom headers in the modals for adding and editing API keys.
- Enhanced internationalization strings to support custom headers in both English and Chinese.
- Added corresponding styles for the new header input fields and badges in the UI.
2025-11-09 18:27:29 +08:00
Supra4E8C
8542041981 feat(app.js, i18n): support batch addition of Gemini API keys with enhanced UI
- Updated the Gemini API key modal to allow input of multiple keys, each on a new line.
- Added a hint for users on how to input multiple keys and updated the corresponding internationalization strings.
- Enhanced the key addition logic to handle success, skipped, and failed counts, providing detailed feedback to users.
- Improved error handling and notifications for batch operations.
2025-11-09 18:06:56 +08:00
Supra4E8C
35ceab0dae feat(app.js, i18n): enhance Gemini API key management with base URL support
- Updated the CLIProxyManager to handle both API keys and optional base URLs for Gemini.
- Added new input fields in the modal for base URL entry during key addition and editing.
- Updated internationalization strings to include labels and placeholders for the base URL in both English and Chinese.
- Improved key normalization and rendering logic to accommodate the new structure.
2025-11-09 17:51:38 +08:00
Supra4E8C
d3fe186df7 refactor(app.js): remove modal click event listener to streamline modal behavior 2025-11-09 17:20:02 +08:00
Supra4E8C
5aff22a20b fix(ui): update modal styles for better responsiveness and overflow handling 2025-11-09 17:17:49 +08:00
hkfires
aa1dedc932 feat(ui): mark runtime-only auth files and disable actions 2025-11-07 22:02:29 +08:00
hkfires
61e75eee97 feat(auth-files): add AI Studio and Gemini CLI with filename masking 2025-11-07 21:46:46 +08:00
hkfires
3a2d96725f fix(ui): align file-item footer and adjust badge spacing 2025-11-06 14:23:07 +08:00
Supra4E8C
8283e99909 fix(app.js):尝试修复codex配置异常丢失数据的问题 2025-11-05 18:06:22 +08:00
hkfires
181cba6886 feat(logs): limit lines, incremental updates, and highlighting 2025-11-03 18:44:50 +08:00
hkfires
aa729914c5 fix(ui): position API Keys/Providers action buttons; prevent overlap 2025-11-03 16:31:29 +08:00
hkfires
f98f31f2ed fix(i18n, ui): correct syntax error in generateDynamicTypeLabel method
- Move generateDynamicTypeLabel method from inside updateAuthFileFilterButtons to proper class method location
- Fix JavaScript syntax error that prevented app from loading
- Preserve all internationalization functionality from 257260b

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-03 16:05:51 +08:00
hkfires
1e79f918e2 fix(ui): harden key list rendering and config handling 2025-10-31 16:24:43 +08:00
Supra4E8C
257260b1d2 feat(i18n, ui): enhance file type filtering with internationalization support
- Updated the file type display logic to utilize i18n for dynamic translations.
- Refactored filter button definitions to include data attributes for improved localization.
- Added new translation keys for various file types and filter options in both English and Chinese.
- Implemented a method to refresh button texts upon language change, ensuring consistent UI updates.
2025-10-26 17:46:57 +08:00
Supra4E8C
8372906820 为筛选按钮容器 .auth-file-filter 改用事件委托,并在重新渲染时移除旧监听器,避免多次绑定导致回调重复执行。 2025-10-26 17:33:06 +08:00
Supra4E8C
5feea2e345 Merge pull request #10 from coulsontl/new_ui
feat(ui): 添加类型筛选和详细信息视图来优化认证文件管理,并优化布局结构
2025-10-26 17:23:09 +08:00
coulsontl
825ad53c2c refactor(ui): streamline auth file actions with event delegation
- Updated the auth file action buttons to use data attributes for improved event handling.
- Implemented event delegation for button actions (show details, download, delete) to enhance performance and maintainability.
- Added a hidden class in CSS to manage file item visibility more effectively.
- Refactored modal button actions to utilize event delegation for better code organization.
2025-10-26 17:09:33 +08:00
coulsontl
3e9413172c feat(ui): enhance auth file management with type filtering and detailed view
- Implemented file type collection and dynamic filter button updates based on available file types.
- Added a detailed view for auth files, displaying JSON content in a modal with copy functionality.
- Improved UI layout for file items and added responsive design for better usability.
2025-10-26 16:43:06 +08:00
Supra4E8C
89099b58ff update README 2025-10-26 14:56:54 +08:00
Supra4E8C
7509a1eddc 更新补全i18n国际化文本 2025-10-26 14:54:07 +08:00
hkfires
e92784f951 feat(ui): add auth file success/failure stats; expand list height 2025-10-21 21:59:08 +08:00
hkfires
d26695da76 feat(ui,keys): granular masking, stats match, legacy format
- Make maskApiKey progressive for short keys to reduce exposure
- When aggregating usage, fall back to masked key to match stored stats
- Support legacy provider config `api-keys` by mapping to `api-key-entries`
- Add scrolling for provider lists >5 and reset styles when empty
- Improves privacy, fixes mismatched stats display, and preserves compatibility
2025-10-21 21:08:09 +08:00
Supra4E8C
8964030ade 尝试修复bug 2025-10-21 12:31:22 +08:00
hkfires
0b9abdf9b1 fix(logs): auto-scroll to latest on full reload 2025-10-20 14:57:15 +08:00
hkfires
a208a484ff feat(config-ui): add YAML config editor with save/reload support 2025-10-19 22:40:08 +08:00
Supra4E8C
369cf52346 0.1.7 2025-10-18 17:04:29 +08:00
hkfires
dcfffc716b feat(ui): add in-app log viewer and file logging controls
- Add Logs section with refresh, download, and clear actions
- Implement auto-refresh toggle and incremental loading via timestamp
- Add “logging to file” setting; integrate with config and /logging-to-file API
- Auto-load logs when opening Logs; hide nav when logging disabled
- Escape HTML when rendering logs for safety
- Update i18n with strings for logs and settings
- Ignore CLAUDE.md and AGENTS.md in .gitignore

Why: Enable users to monitor and manage logs within the app, reduce overhead with incremental updates, and avoid committing local agent docs.
2025-10-16 12:03:15 +08:00
hkfires
7de5280824 feat(build): auto-inject release version into HTML output 2025-10-15 16:49:53 +08:00
hkfires
86d60aad77 增加使用统计开关 2025-10-13 15:56:26 +08:00
Supra4E8C
020fccc032 1 2025-10-11 15:51:51 +08:00
Supra4E8C
c162ab3a54 删除gemini web tokens 2025-10-11 15:02:57 +08:00
Supra4E8C
85d12e15d8 Merge pull request #4 from tombii/main
Add missing English translations.
2025-10-11 14:51:40 +08:00
tombii
ebffb49f52 Add missing English translations. 2025-10-08 22:08:36 +02:00
Supra4E8C
316c1ffc0d Update README_CN.md 2025-10-06 16:02:15 +08:00
Supra4E8C
b3e54e7f14 Update README.md 2025-10-06 16:01:56 +08:00
Luis Pater
fe11bfb48f Added hostname checking function. If it is not localhost or 127.0.0.1, the OAuth login box will be hidden to improve user experience; Added unique IDs to each OAuth card for easier operation. 2025-10-06 01:51:56 +08:00
Luis Pater
ee0d8f82d7 Implement multiple OAuth functions, including Anthropic, Gemini CLI, Qwen and iFlow, add relevant UI components and styles, optimize user experience, and enhance the usability and feedback mechanism of the authentication process. 2025-10-06 01:48:17 +08:00
Luis Pater
0bbb397df5 Implement the Codex OAuth function, add relevant UI components and styles, optimize the login experience, and fix several UI issues. 2025-10-06 01:12:34 +08:00
10 changed files with 6692 additions and 1691 deletions

View File

@@ -27,6 +27,8 @@ jobs:
- name: Build all-in-one HTML - name: Build all-in-one HTML
run: npm run build run: npm run build
env:
VERSION: ${{ github.ref_name }}
- name: Prepare release assets - name: Prepare release assets
run: | run: |

5
.gitignore vendored
View File

@@ -20,3 +20,8 @@ package-lock.json
# OS files # OS files
.DS_Store .DS_Store
Thumbs.db Thumbs.db
CLAUDE.md
.claude
AGENTS.md
.serena

View File

@@ -10,7 +10,7 @@ Example URL:
https://remote.router-for.me/ https://remote.router-for.me/
Minimum required version: ≥ 6.0.0 Minimum required version: ≥ 6.0.0
Recommended version: ≥ 6.0.19 Recommended version: ≥ 6.2.32
Since version 6.0.19, the WebUI has been rolled into the main program. You can access it by going to `/management.html` on the external port after firing up the main project. Since version 6.0.19, the WebUI has been rolled into the main program. You can access it by going to `/management.html` on the external port after firing up the main project.
@@ -43,7 +43,6 @@ Since version 6.0.19, the WebUI has been rolled into the main program. You can a
- Download existing authentication files - Download existing authentication files
- Delete single or all authentication files - Delete single or all authentication files
- Display file details - Display file details
- **Gemini Web Token**: Direct authentication using browser cookies
### Usage Statistics ### Usage Statistics
- **Real-time Analytics**: Track API usage with interactive charts - **Real-time Analytics**: Track API usage with interactive charts

View File

@@ -8,7 +8,9 @@ https://github.com/router-for-me/CLIProxyAPI
https://remote.router-for.me/ https://remote.router-for.me/
最低可用版本 ≥ 6.0.0 最低可用版本 ≥ 6.0.0
推荐版本 ≥ 6.0.19
推荐版本 ≥ 6.2.32
自6.0.19起WebUI已经集成在主程序中 可以通过主项目开启的外部端口的`/management.html`访问 自6.0.19起WebUI已经集成在主程序中 可以通过主项目开启的外部端口的`/management.html`访问
## 功能特点 ## 功能特点
@@ -40,7 +42,6 @@ https://remote.router-for.me/
- 下载现有认证文件 - 下载现有认证文件
- 删除单个或所有认证文件 - 删除单个或所有认证文件
- 显示文件详细信息 - 显示文件详细信息
- **Gemini Web Token**: 使用浏览器 Cookie 直接认证
### 使用统计 ### 使用统计
- **实时分析**: 通过交互式图表跟踪 API 使用情况 - **实时分析**: 通过交互式图表跟踪 API 使用情况

3171
app.js

File diff suppressed because it is too large Load Diff

View File

@@ -49,6 +49,35 @@ function escapeForStyle(content) {
return content.replace(/<\/(style)/gi, '<\\/$1'); return content.replace(/<\/(style)/gi, '<\\/$1');
} }
function getVersion() {
// 1. 优先从环境变量获取GitHub Actions 会设置)
if (process.env.VERSION) {
return process.env.VERSION;
}
// 2. 尝试从 git tag 获取
try {
const { execSync } = require('child_process');
const gitTag = execSync('git describe --tags --exact-match 2>/dev/null || git describe --tags 2>/dev/null || echo ""', { encoding: 'utf8' }).trim();
if (gitTag) {
return gitTag;
}
} catch (err) {
console.warn('无法从 git 获取版本号');
}
// 3. 回退到 package.json
try {
const packageJson = JSON.parse(fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf8'));
return 'v' + packageJson.version;
} catch (err) {
console.warn('无法从 package.json 读取版本号');
}
// 4. 最后使用默认值
return 'v0.0.0-dev';
}
function ensureDistDir() { function ensureDistDir() {
if (fs.existsSync(distDir)) { if (fs.existsSync(distDir)) {
fs.rmSync(distDir, { recursive: true, force: true }); fs.rmSync(distDir, { recursive: true, force: true });
@@ -83,6 +112,11 @@ function build() {
const i18n = escapeForScript(readFile(sourceFiles.i18n)); const i18n = escapeForScript(readFile(sourceFiles.i18n));
const app = escapeForScript(readFile(sourceFiles.app)); const app = escapeForScript(readFile(sourceFiles.app));
// 获取版本号并替换
const version = getVersion();
console.log(`使用版本号: ${version}`);
html = html.replace(/__VERSION__/g, version);
html = html.replace( html = html.replace(
'<link rel="stylesheet" href="styles.css">', '<link rel="stylesheet" href="styles.css">',
`<style> `<style>

402
i18n.js
View File

@@ -38,6 +38,14 @@ const i18n = {
'common.base_url': '地址', 'common.base_url': '地址',
'common.proxy_url': '代理', 'common.proxy_url': '代理',
'common.alias': '别名', 'common.alias': '别名',
'common.failure': '失败',
'common.unknown_error': '未知错误',
'common.copy': '复制',
'common.custom_headers_label': '自定义请求头',
'common.custom_headers_hint': '可选,设置需要附带到请求中的 HTTP 头,名称和值均不能为空。',
'common.custom_headers_add': '添加请求头',
'common.custom_headers_key_placeholder': 'Header 名称,例如 X-Custom-Header',
'common.custom_headers_value_placeholder': 'Header 值',
// 页面标题 // 页面标题
'title.main': 'CLI Proxy API Management Center', 'title.main': 'CLI Proxy API Management Center',
@@ -82,6 +90,8 @@ const i18n = {
'nav.ai_providers': 'AI 提供商', 'nav.ai_providers': 'AI 提供商',
'nav.auth_files': '认证文件', 'nav.auth_files': '认证文件',
'nav.usage_stats': '使用统计', 'nav.usage_stats': '使用统计',
'nav.config_management': '配置管理',
'nav.logs': '日志查看',
'nav.system_info': '系统信息', 'nav.system_info': '系统信息',
// 基础设置 // 基础设置
@@ -99,6 +109,10 @@ const i18n = {
'basic_settings.quota_title': '配额超出行为', 'basic_settings.quota_title': '配额超出行为',
'basic_settings.quota_switch_project': '自动切换项目', 'basic_settings.quota_switch_project': '自动切换项目',
'basic_settings.quota_switch_preview': '切换到预览模型', 'basic_settings.quota_switch_preview': '切换到预览模型',
'basic_settings.usage_statistics_title': '使用统计',
'basic_settings.usage_statistics_enable': '启用使用统计',
'basic_settings.logging_title': '日志记录',
'basic_settings.logging_to_file_enable': '启用日志记录到文件',
// API 密钥管理 // API 密钥管理
'api_keys.title': 'API 密钥管理', 'api_keys.title': 'API 密钥管理',
@@ -122,10 +136,14 @@ const i18n = {
'ai_providers.gemini_empty_desc': '点击上方按钮添加第一个密钥', 'ai_providers.gemini_empty_desc': '点击上方按钮添加第一个密钥',
'ai_providers.gemini_item_title': 'Gemini密钥', 'ai_providers.gemini_item_title': 'Gemini密钥',
'ai_providers.gemini_add_modal_title': '添加Gemini API密钥', 'ai_providers.gemini_add_modal_title': '添加Gemini API密钥',
'ai_providers.gemini_add_modal_key_label': 'API密钥:', 'ai_providers.gemini_add_modal_key_label': 'API密钥列表:',
'ai_providers.gemini_add_modal_key_placeholder': '请输入Gemini API密钥', 'ai_providers.gemini_add_modal_key_placeholder': '请输入Gemini API密钥(每行一个)',
'ai_providers.gemini_add_modal_key_hint': '可一次粘贴多个密钥,每行一个。',
'ai_providers.gemini_add_modal_url_label': 'Base URL (可选):',
'ai_providers.gemini_add_modal_url_placeholder': '例如: https://generativelanguage.googleapis.com',
'ai_providers.gemini_edit_modal_title': '编辑Gemini API密钥', 'ai_providers.gemini_edit_modal_title': '编辑Gemini API密钥',
'ai_providers.gemini_edit_modal_key_label': 'API密钥:', 'ai_providers.gemini_edit_modal_key_label': 'API密钥:',
'ai_providers.gemini_edit_modal_url_label': 'Base URL (可选):',
'ai_providers.gemini_delete_confirm': '确定要删除这个Gemini密钥吗', 'ai_providers.gemini_delete_confirm': '确定要删除这个Gemini密钥吗',
'ai_providers.codex_title': 'Codex API 配置', 'ai_providers.codex_title': 'Codex API 配置',
@@ -136,13 +154,13 @@ const i18n = {
'ai_providers.codex_add_modal_title': '添加Codex API配置', 'ai_providers.codex_add_modal_title': '添加Codex API配置',
'ai_providers.codex_add_modal_key_label': 'API密钥:', 'ai_providers.codex_add_modal_key_label': 'API密钥:',
'ai_providers.codex_add_modal_key_placeholder': '请输入Codex API密钥', 'ai_providers.codex_add_modal_key_placeholder': '请输入Codex API密钥',
'ai_providers.codex_add_modal_url_label': 'Base URL (可选):', 'ai_providers.codex_add_modal_url_label': 'Base URL (必填):',
'ai_providers.codex_add_modal_url_placeholder': '例如: https://api.example.com', 'ai_providers.codex_add_modal_url_placeholder': '例如: https://api.example.com',
'ai_providers.codex_add_modal_proxy_label': '代理 URL (可选):', 'ai_providers.codex_add_modal_proxy_label': '代理 URL (可选):',
'ai_providers.codex_add_modal_proxy_placeholder': '例如: socks5://proxy.example.com:1080', 'ai_providers.codex_add_modal_proxy_placeholder': '例如: socks5://proxy.example.com:1080',
'ai_providers.codex_edit_modal_title': '编辑Codex API配置', 'ai_providers.codex_edit_modal_title': '编辑Codex API配置',
'ai_providers.codex_edit_modal_key_label': 'API密钥:', 'ai_providers.codex_edit_modal_key_label': 'API密钥:',
'ai_providers.codex_edit_modal_url_label': 'Base URL (可选):', 'ai_providers.codex_edit_modal_url_label': 'Base URL (必填):',
'ai_providers.codex_edit_modal_proxy_label': '代理 URL (可选):', 'ai_providers.codex_edit_modal_proxy_label': '代理 URL (可选):',
'ai_providers.codex_delete_confirm': '确定要删除这个Codex配置吗', 'ai_providers.codex_delete_confirm': '确定要删除这个Codex配置吗',
@@ -213,18 +231,95 @@ const i18n = {
'auth_files.delete_success': '文件删除成功', 'auth_files.delete_success': '文件删除成功',
'auth_files.delete_all_success': '成功删除', 'auth_files.delete_all_success': '成功删除',
'auth_files.files_count': '个文件', 'auth_files.files_count': '个文件',
'auth_files.filter_all': '全部',
'auth_files.filter_qwen': 'Qwen',
'auth_files.filter_gemini': 'Gemini',
'auth_files.filter_gemini-cli': 'GeminiCLI',
'auth_files.filter_aistudio': 'AIStudio',
'auth_files.filter_claude': 'Claude',
'auth_files.filter_codex': 'Codex',
'auth_files.filter_iflow': 'iFlow',
'auth_files.filter_empty': '空文件',
'auth_files.filter_unknown': '其他',
'auth_files.type_qwen': 'Qwen',
'auth_files.type_gemini': 'Gemini',
'auth_files.type_gemini-cli': 'GeminiCLI',
'auth_files.type_aistudio': 'AIStudio',
'auth_files.type_claude': 'Claude',
'auth_files.type_codex': 'Codex',
'auth_files.type_iflow': 'iFlow',
'auth_files.type_empty': '空文件',
'auth_files.type_unknown': '其他',
// Gemini Web Token
'auth_login.gemini_web_title': 'Gemini Web Token', // Codex OAuth
'auth_login.gemini_web_button': '保存 Gemini Web Token', 'auth_login.codex_oauth_title': 'Codex OAuth',
'auth_login.gemini_web_hint': '从浏览器开发者工具中获取 Gemini 网页版的 Cookie 值,用于直接认证访问 Gemini。', 'auth_login.codex_oauth_button': '开始 Codex 登录',
'auth_login.secure_1psid_label': '__Secure-1PSID Cookie:', 'auth_login.codex_oauth_hint': '通过 OAuth 流程登录 Codex 服务,自动获取并保存认证文件。',
'auth_login.secure_1psid_placeholder': '输入 __Secure-1PSID cookie 值', 'auth_login.codex_oauth_url_label': '授权链接:',
'auth_login.secure_1psidts_label': '__Secure-1PSIDTS Cookie:', 'auth_login.codex_open_link': '打开链接',
'auth_login.secure_1psidts_placeholder': '输入 __Secure-1PSIDTS cookie 值', 'auth_login.codex_copy_link': '复制链接',
'auth_login.gemini_web_label_label': '标签 (可选):', 'auth_login.codex_oauth_status_waiting': '等待认证中...',
'auth_login.gemini_web_label_placeholder': '输入标签名称 (可选)', 'auth_login.codex_oauth_status_success': '认证成功!',
'auth_login.gemini_web_saved': 'Gemini Web Token 保存成功', 'auth_login.codex_oauth_status_error': '认证失败:',
'auth_login.codex_oauth_start_error': '启动 Codex OAuth 失败:',
'auth_login.codex_oauth_polling_error': '检查认证状态失败:',
// Anthropic OAuth
'auth_login.anthropic_oauth_title': 'Anthropic OAuth',
'auth_login.anthropic_oauth_button': '开始 Anthropic 登录',
'auth_login.anthropic_oauth_hint': '通过 OAuth 流程登录 Anthropic (Claude) 服务,自动获取并保存认证文件。',
'auth_login.anthropic_oauth_url_label': '授权链接:',
'auth_login.anthropic_open_link': '打开链接',
'auth_login.anthropic_copy_link': '复制链接',
'auth_login.anthropic_oauth_status_waiting': '等待认证中...',
'auth_login.anthropic_oauth_status_success': '认证成功!',
'auth_login.anthropic_oauth_status_error': '认证失败:',
'auth_login.anthropic_oauth_start_error': '启动 Anthropic OAuth 失败:',
'auth_login.anthropic_oauth_polling_error': '检查认证状态失败:',
// Gemini CLI OAuth
'auth_login.gemini_cli_oauth_title': 'Gemini CLI OAuth',
'auth_login.gemini_cli_oauth_button': '开始 Gemini CLI 登录',
'auth_login.gemini_cli_oauth_hint': '通过 OAuth 流程登录 Google Gemini CLI 服务,自动获取并保存认证文件。',
'auth_login.gemini_cli_project_id_label': 'Google Cloud 项目 ID (可选):',
'auth_login.gemini_cli_project_id_placeholder': '输入 Google Cloud 项目 ID (可选)',
'auth_login.gemini_cli_project_id_hint': '如果指定了项目 ID将使用该项目的认证信息。',
'auth_login.gemini_cli_oauth_url_label': '授权链接:',
'auth_login.gemini_cli_open_link': '打开链接',
'auth_login.gemini_cli_copy_link': '复制链接',
'auth_login.gemini_cli_oauth_status_waiting': '等待认证中...',
'auth_login.gemini_cli_oauth_status_success': '认证成功!',
'auth_login.gemini_cli_oauth_status_error': '认证失败:',
'auth_login.gemini_cli_oauth_start_error': '启动 Gemini CLI OAuth 失败:',
'auth_login.gemini_cli_oauth_polling_error': '检查认证状态失败:',
// Qwen OAuth
'auth_login.qwen_oauth_title': 'Qwen OAuth',
'auth_login.qwen_oauth_button': '开始 Qwen 登录',
'auth_login.qwen_oauth_hint': '通过设备授权流程登录 Qwen 服务,自动获取并保存认证文件。',
'auth_login.qwen_oauth_url_label': '授权链接:',
'auth_login.qwen_open_link': '打开链接',
'auth_login.qwen_copy_link': '复制链接',
'auth_login.qwen_oauth_status_waiting': '等待认证中...',
'auth_login.qwen_oauth_status_success': '认证成功!',
'auth_login.qwen_oauth_status_error': '认证失败:',
'auth_login.qwen_oauth_start_error': '启动 Qwen OAuth 失败:',
'auth_login.qwen_oauth_polling_error': '检查认证状态失败:',
'auth_login.missing_state': '无法获取认证状态参数',
// iFlow OAuth
'auth_login.iflow_oauth_title': 'iFlow OAuth',
'auth_login.iflow_oauth_button': '开始 iFlow 登录',
'auth_login.iflow_oauth_hint': '通过 OAuth 流程登录 iFlow 服务,自动获取并保存认证文件。',
'auth_login.iflow_oauth_url_label': '授权链接:',
'auth_login.iflow_open_link': '打开链接',
'auth_login.iflow_copy_link': '复制链接',
'auth_login.iflow_oauth_status_waiting': '等待认证中...',
'auth_login.iflow_oauth_status_success': '认证成功!',
'auth_login.iflow_oauth_status_error': '认证失败:',
'auth_login.iflow_oauth_start_error': '启动 iFlow OAuth 失败:',
'auth_login.iflow_oauth_polling_error': '检查认证状态失败:',
// 使用统计 // 使用统计
'usage_stats.title': '使用统计', 'usage_stats.title': '使用统计',
@@ -245,6 +340,48 @@ const i18n = {
'usage_stats.tokens_count': 'Token数量', 'usage_stats.tokens_count': 'Token数量',
'usage_stats.models': '模型统计', 'usage_stats.models': '模型统计',
'usage_stats.success_rate': '成功率', 'usage_stats.success_rate': '成功率',
'stats.success': '成功',
'stats.failure': '失败',
// 日志查看
'logs.title': '日志查看',
'logs.refresh_button': '刷新日志',
'logs.clear_button': '清空日志',
'logs.download_button': '下载日志',
'logs.empty_title': '暂无日志记录',
'logs.empty_desc': '当启用"日志记录到文件"功能后,日志将显示在这里',
'logs.log_content': '日志内容',
'logs.loading': '正在加载日志...',
'logs.load_error': '加载日志失败',
'logs.clear_confirm': '确定要清空所有日志吗?此操作不可恢复!',
'logs.clear_success': '日志已清空',
'logs.download_success': '日志下载成功',
'logs.auto_refresh': '自动刷新',
'logs.auto_refresh_enabled': '自动刷新已开启',
'logs.auto_refresh_disabled': '自动刷新已关闭',
'logs.lines': '行',
'logs.removed': '已删除',
'logs.upgrade_required_title': '需要升级 CLI Proxy API',
'logs.upgrade_required_desc': '当前服务器版本不支持日志查看功能,请升级到最新版本的 CLI Proxy API 以使用此功能。',
// 配置管理
'config_management.title': '配置管理',
'config_management.editor_title': '配置文件',
'config_management.reload': '重新加载',
'config_management.save': '保存',
'config_management.description': '查看并编辑服务器上的 config.yaml 配置文件。保存前请确认语法正确。',
'config_management.status_idle': '等待操作',
'config_management.status_loading': '加载配置中...',
'config_management.status_loaded': '配置已加载',
'config_management.status_dirty': '有未保存的更改',
'config_management.status_disconnected': '请先连接服务器以加载配置',
'config_management.status_load_failed': '加载失败',
'config_management.status_saving': '正在保存配置...',
'config_management.status_saved': '配置保存完成',
'config_management.status_save_failed': '保存失败',
'config_management.save_success': '配置已保存',
'config_management.error_yaml_not_supported': '服务器未返回 YAML 格式,请确认 /config.yaml 接口可用',
'config_management.editor_placeholder': 'key: value',
// 系统信息 // 系统信息
'system_info.title': '系统信息', 'system_info.title': '系统信息',
@@ -264,15 +401,21 @@ const i18n = {
'notification.retry_updated': '重试设置已更新', 'notification.retry_updated': '重试设置已更新',
'notification.quota_switch_project_updated': '项目切换设置已更新', 'notification.quota_switch_project_updated': '项目切换设置已更新',
'notification.quota_switch_preview_updated': '预览模型切换设置已更新', 'notification.quota_switch_preview_updated': '预览模型切换设置已更新',
'notification.usage_statistics_updated': '使用统计设置已更新',
'notification.logging_to_file_updated': '日志记录设置已更新',
'notification.api_key_added': 'API密钥添加成功', 'notification.api_key_added': 'API密钥添加成功',
'notification.api_key_updated': 'API密钥更新成功', 'notification.api_key_updated': 'API密钥更新成功',
'notification.api_key_deleted': 'API密钥删除成功', 'notification.api_key_deleted': 'API密钥删除成功',
'notification.gemini_key_added': 'Gemini密钥添加成功', 'notification.gemini_key_added': 'Gemini密钥添加成功',
'notification.gemini_key_updated': 'Gemini密钥更新成功', 'notification.gemini_key_updated': 'Gemini密钥更新成功',
'notification.gemini_key_deleted': 'Gemini密钥删除成功', 'notification.gemini_key_deleted': 'Gemini密钥删除成功',
'notification.gemini_multi_input_required': '请先输入至少一个Gemini密钥',
'notification.gemini_multi_failed': 'Gemini密钥批量添加失败',
'notification.gemini_multi_summary': 'Gemini批量添加完成成功 {success},跳过 {skipped},失败 {failed}',
'notification.codex_config_added': 'Codex配置添加成功', 'notification.codex_config_added': 'Codex配置添加成功',
'notification.codex_config_updated': 'Codex配置更新成功', 'notification.codex_config_updated': 'Codex配置更新成功',
'notification.codex_config_deleted': 'Codex配置删除成功', 'notification.codex_config_deleted': 'Codex配置删除成功',
'notification.codex_base_url_required': '请填写Codex Base URL',
'notification.claude_config_added': 'Claude配置添加成功', 'notification.claude_config_added': 'Claude配置添加成功',
'notification.claude_config_updated': 'Claude配置更新成功', 'notification.claude_config_updated': 'Claude配置更新成功',
'notification.claude_config_deleted': 'Claude配置删除成功', 'notification.claude_config_deleted': 'Claude配置删除成功',
@@ -298,6 +441,7 @@ const i18n = {
'notification.gemini_api_key': 'Gemini API密钥', 'notification.gemini_api_key': 'Gemini API密钥',
'notification.codex_api_key': 'Codex API密钥', 'notification.codex_api_key': 'Codex API密钥',
'notification.claude_api_key': 'Claude API密钥', 'notification.claude_api_key': 'Claude API密钥',
'notification.link_copied': '链接已复制到剪贴板',
// 语言切换 // 语言切换
'language.switch': '语言', 'language.switch': '语言',
@@ -312,6 +456,10 @@ const i18n = {
'theme.switch_to_dark': '切换到暗色模式', 'theme.switch_to_dark': '切换到暗色模式',
'theme.auto': '跟随系统', 'theme.auto': '跟随系统',
// 侧边栏
'sidebar.toggle_expand': '展开侧边栏',
'sidebar.toggle_collapse': '收起侧边栏',
// 页脚 // 页脚
'footer.version': '版本', 'footer.version': '版本',
'footer.author': '作者' 'footer.author': '作者'
@@ -347,6 +495,16 @@ const i18n = {
'common.required': 'Required', 'common.required': 'Required',
'common.api_key': 'Key', 'common.api_key': 'Key',
'common.base_url': 'Address', 'common.base_url': 'Address',
'common.proxy_url': 'Proxy',
'common.alias': 'Alias',
'common.failure': 'Failure',
'common.unknown_error': 'Unknown error',
'common.copy': 'Copy',
'common.custom_headers_label': 'Custom Headers',
'common.custom_headers_hint': 'Optional HTTP headers to send with the request. Leave blank to remove.',
'common.custom_headers_add': 'Add Header',
'common.custom_headers_key_placeholder': 'Header name, e.g. X-Custom-Header',
'common.custom_headers_value_placeholder': 'Header value',
// Page titles // Page titles
'title.main': 'CLI Proxy API Management Center', 'title.main': 'CLI Proxy API Management Center',
@@ -391,6 +549,8 @@ const i18n = {
'nav.ai_providers': 'AI Providers', 'nav.ai_providers': 'AI Providers',
'nav.auth_files': 'Auth Files', 'nav.auth_files': 'Auth Files',
'nav.usage_stats': 'Usage Statistics', 'nav.usage_stats': 'Usage Statistics',
'nav.config_management': 'Config Management',
'nav.logs': 'Logs Viewer',
'nav.system_info': 'System Info', 'nav.system_info': 'System Info',
// Basic settings // Basic settings
@@ -408,6 +568,10 @@ const i18n = {
'basic_settings.quota_title': 'Quota Exceeded Behavior', 'basic_settings.quota_title': 'Quota Exceeded Behavior',
'basic_settings.quota_switch_project': 'Auto Switch Project', 'basic_settings.quota_switch_project': 'Auto Switch Project',
'basic_settings.quota_switch_preview': 'Switch to Preview Model', 'basic_settings.quota_switch_preview': 'Switch to Preview Model',
'basic_settings.usage_statistics_title': 'Usage Statistics',
'basic_settings.usage_statistics_enable': 'Enable usage statistics',
'basic_settings.logging_title': 'Logging',
'basic_settings.logging_to_file_enable': 'Enable logging to file',
// API Keys management // API Keys management
'api_keys.title': 'API Keys Management', 'api_keys.title': 'API Keys Management',
@@ -431,10 +595,14 @@ const i18n = {
'ai_providers.gemini_empty_desc': 'Click the button above to add the first key', 'ai_providers.gemini_empty_desc': 'Click the button above to add the first key',
'ai_providers.gemini_item_title': 'Gemini Key', 'ai_providers.gemini_item_title': 'Gemini Key',
'ai_providers.gemini_add_modal_title': 'Add Gemini API Key', 'ai_providers.gemini_add_modal_title': 'Add Gemini API Key',
'ai_providers.gemini_add_modal_key_label': 'API Key:', 'ai_providers.gemini_add_modal_key_label': 'API Keys:',
'ai_providers.gemini_add_modal_key_placeholder': 'Please enter Gemini API key', 'ai_providers.gemini_add_modal_key_placeholder': 'Enter Gemini API keys (one per line)',
'ai_providers.gemini_add_modal_key_hint': 'You can paste multiple keys, one per line.',
'ai_providers.gemini_add_modal_url_label': 'Base URL (optional):',
'ai_providers.gemini_add_modal_url_placeholder': 'e.g. https://generativelanguage.googleapis.com',
'ai_providers.gemini_edit_modal_title': 'Edit Gemini API Key', 'ai_providers.gemini_edit_modal_title': 'Edit Gemini API Key',
'ai_providers.gemini_edit_modal_key_label': 'API Key:', 'ai_providers.gemini_edit_modal_key_label': 'API Key:',
'ai_providers.gemini_edit_modal_url_label': 'Base URL (optional):',
'ai_providers.gemini_delete_confirm': 'Are you sure you want to delete this Gemini key?', 'ai_providers.gemini_delete_confirm': 'Are you sure you want to delete this Gemini key?',
'ai_providers.codex_title': 'Codex API Configuration', 'ai_providers.codex_title': 'Codex API Configuration',
@@ -445,11 +613,14 @@ const i18n = {
'ai_providers.codex_add_modal_title': 'Add Codex API Configuration', 'ai_providers.codex_add_modal_title': 'Add Codex API Configuration',
'ai_providers.codex_add_modal_key_label': 'API Key:', 'ai_providers.codex_add_modal_key_label': 'API Key:',
'ai_providers.codex_add_modal_key_placeholder': 'Please enter Codex API key', 'ai_providers.codex_add_modal_key_placeholder': 'Please enter Codex API key',
'ai_providers.codex_add_modal_url_label': 'Base URL (Optional):', 'ai_providers.codex_add_modal_url_label': 'Base URL (Required):',
'ai_providers.codex_add_modal_url_placeholder': 'e.g.: https://api.example.com', 'ai_providers.codex_add_modal_url_placeholder': 'e.g.: https://api.example.com',
'ai_providers.codex_add_modal_proxy_label': 'Proxy URL (Optional):',
'ai_providers.codex_add_modal_proxy_placeholder': 'e.g.: socks5://proxy.example.com:1080',
'ai_providers.codex_edit_modal_title': 'Edit Codex API Configuration', 'ai_providers.codex_edit_modal_title': 'Edit Codex API Configuration',
'ai_providers.codex_edit_modal_key_label': 'API Key:', 'ai_providers.codex_edit_modal_key_label': 'API Key:',
'ai_providers.codex_edit_modal_url_label': 'Base URL (Optional):', 'ai_providers.codex_edit_modal_url_label': 'Base URL (Required):',
'ai_providers.codex_edit_modal_proxy_label': 'Proxy URL (Optional):',
'ai_providers.codex_delete_confirm': 'Are you sure you want to delete this Codex configuration?', 'ai_providers.codex_delete_confirm': 'Are you sure you want to delete this Codex configuration?',
'ai_providers.claude_title': 'Claude API Configuration', 'ai_providers.claude_title': 'Claude API Configuration',
@@ -462,9 +633,12 @@ const i18n = {
'ai_providers.claude_add_modal_key_placeholder': 'Please enter Claude API key', 'ai_providers.claude_add_modal_key_placeholder': 'Please enter Claude API key',
'ai_providers.claude_add_modal_url_label': 'Base URL (Optional):', 'ai_providers.claude_add_modal_url_label': 'Base URL (Optional):',
'ai_providers.claude_add_modal_url_placeholder': 'e.g.: https://api.anthropic.com', 'ai_providers.claude_add_modal_url_placeholder': 'e.g.: https://api.anthropic.com',
'ai_providers.claude_add_modal_proxy_label': 'Proxy URL (Optional):',
'ai_providers.claude_add_modal_proxy_placeholder': 'e.g.: socks5://proxy.example.com:1080',
'ai_providers.claude_edit_modal_title': 'Edit Claude API Configuration', 'ai_providers.claude_edit_modal_title': 'Edit Claude API Configuration',
'ai_providers.claude_edit_modal_key_label': 'API Key:', 'ai_providers.claude_edit_modal_key_label': 'API Key:',
'ai_providers.claude_edit_modal_url_label': 'Base URL (Optional):', 'ai_providers.claude_edit_modal_url_label': 'Base URL (Optional):',
'ai_providers.claude_edit_modal_proxy_label': 'Proxy URL (Optional):',
'ai_providers.claude_delete_confirm': 'Are you sure you want to delete this Claude configuration?', 'ai_providers.claude_delete_confirm': 'Are you sure you want to delete this Claude configuration?',
'ai_providers.openai_title': 'OpenAI Compatible Providers', 'ai_providers.openai_title': 'OpenAI Compatible Providers',
@@ -478,10 +652,19 @@ const i18n = {
'ai_providers.openai_add_modal_url_placeholder': 'e.g.: https://openrouter.ai/api/v1', 'ai_providers.openai_add_modal_url_placeholder': 'e.g.: https://openrouter.ai/api/v1',
'ai_providers.openai_add_modal_keys_label': 'API Keys (one per line):', 'ai_providers.openai_add_modal_keys_label': 'API Keys (one per line):',
'ai_providers.openai_add_modal_keys_placeholder': 'sk-key1\nsk-key2', 'ai_providers.openai_add_modal_keys_placeholder': 'sk-key1\nsk-key2',
'ai_providers.openai_add_modal_keys_proxy_label': 'Proxy URL (one per line, optional):',
'ai_providers.openai_add_modal_keys_proxy_placeholder': 'socks5://proxy.example.com:1080\n',
'ai_providers.openai_add_modal_models_label': 'Model List (name[, alias] one per line):',
'ai_providers.openai_models_hint': 'Example: gpt-4o-mini or moonshotai/kimi-k2:free, kimi-k2',
'ai_providers.openai_model_name_placeholder': 'Model name, e.g. moonshotai/kimi-k2:free',
'ai_providers.openai_model_alias_placeholder': 'Model alias (optional)',
'ai_providers.openai_models_add_btn': 'Add Model',
'ai_providers.openai_edit_modal_title': 'Edit OpenAI Compatible Provider', 'ai_providers.openai_edit_modal_title': 'Edit OpenAI Compatible Provider',
'ai_providers.openai_edit_modal_name_label': 'Provider Name:', 'ai_providers.openai_edit_modal_name_label': 'Provider Name:',
'ai_providers.openai_edit_modal_url_label': 'Base URL:', 'ai_providers.openai_edit_modal_url_label': 'Base URL:',
'ai_providers.openai_edit_modal_keys_label': 'API Keys (one per line):', 'ai_providers.openai_edit_modal_keys_label': 'API Keys (one per line):',
'ai_providers.openai_edit_modal_keys_proxy_label': 'Proxy URL (one per line, optional):',
'ai_providers.openai_edit_modal_models_label': 'Model List (name[, alias] one per line):',
'ai_providers.openai_delete_confirm': 'Are you sure you want to delete this OpenAI provider?', 'ai_providers.openai_delete_confirm': 'Are you sure you want to delete this OpenAI provider?',
'ai_providers.openai_keys_count': 'Keys Count', 'ai_providers.openai_keys_count': 'Keys Count',
'ai_providers.openai_models_count': 'Models Count', 'ai_providers.openai_models_count': 'Models Count',
@@ -507,18 +690,94 @@ const i18n = {
'auth_files.delete_success': 'File deleted successfully', 'auth_files.delete_success': 'File deleted successfully',
'auth_files.delete_all_success': 'Successfully deleted', 'auth_files.delete_all_success': 'Successfully deleted',
'auth_files.files_count': 'files', 'auth_files.files_count': 'files',
'auth_files.filter_all': 'All',
'auth_files.filter_qwen': 'Qwen',
'auth_files.filter_gemini': 'Gemini',
'auth_files.filter_gemini-cli': 'GeminiCLI',
'auth_files.filter_aistudio': 'AIStudio',
'auth_files.filter_claude': 'Claude',
'auth_files.filter_codex': 'Codex',
'auth_files.filter_iflow': 'iFlow',
'auth_files.filter_empty': 'Empty',
'auth_files.filter_unknown': 'Other',
'auth_files.type_qwen': 'Qwen',
'auth_files.type_gemini': 'Gemini',
'auth_files.type_gemini-cli': 'GeminiCLI',
'auth_files.type_aistudio': 'AIStudio',
'auth_files.type_claude': 'Claude',
'auth_files.type_codex': 'Codex',
'auth_files.type_iflow': 'iFlow',
'auth_files.type_empty': 'Empty',
'auth_files.type_unknown': 'Other',
// Gemini Web Token // Codex OAuth
'auth_login.gemini_web_title': 'Gemini Web Token', 'auth_login.codex_oauth_title': 'Codex OAuth',
'auth_login.gemini_web_button': 'Save Gemini Web Token', 'auth_login.codex_oauth_button': 'Start Codex Login',
'auth_login.gemini_web_hint': 'Obtain the Cookie value of the Gemini web version from the browser\'s developer tools, used for direct authentication to access Gemini.', 'auth_login.codex_oauth_hint': 'Login to Codex service through OAuth flow, automatically obtain and save authentication files.',
'auth_login.secure_1psid_label': '__Secure-1PSID Cookie:', 'auth_login.codex_oauth_url_label': 'Authorization URL:',
'auth_login.secure_1psid_placeholder': 'Enter __Secure-1PSID cookie value', 'auth_login.codex_open_link': 'Open Link',
'auth_login.secure_1psidts_label': '__Secure-1PSIDTS Cookie:', 'auth_login.codex_copy_link': 'Copy Link',
'auth_login.secure_1psidts_placeholder': 'Enter __Secure-1PSIDTS cookie value', 'auth_login.codex_oauth_status_waiting': 'Waiting for authentication...',
'auth_login.gemini_web_label_label': 'Label (Optional):', 'auth_login.codex_oauth_status_success': 'Authentication successful!',
'auth_login.gemini_web_label_placeholder': 'Enter label name (optional)', 'auth_login.codex_oauth_status_error': 'Authentication failed:',
'auth_login.gemini_web_saved': 'Gemini Web Token saved successfully', 'auth_login.codex_oauth_start_error': 'Failed to start Codex OAuth:',
'auth_login.codex_oauth_polling_error': 'Failed to check authentication status:',
// Anthropic OAuth
'auth_login.anthropic_oauth_title': 'Anthropic OAuth',
'auth_login.anthropic_oauth_button': 'Start Anthropic Login',
'auth_login.anthropic_oauth_hint': 'Login to Anthropic (Claude) service through OAuth flow, automatically obtain and save authentication files.',
'auth_login.anthropic_oauth_url_label': 'Authorization URL:',
'auth_login.anthropic_open_link': 'Open Link',
'auth_login.anthropic_copy_link': 'Copy Link',
'auth_login.anthropic_oauth_status_waiting': 'Waiting for authentication...',
'auth_login.anthropic_oauth_status_success': 'Authentication successful!',
'auth_login.anthropic_oauth_status_error': 'Authentication failed:',
'auth_login.anthropic_oauth_start_error': 'Failed to start Anthropic OAuth:',
'auth_login.anthropic_oauth_polling_error': 'Failed to check authentication status:',
// Gemini CLI OAuth
'auth_login.gemini_cli_oauth_title': 'Gemini CLI OAuth',
'auth_login.gemini_cli_oauth_button': 'Start Gemini CLI Login',
'auth_login.gemini_cli_oauth_hint': 'Login to Google Gemini CLI service through OAuth flow, automatically obtain and save authentication files.',
'auth_login.gemini_cli_project_id_label': 'Google Cloud Project ID (Optional):',
'auth_login.gemini_cli_project_id_placeholder': 'Enter Google Cloud Project ID (optional)',
'auth_login.gemini_cli_project_id_hint': 'If a project ID is specified, authentication information for that project will be used.',
'auth_login.gemini_cli_oauth_url_label': 'Authorization URL:',
'auth_login.gemini_cli_open_link': 'Open Link',
'auth_login.gemini_cli_copy_link': 'Copy Link',
'auth_login.gemini_cli_oauth_status_waiting': 'Waiting for authentication...',
'auth_login.gemini_cli_oauth_status_success': 'Authentication successful!',
'auth_login.gemini_cli_oauth_status_error': 'Authentication failed:',
'auth_login.gemini_cli_oauth_start_error': 'Failed to start Gemini CLI OAuth:',
'auth_login.gemini_cli_oauth_polling_error': 'Failed to check authentication status:',
// Qwen OAuth
'auth_login.qwen_oauth_title': 'Qwen OAuth',
'auth_login.qwen_oauth_button': 'Start Qwen Login',
'auth_login.qwen_oauth_hint': 'Login to Qwen service through device authorization flow, automatically obtain and save authentication files.',
'auth_login.qwen_oauth_url_label': 'Authorization URL:',
'auth_login.qwen_open_link': 'Open Link',
'auth_login.qwen_copy_link': 'Copy Link',
'auth_login.qwen_oauth_status_waiting': 'Waiting for authentication...',
'auth_login.qwen_oauth_status_success': 'Authentication successful!',
'auth_login.qwen_oauth_status_error': 'Authentication failed:',
'auth_login.qwen_oauth_start_error': 'Failed to start Qwen OAuth:',
'auth_login.qwen_oauth_polling_error': 'Failed to check authentication status:',
'auth_login.missing_state': 'Unable to retrieve authentication state parameter',
// iFlow OAuth
'auth_login.iflow_oauth_title': 'iFlow OAuth',
'auth_login.iflow_oauth_button': 'Start iFlow Login',
'auth_login.iflow_oauth_hint': 'Login to iFlow service through OAuth flow, automatically obtain and save authentication files.',
'auth_login.iflow_oauth_url_label': 'Authorization URL:',
'auth_login.iflow_open_link': 'Open Link',
'auth_login.iflow_copy_link': 'Copy Link',
'auth_login.iflow_oauth_status_waiting': 'Waiting for authentication...',
'auth_login.iflow_oauth_status_success': 'Authentication successful!',
'auth_login.iflow_oauth_status_error': 'Authentication failed:',
'auth_login.iflow_oauth_start_error': 'Failed to start iFlow OAuth:',
'auth_login.iflow_oauth_polling_error': 'Failed to check authentication status:',
// Usage Statistics // Usage Statistics
'usage_stats.title': 'Usage Statistics', 'usage_stats.title': 'Usage Statistics',
@@ -539,6 +798,48 @@ const i18n = {
'usage_stats.tokens_count': 'Token Count', 'usage_stats.tokens_count': 'Token Count',
'usage_stats.models': 'Model Statistics', 'usage_stats.models': 'Model Statistics',
'usage_stats.success_rate': 'Success Rate', 'usage_stats.success_rate': 'Success Rate',
'stats.success': 'Success',
'stats.failure': 'Failure',
// Logs viewer
'logs.title': 'Logs Viewer',
'logs.refresh_button': 'Refresh Logs',
'logs.clear_button': 'Clear Logs',
'logs.download_button': 'Download Logs',
'logs.empty_title': 'No Logs Available',
'logs.empty_desc': 'When "Enable logging to file" is enabled, logs will be displayed here',
'logs.log_content': 'Log Content',
'logs.loading': 'Loading logs...',
'logs.load_error': 'Failed to load logs',
'logs.clear_confirm': 'Are you sure you want to clear all logs? This action cannot be undone!',
'logs.clear_success': 'Logs cleared successfully',
'logs.download_success': 'Logs downloaded successfully',
'logs.auto_refresh': 'Auto Refresh',
'logs.auto_refresh_enabled': 'Auto refresh enabled',
'logs.auto_refresh_disabled': 'Auto refresh disabled',
'logs.lines': 'lines',
'logs.removed': 'Removed',
'logs.upgrade_required_title': 'Please Upgrade CLI Proxy API',
'logs.upgrade_required_desc': 'The current server version does not support the logs viewing feature. Please upgrade to the latest version of CLI Proxy API to use this feature.',
// Config management
'config_management.title': 'Config Management',
'config_management.editor_title': 'Configuration File',
'config_management.reload': 'Reload',
'config_management.save': 'Save',
'config_management.description': 'View and edit the server-side config.yaml file. Validate the syntax before saving.',
'config_management.status_idle': 'Waiting for action',
'config_management.status_loading': 'Loading configuration...',
'config_management.status_loaded': 'Configuration loaded',
'config_management.status_dirty': 'Unsaved changes',
'config_management.status_disconnected': 'Connect to the server to load the configuration',
'config_management.status_load_failed': 'Load failed',
'config_management.status_saving': 'Saving configuration...',
'config_management.status_saved': 'Configuration saved',
'config_management.status_save_failed': 'Save failed',
'config_management.save_success': 'Configuration saved successfully',
'config_management.error_yaml_not_supported': 'Server did not return YAML. Verify the /config.yaml endpoint is available.',
'config_management.editor_placeholder': 'key: value',
// System info // System info
'system_info.title': 'System Information', 'system_info.title': 'System Information',
@@ -558,18 +859,26 @@ const i18n = {
'notification.retry_updated': 'Retry settings updated', 'notification.retry_updated': 'Retry settings updated',
'notification.quota_switch_project_updated': 'Project switch settings updated', 'notification.quota_switch_project_updated': 'Project switch settings updated',
'notification.quota_switch_preview_updated': 'Preview model switch settings updated', 'notification.quota_switch_preview_updated': 'Preview model switch settings updated',
'notification.usage_statistics_updated': 'Usage statistics settings updated',
'notification.logging_to_file_updated': 'Logging settings updated',
'notification.api_key_added': 'API key added successfully', 'notification.api_key_added': 'API key added successfully',
'notification.api_key_updated': 'API key updated successfully', 'notification.api_key_updated': 'API key updated successfully',
'notification.api_key_deleted': 'API key deleted successfully', 'notification.api_key_deleted': 'API key deleted successfully',
'notification.gemini_key_added': 'Gemini key added successfully', 'notification.gemini_key_added': 'Gemini key added successfully',
'notification.gemini_key_updated': 'Gemini key updated successfully', 'notification.gemini_key_updated': 'Gemini key updated successfully',
'notification.gemini_key_deleted': 'Gemini key deleted successfully', 'notification.gemini_key_deleted': 'Gemini key deleted successfully',
'notification.gemini_multi_input_required': 'Please enter at least one Gemini key',
'notification.gemini_multi_failed': 'Gemini bulk add failed',
'notification.gemini_multi_summary': 'Gemini bulk add finished: {success} added, {skipped} skipped, {failed} failed',
'notification.codex_config_added': 'Codex configuration added successfully', 'notification.codex_config_added': 'Codex configuration added successfully',
'notification.codex_config_updated': 'Codex configuration updated successfully', 'notification.codex_config_updated': 'Codex configuration updated successfully',
'notification.codex_config_deleted': 'Codex configuration deleted successfully', 'notification.codex_config_deleted': 'Codex configuration deleted successfully',
'notification.codex_base_url_required': 'Please enter the Codex Base URL',
'notification.claude_config_added': 'Claude configuration added successfully', 'notification.claude_config_added': 'Claude configuration added successfully',
'notification.claude_config_updated': 'Claude configuration updated successfully', 'notification.claude_config_updated': 'Claude configuration updated successfully',
'notification.claude_config_deleted': 'Claude configuration deleted successfully', 'notification.claude_config_deleted': 'Claude configuration deleted successfully',
'notification.field_required': 'Required fields cannot be empty',
'notification.openai_provider_required': 'Please fill in provider name and Base URL',
'notification.openai_provider_added': 'OpenAI provider added successfully', 'notification.openai_provider_added': 'OpenAI provider added successfully',
'notification.openai_provider_updated': 'OpenAI provider updated successfully', 'notification.openai_provider_updated': 'OpenAI provider updated successfully',
'notification.openai_provider_deleted': 'OpenAI provider deleted successfully', 'notification.openai_provider_deleted': 'OpenAI provider deleted successfully',
@@ -590,6 +899,7 @@ const i18n = {
'notification.gemini_api_key': 'Gemini API key', 'notification.gemini_api_key': 'Gemini API key',
'notification.codex_api_key': 'Codex API key', 'notification.codex_api_key': 'Codex API key',
'notification.claude_api_key': 'Claude API key', 'notification.claude_api_key': 'Claude API key',
'notification.link_copied': 'Link copied to clipboard',
// Language switch // Language switch
'language.switch': 'Language', 'language.switch': 'Language',
@@ -604,6 +914,10 @@ const i18n = {
'theme.switch_to_dark': 'Switch to dark mode', 'theme.switch_to_dark': 'Switch to dark mode',
'theme.auto': 'Follow system', 'theme.auto': 'Follow system',
// Sidebar
'sidebar.toggle_expand': 'Expand sidebar',
'sidebar.toggle_collapse': 'Collapse sidebar',
// Footer // Footer
'footer.version': 'Version', 'footer.version': 'Version',
'footer.author': 'Author' 'footer.author': 'Author'
@@ -613,8 +927,8 @@ const i18n = {
// 获取翻译文本 // 获取翻译文本
t(key, params = {}) { t(key, params = {}) {
const translation = this.translations[this.currentLanguage]?.[key] || const translation = this.translations[this.currentLanguage]?.[key] ||
this.translations[this.fallbackLanguage]?.[key] || this.translations[this.fallbackLanguage]?.[key] ||
key; key;
// 简单的参数替换 // 简单的参数替换
return translation.replace(/\{(\w+)\}/g, (match, param) => { return translation.replace(/\{(\w+)\}/g, (match, param) => {
@@ -653,6 +967,30 @@ const i18n = {
} }
}); });
// 更新所有包含 data-i18n-placeholder 的输入框占位符
document.querySelectorAll('[data-i18n-placeholder]').forEach(element => {
const key = element.getAttribute('data-i18n-placeholder');
element.placeholder = this.t(key);
});
// 更新 data-i18n-title
document.querySelectorAll('[data-i18n-title]').forEach(element => {
const key = element.getAttribute('data-i18n-title');
element.title = this.t(key);
});
// 更新 data-i18n-tooltip
document.querySelectorAll('[data-i18n-tooltip]').forEach(element => {
const key = element.getAttribute('data-i18n-tooltip');
element.setAttribute('data-tooltip', this.t(key));
});
// 更新 data-i18n-text常用于按钮或标签
document.querySelectorAll('[data-i18n-text]').forEach(element => {
const key = element.getAttribute('data-i18n-text');
element.textContent = this.t(key);
});
// 更新所有带有 data-i18n-html 属性的元素支持HTML // 更新所有带有 data-i18n-html 属性的元素支持HTML
document.querySelectorAll('[data-i18n-html]').forEach(element => { document.querySelectorAll('[data-i18n-html]').forEach(element => {
const key = element.getAttribute('data-i18n-html'); const key = element.getAttribute('data-i18n-html');

1141
index.html

File diff suppressed because it is too large Load Diff

View File

@@ -26,6 +26,5 @@
"repository": { "repository": {
"type": "git", "type": "git",
"url": "local" "url": "local"
}, }
"dependencies": {}
} }

1777
styles.css

File diff suppressed because it is too large Load Diff