diff --git a/public/index.html b/public/index.html index 46938c8..cd1b021 100644 --- a/public/index.html +++ b/public/index.html @@ -139,7 +139,7 @@
- Menu + Menu
@@ -353,6 +353,11 @@ + + + + + diff --git a/public/js/app-init.js b/public/js/app-init.js index 407d48d..401f36c 100644 --- a/public/js/app-init.js +++ b/public/js/app-init.js @@ -115,8 +115,11 @@ document.addEventListener('alpine:init', () => { const messageHandler = (event) => { if (event.data?.type === 'oauth-success') { - const action = reAuthEmail ? 're-authenticated' : 'added'; - Alpine.store('global').showToast(`Account ${event.data.email} ${action} successfully`, 'success'); + const store = Alpine.store('global'); + const successMsg = reAuthEmail + ? store.t('accountReauthSuccess') + : store.t('accountAddedSuccess'); + store.showToast(successMsg, 'success'); Alpine.store('data').fetchData(); const modal = document.getElementById('add_account_modal'); @@ -127,10 +130,10 @@ document.addEventListener('alpine:init', () => { window.addEventListener('message', messageHandler); setTimeout(() => window.removeEventListener('message', messageHandler), 300000); } else { - Alpine.store('global').showToast(data.error || 'Failed to get auth URL', 'error'); + Alpine.store('global').showToast(data.error || Alpine.store('global').t('failedToGetAuthUrl'), 'error'); } } catch (e) { - Alpine.store('global').showToast('Failed to start OAuth flow: ' + e.message, 'error'); + Alpine.store('global').showToast(Alpine.store('global').t('failedToStartOAuth') + ': ' + e.message, 'error'); } } })); diff --git a/public/js/components/claude-config.js b/public/js/components/claude-config.js index fc82c97..c07110a 100644 --- a/public/js/components/claude-config.js +++ b/public/js/components/claude-config.js @@ -318,7 +318,7 @@ window.Components.claudeConfig = () => ({ */ async executeSavePreset(name) { if (!name || !name.trim()) { - Alpine.store('global').showToast('Preset name is required', 'error'); + Alpine.store('global').showToast(Alpine.store('global').t('presetNameRequired'), 'error'); return; } @@ -363,10 +363,10 @@ window.Components.claudeConfig = () => ({ ); document.getElementById('save_preset_modal').close(); } else { - throw new Error(data.error || 'Save failed'); + throw new Error(data.error || Alpine.store('global').t('saveFailed')); } } catch (e) { - Alpine.store('global').showToast('Failed to save preset: ' + e.message, 'error'); + Alpine.store('global').showToast(Alpine.store('global').t('failedToSavePreset') + ': ' + e.message, 'error'); } finally { this.savingPreset = false; } @@ -377,12 +377,13 @@ window.Components.claudeConfig = () => ({ */ async deleteSelectedPreset() { if (!this.selectedPresetName) { - Alpine.store('global').showToast('No preset selected', 'warning'); + Alpine.store('global').showToast(Alpine.store('global').t('noPresetSelected'), 'warning'); return; } // Confirm deletion - if (!confirm(`Delete preset "${this.selectedPresetName}"?`)) { + const confirmMsg = Alpine.store('global').t('deletePresetConfirm', { name: this.selectedPresetName }); + if (!confirm(confirmMsg)) { return; } @@ -408,10 +409,10 @@ window.Components.claudeConfig = () => ({ 'success' ); } else { - throw new Error(data.error || 'Delete failed'); + throw new Error(data.error || Alpine.store('global').t('deleteFailed')); } } catch (e) { - Alpine.store('global').showToast('Failed to delete preset: ' + e.message, 'error'); + Alpine.store('global').showToast(Alpine.store('global').t('failedToDeletePreset') + ': ' + e.message, 'error'); } finally { this.deletingPreset = false; } diff --git a/public/js/components/server-config.js b/public/js/components/server-config.js index 5ab7f8b..e5ca4ed 100644 --- a/public/js/components/server-config.js +++ b/public/js/components/server-config.js @@ -88,15 +88,15 @@ window.Components.serverConfig = () => ({ if (!response.ok) { const data = await response.json(); - throw new Error(data.error || 'Failed to change password'); + throw new Error(data.error || store.t('failedToChangePassword')); } // Update stored password store.webuiPassword = newPassword; - store.showToast('Password changed successfully', 'success'); + store.showToast(store.t('passwordChangedSuccess'), 'success'); this.hidePasswordDialog(); } catch (e) { - store.showToast('Failed to change password: ' + e.message, 'error'); + store.showToast(store.t('failedToChangePassword') + ': ' + e.message, 'error'); } }, @@ -119,16 +119,16 @@ window.Components.serverConfig = () => ({ const data = await response.json(); if (data.status === 'ok') { - const status = enabled ? 'enabled' : 'disabled'; - store.showToast(`Debug mode ${status}`, 'success'); + const status = enabled ? store.t('enabledStatus') : store.t('disabledStatus'); + store.showToast(store.t('debugModeToggled', { status }), 'success'); await this.fetchServerConfig(); // Confirm server state } else { - throw new Error(data.error || 'Failed to update debug mode'); + throw new Error(data.error || store.t('failedToUpdateDebugMode')); } } catch (e) { // Rollback on error this.serverConfig.debug = previousValue; - store.showToast('Failed to update debug mode: ' + e.message, 'error'); + store.showToast(store.t('failedToUpdateDebugMode') + ': ' + e.message, 'error'); } }, @@ -151,16 +151,16 @@ window.Components.serverConfig = () => ({ const data = await response.json(); if (data.status === 'ok') { - const status = enabled ? 'enabled' : 'disabled'; - store.showToast(`Token cache ${status}`, 'success'); + const status = enabled ? store.t('enabledStatus') : store.t('disabledStatus'); + store.showToast(store.t('tokenCacheToggled', { status }), 'success'); await this.fetchServerConfig(); // Confirm server state } else { - throw new Error(data.error || 'Failed to update token cache'); + throw new Error(data.error || store.t('failedToUpdateTokenCache')); } } catch (e) { // Rollback on error this.serverConfig.persistTokenCache = previousValue; - store.showToast('Failed to update token cache: ' + e.message, 'error'); + store.showToast(store.t('failedToUpdateTokenCache') + ': ' + e.message, 'error'); } }, @@ -206,15 +206,15 @@ window.Components.serverConfig = () => ({ const data = await response.json(); if (data.status === 'ok') { - store.showToast(`${displayName} updated to ${value}`, 'success'); + store.showToast(store.t('fieldUpdated', { displayName, value }), 'success'); await this.fetchServerConfig(); // Confirm server state } else { - throw new Error(data.error || `Failed to update ${displayName}`); + throw new Error(data.error || store.t('failedToUpdateField', { displayName })); } } catch (e) { // Rollback on error this.serverConfig[fieldName] = previousValue; - store.showToast(`Failed to update ${displayName}: ` + e.message, 'error'); + store.showToast(store.t('failedToUpdateField', { displayName }) + ': ' + e.message, 'error'); } }, window.AppConstants.INTERVALS.CONFIG_DEBOUNCE); }, diff --git a/public/js/store.js b/public/js/store.js index be6f086..3b13bb9 100644 --- a/public/js/store.js +++ b/public/js/store.js @@ -39,843 +39,7 @@ document.addEventListener('alpine:init', () => { // i18n lang: localStorage.getItem('app_lang') || 'en', - translations: { - en: { - dashboard: "Dashboard", - models: "Models", - accounts: "Accounts", - logs: "Logs", - settings: "Settings", - online: "ONLINE", - offline: "OFFLINE", - totalAccounts: "TOTAL ACCOUNTS", - active: "ACTIVE", - operational: "Operational", - rateLimited: "RATE LIMITED", - quotasDepleted: "{count}/{total} Quotas Depleted", - quotasDepletedTitle: "QUOTAS DEPLETED", - outOfTracked: "Out of {total} Tracked", - cooldown: "Cooldown", - searchPlaceholder: "Search models...", - allAccounts: "All Accounts", - stat: "STAT", - modelIdentity: "MODEL IDENTITY", - globalQuota: "GLOBAL QUOTA", - nextReset: "NEXT RESET", - distribution: "ACCOUNT DISTRIBUTION", - systemConfig: "System Configuration", - language: "Language", - pollingInterval: "Polling Interval", - maxDisplayLogs: "Max Displayed Logs", - showExhausted: "Show Exhausted Models", - showExhaustedDesc: "Display models even if they have 0% remaining quota.", - compactMode: "Compact Mode", - compactModeDesc: "Reduce padding in tables for higher information density.", - saveChanges: "Save Changes", - autoScroll: "Auto-scroll", - clearLogs: "Clear Logs", - accountManagement: "Account Management", - manageTokens: "Manage Google Account tokens and authorization states", - addAccount: "Add Account", - status: "STATUS", - enabled: "ENABLED", - health: "STATUS", - accountEmail: "ACCOUNT (EMAIL)", - source: "SOURCE", - projectId: "PROJECT ID", - sessionState: "SESSION STATE", - operations: "OPERATIONS", - delete: "Delete", - confirmDelete: "Are you sure you want to remove this account?", - cannotDeleteDatabase: "Cannot delete: This account is from Antigravity database (read-only)", - connectGoogle: "Connect Google Account", - reauthenticated: "re-authenticated", - added: "added", - successfully: "successfully", - accountAddedSuccess: "Account added successfully", - accountReauthSuccess: "Account re-authenticated successfully", - failedToGetAuthUrl: "Failed to get auth URL", - failedToStartOAuth: "Failed to start OAuth flow", - oauthInProgress: "OAuth in progress. Please complete authentication in the popup window...", - family: "Family", - model: "Model", - activeSuffix: "Active", - // Tabs - tabInterface: "Interface", - tabClaude: "Claude CLI", - tabModels: "Models", - tabServer: "Server Settings", - // Dashboard - linkedAccounts: "Linked Accounts", - noSignal: "NO SIGNAL DETECTED", - establishingUplink: "ESTABLISHING UPLINK...", - goToAccounts: "Go to Accounts", - // Settings - Models - modelsDesc: "Configure model visibility, pinning, and request routing.", - modelsPageDesc: "Real-time quota and status for all available models.", - showHidden: "Show Hidden Models", - hideHidden: "Hide Hidden Models", - hiddenOn: "Hidden: ON", - hiddenOff: "Hidden: OFF", - modelId: "Model ID", - actions: "Actions", - pinToTop: "Pin to top", - toggleVisibility: "Toggle Visibility", - noModels: "NO MODELS DETECTED", - modelMappingHint: "Server-side model routing. Claude Code users: see 'Claude CLI' tab for client-side setup.", - modelMapping: "Mapping (Target Model ID)", - // Settings - Claude - proxyConnection: "Proxy Connection", - modelSelection: "Model Selection", - defaultModelAliases: "DEFAULT MODEL ALIASES", - opusAlias: "Opus Alias", - sonnetAlias: "Sonnet Alias", - haikuAlias: "Haiku Alias", - claudeSettingsAlertPrefix: "Settings below directly modify", - claudeSettingsAlertSuffix: "Restart Claude CLI to apply.", - applyToClaude: "Apply to Claude CLI", - // Presets - configPresets: "Configuration Presets", - saveAsPreset: "Save as Preset", - deletePreset: "Delete Preset", - loadPreset: "Load preset into form", - load: "Load", - presetHint: "Select a preset to load it. Click \"Apply to Claude CLI\" to save changes.", - presetLoaded: "Preset loaded. Click \"Apply to Claude CLI\" to save.", - presetSaved: "Preset saved", - presetDeleted: "Preset deleted", - unsavedChangesTitle: "Unsaved Changes", - unsavedChangesMessage: "Your current configuration doesn't match any saved preset. If you switch, your current unsaved settings will be lost.", - loadAnyway: "Load Anyway", - savePresetTitle: "Save Preset", - savePresetDesc: "Save the current configuration as a reusable preset.", - presetName: "Preset Name", - presetNamePlaceholder: "e.g., My Work Setup", - savePreset: "Save Preset", - // Settings - Server - port: "Port", - uiVersion: "UI Version", - debugMode: "Debug Mode", - environment: "Environment", - serverReadOnly: "Settings managed via config.json. Restart server to apply changes.", - advancedSettings: "Advanced Settings", - reloadConfigTitle: "Reload Account Config", - reloadConfigDesc: "Force reload accounts.json from disk", - reload: "Reload", - // Config Specific - primaryModel: "Primary Model", - subAgentModel: "Sub-agent Model", - advancedOverrides: "Default Model Overrides", - opusModel: "Opus Model", - sonnetModel: "Sonnet Model", - haikuModel: "Haiku Model", - authToken: "Auth Token", - saveConfig: "Save to Claude CLI settings", - envVar: "Env", - // New Keys - systemName: "ANTIGRAVITY", - systemDesc: "CLAUDE PROXY SYSTEM", - connectGoogleDesc: "Connect a Google Workspace account to increase your API quota limit. The account will be used to proxy Claude requests via Antigravity.", - useCliCommand: "Use CLI Command", - close: "Close", - requestVolume: "Request Volume", - filter: "Filter", - all: "All", - none: "None", - noDataTracked: "No data tracked yet", - selectFamilies: "Select families to display", - selectModels: "Select models to display", - noLogsMatch: "No logs match filter", - connecting: "CONNECTING", - main: "Main", - system: "System", - refreshData: "Refresh Data", - connectionLost: "Connection Lost", - lastUpdated: "Last Updated", - grepLogs: "grep logs...", - noMatchingModels: "No matching models", - typeToSearch: "Type to search or select...", - or: "OR", - refreshingAccount: "Refreshing {email}...", - refreshedAccount: "Refreshed {email}", - refreshFailed: "Refresh failed", - accountToggled: "Account {email} {status}", - toggleFailed: "Toggle failed", - reauthenticating: "Re-authenticating {email}...", - authUrlFailed: "Failed to get auth URL", - deletedAccount: "Deleted {email}", - deleteFailed: "Delete failed", - accountsReloaded: "Accounts reloaded", - reloadFailed: "Reload failed", - claudeConfigSaved: "Claude configuration saved", - claudeConfigRestored: "Claude CLI restored to defaults", - saveConfigFailed: "Failed to save configuration", - restoreConfigFailed: "Failed to restore configuration", - restoreDefault: "Restore Default", - confirmRestoreTitle: "Confirm Restore", - confirmRestoreMessage: "Are you sure you want to restore Claude CLI to default settings? This will remove proxy configuration.", - confirmRestore: "Confirm Restore", - claudeActive: "Claude Active", - claudeEmpty: "Claude Empty", - geminiActive: "Gemini Active", - geminiEmpty: "Gemini Empty", - synced: "SYNCED", - syncing: "SYNCING...", - // Time range labels - last1Hour: "Last 1H", - last6Hours: "Last 6H", - last24Hours: "Last 24H", - last7Days: "Last 7D", - allTime: "All Time", - groupBy: "Group By", - // Additional - reloading: "Reloading...", - reloaded: "Reloaded", - lines: "lines", - enabledSeeLogs: "Enabled (See Logs)", - production: "Production", - configSaved: "Configuration Saved", - enterPassword: "Enter Web UI Password:", - ready: "READY", - depleted: "Depleted", - timeH: "H", - timeM: "M", - familyClaude: "Claude", - familyGemini: "Gemini", - familyOther: "Other", - enabledStatus: "enabled", - disabledStatus: "disabled", - logLevelInfo: "INFO", - logLevelSuccess: "SUCCESS", - logLevelWarn: "WARN", - logLevelError: "ERR", - totalColon: "Total:", - todayColon: "Today:", - hour1Colon: "1H:", - frequentModels: "Frequent", - smartTitle: "Auto-select top 5 most used models (24h)", - activeCount: "{count} Active", - allCaps: "ALL", - claudeCaps: "CLAUDE", - geminiCaps: "GEMINI", - modelMapping: "Mapping (Target Model ID)", - systemInfo: "System Information", - refresh: "Refresh", - runtimeConfig: "Runtime Configuration", - debugDesc: "Enable detailed logging (See Logs tab)", - networkRetry: "Network Retry Settings", - maxRetries: "Max Retries", - retryBaseDelay: "Retry Base Delay (ms)", - retryMaxDelay: "Retry Max Delay (ms)", - persistentSessions: "Persistent Sessions", - persistTokenDesc: "Save OAuth sessions to disk for faster restarts", - rateLimiting: "Account Rate Limiting & Timeouts", - defaultCooldown: "Default Cooldown", - defaultCooldownDesc: "Fallback cooldown when API doesn't provide a reset time.", - maxWaitThreshold: "Max Wait Before Error", - maxWaitDesc: "If all accounts are rate-limited longer than this, error immediately instead of waiting.", - saveConfigServer: "Save Configuration", - serverRestartAlert: "Changes saved to {path}. Restart server to apply some settings.", - changePassword: "Change WebUI Password", - changePasswordDesc: "Update the password for accessing this dashboard", - currentPassword: "Current Password", - newPassword: "New Password", - confirmNewPassword: "Confirm New Password", - passwordEmptyDesc: "Leave empty if no password set", - passwordLengthDesc: "At least 6 characters", - passwordConfirmDesc: "Re-enter new password", - cancel: "Cancel", - passwordsNotMatch: "Passwords do not match", - passwordTooShort: "Password must be at least 6 characters", - // Dashboard drill-down - clickToViewAllAccounts: "Click to view all accounts", - clickToViewModels: "Click to view Models page", - clickToViewLimitedAccounts: "Click to view rate-limited accounts", - clickToFilterClaude: "Click to filter Claude models", - clickToFilterGemini: "Click to filter Gemini models", - // Accounts page - searchAccounts: "Search accounts...", - noAccountsYet: "No Accounts Yet", - noAccountsDesc: "Get started by adding a Google account via OAuth, or use the CLI command to import credentials.", - addFirstAccount: "Add Your First Account", - noSearchResults: "No accounts match your search", - clearSearch: "Clear Search", - disabledAccountsNote: "Disabled accounts will not be used for request routing but remain in the configuration. Dashboard statistics only include enabled accounts.", - dangerousOperation: "⚠️ Dangerous Operation", - confirmDeletePrompt: "Are you sure you want to delete account", - deleteWarning: "⚠️ This action cannot be undone. All configuration and historical records will be permanently deleted.", - // OAuth progress - oauthWaiting: "Waiting for OAuth authorization...", - oauthWaitingDesc: "Please complete the authentication in the popup window. This may take up to 2 minutes.", - oauthCancelled: "OAuth authorization cancelled", - oauthTimeout: "⏱️ OAuth authorization timed out. Please try again.", - oauthWindowClosed: "OAuth window was closed. Authorization may be incomplete.", - cancelOAuth: "Cancel", - // MCP CLI & Gemini 1M - mcpCliExperimental: "Experimental MCP CLI", - mcpCliDesc: "Enables experimental MCP integration for reliable tool usage with reduced context consumption.", - gemini1mMode: "Gemini 1M Context Mode", - gemini1mDesc: "Appends [1m] suffix to Gemini models for 1M context window support.", - gemini1mWarning: "⚠ Large context may reduce Gemini-3-Pro performance.", - clickToSet: "Click to configure...", - none: "None", - // Quota Distribution - quotaDistribution: "Quota Distribution", - resetsIn: "Resets in {time}", - noQuotaData: "No quota data available for this account yet.", - }, - zh: { - dashboard: "仪表盘", - models: "模型列表", - accounts: "账号管理", - logs: "运行日志", - settings: "系统设置", - online: "在线", - offline: "离线", - totalAccounts: "账号总数", - active: "活跃状态", - operational: "运行中", - rateLimited: "受限状态", - quotasDepleted: "{count}/{total} 配额耗尽", - quotasDepletedTitle: "配额耗尽数", - outOfTracked: "共追踪 {total} 个", - cooldown: "冷却中", - searchPlaceholder: "搜索模型...", - allAccounts: "所有账号", - stat: "状态", - modelIdentity: "模型标识", - globalQuota: "全局配额", - nextReset: "重置时间", - distribution: "账号分布", - systemConfig: "系统配置", - language: "语言设置", - pollingInterval: "数据轮询间隔", - maxDisplayLogs: "最大日志显示行数", - showExhausted: "显示耗尽模型", - showExhaustedDesc: "即使配额为 0% 也显示模型。", - compactMode: "紧凑模式", - compactModeDesc: "减少表格间距以显示更多信息。", - saveChanges: "保存更改", - autoScroll: "自动滚动", - clearLogs: "清除日志", - accountManagement: "账号管理", - manageTokens: "管理已授权的 Google 账号及其状态", - addAccount: "添加账号", - status: "状态", - enabled: "启用", - health: "状态", - accountEmail: "账号 (邮箱)", - source: "来源", - projectId: "项目 ID", - sessionState: "会话状态", - operations: "操作", - delete: "删除", - confirmDelete: "确定要移除此账号吗?", - cannotDeleteDatabase: "无法删除:此账号来自 Antigravity 数据库(只读)", - connectGoogle: "连接 Google 账号", - reauthenticated: "已重新认证", - added: "已添加", - successfully: "成功", - accountAddedSuccess: "账号添加成功", - accountReauthSuccess: "账号重新认证成功", - failedToGetAuthUrl: "获取认证链接失败", - failedToStartOAuth: "启动 OAuth 流程失败", - oauthInProgress: "OAuth 授权进行中,请在弹出窗口中完成认证...", - family: "系列", - model: "模型", - activeSuffix: "活跃", - manualReload: "重新加载配置", - // Tabs - tabInterface: "界面设置", - tabClaude: "Claude CLI", - tabModels: "模型管理", - tabServer: "服务器设置", - // Dashboard - linkedAccounts: "已关联账号", - noSignal: "无信号连接", - establishingUplink: "正在建立上行链路...", - goToAccounts: "前往账号管理", - // Settings - Models - modelsDesc: "配置模型的可见性、置顶和请求路由。", - modelsPageDesc: "所有可用模型的实时配额和状态。", - showHidden: "显示隐藏模型", - hideHidden: "隐藏被屏蔽模型", - hiddenOn: "隐藏模型: 显示", - hiddenOff: "隐藏模型: 隐藏", - modelId: "模型 ID", - actions: "操作", - pinToTop: "置顶", - toggleVisibility: "切换可见性", - noModels: "未检测到模型", - modelMappingHint: "服务端模型路由功能。Claude Code 用户请使用 'Claude CLI' 标签页以便捷配置。", - modelMapping: "映射 (目标模型 ID)", - // Settings - Claude - proxyConnection: "代理连接", - modelSelection: "模型选择", - defaultModelAliases: "默认模型映射 (别名)", - opusAlias: "Opus 别名", - sonnetAlias: "Sonnet 别名", - haikuAlias: "Haiku 别名", - claudeSettingsAlertPrefix: "以下设置直接修改", - claudeSettingsAlertSuffix: "重启 Claude CLI 生效。", - applyToClaude: "应用到 Claude CLI", - // Presets - configPresets: "配置预设", - saveAsPreset: "另存为预设", - deletePreset: "删除预设", - loadPreset: "加载预设到表单", - load: "加载", - presetHint: "选择预设以加载。点击“应用到 Claude CLI”以保存更改。", - presetLoaded: "预设已加载。点击“应用到 Claude CLI”以保存。", - presetSaved: "预设已保存", - presetDeleted: "预设已删除", - unsavedChangesTitle: "未保存的更改", - unsavedChangesMessage: "当前配置与任何已保存的预设都不匹配。如果切换预设,当前未保存的设置将会丢失。", - loadAnyway: "仍然加载", - savePresetTitle: "保存预设", - savePresetDesc: "将当前配置保存为可重复使用的预设。", - presetName: "预设名称", - presetNamePlaceholder: "例如:工作配置", - savePreset: "保存预设", - // Settings - Server - port: "端口", - uiVersion: "UI 版本", - debugMode: "调试模式", - environment: "运行环境", - serverReadOnly: "配置由 config.json 管理。重启服务器以应用更改。", - advancedSettings: "高级设置", - reloadConfigTitle: "重载账号配置", - reloadConfigDesc: "强制从磁盘重新读取 accounts.json", - reload: "重载", - // Config Specific - primaryModel: "主模型", - subAgentModel: "子代理模型", - advancedOverrides: "默认模型覆盖 (高级)", - opusModel: "Opus 模型", - sonnetModel: "Sonnet 模型", - haikuModel: "Haiku 模型", - authToken: "认证令牌", - saveConfig: "保存到 Claude CLI 设置", - envVar: "环境变量", - // New Keys - systemName: "ANTIGRAVITY", - systemDesc: "CLAUDE 代理系统", - connectGoogleDesc: "连接 Google Workspace 账号以增加 API 配额。该账号将用于通过 Antigravity 代理 Claude 请求。", - useCliCommand: "使用命令行", - close: "关闭", - requestVolume: "请求量", - filter: "筛选", - all: "全选", - none: "清空", - noDataTracked: "暂无追踪数据", - selectFamilies: "选择要显示的系列", - selectModels: "选择要显示的模型", - noLogsMatch: "没有符合过滤条件的日志", - connecting: "正在连接", - main: "主菜单", - system: "系统", - refreshData: "刷新数据", - connectionLost: "连接已断开", - lastUpdated: "最后更新", - grepLogs: "过滤日志...", - noMatchingModels: "没有匹配的模型", - typeToSearch: "输入以搜索或选择...", - or: "或", - refreshingAccount: "正在刷新 {email}...", - refreshedAccount: "已完成刷新 {email}", - refreshFailed: "刷新失败", - accountToggled: "账号 {email} 已{status}", - toggleFailed: "切换失败", - reauthenticating: "正在重新认证 {email}...", - authUrlFailed: "获取认证链接失败", - deletedAccount: "已删除 {email}", - deleteFailed: "删除失败", - accountsReloaded: "账号配置已重载", - reloadFailed: "重载失败", - claudeConfigSaved: "Claude 配置已保存", - claudeConfigRestored: "Claude CLI 已恢复默认设置", - saveConfigFailed: "保存配置失败", - restoreConfigFailed: "恢复配置失败", - restoreDefault: "恢复默认", - confirmRestoreTitle: "确认恢复", - confirmRestoreMessage: "确定要将 Claude CLI 恢复为默认设置吗?这将移除代理配置。", - confirmRestore: "确认恢复", - claudeActive: "Claude 活跃", - claudeEmpty: "Claude 耗尽", - geminiActive: "Gemini 活跃", - geminiEmpty: "Gemini 耗尽", - synced: "已同步", - syncing: "正在同步...", - // 时间范围标签 - last1Hour: "最近 1 小时", - last6Hours: "最近 6 小时", - last24Hours: "最近 24 小时", - last7Days: "最近 7 天", - allTime: "最后全部", - groupBy: "分组方式", - // Additional - reloading: "正在重载...", - reloaded: "已重载", - lines: "行", - enabledSeeLogs: "已启用 (见日志)", - production: "生产环境", - configSaved: "配置已保存", - enterPassword: "请输入 Web UI 密码:", - ready: "就绪", - depleted: "已耗尽", - timeH: "时", - timeM: "分", - familyClaude: "Claude 系列", - familyGemini: "Gemini 系列", - familyOther: "其他系列", - enabledStatus: "已启用", - disabledStatus: "已禁用", - logLevelInfo: "信息", - logLevelSuccess: "成功", - logLevelWarn: "警告", - logLevelError: "错误", - totalColon: "总计:", - todayColon: "今日:", - hour1Colon: "1小时:", - frequentModels: "常用推荐", - smartTitle: "自动选出过去 24 小时最常用的 5 个模型", - activeCount: "{count} 活跃", - allCaps: "全部", - claudeCaps: "CLAUDE", - geminiCaps: "GEMINI", - modelMapping: "映射 (目标模型 ID)", - systemInfo: "系统信息", - refresh: "刷新", - runtimeConfig: "运行时配置", - debugDesc: "启用详细日志记录 (见运行日志)", - networkRetry: "网络重试设置", - maxRetries: "最大重试次数", - retryBaseDelay: "重试基础延迟 (毫秒)", - retryMaxDelay: "重试最大延迟 (毫秒)", - persistentSessions: "持久化登录会话", - persistTokenDesc: "将登录会话保存到磁盘以实现快速重启", - rateLimiting: "账号限流与超时", - defaultCooldown: "默认冷却时间", - defaultCooldownDesc: "当 API 未提供重置时间时的备用冷却时间。", - maxWaitThreshold: "最大等待阈值", - maxWaitDesc: "如果所有账号的限流时间超过此阈值,立即返回错误而非等待。", - saveConfigServer: "保存配置", - serverRestartAlert: "配置已保存至 {path}。部分更改可能需要重启服务器。", - changePassword: "修改 WebUI 密码", - changePasswordDesc: "更新访问此仪表盘的密码", - currentPassword: "当前密码", - newPassword: "新密码", - confirmNewPassword: "确认新密码", - passwordEmptyDesc: "如果未设置密码请留空", - passwordLengthDesc: "至少 6 个字符", - passwordConfirmDesc: "请再次输入新密码", - cancel: "取消", - passwordsNotMatch: "密码不匹配", - passwordTooShort: "密码至少需要 6 个字符", - // Dashboard drill-down - clickToViewAllAccounts: "点击查看所有账号", - clickToViewModels: "点击查看模型页面", - clickToViewLimitedAccounts: "点击查看受限账号", - clickToFilterClaude: "点击筛选 Claude 模型", - clickToFilterGemini: "点击筛选 Gemini 模型", - // 账号页面 - searchAccounts: "搜索账号...", - noAccountsYet: "还没有添加任何账号", - noAccountsDesc: "点击上方的 \"添加账号\" 按钮通过 OAuth 添加 Google 账号,或者使用 CLI 命令导入凭证。", - addFirstAccount: "添加第一个账号", - noSearchResults: "没有找到匹配的账号", - clearSearch: "清除搜索", - disabledAccountsNote: "已禁用的账号不会用于请求路由,但仍保留在配置中。仪表盘统计数据仅包含已启用的账号。", - dangerousOperation: "⚠️ 危险操作", - confirmDeletePrompt: "确定要删除账号", - deleteWarning: "⚠️ 此操作不可撤销,账号的所有配置和历史记录将永久删除。", - // OAuth 进度 - oauthWaiting: "等待 OAuth 授权中...", - oauthWaitingDesc: "请在弹出窗口中完成认证。此过程最长可能需要 2 分钟。", - oauthCancelled: "已取消 OAuth 授权", - oauthTimeout: "⏱️ OAuth 授权超时,请重试。", - oauthWindowClosed: "OAuth 窗口已关闭,授权可能未完成。", - cancelOAuth: "取消", - // MCP CLI & Gemini 1M - mcpCliExperimental: "实验性 MCP CLI", - mcpCliDesc: "启用实验性 MCP 集成,减少上下文消耗,提高工具调用可靠性。", - gemini1mMode: "Gemini 1M 上下文模式", - gemini1mDesc: "为 Gemini 模型添加 [1m] 后缀以支持 1M 上下文窗口。", - gemini1mWarning: "⚠ 大上下文可能降低 Gemini-3-Pro 性能。", - clickToSet: "点击进行配置...", - none: "无", - // Quota Distribution - quotaDistribution: "配额分布", - resetsIn: "{time} 后重置", - noQuotaData: "暂无此账号的配额数据。", - }, - tr: { - dashboard: "Panel", - models: "Modeller", - accounts: "Hesaplar", - logs: "Günlükler", - settings: "Ayarlar", - online: "ÇEVRİMİÇİ", - offline: "ÇEVRİMDIŞI", - totalAccounts: "TOPLAM HESAP", - active: "AKTİF", - operational: "Çalışıyor", - rateLimited: "HIZ SINIRLANDI", - quotasDepleted: "{count}/{total} Kota Tükendi", - quotasDepletedTitle: "KOTA TÜKENDİ", - outOfTracked: "{total} Takip Edilen İçinden", - cooldown: "Soğuma", - searchPlaceholder: "Modelleri ara...", - allAccounts: "Tüm Hesaplar", - stat: "DURUM", - modelIdentity: "MODEL KİMLİĞİ", - globalQuota: "GENEL KOTA", - nextReset: "SONRAKİ SIFIRLAMA", - distribution: "HESAP DAĞILIMI", - systemConfig: "Sistem Yapılandırması", - language: "Dil", - pollingInterval: "Veri Güncelleme Aralığı", - maxDisplayLogs: "Maksimum Görüntülenen Günlük", - showExhausted: "Tükenmiş Modelleri Göster", - showExhaustedDesc: "%0 kotası kalan modelleri de göster.", - compactMode: "Kompakt Mod", - compactModeDesc: "Daha fazla bilgi göstermek için tablo boşluklarını azalt.", - saveChanges: "Değişiklikleri Kaydet", - autoScroll: "Otomatik Kaydır", - clearLogs: "Günlükleri Temizle", - accountManagement: "Hesap Yönetimi", - manageTokens: "Google Hesap jetonlarını ve yetkilendirme durumlarını yönet", - addAccount: "Hesap Ekle", - status: "DURUM", - enabled: "ETKİN", - health: "SAĞLIK", - accountEmail: "HESAP (E-POSTA)", - source: "KAYNAK", - projectId: "PROJE ID", - sessionState: "OTURUM DURUMU", - operations: "İŞLEMLER", - delete: "Sil", - confirmDelete: "Bu hesabı kaldırmak istediğinizden emin misiniz?", - cannotDeleteDatabase: "Silinemez: Bu hesap Antigravity veritabanından (salt okunur)", - connectGoogle: "Google Hesabı Bağla", - reauthenticated: "yeniden doğrulandı", - added: "eklendi", - successfully: "başarıyla", - accountAddedSuccess: "Hesap başarıyla eklendi", - accountReauthSuccess: "Hesap başarıyla yeniden doğrulandı", - failedToGetAuthUrl: "Yetkilendirme URL'si alınamadı", - failedToStartOAuth: "OAuth akışı başlatılamadı", - oauthInProgress: "OAuth devam ediyor. Lütfen açılır pencerede kimlik doğrulamayı tamamlayın...", - family: "Aile", - model: "Model", - activeSuffix: "Aktif", - manualReload: "Yapılandırmayı Yeniden Yükle", - // Tabs - tabInterface: "Arayüz", - tabClaude: "Claude CLI", - tabModels: "Modeller", - tabServer: "Sunucu Ayarları", - // Dashboard - linkedAccounts: "Bağlı Hesaplar", - noSignal: "SİNYAL YOK", - establishingUplink: "BAĞLANTI KURULUYOR...", - goToAccounts: "Hesaplara Git", - // Settings - Models - modelsDesc: "Model görünürlüğünü, sabitlemeyi ve istek yönlendirmeyi yapılandırın.", - modelsPageDesc: "Tüm mevcut modeller için gerçek zamanlı kota ve durum.", - showHidden: "Gizli Modelleri Göster", - hideHidden: "Gizli Modelleri Gizle", - hiddenOn: "Gizli: AÇIK", - hiddenOff: "Gizli: KAPALI", - modelId: "Model ID", - actions: "İşlemler", - pinToTop: "En Üste Sabitle", - toggleVisibility: "Görünürlüğü Değiştir", - noModels: "MODEL ALGILANMADI", - modelMappingHint: "Sunucu tarafı model yönlendirme. Claude Code kullanıcıları: istemci tarafı kurulumu için 'Claude CLI' sekmesine bakın.", - modelMapping: "Eşleştirme (Hedef Model ID)", - // Settings - Claude - proxyConnection: "Proxy Bağlantısı", - modelSelection: "Model Seçimi", - defaultModelAliases: "VARSAYILAN MODEL TAKMA ADLARI", - opusAlias: "Opus Takma Adı", - sonnetAlias: "Sonnet Takma Adı", - haikuAlias: "Haiku Takma Adı", - claudeSettingsAlertPrefix: "Aşağıdaki ayarlar doğrudan değiştirir", - claudeSettingsAlertSuffix: "Uygulamak için Claude CLI'yı yeniden başlatın.", - applyToClaude: "Claude CLI'ya Uygula", - // Settings - Server - port: "Port", - uiVersion: "Arayüz Sürümü", - debugMode: "Hata Ayıklama Modu", - environment: "Ortam", - serverReadOnly: "Ayarlar config.json üzerinden yönetilir. Değişiklikleri uygulamak için sunucuyu yeniden başlatın.", - advancedSettings: "Gelişmiş Ayarlar", - reloadConfigTitle: "Hesap Yapılandırmasını Yeniden Yükle", - reloadConfigDesc: "accounts.json dosyasını diskten yeniden yüklemeye zorla", - reload: "Yeniden Yükle", - // Config Specific - primaryModel: "Birincil Model", - subAgentModel: "Alt Ajan Modeli", - advancedOverrides: "Varsayılan Model Geçersiz Kılmaları", - opusModel: "Opus Modeli", - sonnetModel: "Sonnet Modeli", - haikuModel: "Haiku Modeli", - authToken: "Yetkilendirme Jetonu", - saveConfig: "Claude CLI ayarlarına kaydet", - envVar: "Ortam Değişkeni", - // New Keys - systemName: "ANTIGRAVITY", - systemDesc: "CLAUDE PROXY SİSTEMİ", - connectGoogleDesc: "API kota limitinizi artırmak için bir Google Workspace hesabı bağlayın. Bu hesap, Claude isteklerini Antigravity üzerinden vekil sunucu olarak kullanmak için kullanılacaktır.", - useCliCommand: "CLI Komutunu Kullan", - close: "Kapat", - requestVolume: "İstek Hacmi", - filter: "Filtrele", - all: "Tümü", - none: "Hiçbiri", - noDataTracked: "Henüz veri izlenmedi", - selectFamilies: "Görüntülenecek aileleri seçin", - selectModels: "Görüntülenecek modelleri seçin", - noLogsMatch: "Filtreyle eşleşen günlük yok", - connecting: "BAĞLANILIYOR", - main: "Ana", - system: "Sistem", - refreshData: "Verileri Yenile", - connectionLost: "Bağlantı Kaybedildi", - lastUpdated: "Son Güncelleme", - grepLogs: "günlükleri ara...", - noMatchingModels: "Eşleşen model yok", - typeToSearch: "Aramak veya seçmek için yazın...", - or: "VEYA", - refreshingAccount: "{email} yenileniyor...", - refreshedAccount: "{email} yenilendi", - refreshFailed: "Yenileme başarısız", - accountToggled: "Hesap {email} {status}", - toggleFailed: "Değiştirme başarısız", - reauthenticating: "{email} yeniden doğrulanıyor...", - authUrlFailed: "Yetkilendirme URL'si alınamadı", - deletedAccount: "{email} silindi", - deleteFailed: "Silme başarısız", - accountsReloaded: "Hesaplar yeniden yüklendi", - reloadFailed: "Yeniden yükleme başarısız", - claudeConfigSaved: "Claude yapılandırması kaydedildi", - claudeConfigRestored: "Claude CLI varsayılanlara geri yüklendi", - saveConfigFailed: "Yapılandırma kaydedilemedi", - restoreConfigFailed: "Yapılandırma geri yüklenemedi", - restoreDefault: "Varsayılana Dön", - confirmRestoreTitle: "Geri Yüklemeyi Onayla", - confirmRestoreMessage: "Claude CLI'yı varsayılan ayarlara geri yüklemek istediğinizden emin misiniz? Bu işlem proxy yapılandırmasını kaldıracaktır.", - confirmRestore: "Geri Yüklemeyi Onayla", - claudeActive: "Claude Aktif", - claudeEmpty: "Claude Boş", - geminiActive: "Gemini Aktif", - geminiEmpty: "Gemini Boş", - synced: "EŞİTLENDİ", - syncing: "EŞİTLENİYOR...", - // Time range labels - last1Hour: "Son 1S", - last6Hours: "Son 6S", - last24Hours: "Son 24S", - last7Days: "Son 7G", - allTime: "Tüm Zamanlar", - groupBy: "Gruplama Ölçütü", - // Additional - reloading: "Yeniden yükleniyor...", - reloaded: "Yeniden yüklendi", - lines: "satır", - enabledSeeLogs: "Etkin (Günlüklere Bak)", - production: "Üretim", - configSaved: "Yapılandırma Kaydedildi", - enterPassword: "Web UI Parolasını Girin:", - ready: "HAZIR", - depleted: "Tükendi", - timeH: "S", - timeM: "D", - familyClaude: "Claude", - familyGemini: "Gemini", - familyOther: "Diğer", - enabledStatus: "etkin", - disabledStatus: "devre dışı", - logLevelInfo: "BİLGİ", - logLevelSuccess: "BAŞARILI", - logLevelWarn: "UYARI", - logLevelError: "HATA", - totalColon: "Toplam:", - todayColon: "Bugün:", - hour1Colon: "1S:", - frequentModels: "Sık Kullanılan", - smartTitle: "En çok kullanılan 5 modeli otomatik seç (24s)", - activeCount: "{count} Aktif", - allCaps: "TÜMÜ", - claudeCaps: "CLAUDE", - geminiCaps: "GEMINI", - modelMapping: "Eşleştirme (Hedef Model ID)", - systemInfo: "Sistem Bilgisi", - refresh: "Yenile", - runtimeConfig: "Çalışma Zamanı Yapılandırması", - debugDesc: "Ayrıntılı günlük kaydını etkinleştir (Günlükler sekmesine bakın)", - networkRetry: "Ağ Yeniden Deneme Ayarları", - maxRetries: "Maksimum Deneme", - retryBaseDelay: "Yeniden Deneme Temel Gecikmesi (ms)", - retryMaxDelay: "Yeniden Deneme Maksimum Gecikmesi (ms)", - persistentSessions: "Kalıcı Oturumlar", - persistTokenDesc: "Daha hızlı yeniden başlatmalar için OAuth oturumlarını diske kaydet", - rateLimiting: "Hesap Hız Sınırlama ve Zaman Aşımları", - defaultCooldown: "Varsayılan Soğuma Süresi", - maxWaitThreshold: "Maksimum Bekleme Eşiği (Yapışkan)", - maxWaitDesc: "Yapışkan bir hesabın değiştirmeden önce sıfırlanması için beklenecek maksimum süre.", - saveConfigServer: "Yapılandırmayı Kaydet", - serverRestartAlert: "Değişiklikler {path} konumuna kaydedildi. Bazı ayarları uygulamak için sunucuyu yeniden başlatın.", - changePassword: "WebUI Parolasını Değiştir", - changePasswordDesc: "Bu panoya erişim parolasını güncelle", - currentPassword: "Mevcut Parola", - newPassword: "Yeni Parola", - confirmNewPassword: "Yeni Parolayı Onayla", - passwordEmptyDesc: "Parola ayarlanmamışsa boş bırakın", - passwordLengthDesc: "En az 6 karakter", - passwordConfirmDesc: "Yeni parolayı tekrar girin", - cancel: "İptal", - passwordsNotMatch: "Parolalar eşleşmiyor", - passwordTooShort: "Parola en az 6 karakter olmalıdır", - // Dashboard drill-down - clickToViewAllAccounts: "Tüm hesapları görüntülemek için tıklayın", - clickToViewModels: "Modeller sayfasını görüntülemek için tıklayın", - clickToViewLimitedAccounts: "Hız sınırı olan hesapları görüntülemek için tıklayın", - clickToFilterClaude: "Claude modellerini filtrelemek için tıklayın", - clickToFilterGemini: "Gemini modellerini filtrelemek için tıklayın", - // Accounts page - searchAccounts: "Hesap ara...", - noAccountsYet: "Henüz Hesap Yok", - noAccountsDesc: "OAuth üzerinden bir Google hesabı ekleyerek veya kimlik bilgilerini içe aktarmak için CLI komutunu kullanarak başlayın.", - addFirstAccount: "İlk Hesabınızı Ekleyin", - noSearchResults: "Aramanızla eşleşen hesap yok", - clearSearch: "Aramayı Temizle", - disabledAccountsNote: "Devre dışı bırakılan hesaplar istek yönlendirmesi için kullanılmayacak ancak yapılandırmada kalacaktır. Pano istatistikleri yalnızca etkin hesapları içerir.", - dangerousOperation: "⚠️ Tehlikeli İşlem", - confirmDeletePrompt: "Hesabı silmek istediğinizden emin misiniz", - deleteWarning: "⚠️ Bu işlem geri alınamaz. Tüm yapılandırma ve geçmiş kayıtları kalıcı olarak silinecektir.", - // OAuth progress - oauthWaiting: "OAuth yetkilendirmesi bekleniyor...", - oauthWaitingDesc: "Lütfen açılır pencerede kimlik doğrulamasını tamamlayın. Bu işlem 2 dakikaya kadar sürebilir.", - oauthCancelled: "OAuth yetkilendirmesi iptal edildi", - oauthTimeout: "⏱️ OAuth yetkilendirmesi zaman aşımına uğradı. Lütfen tekrar deneyin.", - oauthWindowClosed: "OAuth penceresi kapatıldı. Yetkilendirme tamamlanmamış olabilir.", - cancelOAuth: "İptal", - // MCP CLI & Gemini 1M - mcpCliExperimental: "Deneysel MCP CLI", - mcpCliDesc: "Daha az bağlam tüketimi ile güvenilir araç kullanımı için deneysel MCP entegrasyonunu etkinleştirir.", - gemini1mMode: "Gemini 1M Bağlam Modu", - gemini1mDesc: "1M bağlam penceresi desteği için Gemini modellerine [1m] son eki ekler.", - gemini1mWarning: "⚠ Büyük bağlam, Gemini-3-Pro performansını düşürebilir.", - clickToSet: "Yapılandırmak için tıklayın...", - none: "Hiçbiri", - // Quota Distribution - quotaDistribution: "Kota Dağılımı", - resetsIn: "{time} içinde sıfırlanır", - noQuotaData: "Bu hesap için henüz kota verisi yok.", - }, - }, + translations: window.translations || {}, // Toast Messages toast: null, diff --git a/public/js/translations/en.js b/public/js/translations/en.js new file mode 100644 index 0000000..61942ca --- /dev/null +++ b/public/js/translations/en.js @@ -0,0 +1,327 @@ +/** + * English Translations + */ +window.translations = window.translations || {}; +window.translations.en = { + dashboard: "Dashboard", + models: "Models", + accounts: "Accounts", + logs: "Logs", + settings: "Settings", + online: "ONLINE", + offline: "OFFLINE", + totalAccounts: "TOTAL ACCOUNTS", + active: "ACTIVE", + operational: "Operational", + rateLimited: "RATE LIMITED", + quotasDepleted: "{count}/{total} Quotas Depleted", + quotasDepletedTitle: "QUOTAS DEPLETED", + outOfTracked: "Out of {total} Tracked", + cooldown: "Cooldown", + searchPlaceholder: "Search models...", + allAccounts: "All Accounts", + stat: "STAT", + modelIdentity: "MODEL IDENTITY", + globalQuota: "GLOBAL QUOTA", + nextReset: "NEXT RESET", + distribution: "ACCOUNT DISTRIBUTION", + systemConfig: "System Configuration", + language: "Language", + pollingInterval: "Polling Interval", + maxDisplayLogs: "Max Displayed Logs", + showExhausted: "Show Exhausted Models", + showExhaustedDesc: "Display models even if they have 0% remaining quota.", + compactMode: "Compact Mode", + compactModeDesc: "Reduce padding in tables for higher information density.", + saveChanges: "Save Changes", + autoScroll: "Auto-scroll", + clearLogs: "Clear Logs", + accountManagement: "Account Management", + manageTokens: "Manage Google Account tokens and authorization states", + addAccount: "Add Account", + status: "STATUS", + enabled: "ENABLED", + health: "STATUS", + accountEmail: "ACCOUNT (EMAIL)", + source: "SOURCE", + projectId: "PROJECT ID", + sessionState: "SESSION STATE", + operations: "OPERATIONS", + delete: "Delete", + fix: "Fix", + confirmDelete: "Are you sure you want to remove this account?", + cannotDeleteDatabase: "Cannot delete: This account is from Antigravity database (read-only)", + connectGoogle: "Connect Google Account", + reauthenticated: "re-authenticated", + added: "added", + successfully: "successfully", + accountAddedSuccess: "Account added successfully", + accountReauthSuccess: "Account re-authenticated successfully", + failedToGetAuthUrl: "Failed to get auth URL", + failedToStartOAuth: "Failed to start OAuth flow", + oauthInProgress: "OAuth in progress. Please complete authentication in the popup window...", + family: "Family", + model: "Model", + activeSuffix: "Active", + // Tabs + tabInterface: "Interface", + tabClaude: "Claude CLI", + tabModels: "Models", + tabServer: "Server Settings", + // Dashboard + linkedAccounts: "Linked Accounts", + noSignal: "NO SIGNAL DETECTED", + establishingUplink: "ESTABLISHING UPLINK...", + goToAccounts: "Go to Accounts", + // Settings - Models + modelsDesc: "Configure model visibility, pinning, and request routing.", + modelsPageDesc: "Real-time quota and status for all available models.", + showHidden: "Show Hidden Models", + hideHidden: "Hide Hidden Models", + hiddenOn: "Hidden: ON", + hiddenOff: "Hidden: OFF", + modelId: "Model ID", + actions: "Actions", + pinToTop: "Pin to top", + toggleVisibility: "Toggle Visibility", + noModels: "NO MODELS DETECTED", + modelMappingHint: "Server-side model routing. Claude Code users: see 'Claude CLI' tab for client-side setup.", + modelMapping: "Mapping (Target Model ID)", + // Settings - Claude + proxyConnection: "Proxy Connection", + modelSelection: "Model Selection", + defaultModelAliases: "DEFAULT MODEL ALIASES", + opusAlias: "Opus Alias", + sonnetAlias: "Sonnet Alias", + haikuAlias: "Haiku Alias", + claudeSettingsAlertPrefix: "Settings below directly modify", + claudeSettingsAlertSuffix: "Restart Claude CLI to apply.", + applyToClaude: "Apply to Claude CLI", + // Presets + configPresets: "Configuration Presets", + saveAsPreset: "Save as Preset", + deletePreset: "Delete Preset", + loadPreset: "Load preset into form", + load: "Load", + presetHint: "Select a preset to load it. Click \"Apply to Claude CLI\" to save changes.", + presetLoaded: "Preset loaded. Click \"Apply to Claude CLI\" to save.", + presetSaved: "Preset saved", + presetDeleted: "Preset deleted", + unsavedChangesTitle: "Unsaved Changes", + unsavedChangesMessage: "Your current configuration doesn't match any saved preset. If you switch, your current unsaved settings will be lost.", + loadAnyway: "Load Anyway", + savePresetTitle: "Save Preset", + savePresetDesc: "Save the current configuration as a reusable preset.", + presetName: "Preset Name", + presetNamePlaceholder: "e.g., My Work Setup", + savePreset: "Save Preset", + // Settings - Server + port: "Port", + uiVersion: "UI Version", + debugMode: "Debug Mode", + environment: "Environment", + serverReadOnly: "Settings managed via config.json. Restart server to apply changes.", + advancedSettings: "Advanced Settings", + reloadConfigTitle: "Reload Account Config", + reloadConfigDesc: "Force reload accounts.json from disk", + reload: "Reload", + // Config Specific + primaryModel: "Primary Model", + subAgentModel: "Sub-agent Model", + advancedOverrides: "Default Model Overrides", + opusModel: "Opus Model", + sonnetModel: "Sonnet Model", + haikuModel: "Haiku Model", + authToken: "Auth Token", + saveConfig: "Save to Claude CLI settings", + envVar: "Env", + // New Keys + systemName: "ANTIGRAVITY", + systemDesc: "CLAUDE PROXY SYSTEM", + connectGoogleDesc: "Connect a Google Workspace account to increase your API quota limit. The account will be used to proxy Claude requests via Antigravity.", + useCliCommand: "Use CLI Command", + close: "Close", + requestVolume: "Request Volume", + filter: "Filter", + all: "All", + none: "None", + noDataTracked: "No data tracked yet", + selectFamilies: "Select families to display", + selectModels: "Select models to display", + noLogsMatch: "No logs match filter", + connecting: "CONNECTING", + main: "Main", + system: "System", + refreshData: "Refresh Data", + connectionLost: "Connection Lost", + lastUpdated: "Last Updated", + grepLogs: "grep logs...", + noMatchingModels: "No matching models", + typeToSearch: "Type to search or select...", + or: "OR", + refreshingAccount: "Refreshing {email}...", + refreshedAccount: "Refreshed {email}", + refreshFailed: "Refresh failed", + accountToggled: "Account {email} {status}", + toggleFailed: "Toggle failed", + reauthenticating: "Re-authenticating {email}...", + authUrlFailed: "Failed to get auth URL", + deletedAccount: "Deleted {email}", + deleteFailed: "Delete failed", + accountsReloaded: "Accounts reloaded", + reloadFailed: "Reload failed", + claudeConfigSaved: "Claude configuration saved", + claudeConfigRestored: "Claude CLI restored to defaults", + saveConfigFailed: "Failed to save configuration", + restoreConfigFailed: "Failed to restore configuration", + restoreDefault: "Restore Default", + confirmRestoreTitle: "Confirm Restore", + confirmRestoreMessage: "Are you sure you want to restore Claude CLI to default settings? This will remove proxy configuration.", + confirmRestore: "Confirm Restore", + claudeActive: "Claude Active", + claudeEmpty: "Claude Empty", + geminiActive: "Gemini Active", + geminiEmpty: "Gemini Empty", + synced: "SYNCED", + syncing: "SYNCING...", + // Time range labels + last1Hour: "Last 1H", + last6Hours: "Last 6H", + last24Hours: "Last 24H", + last7Days: "Last 7D", + allTime: "All Time", + groupBy: "Group By", + // Additional + reloading: "Reloading...", + reloaded: "Reloaded", + lines: "lines", + enabledSeeLogs: "Enabled (See Logs)", + production: "Production", + configSaved: "Configuration Saved", + enterPassword: "Enter Web UI Password:", + ready: "READY", + depleted: "Depleted", + timeH: "H", + timeM: "M", + familyClaude: "Claude", + familyGemini: "Gemini", + familyOther: "Other", + enabledStatus: "enabled", + disabledStatus: "disabled", + logLevelInfo: "INFO", + logLevelSuccess: "SUCCESS", + logLevelWarn: "WARN", + logLevelError: "ERR", + totalColon: "Total:", + todayColon: "Today:", + hour1Colon: "1H:", + frequentModels: "Frequent", + smartTitle: "Auto-select top 5 most used models (24h)", + activeCount: "{count} Active", + allCaps: "ALL", + claudeCaps: "CLAUDE", + geminiCaps: "GEMINI", + modelMapping: "Mapping (Target Model ID)", + systemInfo: "System Information", + refresh: "Refresh", + runtimeConfig: "Runtime Configuration", + debugDesc: "Enable detailed logging (See Logs tab)", + networkRetry: "Network Retry Settings", + maxRetries: "Max Retries", + retryBaseDelay: "Retry Base Delay (ms)", + retryMaxDelay: "Retry Max Delay (ms)", + persistentSessions: "Persistent Sessions", + persistTokenDesc: "Save OAuth sessions to disk for faster restarts", + rateLimiting: "Account Rate Limiting & Timeouts", + defaultCooldown: "Default Cooldown", + defaultCooldownDesc: "Fallback cooldown when API doesn't provide a reset time.", + maxWaitThreshold: "Max Wait Before Error", + maxWaitDesc: "If all accounts are rate-limited longer than this, error immediately instead of waiting.", + saveConfigServer: "Save Configuration", + serverRestartAlert: "Changes saved to {path}. Restart server to apply some settings.", + changePassword: "Change WebUI Password", + changePasswordDesc: "Update the password for accessing this dashboard", + currentPassword: "Current Password", + newPassword: "New Password", + confirmNewPassword: "Confirm New Password", + passwordEmptyDesc: "Leave empty if no password set", + passwordLengthDesc: "At least 6 characters", + passwordConfirmDesc: "Re-enter new password", + cancel: "Cancel", + passwordsNotMatch: "Passwords do not match", + passwordTooShort: "Password must be at least 6 characters", + // Dashboard drill-down + clickToViewAllAccounts: "Click to view all accounts", + clickToViewModels: "Click to view Models page", + clickToViewLimitedAccounts: "Click to view rate-limited accounts", + clickToFilterClaude: "Click to filter Claude models", + clickToFilterGemini: "Click to filter Gemini models", + // Accounts page + searchAccounts: "Search accounts...", + noAccountsYet: "No Accounts Yet", + noAccountsDesc: "Get started by adding a Google account via OAuth, or use the CLI command to import credentials.", + addFirstAccount: "Add Your First Account", + noSearchResults: "No accounts match your search", + clearSearch: "Clear Search", + disabledAccountsNote: "Disabled accounts will not be used for request routing but remain in the configuration. Dashboard statistics only include enabled accounts.", + dangerousOperation: "⚠️ Dangerous Operation", + confirmDeletePrompt: "Are you sure you want to delete account", + deleteWarning: "⚠️ This action cannot be undone. All configuration and historical records will be permanently deleted.", + // OAuth progress + oauthWaiting: "Waiting for OAuth authorization...", + oauthWaitingDesc: "Please complete the authentication in the popup window. This may take up to 2 minutes.", + oauthCancelled: "OAuth authorization cancelled", + oauthTimeout: "⏱️ OAuth authorization timed out. Please try again.", + oauthWindowClosed: "OAuth window was closed. Authorization may be incomplete.", + cancelOAuth: "Cancel", + // MCP CLI & Gemini 1M + mcpCliExperimental: "Experimental MCP CLI", + mcpCliDesc: "Enables experimental MCP integration for reliable tool usage with reduced context consumption.", + gemini1mMode: "Gemini 1M Context Mode", + gemini1mDesc: "Appends [1m] suffix to Gemini models for 1M context window support.", + gemini1mWarning: "⚠ Large context may reduce Gemini-3-Pro performance.", + clickToSet: "Click to configure...", + none: "None", + // Quota Distribution + quotaDistribution: "Quota Distribution", + resetsIn: "Resets in {time}", + noQuotaData: "No quota data available for this account yet.", + // UI Elements + pageTitle: "Antigravity Console", + live: "Live", + tier: "Tier", + quota: "Quota", + tierUltra: "Ultra", + tierPro: "Pro", + tierFree: "Free", + menu: "Menu", + github: "GitHub", + noData: "No data", + // Error Messages + operationFailed: "Operation failed", + unknownError: "Unknown error", + presetNameRequired: "Preset name is required", + saveFailed: "Save failed", + failedToSavePreset: "Failed to save preset", + noPresetSelected: "No preset selected", + deletePresetConfirm: "Delete preset \"{name}\"?", + failedToDeletePreset: "Failed to delete preset", + failedToChangePassword: "Failed to change password", + passwordChangedSuccess: "Password changed successfully", + debugModeToggled: "Debug mode {status}", + tokenCacheToggled: "Token cache {status}", + failedToUpdateTokenCache: "Failed to update token cache", + failedToUpdateDebugMode: "Failed to update debug mode", + failedToRefreshAccount: "Failed to refresh account", + failedToDeleteAccount: "Failed to delete account", + failedToReloadAccounts: "Failed to reload accounts", + failedToUpdateModelConfig: "Failed to update model config", + fieldUpdated: "{displayName} updated to {value}", + failedToUpdateField: "Failed to update {displayName}", + // Validation Messages + mustBeValidNumber: "{fieldName} must be a valid number", + mustBeAtLeast: "{fieldName} must be at least {min}", + mustBeAtMost: "{fieldName} must be at most {max}", + cannotBeEmpty: "{fieldName} cannot be empty", + mustBeTrueOrFalse: "Value must be true or false", +}; diff --git a/public/js/translations/id.js b/public/js/translations/id.js new file mode 100644 index 0000000..6e53bb1 --- /dev/null +++ b/public/js/translations/id.js @@ -0,0 +1,371 @@ +/** + * Indonesian (Bahasa Indonesia) Translations + * + * Panduan Terminologi IT: + * - Istilah teknis umum tetap dalam bahasa Inggris (OAuth, API, token, proxy, debug, cache, dll.) + * - Istilah UI umum diterjemahkan (Simpan, Hapus, Batal, dll.) + * - Pesan error dan status menggunakan campuran yang konsisten + */ +window.translations = window.translations || {}; +window.translations.id = { + // Navigation + dashboard: "Dashboard", + models: "Model", + accounts: "Akun", + logs: "Log", + settings: "Pengaturan", + + // Status + online: "ONLINE", + offline: "OFFLINE", + totalAccounts: "TOTAL AKUN", + active: "AKTIF", + operational: "Berjalan Normal", + rateLimited: "DIBATASI", + quotasDepleted: "{count}/{total} Kuota Habis", + quotasDepletedTitle: "KUOTA HABIS", + outOfTracked: "Dari {total} Terpantau", + cooldown: "Cooldown", + + // Search & Filters + searchPlaceholder: "Cari model...", + allAccounts: "Semua Akun", + stat: "STATUS", + modelIdentity: "IDENTITAS MODEL", + globalQuota: "KUOTA GLOBAL", + nextReset: "RESET BERIKUTNYA", + distribution: "DISTRIBUSI AKUN", + + // System Configuration + systemConfig: "Konfigurasi Sistem", + language: "Bahasa", + pollingInterval: "Interval Polling", + maxDisplayLogs: "Maks. Log Ditampilkan", + showExhausted: "Tampilkan Model Habis", + showExhaustedDesc: "Tampilkan model meskipun kuotanya sudah 0%.", + compactMode: "Mode Ringkas", + compactModeDesc: "Tampilan tabel lebih padat untuk informasi lebih banyak.", + saveChanges: "Simpan Perubahan", + + // Logs + autoScroll: "Auto-scroll", + clearLogs: "Hapus Log", + + // Account Management + accountManagement: "Kelola Akun", + manageTokens: "Kelola token akun Google dan status otorisasi", + addAccount: "Tambah Akun", + status: "STATUS", + enabled: "AKTIF", + health: "STATUS", + accountEmail: "AKUN (EMAIL)", + source: "SUMBER", + projectId: "PROJECT ID", + sessionState: "STATUS SESI", + operations: "AKSI", + delete: "Hapus", + confirmDelete: "Yakin ingin menghapus akun ini?", + cannotDeleteDatabase: "Tidak bisa dihapus: Akun ini dari database Antigravity (read-only)", + connectGoogle: "Hubungkan Akun Google", + reauthenticated: "diautentikasi ulang", + added: "ditambahkan", + successfully: "berhasil", + accountAddedSuccess: "Akun berhasil ditambahkan", + accountReauthSuccess: "Akun berhasil diautentikasi ulang", + failedToGetAuthUrl: "Gagal mendapatkan URL autentikasi", + failedToStartOAuth: "Gagal memulai proses OAuth", + oauthInProgress: "Proses OAuth sedang berjalan. Silakan selesaikan autentikasi di jendela popup...", + family: "Jenis", + model: "Model", + activeSuffix: "Aktif", + manualReload: "Muat Ulang Konfigurasi", + + // Tabs + tabInterface: "Tampilan", + tabClaude: "Claude CLI", + tabModels: "Model", + tabServer: "Server", + + // Dashboard + linkedAccounts: "Akun Terhubung", + noSignal: "TIDAK ADA SINYAL", + establishingUplink: "MENGHUBUNGKAN...", + goToAccounts: "Lihat Akun", + + // Settings - Models + modelsDesc: "Atur visibilitas model, pin, dan routing request.", + modelsPageDesc: "Kuota dan status real-time untuk semua model yang tersedia.", + showHidden: "Tampilkan Model Tersembunyi", + hideHidden: "Sembunyikan Model Tersembunyi", + hiddenOn: "Tersembunyi: YA", + hiddenOff: "Tersembunyi: TIDAK", + modelId: "ID Model", + actions: "Aksi", + pinToTop: "Pin ke atas", + toggleVisibility: "Tampilkan/Sembunyikan", + noModels: "MODEL TIDAK DITEMUKAN", + modelMappingHint: "Routing model di sisi server. Pengguna Claude Code: lihat tab 'Claude CLI' untuk pengaturan di sisi klien.", + modelMapping: "Mapping (Target Model ID)", + + // Settings - Claude + proxyConnection: "Koneksi Proxy", + modelSelection: "Pilihan Model", + defaultModelAliases: "ALIAS MODEL DEFAULT", + opusAlias: "Alias Opus", + sonnetAlias: "Alias Sonnet", + haikuAlias: "Alias Haiku", + claudeSettingsAlertPrefix: "Pengaturan di bawah langsung mengubah", + claudeSettingsAlertSuffix: "Restart Claude CLI untuk menerapkan.", + applyToClaude: "Simpan ke Claude CLI", + + // Presets + configPresets: "Preset Konfigurasi", + saveAsPreset: "Simpan sebagai Preset", + deletePreset: "Hapus Preset", + loadPreset: "Muat preset", + load: "Muat", + presetHint: "Pilih preset untuk dimuat. Klik \"Simpan ke Claude CLI\" untuk menyimpan.", + presetLoaded: "Preset dimuat. Klik \"Simpan ke Claude CLI\" untuk menyimpan.", + presetSaved: "Preset tersimpan", + presetDeleted: "Preset terhapus", + unsavedChangesTitle: "Ada Perubahan Belum Disimpan", + unsavedChangesMessage: "Konfigurasi saat ini tidak cocok dengan preset tersimpan. Jika beralih, perubahan akan hilang.", + loadAnyway: "Tetap Muat", + savePresetTitle: "Simpan Preset", + savePresetDesc: "Simpan konfigurasi saat ini sebagai preset.", + presetName: "Nama Preset", + presetNamePlaceholder: "contoh: Setup Kantor", + savePreset: "Simpan Preset", + + // Settings - Server + port: "Port", + uiVersion: "Versi UI", + debugMode: "Mode Debug", + environment: "Environment", + serverReadOnly: "Pengaturan dikelola melalui config.json. Restart server untuk menerapkan.", + advancedSettings: "Pengaturan Lanjutan", + reloadConfigTitle: "Muat Ulang Konfigurasi Akun", + reloadConfigDesc: "Paksa muat ulang accounts.json dari disk", + reload: "Muat Ulang", + + // Config Specific + primaryModel: "Model Utama", + subAgentModel: "Model Sub-agent", + advancedOverrides: "Timpa Model Default", + opusModel: "Model Opus", + sonnetModel: "Model Sonnet", + haikuModel: "Model Haiku", + authToken: "Token Auth", + saveConfig: "Simpan ke Claude CLI", + envVar: "Env", + + // System + systemName: "ANTIGRAVITY", + systemDesc: "CLAUDE PROXY SYSTEM", + connectGoogleDesc: "Hubungkan akun Google Workspace untuk meningkatkan kuota API. Akun akan digunakan untuk meneruskan request Claude via Antigravity.", + useCliCommand: "Gunakan Perintah CLI", + close: "Tutup", + requestVolume: "Volume Request", + filter: "Filter", + all: "Semua", + none: "Tidak Ada", + noDataTracked: "Belum ada data tercatat", + selectFamilies: "Pilih jenis model untuk ditampilkan", + selectModels: "Pilih model untuk ditampilkan", + noLogsMatch: "Tidak ada log yang sesuai filter", + connecting: "MENGHUBUNGKAN", + main: "Utama", + system: "Sistem", + refreshData: "Refresh Data", + connectionLost: "Koneksi Terputus", + lastUpdated: "Terakhir Diperbarui", + grepLogs: "cari log...", + noMatchingModels: "Tidak ada model yang cocok", + typeToSearch: "Ketik untuk mencari...", + or: "ATAU", + + // Account Operations + refreshingAccount: "Memperbarui {email}...", + refreshedAccount: "{email} berhasil diperbarui", + refreshFailed: "Gagal memperbarui", + accountToggled: "Akun {email} {status}", + toggleFailed: "Gagal mengubah status", + reauthenticating: "Autentikasi ulang {email}...", + authUrlFailed: "Gagal mendapatkan URL autentikasi", + deletedAccount: "{email} berhasil dihapus", + deleteFailed: "Gagal menghapus", + accountsReloaded: "Akun berhasil dimuat ulang", + reloadFailed: "Gagal memuat ulang", + + // Claude Config + claudeConfigSaved: "Konfigurasi Claude tersimpan", + claudeConfigRestored: "Claude CLI dikembalikan ke default", + saveConfigFailed: "Gagal menyimpan konfigurasi", + restoreConfigFailed: "Gagal mengembalikan konfigurasi", + restoreDefault: "Reset ke Default", + confirmRestoreTitle: "Konfirmasi Reset", + confirmRestoreMessage: "Yakin ingin mengembalikan Claude CLI ke pengaturan default? Konfigurasi proxy akan dihapus.", + confirmRestore: "Ya, Reset", + + // Status Labels + claudeActive: "Claude Aktif", + claudeEmpty: "Claude Kosong", + geminiActive: "Gemini Aktif", + geminiEmpty: "Gemini Kosong", + synced: "SINKRON", + syncing: "SINKRONISASI...", + + // Time range labels + last1Hour: "1 Jam Terakhir", + last6Hours: "6 Jam Terakhir", + last24Hours: "24 Jam Terakhir", + last7Days: "7 Hari Terakhir", + allTime: "Semua Waktu", + groupBy: "Kelompokkan", + + // Additional + reloading: "Memuat ulang...", + reloaded: "Dimuat ulang", + lines: "baris", + enabledSeeLogs: "Aktif (Lihat Log)", + production: "Produksi", + configSaved: "Konfigurasi Tersimpan", + enterPassword: "Masukkan Password Web UI:", + ready: "SIAP", + depleted: "Habis", + timeH: "j", + timeM: "m", + familyClaude: "Claude", + familyGemini: "Gemini", + familyOther: "Lainnya", + enabledStatus: "diaktifkan", + disabledStatus: "dinonaktifkan", + logLevelInfo: "INFO", + logLevelSuccess: "OK", + logLevelWarn: "WARN", + logLevelError: "ERROR", + totalColon: "Total:", + todayColon: "Hari Ini:", + hour1Colon: "1j:", + frequentModels: "Sering Dipakai", + smartTitle: "Otomatis pilih 5 model paling sering dipakai (24 jam)", + activeCount: "{count} Aktif", + allCaps: "SEMUA", + claudeCaps: "CLAUDE", + geminiCaps: "GEMINI", + + // System Info + systemInfo: "Informasi Sistem", + refresh: "Refresh", + runtimeConfig: "Konfigurasi Runtime", + debugDesc: "Aktifkan log detail (Lihat tab Log)", + networkRetry: "Pengaturan Retry Jaringan", + maxRetries: "Maks. Retry", + retryBaseDelay: "Jeda Awal Retry (ms)", + retryMaxDelay: "Jeda Maks. Retry (ms)", + persistentSessions: "Sesi Persisten", + persistTokenDesc: "Simpan sesi OAuth ke disk agar startup lebih cepat", + rateLimiting: "Rate Limiting & Timeout Akun", + defaultCooldown: "Cooldown Default", + defaultCooldownDesc: "Cooldown bawaan jika API tidak memberikan waktu reset.", + maxWaitThreshold: "Batas Tunggu Maksimal", + maxWaitDesc: "Jika semua akun terkena rate limit lebih lama dari ini, langsung gagal.", + saveConfigServer: "Simpan Konfigurasi", + serverRestartAlert: "Tersimpan ke {path}. Restart server untuk menerapkan.", + + // Password + changePassword: "Ubah Password WebUI", + changePasswordDesc: "Ubah password untuk akses dashboard ini", + currentPassword: "Password Saat Ini", + newPassword: "Password Baru", + confirmNewPassword: "Konfirmasi Password Baru", + passwordEmptyDesc: "Kosongkan jika belum ada password", + passwordLengthDesc: "Minimal 6 karakter", + passwordConfirmDesc: "Masukkan ulang password baru", + cancel: "Batal", + passwordsNotMatch: "Password tidak cocok", + passwordTooShort: "Password minimal 6 karakter", + + // Dashboard drill-down + clickToViewAllAccounts: "Klik untuk lihat semua akun", + clickToViewModels: "Klik untuk lihat halaman Model", + clickToViewLimitedAccounts: "Klik untuk lihat akun yang dibatasi", + clickToFilterClaude: "Klik untuk filter model Claude", + clickToFilterGemini: "Klik untuk filter model Gemini", + + // Accounts page + searchAccounts: "Cari akun...", + noAccountsYet: "Belum Ada Akun", + noAccountsDesc: "Mulai dengan menambahkan akun Google via OAuth, atau gunakan perintah CLI untuk import kredensial.", + addFirstAccount: "Tambah Akun Pertama", + noSearchResults: "Tidak ada akun yang cocok", + clearSearch: "Reset Pencarian", + disabledAccountsNote: "Akun nonaktif tidak akan digunakan untuk routing tapi tetap tersimpan di konfigurasi. Statistik dashboard hanya mencakup akun aktif.", + dangerousOperation: "⚠️ Operasi Berbahaya", + confirmDeletePrompt: "Yakin ingin menghapus akun", + deleteWarning: "⚠️ Tindakan ini tidak bisa dibatalkan. Semua pengaturan dan riwayat akan dihapus permanen.", + + // OAuth progress + oauthWaiting: "Menunggu otorisasi OAuth...", + oauthWaitingDesc: "Silakan selesaikan autentikasi di jendela popup. Proses ini bisa memakan waktu hingga 2 menit.", + oauthCancelled: "Otorisasi OAuth dibatalkan", + oauthTimeout: "⏱️ Waktu otorisasi OAuth habis. Silakan coba lagi.", + oauthWindowClosed: "Jendela OAuth ditutup. Otorisasi mungkin tidak lengkap.", + cancelOAuth: "Batal", + + // MCP CLI & Gemini 1M + mcpCliExperimental: "MCP CLI (Eksperimental)", + mcpCliDesc: "Aktifkan integrasi MCP eksperimental untuk penggunaan tool yang lebih stabil dengan konsumsi konteks lebih rendah.", + gemini1mMode: "Mode Konteks Gemini 1M", + gemini1mDesc: "Tambahkan suffix [1m] ke model Gemini untuk context window 1M.", + gemini1mWarning: "⚠ Konteks besar dapat menurunkan performa Gemini-3-Pro.", + clickToSet: "Klik untuk atur...", + + // Quota Distribution + quotaDistribution: "Distribusi Kuota", + resetsIn: "Reset dalam {time}", + noQuotaData: "Data kuota belum tersedia untuk akun ini.", + + // Completed TODOs + pageTitle: "Antigravity Console", + live: "Live", + tier: "Tier", + quota: "Kuota", + tierUltra: "Ultra", + tierPro: "Pro", + tierFree: "Gratis", + menu: "Menu", + github: "GitHub", + noData: "Tidak ada data", + fix: "Perbaiki", + + // Error Messages + operationFailed: "Operasi gagal", + unknownError: "Error tidak diketahui", + presetNameRequired: "Nama preset wajib diisi", + saveFailed: "Gagal menyimpan", + failedToSavePreset: "Gagal menyimpan preset", + noPresetSelected: "Tidak ada preset dipilih", + deletePresetConfirm: "Hapus preset \"{name}\"?", + deleteFailed: "Gagal menghapus", + failedToDeletePreset: "Gagal menghapus preset", + failedToChangePassword: "Gagal mengubah password", + passwordChangedSuccess: "Password berhasil diubah", + debugModeToggled: "Mode debug {status}", + tokenCacheToggled: "Cache token {status}", + failedToUpdateTokenCache: "Gagal memperbarui cache token", + failedToUpdateDebugMode: "Gagal memperbarui mode debug", + failedToRefreshAccount: "Gagal memperbarui akun", + failedToDeleteAccount: "Gagal menghapus akun", + failedToReloadAccounts: "Gagal memuat ulang akun", + failedToUpdateModelConfig: "Gagal memperbarui konfigurasi model", + fieldUpdated: "{displayName} diubah menjadi {value}", + failedToUpdateField: "Gagal memperbarui {displayName}", + + // Validation + mustBeValidNumber: "{fieldName} harus berupa angka valid", + mustBeAtLeast: "{fieldName} minimal {min}", + mustBeAtMost: "{fieldName} maksimal {max}", + cannotBeEmpty: "{fieldName} tidak boleh kosong", + mustBeTrueOrFalse: "Nilai harus true atau false", +}; diff --git a/public/js/translations/tr.js b/public/js/translations/tr.js new file mode 100644 index 0000000..746b083 --- /dev/null +++ b/public/js/translations/tr.js @@ -0,0 +1,316 @@ +/** + * Turkish (Türkçe) Translations + */ +window.translations = window.translations || {}; +window.translations.tr = { + dashboard: "Panel", + models: "Modeller", + accounts: "Hesaplar", + logs: "Günlükler", + settings: "Ayarlar", + online: "ÇEVRİMİÇİ", + offline: "ÇEVRİMDIŞI", + totalAccounts: "TOPLAM HESAP", + active: "AKTİF", + operational: "Çalışıyor", + rateLimited: "HIZ SINIRLANDI", + quotasDepleted: "{count}/{total} Kota Tükendi", + quotasDepletedTitle: "KOTA TÜKENDİ", + outOfTracked: "{total} Takip Edilen İçinden", + cooldown: "Soğuma", + searchPlaceholder: "Modelleri ara...", + allAccounts: "Tüm Hesaplar", + stat: "DURUM", + modelIdentity: "MODEL KİMLİĞİ", + globalQuota: "GENEL KOTA", + nextReset: "SONRAKİ SIFIRLAMA", + distribution: "HESAP DAĞILIMI", + systemConfig: "Sistem Yapılandırması", + language: "Dil", + pollingInterval: "Veri Güncelleme Aralığı", + maxDisplayLogs: "Maksimum Görüntülenen Günlük", + showExhausted: "Tükenmiş Modelleri Göster", + showExhaustedDesc: "%0 kotası kalan modelleri de göster.", + compactMode: "Kompakt Mod", + compactModeDesc: "Daha fazla bilgi göstermek için tablo boşluklarını azalt.", + saveChanges: "Değişiklikleri Kaydet", + autoScroll: "Otomatik Kaydır", + clearLogs: "Günlükleri Temizle", + accountManagement: "Hesap Yönetimi", + manageTokens: "Google Hesap jetonlarını ve yetkilendirme durumlarını yönet", + addAccount: "Hesap Ekle", + status: "DURUM", + enabled: "ETKİN", + health: "SAĞLIK", + accountEmail: "HESAP (E-POSTA)", + source: "KAYNAK", + projectId: "PROJE ID", + sessionState: "OTURUM DURUMU", + operations: "İŞLEMLER", + delete: "Sil", + confirmDelete: "Bu hesabı kaldırmak istediğinizden emin misiniz?", + cannotDeleteDatabase: "Silinemez: Bu hesap Antigravity veritabanından (salt okunur)", + connectGoogle: "Google Hesabı Bağla", + reauthenticated: "yeniden doğrulandı", + added: "eklendi", + successfully: "başarıyla", + accountAddedSuccess: "Hesap başarıyla eklendi", + accountReauthSuccess: "Hesap başarıyla yeniden doğrulandı", + failedToGetAuthUrl: "Yetkilendirme URL'si alınamadı", + failedToStartOAuth: "OAuth akışı başlatılamadı", + oauthInProgress: "OAuth devam ediyor. Lütfen açılır pencerede kimlik doğrulamayı tamamlayın...", + family: "Aile", + model: "Model", + activeSuffix: "Aktif", + manualReload: "Yapılandırmayı Yeniden Yükle", + // Tabs + tabInterface: "Arayüz", + tabClaude: "Claude CLI", + tabModels: "Modeller", + tabServer: "Sunucu Ayarları", + // Dashboard + linkedAccounts: "Bağlı Hesaplar", + noSignal: "SİNYAL YOK", + establishingUplink: "BAĞLANTI KURULUYOR...", + goToAccounts: "Hesaplara Git", + // Settings - Models + modelsDesc: "Model görünürlüğünü, sabitlemeyi ve istek yönlendirmeyi yapılandırın.", + modelsPageDesc: "Tüm mevcut modeller için gerçek zamanlı kota ve durum.", + showHidden: "Gizli Modelleri Göster", + hideHidden: "Gizli Modelleri Gizle", + hiddenOn: "Gizli: AÇIK", + hiddenOff: "Gizli: KAPALI", + modelId: "Model ID", + actions: "İşlemler", + pinToTop: "En Üste Sabitle", + toggleVisibility: "Görünürlüğü Değiştir", + noModels: "MODEL ALGILANMADI", + modelMappingHint: "Sunucu tarafı model yönlendirme. Claude Code kullanıcıları: istemci tarafı kurulumu için 'Claude CLI' sekmesine bakın.", + modelMapping: "Eşleştirme (Hedef Model ID)", + // Settings - Claude + proxyConnection: "Proxy Bağlantısı", + modelSelection: "Model Seçimi", + defaultModelAliases: "VARSAYILAN MODEL TAKMA ADLARI", + opusAlias: "Opus Takma Adı", + sonnetAlias: "Sonnet Takma Adı", + haikuAlias: "Haiku Takma Adı", + claudeSettingsAlertPrefix: "Aşağıdaki ayarlar doğrudan değiştirir", + claudeSettingsAlertSuffix: "Uygulamak için Claude CLI'yı yeniden başlatın.", + applyToClaude: "Claude CLI'ya Uygula", + // Settings - Server + port: "Port", + uiVersion: "Arayüz Sürümü", + debugMode: "Hata Ayıklama Modu", + environment: "Ortam", + serverReadOnly: "Ayarlar config.json üzerinden yönetilir. Değişiklikleri uygulamak için sunucuyu yeniden başlatın.", + advancedSettings: "Gelişmiş Ayarlar", + reloadConfigTitle: "Hesap Yapılandırmasını Yeniden Yükle", + reloadConfigDesc: "accounts.json dosyasını diskten yeniden yüklemeye zorla", + reload: "Yeniden Yükle", + // Config Specific + primaryModel: "Birincil Model", + subAgentModel: "Alt Ajan Modeli", + advancedOverrides: "Varsayılan Model Geçersiz Kılmaları", + opusModel: "Opus Modeli", + sonnetModel: "Sonnet Modeli", + haikuModel: "Haiku Modeli", + authToken: "Yetkilendirme Jetonu", + saveConfig: "Claude CLI ayarlarına kaydet", + envVar: "Ortam Değişkeni", + // New Keys + systemName: "ANTIGRAVITY", + systemDesc: "CLAUDE PROXY SİSTEMİ", + connectGoogleDesc: "API kota limitinizi artırmak için bir Google Workspace hesabı bağlayın. Bu hesap, Claude isteklerini Antigravity üzerinden vekil sunucu olarak kullanmak için kullanılacaktır.", + useCliCommand: "CLI Komutunu Kullan", + close: "Kapat", + requestVolume: "İstek Hacmi", + filter: "Filtrele", + all: "Tümü", + none: "Hiçbiri", + noDataTracked: "Henüz veri izlenmedi", + selectFamilies: "Görüntülenecek aileleri seçin", + selectModels: "Görüntülenecek modelleri seçin", + noLogsMatch: "Filtreyle eşleşen günlük yok", + connecting: "BAĞLANILIYOR", + main: "Ana", + system: "Sistem", + refreshData: "Verileri Yenile", + connectionLost: "Bağlantı Kaybedildi", + lastUpdated: "Son Güncelleme", + grepLogs: "günlükleri ara...", + noMatchingModels: "Eşleşen model yok", + typeToSearch: "Aramak veya seçmek için yazın...", + or: "VEYA", + refreshingAccount: "{email} yenileniyor...", + refreshedAccount: "{email} yenilendi", + refreshFailed: "Yenileme başarısız", + accountToggled: "Hesap {email} {status}", + toggleFailed: "Değiştirme başarısız", + reauthenticating: "{email} yeniden doğrulanıyor...", + authUrlFailed: "Yetkilendirme URL'si alınamadı", + deletedAccount: "{email} silindi", + deleteFailed: "Silme başarısız", + accountsReloaded: "Hesaplar yeniden yüklendi", + reloadFailed: "Yeniden yükleme başarısız", + claudeConfigSaved: "Claude yapılandırması kaydedildi", + claudeConfigRestored: "Claude CLI varsayılanlara geri yüklendi", + saveConfigFailed: "Yapılandırma kaydedilemedi", + restoreConfigFailed: "Yapılandırma geri yüklenemedi", + restoreDefault: "Varsayılana Dön", + confirmRestoreTitle: "Geri Yüklemeyi Onayla", + confirmRestoreMessage: "Claude CLI'yı varsayılan ayarlara geri yüklemek istediğinizden emin misiniz? Bu işlem proxy yapılandırmasını kaldıracaktır.", + confirmRestore: "Geri Yüklemeyi Onayla", + claudeActive: "Claude Aktif", + claudeEmpty: "Claude Boş", + geminiActive: "Gemini Aktif", + geminiEmpty: "Gemini Boş", + synced: "EŞİTLENDİ", + syncing: "EŞİTLENİYOR...", + // Time range labels + last1Hour: "Son 1S", + last6Hours: "Son 6S", + last24Hours: "Son 24S", + last7Days: "Son 7G", + allTime: "Tüm Zamanlar", + groupBy: "Gruplama Ölçütü", + // Additional + reloading: "Yeniden yükleniyor...", + reloaded: "Yeniden yüklendi", + lines: "satır", + enabledSeeLogs: "Etkin (Günlüklere Bak)", + production: "Üretim", + configSaved: "Yapılandırma Kaydedildi", + enterPassword: "Web UI Parolasını Girin:", + ready: "HAZIR", + depleted: "Tükendi", + timeH: "S", + timeM: "D", + familyClaude: "Claude", + familyGemini: "Gemini", + familyOther: "Diğer", + enabledStatus: "etkin", + disabledStatus: "devre dışı", + logLevelInfo: "BİLGİ", + logLevelSuccess: "BAŞARILI", + logLevelWarn: "UYARI", + logLevelError: "HATA", + totalColon: "Toplam:", + todayColon: "Bugün:", + hour1Colon: "1S:", + frequentModels: "Sık Kullanılan", + smartTitle: "En çok kullanılan 5 modeli otomatik seç (24s)", + activeCount: "{count} Aktif", + allCaps: "TÜMÜ", + claudeCaps: "CLAUDE", + geminiCaps: "GEMINI", + modelMapping: "Eşleştirme (Hedef Model ID)", + systemInfo: "Sistem Bilgisi", + refresh: "Yenile", + runtimeConfig: "Çalışma Zamanı Yapılandırması", + debugDesc: "Ayrıntılı günlük kaydını etkinleştir (Günlükler sekmesine bakın)", + networkRetry: "Ağ Yeniden Deneme Ayarları", + maxRetries: "Maksimum Deneme", + retryBaseDelay: "Yeniden Deneme Temel Gecikmesi (ms)", + retryMaxDelay: "Yeniden Deneme Maksimum Gecikmesi (ms)", + persistentSessions: "Kalıcı Oturumlar", + persistTokenDesc: "Daha hızlı yeniden başlatmalar için OAuth oturumlarını diske kaydet", + rateLimiting: "Hesap Hız Sınırlama ve Zaman Aşımları", + defaultCooldown: "Varsayılan Soğuma Süresi", + maxWaitThreshold: "Maksimum Bekleme Eşiği (Yapışkan)", + maxWaitDesc: "Yapışkan bir hesabın değiştirmeden önce sıfırlanması için beklenecek maksimum süre.", + saveConfigServer: "Yapılandırmayı Kaydet", + serverRestartAlert: "Değişiklikler {path} konumuna kaydedildi. Bazı ayarları uygulamak için sunucuyu yeniden başlatın.", + changePassword: "WebUI Parolasını Değiştir", + changePasswordDesc: "Bu panoya erişim parolasını güncelle", + currentPassword: "Mevcut Parola", + newPassword: "Yeni Parola", + confirmNewPassword: "Yeni Parolayı Onayla", + passwordEmptyDesc: "Parola ayarlanmamışsa boş bırakın", + passwordLengthDesc: "En az 6 karakter", + passwordConfirmDesc: "Yeni parolayı tekrar girin", + cancel: "İptal", + passwordsNotMatch: "Parolalar eşleşmiyor", + passwordTooShort: "Parola en az 6 karakter olmalıdır", + // Dashboard drill-down + clickToViewAllAccounts: "Tüm hesapları görüntülemek için tıklayın", + clickToViewModels: "Modeller sayfasını görüntülemek için tıklayın", + clickToViewLimitedAccounts: "Hız sınırı olan hesapları görüntülemek için tıklayın", + clickToFilterClaude: "Claude modellerini filtrelemek için tıklayın", + clickToFilterGemini: "Gemini modellerini filtrelemek için tıklayın", + // Accounts page + searchAccounts: "Hesap ara...", + noAccountsYet: "Henüz Hesap Yok", + noAccountsDesc: "OAuth üzerinden bir Google hesabı ekleyerek veya kimlik bilgilerini içe aktarmak için CLI komutunu kullanarak başlayın.", + addFirstAccount: "İlk Hesabınızı Ekleyin", + noSearchResults: "Aramanızla eşleşen hesap yok", + clearSearch: "Aramayı Temizle", + disabledAccountsNote: "Devre dışı bırakılan hesaplar istek yönlendirmesi için kullanılmayacak ancak yapılandırmada kalacaktır. Pano istatistikleri yalnızca etkin hesapları içerir.", + dangerousOperation: "⚠️ Tehlikeli İşlem", + confirmDeletePrompt: "Hesabı silmek istediğinizden emin misiniz", + deleteWarning: "⚠️ Bu işlem geri alınamaz. Tüm yapılandırma ve geçmiş kayıtları kalıcı olarak silinecektir.", + // OAuth progress + oauthWaiting: "OAuth yetkilendirmesi bekleniyor...", + oauthWaitingDesc: "Lütfen açılır pencerede kimlik doğrulamasını tamamlayın. Bu işlem 2 dakikaya kadar sürebilir.", + oauthCancelled: "OAuth yetkilendirmesi iptal edildi", + oauthTimeout: "⏱️ OAuth yetkilendirmesi zaman aşımına uğradı. Lütfen tekrar deneyin.", + oauthWindowClosed: "OAuth penceresi kapatıldı. Yetkilendirme tamamlanmamış olabilir.", + cancelOAuth: "İptal", + // MCP CLI & Gemini 1M + mcpCliExperimental: "Deneysel MCP CLI", + mcpCliDesc: "Daha az bağlam tüketimi ile güvenilir araç kullanımı için deneysel MCP entegrasyonunu etkinleştirir.", + gemini1mMode: "Gemini 1M Bağlam Modu", + gemini1mDesc: "1M bağlam penceresi desteği için Gemini modellerine [1m] son eki ekler.", + gemini1mWarning: "⚠ Büyük bağlam, Gemini-3-Pro performansını düşürebilir.", + clickToSet: "Yapılandırmak için tıklayın...", + none: "Hiçbiri", + // Quota Distribution + quotaDistribution: "Kota Dağılımı", + resetsIn: "{time} içinde sıfırlanır", + noQuotaData: "Bu hesap için henüz kota verisi yok.", + + // TODO: Missing translations - Hardcoded strings from HTML + // pageTitle: "Antigravity Console", + // live: "Live", + // tier: "Tier", + // quota: "Quota", + // tierUltra: "Ultra", + // tierPro: "Pro", + // tierFree: "Free", + // menu: "Menu", + // github: "GitHub", + // noData: "No data", + // fix: "Fix", + + // TODO: Missing translations - Hardcoded strings from JS (Error Messages) + // operationFailed: "Operation failed", + // unknownError: "Unknown error", + // presetNameRequired: "Preset name is required", + // saveFailed: "Save failed", + // failedToSavePreset: "Failed to save preset", + // noPresetSelected: "No preset selected", + // deletePresetConfirm: "Delete preset \"{name}\"?", + // deleteFailed: "Delete failed", + // failedToDeletePreset: "Failed to delete preset", + // failedToChangePassword: "Failed to change password", + // passwordChangedSuccess: "Password changed successfully", + // debugModeToggled: "Debug mode {status}", + // tokenCacheToggled: "Token cache {status}", + // failedToUpdateTokenCache: "Failed to update token cache", + // failedToUpdateDebugMode: "Failed to update debug mode", + // failedToRefreshAccount: "Failed to refresh account", + // failedToDeleteAccount: "Failed to delete account", + // failedToReloadAccounts: "Failed to reload accounts", + // failedToUpdateModelConfig: "Failed to update model config", + // fieldUpdated: "{displayName} updated to {value}", + // failedToUpdateField: "Failed to update {displayName}", + + // TODO: Missing translations - Validation messages from validators.js + // mustBeValidNumber: "{fieldName} must be a valid number", + // mustBeAtLeast: "{fieldName} must be at least {min}", + // mustBeAtMost: "{fieldName} must be at most {max}", + // cannotBeEmpty: "{fieldName} cannot be empty", + // mustBeTrueOrFalse: "Value must be true or false", + + // TODO: Missing translation - Server config (exists in EN but missing here) + // defaultCooldownDesc: "Fallback cooldown when API doesn't provide a reset time.", +}; diff --git a/public/js/translations/zh.js b/public/js/translations/zh.js new file mode 100644 index 0000000..e441c22 --- /dev/null +++ b/public/js/translations/zh.js @@ -0,0 +1,332 @@ +/** + * Chinese (中文) Translations + */ +window.translations = window.translations || {}; +window.translations.zh = { + dashboard: "仪表盘", + models: "模型列表", + accounts: "账号管理", + logs: "运行日志", + settings: "系统设置", + online: "在线", + offline: "离线", + totalAccounts: "账号总数", + active: "活跃状态", + operational: "运行中", + rateLimited: "受限状态", + quotasDepleted: "{count}/{total} 配额耗尽", + quotasDepletedTitle: "配额耗尽数", + outOfTracked: "共追踪 {total} 个", + cooldown: "冷却中", + searchPlaceholder: "搜索模型...", + allAccounts: "所有账号", + stat: "状态", + modelIdentity: "模型标识", + globalQuota: "全局配额", + nextReset: "重置时间", + distribution: "账号分布", + systemConfig: "系统配置", + language: "语言设置", + pollingInterval: "数据轮询间隔", + maxDisplayLogs: "最大日志显示行数", + showExhausted: "显示耗尽模型", + showExhaustedDesc: "即使配额为 0% 也显示模型。", + compactMode: "紧凑模式", + compactModeDesc: "减少表格间距以显示更多信息。", + saveChanges: "保存更改", + autoScroll: "自动滚动", + clearLogs: "清除日志", + accountManagement: "账号管理", + manageTokens: "管理已授权的 Google 账号及其状态", + addAccount: "添加账号", + status: "状态", + enabled: "启用", + health: "状态", + accountEmail: "账号 (邮箱)", + source: "来源", + projectId: "项目 ID", + sessionState: "会话状态", + operations: "操作", + delete: "删除", + confirmDelete: "确定要移除此账号吗?", + cannotDeleteDatabase: "无法删除:此账号来自 Antigravity 数据库(只读)", + connectGoogle: "连接 Google 账号", + reauthenticated: "已重新认证", + added: "已添加", + successfully: "成功", + accountAddedSuccess: "账号添加成功", + accountReauthSuccess: "账号重新认证成功", + failedToGetAuthUrl: "获取认证链接失败", + failedToStartOAuth: "启动 OAuth 流程失败", + oauthInProgress: "OAuth 授权进行中,请在弹出窗口中完成认证...", + family: "系列", + model: "模型", + activeSuffix: "活跃", + manualReload: "重新加载配置", + // Tabs + tabInterface: "界面设置", + tabClaude: "Claude CLI", + tabModels: "模型管理", + tabServer: "服务器设置", + // Dashboard + linkedAccounts: "已关联账号", + noSignal: "无信号连接", + establishingUplink: "正在建立上行链路...", + goToAccounts: "前往账号管理", + // Settings - Models + modelsDesc: "配置模型的可见性、置顶和请求路由。", + modelsPageDesc: "所有可用模型的实时配额和状态。", + showHidden: "显示隐藏模型", + hideHidden: "隐藏被屏蔽模型", + hiddenOn: "隐藏模型: 显示", + hiddenOff: "隐藏模型: 隐藏", + modelId: "模型 ID", + actions: "操作", + pinToTop: "置顶", + toggleVisibility: "切换可见性", + noModels: "未检测到模型", + modelMappingHint: "服务端模型路由功能。Claude Code 用户请使用 'Claude CLI' 标签页以便捷配置。", + modelMapping: "映射 (目标模型 ID)", + // Settings - Claude + proxyConnection: "代理连接", + modelSelection: "模型选择", + defaultModelAliases: "默认模型映射 (别名)", + opusAlias: "Opus 别名", + sonnetAlias: "Sonnet 别名", + haikuAlias: "Haiku 别名", + claudeSettingsAlertPrefix: "以下设置直接修改", + claudeSettingsAlertSuffix: "重启 Claude CLI 生效。", + applyToClaude: "应用到 Claude CLI", + // Presets + configPresets: "配置预设", + saveAsPreset: "另存为预设", + deletePreset: "删除预设", + loadPreset: "加载预设到表单", + load: "加载", + presetHint: "选择预设以加载。点击“应用到 Claude CLI”以保存更改。", + presetLoaded: "预设已加载。点击“应用到 Claude CLI”以保存。", + presetSaved: "预设已保存", + presetDeleted: "预设已删除", + unsavedChangesTitle: "未保存的更改", + unsavedChangesMessage: "当前配置与任何已保存的预设都不匹配。如果切换预设,当前未保存的设置将会丢失。", + loadAnyway: "仍然加载", + savePresetTitle: "保存预设", + savePresetDesc: "将当前配置保存为可重复使用的预设。", + presetName: "预设名称", + presetNamePlaceholder: "例如:工作配置", + savePreset: "保存预设", + // Settings - Server + port: "端口", + uiVersion: "UI 版本", + debugMode: "调试模式", + environment: "运行环境", + serverReadOnly: "配置由 config.json 管理。重启服务器以应用更改。", + advancedSettings: "高级设置", + reloadConfigTitle: "重载账号配置", + reloadConfigDesc: "强制从磁盘重新读取 accounts.json", + reload: "重载", + // Config Specific + primaryModel: "主模型", + subAgentModel: "子代理模型", + advancedOverrides: "默认模型覆盖 (高级)", + opusModel: "Opus 模型", + sonnetModel: "Sonnet 模型", + haikuModel: "Haiku 模型", + authToken: "认证令牌", + saveConfig: "保存到 Claude CLI 设置", + envVar: "环境变量", + // New Keys + systemName: "ANTIGRAVITY", + systemDesc: "CLAUDE 代理系统", + connectGoogleDesc: "连接 Google Workspace 账号以增加 API 配额。该账号将用于通过 Antigravity 代理 Claude 请求。", + useCliCommand: "使用命令行", + close: "关闭", + requestVolume: "请求量", + filter: "筛选", + all: "全选", + none: "清空", + noDataTracked: "暂无追踪数据", + selectFamilies: "选择要显示的系列", + selectModels: "选择要显示的模型", + noLogsMatch: "没有符合过滤条件的日志", + connecting: "正在连接", + main: "主菜单", + system: "系统", + refreshData: "刷新数据", + connectionLost: "连接已断开", + lastUpdated: "最后更新", + grepLogs: "过滤日志...", + noMatchingModels: "没有匹配的模型", + typeToSearch: "输入以搜索或选择...", + or: "或", + refreshingAccount: "正在刷新 {email}...", + refreshedAccount: "已完成刷新 {email}", + refreshFailed: "刷新失败", + accountToggled: "账号 {email} 已{status}", + toggleFailed: "切换失败", + reauthenticating: "正在重新认证 {email}...", + authUrlFailed: "获取认证链接失败", + deletedAccount: "已删除 {email}", + deleteFailed: "删除失败", + accountsReloaded: "账号配置已重载", + reloadFailed: "重载失败", + claudeConfigSaved: "Claude 配置已保存", + claudeConfigRestored: "Claude CLI 已恢复默认设置", + saveConfigFailed: "保存配置失败", + restoreConfigFailed: "恢复配置失败", + restoreDefault: "恢复默认", + confirmRestoreTitle: "确认恢复", + confirmRestoreMessage: "确定要将 Claude CLI 恢复为默认设置吗?这将移除代理配置。", + confirmRestore: "确认恢复", + claudeActive: "Claude 活跃", + claudeEmpty: "Claude 耗尽", + geminiActive: "Gemini 活跃", + geminiEmpty: "Gemini 耗尽", + synced: "已同步", + syncing: "正在同步...", + // 时间范围标签 + last1Hour: "最近 1 小时", + last6Hours: "最近 6 小时", + last24Hours: "最近 24 小时", + last7Days: "最近 7 天", + allTime: "最后全部", + groupBy: "分组方式", + // Additional + reloading: "正在重载...", + reloaded: "已重载", + lines: "行", + enabledSeeLogs: "已启用 (见日志)", + production: "生产环境", + configSaved: "配置已保存", + enterPassword: "请输入 Web UI 密码:", + ready: "就绪", + depleted: "已耗尽", + timeH: "时", + timeM: "分", + familyClaude: "Claude 系列", + familyGemini: "Gemini 系列", + familyOther: "其他系列", + enabledStatus: "已启用", + disabledStatus: "已禁用", + logLevelInfo: "信息", + logLevelSuccess: "成功", + logLevelWarn: "警告", + logLevelError: "错误", + totalColon: "总计:", + todayColon: "今日:", + hour1Colon: "1小时:", + frequentModels: "常用推荐", + smartTitle: "自动选出过去 24 小时最常用的 5 个模型", + activeCount: "{count} 活跃", + allCaps: "全部", + claudeCaps: "CLAUDE", + geminiCaps: "GEMINI", + modelMapping: "映射 (目标模型 ID)", + systemInfo: "系统信息", + refresh: "刷新", + runtimeConfig: "运行时配置", + debugDesc: "启用详细日志记录 (见运行日志)", + networkRetry: "网络重试设置", + maxRetries: "最大重试次数", + retryBaseDelay: "重试基础延迟 (毫秒)", + retryMaxDelay: "重试最大延迟 (毫秒)", + persistentSessions: "持久化登录会话", + persistTokenDesc: "将登录会话保存到磁盘以实现快速重启", + rateLimiting: "账号限流与超时", + defaultCooldown: "默认冷却时间", + defaultCooldownDesc: "当 API 未提供重置时间时的备用冷却时间。", + maxWaitThreshold: "最大等待阈值", + maxWaitDesc: "如果所有账号的限流时间超过此阈值,立即返回错误而非等待。", + saveConfigServer: "保存配置", + serverRestartAlert: "配置已保存至 {path}。部分更改可能需要重启服务器。", + changePassword: "修改 WebUI 密码", + changePasswordDesc: "更新访问此仪表盘的密码", + currentPassword: "当前密码", + newPassword: "新密码", + confirmNewPassword: "确认新密码", + passwordEmptyDesc: "如果未设置密码请留空", + passwordLengthDesc: "至少 6 个字符", + passwordConfirmDesc: "请再次输入新密码", + cancel: "取消", + passwordsNotMatch: "密码不匹配", + passwordTooShort: "密码至少需要 6 个字符", + // Dashboard drill-down + clickToViewAllAccounts: "点击查看所有账号", + clickToViewModels: "点击查看模型页面", + clickToViewLimitedAccounts: "点击查看受限账号", + clickToFilterClaude: "点击筛选 Claude 模型", + clickToFilterGemini: "点击筛选 Gemini 模型", + // 账号页面 + searchAccounts: "搜索账号...", + noAccountsYet: "还没有添加任何账号", + noAccountsDesc: "点击上方的 \"添加账号\" 按钮通过 OAuth 添加 Google 账号,或者使用 CLI 命令导入凭证。", + addFirstAccount: "添加第一个账号", + noSearchResults: "没有找到匹配的账号", + clearSearch: "清除搜索", + disabledAccountsNote: "已禁用的账号不会用于请求路由,但仍保留在配置中。仪表盘统计数据仅包含已启用的账号。", + dangerousOperation: "⚠️ 危险操作", + confirmDeletePrompt: "确定要删除账号", + deleteWarning: "⚠️ 此操作不可撤销,账号的所有配置和历史记录将永久删除。", + // OAuth 进度 + oauthWaiting: "等待 OAuth 授权中...", + oauthWaitingDesc: "请在弹出窗口中完成认证。此过程最长可能需要 2 分钟。", + oauthCancelled: "已取消 OAuth 授权", + oauthTimeout: "⏱️ OAuth 授权超时,请重试。", + oauthWindowClosed: "OAuth 窗口已关闭,授权可能未完成。", + cancelOAuth: "取消", + // MCP CLI & Gemini 1M + mcpCliExperimental: "实验性 MCP CLI", + mcpCliDesc: "启用实验性 MCP 集成,减少上下文消耗,提高工具调用可靠性。", + gemini1mMode: "Gemini 1M 上下文模式", + gemini1mDesc: "为 Gemini 模型添加 [1m] 后缀以支持 1M 上下文窗口。", + gemini1mWarning: "⚠ 大上下文可能降低 Gemini-3-Pro 性能。", + clickToSet: "点击进行配置...", + none: "无", + // Quota Distribution + quotaDistribution: "配额分布", + resetsIn: "{time} 后重置", + noQuotaData: "暂无此账号的配额数据。", + + // TODO: Missing translations - Hardcoded strings from HTML + // pageTitle: "Antigravity Console", + // live: "Live", + // tier: "Tier", + // quota: "Quota", + // tierUltra: "Ultra", + // tierPro: "Pro", + // tierFree: "Free", + // menu: "Menu", + // github: "GitHub", + // noData: "No data", + // fix: "Fix", + + // TODO: Missing translations - Hardcoded strings from JS (Error Messages) + // operationFailed: "Operation failed", + // unknownError: "Unknown error", + // presetNameRequired: "Preset name is required", + // saveFailed: "Save failed", + // failedToSavePreset: "Failed to save preset", + // noPresetSelected: "No preset selected", + // deletePresetConfirm: "Delete preset \"{name}\"?", + // deleteFailed: "Delete failed", + // failedToDeletePreset: "Failed to delete preset", + // failedToChangePassword: "Failed to change password", + // passwordChangedSuccess: "Password changed successfully", + // debugModeToggled: "Debug mode {status}", + // tokenCacheToggled: "Token cache {status}", + // failedToUpdateTokenCache: "Failed to update token cache", + // failedToUpdateDebugMode: "Failed to update debug mode", + // failedToRefreshAccount: "Failed to refresh account", + // failedToDeleteAccount: "Failed to delete account", + // failedToReloadAccounts: "Failed to reload accounts", + // failedToUpdateModelConfig: "Failed to update model config", + // fieldUpdated: "{displayName} updated to {value}", + // failedToUpdateField: "Failed to update {displayName}", + + // TODO: Missing translations - Validation messages from validators.js + // mustBeValidNumber: "{fieldName} must be a valid number", + // mustBeAtLeast: "{fieldName} must be at least {min}", + // mustBeAtMost: "{fieldName} must be at most {max}", + // cannotBeEmpty: "{fieldName} cannot be empty", + // mustBeTrueOrFalse: "Value must be true or false", +}; diff --git a/public/js/utils/account-actions.js b/public/js/utils/account-actions.js index d2757ff..e75db80 100644 --- a/public/js/utils/account-actions.js +++ b/public/js/utils/account-actions.js @@ -26,7 +26,7 @@ window.AccountActions.refreshAccount = async function(email) { const data = await response.json(); if (data.status !== 'ok') { - return { success: false, error: data.error || 'Refresh failed' }; + return { success: false, error: data.error || Alpine.store('global').t('refreshFailed') }; } // 触发数据刷新 @@ -73,7 +73,7 @@ window.AccountActions.toggleAccount = async function(email, enabled) { const data = await response.json(); if (data.status !== 'ok') { - throw new Error(data.error || 'Toggle failed'); + throw new Error(data.error || Alpine.store('global').t('toggleFailed')); } // 确认服务器状态 @@ -111,7 +111,7 @@ window.AccountActions.deleteAccount = async function(email) { const data = await response.json(); if (data.status !== 'ok') { - return { success: false, error: data.error || 'Delete failed' }; + return { success: false, error: data.error || Alpine.store('global').t('deleteFailed') }; } // 触发数据刷新 @@ -146,7 +146,7 @@ window.AccountActions.getFixAccountUrl = async function(email) { const data = await response.json(); if (data.status !== 'ok') { - return { success: false, error: data.error || 'Failed to get auth URL' }; + return { success: false, error: data.error || Alpine.store('global').t('authUrlFailed') }; } return { success: true, url: data.url }; @@ -176,7 +176,7 @@ window.AccountActions.reloadAccounts = async function() { const data = await response.json(); if (data.status !== 'ok') { - return { success: false, error: data.error || 'Reload failed' }; + return { success: false, error: data.error || Alpine.store('global').t('reloadFailed') }; } // 触发数据刷新 diff --git a/public/js/utils/error-handler.js b/public/js/utils/error-handler.js index 0835357..a44b76a 100644 --- a/public/js/utils/error-handler.js +++ b/public/js/utils/error-handler.js @@ -13,18 +13,19 @@ window.ErrorHandler = window.ErrorHandler || {}; * @param {Function} options.onError - Custom error handler callback * @returns {Promise} Result of the function or undefined on error */ -window.ErrorHandler.safeAsync = async function(fn, errorMessage = 'Operation failed', options = {}) { +window.ErrorHandler.safeAsync = async function(fn, errorMessage = null, options = {}) { const { rethrow = false, onError = null } = options; const store = Alpine.store('global'); + const defaultErrorMessage = errorMessage || store.t('operationFailed'); try { return await fn(); } catch (error) { // Log error for debugging - console.error(`[ErrorHandler] ${errorMessage}:`, error); + console.error(`[ErrorHandler] ${defaultErrorMessage}:`, error); // Show toast notification - const fullMessage = `${errorMessage}: ${error.message || 'Unknown error'}`; + const fullMessage = `${defaultErrorMessage}: ${error.message || store.t('unknownError')}`; store.showToast(fullMessage, 'error'); // Call custom error handler if provided @@ -51,11 +52,11 @@ window.ErrorHandler.safeAsync = async function(fn, errorMessage = 'Operation fai * @param {string} errorMessage - Error message prefix * @returns {Function} Wrapped method */ -window.ErrorHandler.wrapMethod = function(method, errorMessage = 'Operation failed') { +window.ErrorHandler.wrapMethod = function(method, errorMessage = null) { return async function(...args) { return window.ErrorHandler.safeAsync( () => method.apply(this, args), - errorMessage + errorMessage || Alpine.store('global').t('operationFailed') ); }; }; diff --git a/public/js/utils/model-config.js b/public/js/utils/model-config.js index 46a2cc7..0a9577a 100644 --- a/public/js/utils/model-config.js +++ b/public/js/utils/model-config.js @@ -26,7 +26,7 @@ window.ModelConfigUtils.updateModelConfig = async function(modelId, configUpdate } if (!response.ok) { - throw new Error('Failed to update model config'); + throw new Error(store.t('failedToUpdateModelConfig')); } // Optimistic update of local state @@ -38,5 +38,5 @@ window.ModelConfigUtils.updateModelConfig = async function(modelId, configUpdate // Recompute quota rows to reflect changes dataStore.computeQuotaRows(); - }, 'Failed to update model config'); + }, Alpine.store('global').t('failedToUpdateModelConfig')); }; diff --git a/public/js/utils/validators.js b/public/js/utils/validators.js index cedbb2f..b8cd3bb 100644 --- a/public/js/utils/validators.js +++ b/public/js/utils/validators.js @@ -14,12 +14,13 @@ window.Validators = window.Validators || {}; */ window.Validators.validateRange = function(value, min, max, fieldName = 'Value') { const numValue = Number(value); + const t = Alpine.store('global').t; if (isNaN(numValue)) { return { isValid: false, value: min, - error: `${fieldName} must be a valid number` + error: t('mustBeValidNumber', { fieldName }) }; } @@ -27,7 +28,7 @@ window.Validators.validateRange = function(value, min, max, fieldName = 'Value') return { isValid: false, value: min, - error: `${fieldName} must be at least ${min}` + error: t('mustBeAtLeast', { fieldName, min }) }; } @@ -35,7 +36,7 @@ window.Validators.validateRange = function(value, min, max, fieldName = 'Value') return { isValid: false, value: max, - error: `${fieldName} must be at most ${max}` + error: t('mustBeAtMost', { fieldName, max }) }; } @@ -64,12 +65,13 @@ window.Validators.validatePort = function(port) { */ window.Validators.validateNotEmpty = function(value, fieldName = 'Field') { const trimmedValue = String(value || '').trim(); + const t = Alpine.store('global').t; if (trimmedValue.length === 0) { return { isValid: false, value: trimmedValue, - error: `${fieldName} cannot be empty` + error: t('cannotBeEmpty', { fieldName }) }; } @@ -106,7 +108,7 @@ window.Validators.validateBoolean = function(value) { return { isValid: false, value: false, - error: 'Value must be true or false' + error: Alpine.store('global').t('mustBeTrueOrFalse') }; }; diff --git a/public/views/accounts.html b/public/views/accounts.html index b06616d..7362c11 100644 --- a/public/views/accounts.html +++ b/public/views/accounts.html @@ -57,8 +57,8 @@ Enabled Account (Email) Source - Tier - Quota + Tier + Quota Health Operations @@ -265,7 +265,7 @@ @@ -323,7 +323,7 @@ \ No newline at end of file diff --git a/public/views/dashboard.html b/public/views/dashboard.html index 25e9b0e..851ce85 100644 --- a/public/views/dashboard.html +++ b/public/views/dashboard.html @@ -20,7 +20,7 @@ - Live + Live @@ -78,17 +78,17 @@
diff --git a/public/views/models.html b/public/views/models.html index 4d99935..08f1b47 100644 --- a/public/views/models.html +++ b/public/views/models.html @@ -213,7 +213,7 @@