Compare commits

...

20 Commits

Author SHA1 Message Date
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
9 changed files with 4709 additions and 1609 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 使用情况

2006
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>

320
i18n.js
View File

@@ -38,6 +38,8 @@ const i18n = {
'common.base_url': '地址', 'common.base_url': '地址',
'common.proxy_url': '代理', 'common.proxy_url': '代理',
'common.alias': '别名', 'common.alias': '别名',
'common.failure': '失败',
'common.unknown_error': '未知错误',
// 页面标题 // 页面标题
'title.main': 'CLI Proxy API Management Center', 'title.main': 'CLI Proxy API Management Center',
@@ -82,6 +84,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 +103,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 密钥管理',
@@ -214,17 +222,75 @@ const i18n = {
'auth_files.delete_all_success': '成功删除', 'auth_files.delete_all_success': '成功删除',
'auth_files.files_count': '个文件', 'auth_files.files_count': '个文件',
// 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 +311,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,6 +372,8 @@ 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密钥删除成功',
@@ -298,6 +408,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 +423,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 +462,10 @@ 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',
// Page titles // Page titles
'title.main': 'CLI Proxy API Management Center', 'title.main': 'CLI Proxy API Management Center',
@@ -391,6 +510,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 +529,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',
@@ -447,9 +572,12 @@ const i18n = {
'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 (Optional):',
'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 (Optional):',
'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 +590,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 +609,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',
@@ -508,17 +648,74 @@ const i18n = {
'auth_files.delete_all_success': 'Successfully deleted', 'auth_files.delete_all_success': 'Successfully deleted',
'auth_files.files_count': 'files', 'auth_files.files_count': 'files',
// 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 +736,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,6 +797,8 @@ 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',
@@ -570,6 +811,8 @@ const i18n = {
'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 +833,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 +848,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 +861,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 +901,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');

1127
index.html

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff