mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-02-02 19:00:49 +08:00
更新补全i18n国际化文本
This commit is contained in:
142
app.js
142
app.js
@@ -182,12 +182,12 @@ class CLIProxyManager {
|
||||
// 如果有完整的连接信息且之前已登录,尝试自动登录
|
||||
if (savedBase && savedKey && wasLoggedIn) {
|
||||
try {
|
||||
console.log('检测到本地连接数据,尝试自动登录...');
|
||||
console.log(i18n.t('auto_login.title'));
|
||||
this.showAutoLoginLoading();
|
||||
await this.attemptAutoLogin(savedBase, savedKey);
|
||||
return; // 自动登录成功,不显示登录页面
|
||||
} catch (error) {
|
||||
console.log('自动登录失败:', error.message);
|
||||
console.log(`${i18n.t('notification.login_failed')}: ${error.message}`);
|
||||
// 清除无效的登录状态
|
||||
localStorage.removeItem('isLoggedIn');
|
||||
this.hideAutoLoginLoading();
|
||||
@@ -232,7 +232,7 @@ class CLIProxyManager {
|
||||
this.hideAutoLoginLoading();
|
||||
this.showMainPage();
|
||||
|
||||
console.log('自动登录成功');
|
||||
console.log(i18n.t('auto_login.title'));
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('自动登录失败:', error);
|
||||
@@ -807,7 +807,8 @@ class CLIProxyManager {
|
||||
// 更新按钮提示文本
|
||||
const toggleBtn = document.getElementById('sidebar-toggle-btn-desktop');
|
||||
if (toggleBtn) {
|
||||
toggleBtn.setAttribute('title', isCollapsed ? '展开侧边栏' : '收起侧边栏');
|
||||
toggleBtn.setAttribute('data-i18n-title', isCollapsed ? 'sidebar.toggle_expand' : 'sidebar.toggle_collapse');
|
||||
toggleBtn.title = i18n.t(isCollapsed ? 'sidebar.toggle_expand' : 'sidebar.toggle_collapse');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -828,7 +829,8 @@ class CLIProxyManager {
|
||||
// 更新按钮提示文本
|
||||
const toggleBtn = document.getElementById('sidebar-toggle-btn-desktop');
|
||||
if (toggleBtn) {
|
||||
toggleBtn.setAttribute('title', '展开侧边栏');
|
||||
toggleBtn.setAttribute('data-i18n-title', 'sidebar.toggle_expand');
|
||||
toggleBtn.title = i18n.t('sidebar.toggle_expand');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1420,7 +1422,7 @@ class CLIProxyManager {
|
||||
// 加载所有数据 - 使用新的 /config 端点一次性获取所有配置
|
||||
async loadAllData(forceRefresh = false) {
|
||||
try {
|
||||
console.log('使用新的 /config 端点加载所有配置...');
|
||||
console.log(i18n.t('system_info.real_time_data'));
|
||||
// 使用新的 /config 端点一次性获取所有配置
|
||||
const config = await this.getConfig(forceRefresh);
|
||||
|
||||
@@ -2213,10 +2215,10 @@ class CLIProxyManager {
|
||||
<div class="item-value">${this.maskApiKey(key)}</div>
|
||||
<div class="item-stats">
|
||||
<span class="stat-badge stat-success">
|
||||
<i class="fas fa-check-circle"></i> 成功: ${keyStats.success}
|
||||
<i class="fas fa-check-circle"></i> ${i18n.t('stats.success')}: ${keyStats.success}
|
||||
</span>
|
||||
<span class="stat-badge stat-failure">
|
||||
<i class="fas fa-times-circle"></i> 失败: ${keyStats.failure}
|
||||
<i class="fas fa-times-circle"></i> ${i18n.t('stats.failure')}: ${keyStats.failure}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2238,14 +2240,14 @@ class CLIProxyManager {
|
||||
const modalBody = document.getElementById('modal-body');
|
||||
|
||||
modalBody.innerHTML = `
|
||||
<h3>添加Gemini API密钥</h3>
|
||||
<h3>${i18n.t('ai_providers.gemini_add_modal_title')}</h3>
|
||||
<div class="form-group">
|
||||
<label for="new-gemini-key">API密钥:</label>
|
||||
<input type="text" id="new-gemini-key" placeholder="请输入Gemini API密钥">
|
||||
<label for="new-gemini-key">${i18n.t('ai_providers.gemini_add_modal_key_label')}</label>
|
||||
<input type="text" id="new-gemini-key" placeholder="${i18n.t('ai_providers.gemini_add_modal_key_placeholder')}">
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="btn btn-secondary" onclick="manager.closeModal()">取消</button>
|
||||
<button class="btn btn-primary" onclick="manager.addGeminiKey()">添加</button>
|
||||
<button class="btn btn-secondary" onclick="manager.closeModal()">${i18n.t('common.cancel')}</button>
|
||||
<button class="btn btn-primary" onclick="manager.addGeminiKey()">${i18n.t('common.add')}</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -2257,7 +2259,7 @@ class CLIProxyManager {
|
||||
const newKey = document.getElementById('new-gemini-key').value.trim();
|
||||
|
||||
if (!newKey) {
|
||||
this.showNotification('请输入Gemini API密钥', 'error');
|
||||
this.showNotification(i18n.t('notification.please_enter') + ' ' + i18n.t('notification.gemini_api_key'), 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2274,9 +2276,9 @@ class CLIProxyManager {
|
||||
this.clearCache(); // 清除缓存
|
||||
this.closeModal();
|
||||
this.loadGeminiKeys();
|
||||
this.showNotification('Gemini密钥添加成功', 'success');
|
||||
this.showNotification(i18n.t('notification.gemini_key_added'), 'success');
|
||||
} catch (error) {
|
||||
this.showNotification(`添加Gemini密钥失败: ${error.message}`, 'error');
|
||||
this.showNotification(`${i18n.t('notification.add_failed')}: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2286,14 +2288,14 @@ class CLIProxyManager {
|
||||
const modalBody = document.getElementById('modal-body');
|
||||
|
||||
modalBody.innerHTML = `
|
||||
<h3>编辑Gemini API密钥</h3>
|
||||
<h3>${i18n.t('ai_providers.gemini_edit_modal_title')}</h3>
|
||||
<div class="form-group">
|
||||
<label for="edit-gemini-key">API密钥:</label>
|
||||
<label for="edit-gemini-key">${i18n.t('ai_providers.gemini_edit_modal_key_label')}</label>
|
||||
<input type="text" id="edit-gemini-key" value="${currentKey}">
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button class="btn btn-secondary" onclick="manager.closeModal()">取消</button>
|
||||
<button class="btn btn-primary" onclick="manager.updateGeminiKey('${currentKey}')">更新</button>
|
||||
<button class="btn btn-secondary" onclick="manager.closeModal()">${i18n.t('common.cancel')}</button>
|
||||
<button class="btn btn-primary" onclick="manager.updateGeminiKey('${currentKey}')">${i18n.t('common.update')}</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -2305,7 +2307,7 @@ class CLIProxyManager {
|
||||
const newKey = document.getElementById('edit-gemini-key').value.trim();
|
||||
|
||||
if (!newKey) {
|
||||
this.showNotification('请输入Gemini API密钥', 'error');
|
||||
this.showNotification(i18n.t('notification.please_enter') + ' ' + i18n.t('notification.gemini_api_key'), 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2318,9 +2320,9 @@ class CLIProxyManager {
|
||||
this.clearCache(); // 清除缓存
|
||||
this.closeModal();
|
||||
this.loadGeminiKeys();
|
||||
this.showNotification('Gemini密钥更新成功', 'success');
|
||||
this.showNotification(i18n.t('notification.gemini_key_updated'), 'success');
|
||||
} catch (error) {
|
||||
this.showNotification(`更新Gemini密钥失败: ${error.message}`, 'error');
|
||||
this.showNotification(`${i18n.t('notification.update_failed')}: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2332,9 +2334,9 @@ class CLIProxyManager {
|
||||
await this.makeRequest(`/generative-language-api-key?value=${encodeURIComponent(key)}`, { method: 'DELETE' });
|
||||
this.clearCache(); // 清除缓存
|
||||
this.loadGeminiKeys();
|
||||
this.showNotification('Gemini密钥删除成功', 'success');
|
||||
this.showNotification(i18n.t('notification.gemini_key_deleted'), 'success');
|
||||
} catch (error) {
|
||||
this.showNotification(`删除Gemini密钥失败: ${error.message}`, 'error');
|
||||
this.showNotification(`${i18n.t('notification.delete_failed')}: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2381,10 +2383,10 @@ class CLIProxyManager {
|
||||
${config['proxy-url'] ? `<div class="item-subtitle">${i18n.t('common.proxy_url')}: ${this.escapeHtml(config['proxy-url'])}</div>` : ''}
|
||||
<div class="item-stats">
|
||||
<span class="stat-badge stat-success">
|
||||
<i class="fas fa-check-circle"></i> 成功: ${keyStats.success}
|
||||
<i class="fas fa-check-circle"></i> ${i18n.t('stats.success')}: ${keyStats.success}
|
||||
</span>
|
||||
<span class="stat-badge stat-failure">
|
||||
<i class="fas fa-times-circle"></i> 失败: ${keyStats.failure}
|
||||
<i class="fas fa-times-circle"></i> ${i18n.t('stats.failure')}: ${keyStats.failure}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2461,9 +2463,9 @@ class CLIProxyManager {
|
||||
this.clearCache(); // 清除缓存
|
||||
this.closeModal();
|
||||
this.loadCodexKeys();
|
||||
this.showNotification('Codex配置添加成功', 'success');
|
||||
this.showNotification(i18n.t('notification.codex_config_added'), 'success');
|
||||
} catch (error) {
|
||||
this.showNotification(`添加Codex配置失败: ${error.message}`, 'error');
|
||||
this.showNotification(`${i18n.t('notification.add_failed')}: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2523,9 +2525,9 @@ class CLIProxyManager {
|
||||
this.clearCache(); // 清除缓存
|
||||
this.closeModal();
|
||||
this.loadCodexKeys();
|
||||
this.showNotification('Codex配置更新成功', 'success');
|
||||
this.showNotification(i18n.t('notification.codex_config_updated'), 'success');
|
||||
} catch (error) {
|
||||
this.showNotification(`更新Codex配置失败: ${error.message}`, 'error');
|
||||
this.showNotification(`${i18n.t('notification.update_failed')}: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2537,9 +2539,9 @@ class CLIProxyManager {
|
||||
await this.makeRequest(`/codex-api-key?api-key=${encodeURIComponent(apiKey)}`, { method: 'DELETE' });
|
||||
this.clearCache(); // 清除缓存
|
||||
this.loadCodexKeys();
|
||||
this.showNotification('Codex配置删除成功', 'success');
|
||||
this.showNotification(i18n.t('notification.codex_config_deleted'), 'success');
|
||||
} catch (error) {
|
||||
this.showNotification(`删除Codex配置失败: ${error.message}`, 'error');
|
||||
this.showNotification(`${i18n.t('notification.delete_failed')}: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2586,10 +2588,10 @@ class CLIProxyManager {
|
||||
${config['proxy-url'] ? `<div class="item-subtitle">${i18n.t('common.proxy_url')}: ${this.escapeHtml(config['proxy-url'])}</div>` : ''}
|
||||
<div class="item-stats">
|
||||
<span class="stat-badge stat-success">
|
||||
<i class="fas fa-check-circle"></i> 成功: ${keyStats.success}
|
||||
<i class="fas fa-check-circle"></i> ${i18n.t('stats.success')}: ${keyStats.success}
|
||||
</span>
|
||||
<span class="stat-badge stat-failure">
|
||||
<i class="fas fa-times-circle"></i> 失败: ${keyStats.failure}
|
||||
<i class="fas fa-times-circle"></i> ${i18n.t('stats.failure')}: ${keyStats.failure}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2666,9 +2668,9 @@ class CLIProxyManager {
|
||||
this.clearCache(); // 清除缓存
|
||||
this.closeModal();
|
||||
this.loadClaudeKeys();
|
||||
this.showNotification('Claude配置添加成功', 'success');
|
||||
this.showNotification(i18n.t('notification.claude_config_added'), 'success');
|
||||
} catch (error) {
|
||||
this.showNotification(`添加Claude配置失败: ${error.message}`, 'error');
|
||||
this.showNotification(`${i18n.t('notification.add_failed')}: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2728,9 +2730,9 @@ class CLIProxyManager {
|
||||
this.clearCache(); // 清除缓存
|
||||
this.closeModal();
|
||||
this.loadClaudeKeys();
|
||||
this.showNotification('Claude配置更新成功', 'success');
|
||||
this.showNotification(i18n.t('notification.claude_config_updated'), 'success');
|
||||
} catch (error) {
|
||||
this.showNotification(`更新Claude配置失败: ${error.message}`, 'error');
|
||||
this.showNotification(`${i18n.t('notification.update_failed')}: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2742,9 +2744,9 @@ class CLIProxyManager {
|
||||
await this.makeRequest(`/claude-api-key?api-key=${encodeURIComponent(apiKey)}`, { method: 'DELETE' });
|
||||
this.clearCache(); // 清除缓存
|
||||
this.loadClaudeKeys();
|
||||
this.showNotification('Claude配置删除成功', 'success');
|
||||
this.showNotification(i18n.t('notification.claude_config_deleted'), 'success');
|
||||
} catch (error) {
|
||||
this.showNotification(`删除Claude配置失败: ${error.message}`, 'error');
|
||||
this.showNotification(`${i18n.t('notification.delete_failed')}: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2829,10 +2831,10 @@ class CLIProxyManager {
|
||||
${this.renderOpenAIModelBadges(models)}
|
||||
<div class="item-stats">
|
||||
<span class="stat-badge stat-success">
|
||||
<i class="fas fa-check-circle"></i> 成功: ${totalSuccess}
|
||||
<i class="fas fa-check-circle"></i> ${i18n.t('stats.success')}: ${totalSuccess}
|
||||
</span>
|
||||
<span class="stat-badge stat-failure">
|
||||
<i class="fas fa-times-circle"></i> 失败: ${totalFailure}
|
||||
<i class="fas fa-times-circle"></i> ${i18n.t('stats.failure')}: ${totalFailure}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2927,9 +2929,9 @@ class CLIProxyManager {
|
||||
this.clearCache(); // 清除缓存
|
||||
this.closeModal();
|
||||
this.loadOpenAIProviders();
|
||||
this.showNotification('OpenAI提供商添加成功', 'success');
|
||||
this.showNotification(i18n.t('notification.openai_provider_added'), 'success');
|
||||
} catch (error) {
|
||||
this.showNotification(`添加OpenAI提供商失败: ${error.message}`, 'error');
|
||||
this.showNotification(`${i18n.t('notification.add_failed')}: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3021,9 +3023,9 @@ class CLIProxyManager {
|
||||
this.clearCache(); // 清除缓存
|
||||
this.closeModal();
|
||||
this.loadOpenAIProviders();
|
||||
this.showNotification('OpenAI提供商更新成功', 'success');
|
||||
this.showNotification(i18n.t('notification.openai_provider_updated'), 'success');
|
||||
} catch (error) {
|
||||
this.showNotification(`更新OpenAI提供商失败: ${error.message}`, 'error');
|
||||
this.showNotification(`${i18n.t('notification.update_failed')}: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3035,9 +3037,9 @@ class CLIProxyManager {
|
||||
await this.makeRequest(`/openai-compatibility?name=${encodeURIComponent(name)}`, { method: 'DELETE' });
|
||||
this.clearCache(); // 清除缓存
|
||||
this.loadOpenAIProviders();
|
||||
this.showNotification('OpenAI提供商删除成功', 'success');
|
||||
this.showNotification(i18n.t('notification.openai_provider_deleted'), 'success');
|
||||
} catch (error) {
|
||||
this.showNotification(`删除OpenAI提供商失败: ${error.message}`, 'error');
|
||||
this.showNotification(`${i18n.t('notification.delete_failed')}: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3124,10 +3126,10 @@ class CLIProxyManager {
|
||||
<div class="item-subtitle">${i18n.t('auth_files.file_modified')}: ${new Date(file.modtime).toLocaleString(i18n.currentLanguage === 'zh-CN' ? 'zh-CN' : 'en-US')}</div>
|
||||
<div class="item-stats">
|
||||
<span class="stat-badge stat-success">
|
||||
<i class="fas fa-check-circle"></i> 成功: ${fileStats.success}
|
||||
<i class="fas fa-check-circle"></i> ${i18n.t('stats.success')}: ${fileStats.success}
|
||||
</span>
|
||||
<span class="stat-badge stat-failure">
|
||||
<i class="fas fa-times-circle"></i> 失败: ${fileStats.failure}
|
||||
<i class="fas fa-times-circle"></i> ${i18n.t('stats.failure')}: ${fileStats.failure}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -3189,7 +3191,7 @@ class CLIProxyManager {
|
||||
this.loadAuthFiles();
|
||||
this.showNotification(i18n.t('auth_files.upload_success'), 'success');
|
||||
} catch (error) {
|
||||
this.showNotification(`文件上传失败: ${error.message}`, 'error');
|
||||
this.showNotification(`${i18n.t('notification.upload_failed')}: ${error.message}`, 'error');
|
||||
}
|
||||
|
||||
// 清空文件输入
|
||||
@@ -3219,7 +3221,7 @@ class CLIProxyManager {
|
||||
|
||||
this.showNotification(i18n.t('auth_files.download_success'), 'success');
|
||||
} catch (error) {
|
||||
this.showNotification(`文件下载失败: ${error.message}`, 'error');
|
||||
this.showNotification(`${i18n.t('notification.download_failed')}: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3233,7 +3235,7 @@ class CLIProxyManager {
|
||||
this.loadAuthFiles();
|
||||
this.showNotification(i18n.t('auth_files.delete_success'), 'success');
|
||||
} catch (error) {
|
||||
this.showNotification(`文件删除失败: ${error.message}`, 'error');
|
||||
this.showNotification(`${i18n.t('notification.delete_failed')}: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3247,7 +3249,7 @@ class CLIProxyManager {
|
||||
this.loadAuthFiles();
|
||||
this.showNotification(`${i18n.t('auth_files.delete_all_success')} ${response.deleted} ${i18n.t('auth_files.files_count')}`, 'success');
|
||||
} catch (error) {
|
||||
this.showNotification(`删除文件失败: ${error.message}`, 'error');
|
||||
this.showNotification(`${i18n.t('notification.delete_failed')}: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3313,12 +3315,12 @@ class CLIProxyManager {
|
||||
if (urlInput && urlInput.value) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(urlInput.value);
|
||||
this.showNotification('链接已复制到剪贴板', 'success');
|
||||
this.showNotification(i18n.t('notification.link_copied'), 'success');
|
||||
} catch (error) {
|
||||
// 降级方案:使用传统的复制方法
|
||||
urlInput.select();
|
||||
document.execCommand('copy');
|
||||
this.showNotification('链接已复制到剪贴板', 'success');
|
||||
this.showNotification(i18n.t('notification.link_copied'), 'success');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3326,7 +3328,7 @@ class CLIProxyManager {
|
||||
// 开始轮询 OAuth 状态
|
||||
startCodexOAuthPolling(state) {
|
||||
if (!state) {
|
||||
this.showNotification('无法获取认证状态参数', 'error');
|
||||
this.showNotification(i18n.t('auth_login.missing_state'), 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3458,12 +3460,12 @@ class CLIProxyManager {
|
||||
if (urlInput && urlInput.value) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(urlInput.value);
|
||||
this.showNotification('链接已复制到剪贴板', 'success');
|
||||
this.showNotification(i18n.t('notification.link_copied'), 'success');
|
||||
} catch (error) {
|
||||
// 降级方案:使用传统的复制方法
|
||||
urlInput.select();
|
||||
document.execCommand('copy');
|
||||
this.showNotification('链接已复制到剪贴板', 'success');
|
||||
this.showNotification(i18n.t('notification.link_copied'), 'success');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3471,7 +3473,7 @@ class CLIProxyManager {
|
||||
// 开始轮询 Anthropic OAuth 状态
|
||||
startAnthropicOAuthPolling(state) {
|
||||
if (!state) {
|
||||
this.showNotification('无法获取认证状态参数', 'error');
|
||||
this.showNotification(i18n.t('auth_login.missing_state'), 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3612,12 +3614,12 @@ class CLIProxyManager {
|
||||
if (urlInput && urlInput.value) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(urlInput.value);
|
||||
this.showNotification('链接已复制到剪贴板', 'success');
|
||||
this.showNotification(i18n.t('notification.link_copied'), 'success');
|
||||
} catch (error) {
|
||||
// 降级方案:使用传统的复制方法
|
||||
urlInput.select();
|
||||
document.execCommand('copy');
|
||||
this.showNotification('链接已复制到剪贴板', 'success');
|
||||
this.showNotification(i18n.t('notification.link_copied'), 'success');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3625,7 +3627,7 @@ class CLIProxyManager {
|
||||
// 开始轮询 Gemini CLI OAuth 状态
|
||||
startGeminiCliOAuthPolling(state) {
|
||||
if (!state) {
|
||||
this.showNotification('无法获取认证状态参数', 'error');
|
||||
this.showNotification(i18n.t('auth_login.missing_state'), 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3757,12 +3759,12 @@ class CLIProxyManager {
|
||||
if (urlInput && urlInput.value) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(urlInput.value);
|
||||
this.showNotification('链接已复制到剪贴板', 'success');
|
||||
this.showNotification(i18n.t('notification.link_copied'), 'success');
|
||||
} catch (error) {
|
||||
// 降级方案:使用传统的复制方法
|
||||
urlInput.select();
|
||||
document.execCommand('copy');
|
||||
this.showNotification('链接已复制到剪贴板', 'success');
|
||||
this.showNotification(i18n.t('notification.link_copied'), 'success');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3770,7 +3772,7 @@ class CLIProxyManager {
|
||||
// 开始轮询 Qwen OAuth 状态
|
||||
startQwenOAuthPolling(state) {
|
||||
if (!state) {
|
||||
this.showNotification('无法获取认证状态参数', 'error');
|
||||
this.showNotification(i18n.t('auth_login.missing_state'), 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3902,12 +3904,12 @@ class CLIProxyManager {
|
||||
if (urlInput && urlInput.value) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(urlInput.value);
|
||||
this.showNotification('链接已复制到剪贴板', 'success');
|
||||
this.showNotification(i18n.t('notification.link_copied'), 'success');
|
||||
} catch (error) {
|
||||
// 降级方案:使用传统的复制方法
|
||||
urlInput.select();
|
||||
document.execCommand('copy');
|
||||
this.showNotification('链接已复制到剪贴板', 'success');
|
||||
this.showNotification(i18n.t('notification.link_copied'), 'success');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3915,7 +3917,7 @@ class CLIProxyManager {
|
||||
// 开始轮询 iFlow OAuth 状态
|
||||
startIflowOAuthPolling(state) {
|
||||
if (!state) {
|
||||
this.showNotification('无法获取认证状态参数', 'error');
|
||||
this.showNotification(i18n.t('auth_login.missing_state'), 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
46
i18n.js
46
i18n.js
@@ -38,6 +38,8 @@ const i18n = {
|
||||
'common.base_url': '地址',
|
||||
'common.proxy_url': '代理',
|
||||
'common.alias': '别名',
|
||||
'common.failure': '失败',
|
||||
'common.unknown_error': '未知错误',
|
||||
|
||||
// 页面标题
|
||||
'title.main': 'CLI Proxy API Management Center',
|
||||
@@ -275,6 +277,7 @@ const i18n = {
|
||||
'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',
|
||||
@@ -308,6 +311,8 @@ const i18n = {
|
||||
'usage_stats.tokens_count': 'Token数量',
|
||||
'usage_stats.models': '模型统计',
|
||||
'usage_stats.success_rate': '成功率',
|
||||
'stats.success': '成功',
|
||||
'stats.failure': '失败',
|
||||
|
||||
// 日志查看
|
||||
'logs.title': '日志查看',
|
||||
@@ -347,6 +352,7 @@ const i18n = {
|
||||
'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': '系统信息',
|
||||
@@ -402,6 +408,7 @@ const i18n = {
|
||||
'notification.gemini_api_key': 'Gemini API密钥',
|
||||
'notification.codex_api_key': 'Codex API密钥',
|
||||
'notification.claude_api_key': 'Claude API密钥',
|
||||
'notification.link_copied': '链接已复制到剪贴板',
|
||||
|
||||
// 语言切换
|
||||
'language.switch': '语言',
|
||||
@@ -416,6 +423,10 @@ const i18n = {
|
||||
'theme.switch_to_dark': '切换到暗色模式',
|
||||
'theme.auto': '跟随系统',
|
||||
|
||||
// 侧边栏
|
||||
'sidebar.toggle_expand': '展开侧边栏',
|
||||
'sidebar.toggle_collapse': '收起侧边栏',
|
||||
|
||||
// 页脚
|
||||
'footer.version': '版本',
|
||||
'footer.author': '作者'
|
||||
@@ -453,6 +464,8 @@ const i18n = {
|
||||
'common.base_url': 'Address',
|
||||
'common.proxy_url': 'Proxy',
|
||||
'common.alias': 'Alias',
|
||||
'common.failure': 'Failure',
|
||||
'common.unknown_error': 'Unknown error',
|
||||
|
||||
// Page titles
|
||||
'title.main': 'CLI Proxy API Management Center',
|
||||
@@ -689,6 +702,7 @@ const i18n = {
|
||||
'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',
|
||||
@@ -722,6 +736,8 @@ const i18n = {
|
||||
'usage_stats.tokens_count': 'Token Count',
|
||||
'usage_stats.models': 'Model Statistics',
|
||||
'usage_stats.success_rate': 'Success Rate',
|
||||
'stats.success': 'Success',
|
||||
'stats.failure': 'Failure',
|
||||
|
||||
// Logs viewer
|
||||
'logs.title': 'Logs Viewer',
|
||||
@@ -761,6 +777,7 @@ const i18n = {
|
||||
'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.title': 'System Information',
|
||||
@@ -816,6 +833,7 @@ const i18n = {
|
||||
'notification.gemini_api_key': 'Gemini API key',
|
||||
'notification.codex_api_key': 'Codex API key',
|
||||
'notification.claude_api_key': 'Claude API key',
|
||||
'notification.link_copied': 'Link copied to clipboard',
|
||||
|
||||
// Language switch
|
||||
'language.switch': 'Language',
|
||||
@@ -830,6 +848,10 @@ const i18n = {
|
||||
'theme.switch_to_dark': 'Switch to dark mode',
|
||||
'theme.auto': 'Follow system',
|
||||
|
||||
// Sidebar
|
||||
'sidebar.toggle_expand': 'Expand sidebar',
|
||||
'sidebar.toggle_collapse': 'Collapse sidebar',
|
||||
|
||||
// Footer
|
||||
'footer.version': 'Version',
|
||||
'footer.author': 'Author'
|
||||
@@ -879,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)
|
||||
document.querySelectorAll('[data-i18n-html]').forEach(element => {
|
||||
const key = element.getAttribute('data-i18n-html');
|
||||
|
||||
41
index.html
41
index.html
@@ -77,8 +77,7 @@
|
||||
<div class="form-group">
|
||||
<label for="login-api-base" data-i18n="login.custom_connection_label">自定义连接地址:</label>
|
||||
<div class="input-group">
|
||||
<input type="text" id="login-api-base" data-i18n="login.custom_connection_placeholder"
|
||||
placeholder="例如: https://example.com:8317">
|
||||
<input type="text" id="login-api-base" data-i18n-placeholder="login.custom_connection_placeholder">
|
||||
<button type="button" id="login-reset-api-base"
|
||||
class="btn btn-secondary connection-reset-btn">
|
||||
<i class="fas fa-location-arrow"></i>
|
||||
@@ -91,8 +90,7 @@
|
||||
<div class="form-group">
|
||||
<label for="login-management-key" data-i18n="login.management_key_label">管理密钥:</label>
|
||||
<div class="input-group">
|
||||
<input type="password" id="login-management-key"
|
||||
data-i18n="login.management_key_placeholder" placeholder="请输入管理密钥" required>
|
||||
<input type="password" id="login-management-key" data-i18n-placeholder="login.management_key_placeholder" required>
|
||||
<button type="button" class="btn btn-secondary toggle-key-visibility">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
@@ -123,7 +121,7 @@
|
||||
<button class="mobile-menu-btn" id="mobile-menu-btn">
|
||||
<i class="fas fa-bars"></i>
|
||||
</button>
|
||||
<button class="sidebar-toggle-btn-desktop" id="sidebar-toggle-btn-desktop" title="收起/展开侧边栏">
|
||||
<button class="sidebar-toggle-btn-desktop" id="sidebar-toggle-btn-desktop" data-i18n-title="sidebar.toggle_collapse">
|
||||
<i class="fas fa-bars"></i>
|
||||
</button>
|
||||
<div class="top-navbar-brand">
|
||||
@@ -161,29 +159,29 @@
|
||||
<nav class="sidebar" id="sidebar">
|
||||
<!-- 导航菜单 -->
|
||||
<ul class="nav-menu">
|
||||
<li data-tooltip="基础设置"><a href="#basic-settings" class="nav-item active"
|
||||
<li data-i18n-tooltip="nav.basic_settings"><a href="#basic-settings" class="nav-item active"
|
||||
data-section="basic-settings">
|
||||
<i class="fas fa-sliders-h"></i> <span data-i18n="nav.basic_settings">基础设置</span>
|
||||
</a></li>
|
||||
<li data-tooltip="API 密钥"><a href="#api-keys" class="nav-item" data-section="api-keys">
|
||||
<li data-i18n-tooltip="nav.api_keys"><a href="#api-keys" class="nav-item" data-section="api-keys">
|
||||
<i class="fas fa-key"></i> <span data-i18n="nav.api_keys">API 密钥</span>
|
||||
</a></li>
|
||||
<li data-tooltip="AI 提供商"><a href="#ai-providers" class="nav-item" data-section="ai-providers">
|
||||
<li data-i18n-tooltip="nav.ai_providers"><a href="#ai-providers" class="nav-item" data-section="ai-providers">
|
||||
<i class="fas fa-robot"></i> <span data-i18n="nav.ai_providers">AI 提供商</span>
|
||||
</a></li>
|
||||
<li data-tooltip="认证文件"><a href="#auth-files" class="nav-item" data-section="auth-files">
|
||||
<li data-i18n-tooltip="nav.auth_files"><a href="#auth-files" class="nav-item" data-section="auth-files">
|
||||
<i class="fas fa-file-alt"></i> <span data-i18n="nav.auth_files">认证文件</span>
|
||||
</a></li>
|
||||
<li data-tooltip="使用统计"><a href="#usage-stats" class="nav-item" data-section="usage-stats">
|
||||
<li data-i18n-tooltip="nav.usage_stats"><a href="#usage-stats" class="nav-item" data-section="usage-stats">
|
||||
<i class="fas fa-chart-line"></i> <span data-i18n="nav.usage_stats">使用统计</span>
|
||||
</a></li>
|
||||
<li data-tooltip="配置管理"><a href="#config-management" class="nav-item" data-section="config-management">
|
||||
<li data-i18n-tooltip="nav.config_management"><a href="#config-management" class="nav-item" data-section="config-management">
|
||||
<i class="fas fa-cog"></i> <span data-i18n="nav.config_management">配置管理</span>
|
||||
</a></li>
|
||||
<li id="logs-nav-item" data-tooltip="日志查看" style="display: none;"><a href="#logs" class="nav-item" data-section="logs">
|
||||
<li id="logs-nav-item" data-i18n-tooltip="nav.logs" style="display: none;"><a href="#logs" class="nav-item" data-section="logs">
|
||||
<i class="fas fa-scroll"></i> <span data-i18n="nav.logs">日志查看</span>
|
||||
</a></li>
|
||||
<li data-tooltip="系统信息"><a href="#system-info" class="nav-item" data-section="system-info">
|
||||
<li data-i18n-tooltip="nav.system_info"><a href="#system-info" class="nav-item" data-section="system-info">
|
||||
<i class="fas fa-info-circle"></i> <span data-i18n="nav.system_info">系统信息</span>
|
||||
</a></li>
|
||||
</ul>
|
||||
@@ -230,9 +228,7 @@
|
||||
<label for="proxy-url" data-i18n="basic_settings.proxy_url_label">代理
|
||||
URL:</label>
|
||||
<div class="input-group">
|
||||
<input type="text" id="proxy-url"
|
||||
data-i18n="basic_settings.proxy_url_placeholder"
|
||||
placeholder="例如: socks5://user:pass@127.0.0.1:1080/">
|
||||
<input type="text" id="proxy-url" data-i18n-placeholder="basic_settings.proxy_url_placeholder">
|
||||
<button id="update-proxy" class="btn btn-primary"
|
||||
data-i18n="basic_settings.proxy_update">更新</button>
|
||||
<button id="clear-proxy" class="btn btn-danger"
|
||||
@@ -461,7 +457,7 @@
|
||||
<div class="form-group">
|
||||
<label data-i18n="auth_login.codex_oauth_url_label">授权链接:</label>
|
||||
<div class="input-group">
|
||||
<input type="text" id="codex-oauth-url" readonly>
|
||||
<input type="text" id="codex-oauth-url" readonly>
|
||||
<button id="codex-open-link" class="btn btn-primary">
|
||||
<i class="fas fa-external-link-alt"></i> <span
|
||||
data-i18n="auth_login.codex_open_link">打开链接</span>
|
||||
@@ -533,11 +529,10 @@
|
||||
data-i18n="auth_login.gemini_cli_project_id_label">Google Cloud 项目 ID
|
||||
(可选):</label>
|
||||
<input type="text" id="gemini-cli-project-id"
|
||||
data-i18n="auth_login.gemini_cli_project_id_placeholder"
|
||||
placeholder="输入 Google Cloud 项目 ID (可选)">
|
||||
<div class="form-hint" data-i18n="auth_login.gemini_cli_project_id_hint">
|
||||
如果指定了项目 ID,将使用该项目的认证信息。
|
||||
</div>
|
||||
data-i18n-placeholder="auth_login.gemini_cli_project_id_placeholder">
|
||||
<div class="form-hint" data-i18n="auth_login.gemini_cli_project_id_hint">
|
||||
如果指定了项目 ID,将使用该项目的认证信息。
|
||||
</div>
|
||||
</div>
|
||||
<div id="gemini-cli-oauth-content" style="display: none;">
|
||||
<div class="form-group">
|
||||
@@ -794,7 +789,7 @@
|
||||
<div class="card-content">
|
||||
<p class="form-hint" data-i18n="config_management.description">查看并编辑服务器上的 config.yaml 配置文件。保存前请确认语法正确。</p>
|
||||
<div class="yaml-editor-container">
|
||||
<textarea id="config-editor" class="yaml-editor" spellcheck="false" placeholder="key: value"></textarea>
|
||||
<textarea id="config-editor" class="yaml-editor" spellcheck="false" data-i18n="config_management.editor_placeholder"></textarea>
|
||||
<div id="config-editor-status" class="editor-status" data-i18n="config_management.status_idle">等待操作</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user