From bceed08fc32d0b8d528fbf94c480e6e38aadcd76 Mon Sep 17 00:00:00 2001 From: ianshaw Date: Thu, 25 Dec 2025 08:40:35 -0800 Subject: [PATCH] =?UTF-8?q?feat(frontend):=20=E6=B7=BB=E5=8A=A0=20Gemini?= =?UTF-8?q?=20=E5=B9=B3=E5=8F=B0=E5=9B=BD=E9=99=85=E5=8C=96=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增中文 Gemini OAuth 相关翻译(步骤说明、错误提示等) - 新增英文 Gemini OAuth 相关翻译 - 添加 Gemini 账号类型、平台名称等基础翻译 - 优化代码格式 --- frontend/src/i18n/index.ts | 6 +- frontend/src/i18n/locales/en.ts | 145 ++++++++++++++++---------- frontend/src/i18n/locales/zh.ts | 174 +++++++++++++++++++------------- 3 files changed, 197 insertions(+), 128 deletions(-) diff --git a/frontend/src/i18n/index.ts b/frontend/src/i18n/index.ts index 4904e07c..298263a7 100644 --- a/frontend/src/i18n/index.ts +++ b/frontend/src/i18n/index.ts @@ -26,8 +26,8 @@ export const i18n = createI18n({ fallbackLocale: 'en', messages: { en, - zh, - }, + zh + } }) export function setLocale(locale: string) { @@ -44,7 +44,7 @@ export function getLocale(): string { export const availableLocales = [ { code: 'en', name: 'English', flag: '🇺🇸' }, - { code: 'zh', name: '中文', flag: '🇨🇳' }, + { code: 'zh', name: '中文', flag: '🇨🇳' } ] export default i18n diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts index 27fcec8c..031923a1 100644 --- a/frontend/src/i18n/locales/en.ts +++ b/frontend/src/i18n/locales/en.ts @@ -13,7 +13,7 @@ export default { tags: { subscriptionToApi: 'Subscription to API', stickySession: 'Sticky Session', - realtimeBilling: 'Real-time Billing', + realtimeBilling: 'Real-time Billing' }, features: { unifiedGateway: 'Unified API Gateway', @@ -24,17 +24,17 @@ export default { 'Manage multiple upstream accounts with smart load balancing. Support OAuth and API Key authentication.', balanceQuota: 'Balance & Quota', balanceQuotaDesc: - 'Token-based billing with precise usage tracking. Manage quotas and recharge with redeem codes.', + 'Token-based billing with precise usage tracking. Manage quotas and recharge with redeem codes.' }, providers: { title: 'Supported Providers', description: 'Unified API interface for AI services', supported: 'Supported', - soon: 'Soon', + soon: 'Soon' }, footer: { - allRightsReserved: 'All rights reserved.', - }, + allRightsReserved: 'All rights reserved.' + } }, // Common @@ -84,7 +84,7 @@ export default { searchPlaceholder: 'Search...', noOptionsFound: 'No options found', saving: 'Saving...', - refresh: 'Refresh', + refresh: 'Refresh' }, // Navigation @@ -108,7 +108,7 @@ export default { expand: 'Expand', logout: 'Logout', github: 'GitHub', - mySubscriptions: 'My Subscriptions', + mySubscriptions: 'My Subscriptions' }, // Auth @@ -142,7 +142,7 @@ export default { accountCreatedSuccess: 'Account created successfully! Welcome to {siteName}.', turnstileExpired: 'Verification expired, please try again', turnstileFailed: 'Verification failed, please try again', - completeVerification: 'Please complete the verification', + completeVerification: 'Please complete the verification' }, // Dashboard @@ -185,12 +185,12 @@ export default { viewUsage: 'View Usage', checkDetailedLogs: 'Check detailed usage logs', redeemCode: 'Redeem Code', - addBalanceWithCode: 'Add balance with a code', + addBalanceWithCode: 'Add balance with a code' }, // Groups (shared) groups: { - subscription: 'Sub', + subscription: 'Sub' }, // API Keys @@ -257,7 +257,7 @@ export default { customKeyHint: 'Only letters, numbers, underscores and hyphens allowed. Minimum 16 characters.', customKeyTooShort: 'Custom key must be at least 16 characters', customKeyInvalidChars: 'Custom key can only contain letters, numbers, underscores, and hyphens', - customKeyRequired: 'Please enter a custom key', + customKeyRequired: 'Please enter a custom key' }, // Usage @@ -298,7 +298,7 @@ export default { exportSuccess: 'Usage data exported successfully', billingType: 'Billing', balance: 'Balance', - subscription: 'Subscription', + subscription: 'Subscription' }, // Redeem @@ -338,7 +338,7 @@ export default { subscriptionDays: '{days} days', days: ' days', codeRedeemSuccess: 'Code redeemed successfully!', - failedToRedeem: 'Failed to redeem code. Please check the code and try again.', + failedToRedeem: 'Failed to redeem code. Please check the code and try again.' }, // Profile @@ -369,12 +369,12 @@ export default { passwordsNotMatch: 'New passwords do not match', passwordTooShort: 'Password must be at least 8 characters long', passwordChangeSuccess: 'Password changed successfully', - passwordChangeFailed: 'Failed to change password', + passwordChangeFailed: 'Failed to change password' }, // Empty States empty: { - noData: 'No data found', + noData: 'No data found' }, // Pagination @@ -388,7 +388,7 @@ export default { previous: 'Previous', next: 'Next', perPage: 'Per page', - goToPage: 'Go to page {page}', + goToPage: 'Go to page {page}' }, // Errors @@ -400,7 +400,7 @@ export default { serverError: 'Server error', networkError: 'Network error', timeout: 'Request timeout', - tryAgain: 'Please try again', + tryAgain: 'Please try again' }, // Dates @@ -418,7 +418,7 @@ export default { startDate: 'Start Date', endDate: 'End Date', apply: 'Apply', - selectDateRange: 'Select date range', + selectDateRange: 'Select date range' }, // Admin @@ -455,7 +455,7 @@ export default { actual: 'Actual', standard: 'Standard', noDataAvailable: 'No data available', - failedToLoad: 'Failed to load dashboard statistics', + failedToLoad: 'Failed to load dashboard statistics' }, // Users @@ -500,7 +500,7 @@ export default { concurrency: 'Concurrency', status: 'Status', created: 'Created', - actions: 'Actions', + actions: 'Actions' }, today: 'Today', total: 'Total', @@ -558,7 +558,7 @@ export default { failedToDeposit: 'Failed to deposit', failedToWithdraw: 'Failed to withdraw', useDepositWithdrawButtons: 'Please use deposit/withdraw buttons to adjust balance', - insufficientBalance: 'Insufficient balance, balance cannot be negative after withdrawal', + insufficientBalance: 'Insufficient balance, balance cannot be negative after withdrawal' }, // Groups @@ -582,7 +582,7 @@ export default { accounts: 'Accounts', status: 'Status', actions: 'Actions', - billingType: 'Billing Type', + billingType: 'Billing Type' }, accountsCount: '{count} accounts', form: { @@ -590,7 +590,7 @@ export default { description: 'Description', platform: 'Platform', rateMultiplier: 'Rate Multiplier', - status: 'Status', + status: 'Status' }, enterGroupName: 'Enter group name', optionalDescription: 'Optional description', @@ -629,8 +629,8 @@ export default { monthlyLimit: 'Monthly Limit (USD)', defaultValidityDays: 'Default Validity (Days)', validityHint: 'Number of days the subscription is valid when assigned to a user', - noLimit: 'No limit', - }, + noLimit: 'No limit' + } }, // Subscriptions @@ -656,7 +656,7 @@ export default { status: { active: 'Active', expired: 'Expired', - revoked: 'Revoked', + revoked: 'Revoked' }, columns: { user: 'User', @@ -664,13 +664,13 @@ export default { usage: 'Usage', expires: 'Expires', status: 'Status', - actions: 'Actions', + actions: 'Actions' }, form: { user: 'User', group: 'Subscription Group', validityDays: 'Validity (Days)', - extendDays: 'Extend by (Days)', + extendDays: 'Extend by (Days)' }, selectUser: 'Select a user', selectGroup: 'Select a subscription group', @@ -693,7 +693,7 @@ export default { failedToExtend: 'Failed to extend subscription', failedToRevoke: 'Failed to revoke subscription', revokeConfirm: - "Are you sure you want to revoke the subscription for '{user}'? This action cannot be undone.", + "Are you sure you want to revoke the subscription for '{user}'? This action cannot be undone." }, // Accounts @@ -740,6 +740,7 @@ export default { anthropic: 'Anthropic', claude: 'Claude', openai: 'OpenAI', + gemini: 'Gemini' }, columns: { name: 'Name', @@ -754,7 +755,7 @@ export default { usageWindows: 'Usage Windows', priority: 'Priority', lastUsed: 'Last Used', - actions: 'Actions', + actions: 'Actions' }, clearRateLimit: 'Clear Rate Limit', testConnection: 'Test Connection', @@ -770,7 +771,7 @@ export default { selectCurrentPage: 'Select this page', clear: 'Clear selection', edit: 'Bulk Edit', - delete: 'Bulk Delete', + delete: 'Bulk Delete' }, bulkEdit: { title: 'Bulk Edit Accounts', @@ -784,7 +785,7 @@ export default { partialSuccess: 'Partially updated: {success} succeeded, {failed} failed', failed: 'Bulk update failed', noSelection: 'Please select accounts to edit', - noFieldsSelected: 'Select at least one field to update', + noFieldsSelected: 'Select at least one field to update' }, bulkDeleteTitle: 'Bulk Delete Accounts', bulkDeleteConfirm: 'Delete the selected {count} account(s)? This action cannot be undone.', @@ -919,13 +920,49 @@ export default { authCodePlaceholder: 'Option 1: Copy the complete URL\n(http://localhost:xxx/auth/callback?code=...)\nOption 2: Copy only the code parameter value', authCodeHint: - 'You can copy the entire URL or just the code parameter value, the system will auto-detect', + 'You can copy the entire URL or just the code parameter value, the system will auto-detect' }, + // Gemini specific + gemini: { + title: 'Gemini Account Authorization', + followSteps: 'Follow these steps to authorize your Gemini account:', + step1GenerateUrl: 'Generate the authorization URL (requires a redirect URI)', + generateAuthUrl: 'Generate Auth URL', + step2OpenUrl: 'Open the URL in your browser and complete authorization', + openUrlDesc: + 'Open the authorization URL in a new tab, log in to your Google account and authorize.', + step3EnterCode: 'Enter Authorization URL or Code', + authCodeDesc: + 'After authorization, you will be redirected to the redirect URI with code and state. Paste the full URL or just the code below:', + authCode: 'Authorization URL or Code', + authCodePlaceholder: + 'Option 1: Paste the complete callback URL\n(https://your-domain/auth/callback?code=...&state=...)\nOption 2: Paste only the code value', + authCodeHint: + 'If you paste the full URL, the system will auto-extract code/state for you', + redirectUri: 'Redirect URI', + redirectUriHint: + 'This must be configured in your Google OAuth client and must match exactly.', + confirmRedirectUri: + 'I have configured this Redirect URI in the Google OAuth client (must match exactly)', + invalidRedirectUri: 'Redirect URI must be a valid http(s) URL', + redirectUriNotConfirmed: 'Please confirm the Redirect URI is configured correctly', + missingRedirectUri: 'Missing redirect URI', + failedToGenerateUrl: 'Failed to generate Gemini auth URL', + missingExchangeParams: 'Missing auth code, session ID, state, or redirect URI', + failedToExchangeCode: 'Failed to exchange Gemini auth code', + modelPassthrough: 'Gemini Model Passthrough', + modelPassthroughDesc: + 'All model requests are forwarded directly to the Gemini API without model restrictions or mappings.', + stateWarningTitle: '⚠️ Important: Gemini requires both code and state', + stateWarningDesc: + 'We recommend pasting the complete callback URL so the system can auto-extract both code and state. Pasting only the code will cause authorization to fail.' + } }, // Re-Auth Modal reAuthorizeAccount: 'Re-Authorize Account', claudeCodeAccount: 'Claude Code Account', openaiAccount: 'OpenAI Account', + geminiAccount: 'Gemini Account', inputMethod: 'Input Method', reAuthorizedSuccess: 'Account re-authorized successfully', // Test Modal @@ -979,8 +1016,8 @@ export default { todayTokens: 'Today Tokens', todayCost: 'Today Cost', usageTrend: '30-Day Cost & Request Trend', - noData: 'No usage data available for this account', - }, + noData: 'No usage data available for this account' + } }, // Proxies @@ -998,7 +1035,7 @@ export default { protocol: 'Protocol', address: 'Address', status: 'Status', - actions: 'Actions', + actions: 'Actions' }, testConnection: 'Test Connection', batchTest: 'Test All Proxies', @@ -1046,7 +1083,7 @@ export default { failedToDelete: 'Failed to delete proxy', failedToTest: 'Failed to test proxy', deleteConfirm: - "Are you sure you want to delete '{name}'? Accounts using this proxy will have their proxy removed.", + "Are you sure you want to delete '{name}'? Accounts using this proxy will have their proxy removed." }, // Redeem Codes @@ -1069,7 +1106,7 @@ export default { status: 'Status', usedBy: 'Used By', usedAt: 'Used At', - actions: 'Actions', + actions: 'Actions' }, userPrefix: 'User #{id}', exportCsv: 'Export CSV', @@ -1106,7 +1143,7 @@ export default { selectGroupPlaceholder: 'Choose a subscription group', validityDays: 'Validity Days', groupRequired: 'Please select a subscription group', - days: ' days', + days: ' days' }, // Usage Records @@ -1117,7 +1154,7 @@ export default { searchUserPlaceholder: 'Search user by email...', selectedUser: 'Selected', user: 'User', - failedToLoad: 'Failed to load usage records', + failedToLoad: 'Failed to load usage records' }, // Settings @@ -1130,7 +1167,7 @@ export default { enableRegistration: 'Enable Registration', enableRegistrationHint: 'Allow new users to register', emailVerification: 'Email Verification', - emailVerificationHint: 'Require email verification for new registrations', + emailVerificationHint: 'Require email verification for new registrations' }, turnstile: { title: 'Cloudflare Turnstile', @@ -1140,7 +1177,7 @@ export default { siteKey: 'Site Key', secretKey: 'Secret Key', siteKeyHint: 'Get this from your Cloudflare Dashboard', - secretKeyHint: 'Server-side verification key (keep this secret)', + secretKeyHint: 'Server-side verification key (keep this secret)' }, defaults: { title: 'Default User Settings', @@ -1148,7 +1185,7 @@ export default { defaultBalance: 'Default Balance', defaultBalanceHint: 'Initial balance for new users', defaultConcurrency: 'Default Concurrency', - defaultConcurrencyHint: 'Maximum concurrent requests for new users', + defaultConcurrencyHint: 'Maximum concurrent requests for new users' }, site: { title: 'Site Settings', @@ -1171,7 +1208,7 @@ export default { logoHint: 'PNG, JPG, or SVG. Max 300KB. Recommended: 80x80px square image.', logoSizeError: 'Image size exceeds 300KB limit ({size}KB)', logoTypeError: 'Please select an image file', - logoReadError: 'Failed to read the image file', + logoReadError: 'Failed to read the image file' }, smtp: { title: 'SMTP Settings', @@ -1186,7 +1223,7 @@ export default { fromEmail: 'From Email', fromName: 'From Name', useTls: 'Use TLS', - useTlsHint: 'Enable TLS encryption for SMTP connection', + useTlsHint: 'Enable TLS encryption for SMTP connection' }, testEmail: { title: 'Send Test Email', @@ -1194,7 +1231,7 @@ export default { recipientEmail: 'Recipient Email', sendTestEmail: 'Send Test Email', sending: 'Sending...', - enterRecipientHint: 'Please enter a recipient email address', + enterRecipientHint: 'Please enter a recipient email address' }, adminApiKey: { title: 'Admin API Key', @@ -1217,7 +1254,7 @@ export default { keyCopied: 'Key copied to clipboard', keyWarning: 'This key will only be shown once. Please copy it now.', securityWarning: 'Warning: This key provides full admin access. Keep it secure.', - usage: 'Usage: Add to request header - x-api-key: ', + usage: 'Usage: Add to request header - x-api-key: ' }, saveSettings: 'Save Settings', saving: 'Saving...', @@ -1227,8 +1264,8 @@ export default { failedToLoad: 'Failed to load settings', failedToSave: 'Failed to save settings', failedToTestSmtp: 'SMTP connection test failed', - failedToSendTestEmail: 'Failed to send test email', - }, + failedToSendTestEmail: 'Failed to send test email' + } }, // Subscription Progress (Header component) @@ -1244,7 +1281,7 @@ export default { expiresToday: 'Expires today', expiresTomorrow: 'Expires tomorrow', viewAll: 'View all subscriptions', - noSubscriptions: 'No active subscriptions', + noSubscriptions: 'No active subscriptions' }, // Version Badge @@ -1268,7 +1305,7 @@ export default { restartRequired: 'Please restart the service to apply the update', restartNow: 'Restart Now', restarting: 'Restarting...', - retry: 'Retry', + retry: 'Retry' }, // User Subscriptions Page @@ -1281,7 +1318,7 @@ export default { status: { active: 'Active', expired: 'Expired', - revoked: 'Revoked', + revoked: 'Revoked' }, usage: 'Usage', expires: 'Expires', @@ -1294,6 +1331,6 @@ export default { expiresOn: 'Expires on {date}', resetIn: 'Resets in {time}', windowNotActive: 'Awaiting first use', - usageOf: '{used} of {limit}', - }, + usageOf: '{used} of {limit}' + } } diff --git a/frontend/src/i18n/locales/zh.ts b/frontend/src/i18n/locales/zh.ts index e3db5ccf..b309e8a6 100644 --- a/frontend/src/i18n/locales/zh.ts +++ b/frontend/src/i18n/locales/zh.ts @@ -13,7 +13,7 @@ export default { tags: { subscriptionToApi: '订阅转 API', stickySession: '粘性会话', - realtimeBilling: '实时计费', + realtimeBilling: '实时计费' }, features: { unifiedGateway: '统一 API 网关', @@ -21,17 +21,17 @@ export default { multiAccount: '多账号池', multiAccountDesc: '智能负载均衡管理多个上游账号,支持 OAuth 和 API Key 认证。', balanceQuota: '余额与配额', - balanceQuotaDesc: '基于 Token 的精确计费和用量追踪,支持配额管理和兑换码充值。', + balanceQuotaDesc: '基于 Token 的精确计费和用量追踪,支持配额管理和兑换码充值。' }, providers: { title: '支持的服务商', description: 'AI 服务的统一 API 接口', supported: '已支持', - soon: '即将推出', + soon: '即将推出' }, footer: { - allRightsReserved: '保留所有权利。', - }, + allRightsReserved: '保留所有权利。' + } }, // Common @@ -81,7 +81,7 @@ export default { searchPlaceholder: '搜索...', noOptionsFound: '无匹配选项', saving: '保存中...', - refresh: '刷新', + refresh: '刷新' }, // Navigation @@ -105,7 +105,7 @@ export default { expand: '展开', logout: '退出登录', github: 'GitHub', - mySubscriptions: '我的订阅', + mySubscriptions: '我的订阅' }, // Auth @@ -139,7 +139,7 @@ export default { accountCreatedSuccess: '账户创建成功!欢迎使用 {siteName}。', turnstileExpired: '验证已过期,请重试', turnstileFailed: '验证失败,请重试', - completeVerification: '请完成验证', + completeVerification: '请完成验证' }, // Dashboard @@ -182,12 +182,12 @@ export default { viewUsage: '查看使用记录', checkDetailedLogs: '查看详细的使用日志', redeemCode: '兑换码', - addBalanceWithCode: '使用兑换码充值', + addBalanceWithCode: '使用兑换码充值' }, // Groups (shared) groups: { - subscription: '订阅', + subscription: '订阅' }, // API Keys @@ -253,7 +253,7 @@ export default { customKeyHint: '仅允许字母、数字、下划线和连字符,最少16个字符。', customKeyTooShort: '自定义密钥至少需要16个字符', customKeyInvalidChars: '自定义密钥只能包含字母、数字、下划线和连字符', - customKeyRequired: '请输入自定义密钥', + customKeyRequired: '请输入自定义密钥' }, // Usage @@ -294,7 +294,7 @@ export default { exportSuccess: '使用数据导出成功', billingType: '消费类型', balance: '余额', - subscription: '订阅', + subscription: '订阅' }, // Redeem @@ -334,7 +334,7 @@ export default { subscriptionDays: '{days} 天', days: '天', codeRedeemSuccess: '兑换成功!', - failedToRedeem: '兑换失败,请检查兑换码后重试。', + failedToRedeem: '兑换失败,请检查兑换码后重试。' }, // Profile @@ -365,12 +365,12 @@ export default { passwordsNotMatch: '两次输入的密码不一致', passwordTooShort: '密码至少需要 8 个字符', passwordChangeSuccess: '密码修改成功', - passwordChangeFailed: '密码修改失败', + passwordChangeFailed: '密码修改失败' }, // Empty States empty: { - noData: '暂无数据', + noData: '暂无数据' }, // Pagination @@ -384,7 +384,7 @@ export default { previous: '上一页', next: '下一页', perPage: '每页', - goToPage: '跳转到第 {page} 页', + goToPage: '跳转到第 {page} 页' }, // Errors @@ -396,7 +396,7 @@ export default { serverError: '服务器错误', networkError: '网络错误', timeout: '请求超时', - tryAgain: '请重试', + tryAgain: '请重试' }, // Dates @@ -414,7 +414,7 @@ export default { startDate: '开始日期', endDate: '结束日期', apply: '应用', - selectDateRange: '选择日期范围', + selectDateRange: '选择日期范围' }, // Admin @@ -469,7 +469,7 @@ export default { configureAiAccounts: '配置 AI 平台账号', systemSettings: '系统设置', configureSystem: '配置系统设置', - failedToLoad: '加载仪表盘数据失败', + failedToLoad: '加载仪表盘数据失败' }, // Users Management @@ -520,7 +520,7 @@ export default { concurrency: '并发数', status: '状态', created: '创建时间', - actions: '操作', + actions: '操作' }, today: '今日', total: '累计', @@ -550,11 +550,11 @@ export default { deleteConfirm: "确定要删除用户 '{email}' 吗?此操作无法撤销。", roles: { admin: '管理员', - user: '用户', + user: '用户' }, statuses: { active: '正常', - banned: '禁用', + banned: '禁用' }, form: { emailLabel: '邮箱', @@ -573,7 +573,7 @@ export default { balanceLabel: '余额', concurrencyLabel: '并发数', statusLabel: '状态', - selectStatus: '选择状态', + selectStatus: '选择状态' }, adjustBalance: '调整余额', adjustConcurrency: '调整并发数', @@ -617,7 +617,7 @@ export default { failedToDeposit: '充值失败', failedToWithdraw: '退款失败', useDepositWithdrawButtons: '请使用充值/退款按钮调整余额', - insufficientBalance: '余额不足,退款后余额不能为负数', + insufficientBalance: '余额不足,退款后余额不能为负数' }, // Groups Management @@ -641,7 +641,7 @@ export default { accounts: '账号数', status: '状态', actions: '操作', - billingType: '计费类型', + billingType: '计费类型' }, form: { name: '名称', @@ -663,16 +663,16 @@ export default { accountsPlaceholder: '选择账号(留空则不限制)', priorityLabel: '优先级', priorityHint: '数值越高优先级越高,用于账号调度', - statusLabel: '状态', + statusLabel: '状态' }, exclusive: { yes: '是', - no: '否', + no: '否' }, platforms: { all: '全部平台', claude: 'Claude', - openai: 'OpenAI', + openai: 'OpenAI' }, saving: '保存中...', noGroups: '暂无分组', @@ -718,8 +718,8 @@ export default { monthlyLimit: '每月限额(USD)', defaultValidityDays: '默认有效期(天)', validityHint: '分配给用户时订阅的有效天数', - noLimit: '无限制', - }, + noLimit: '无限制' + } }, // Subscriptions Management @@ -745,7 +745,7 @@ export default { status: { active: '生效中', expired: '已过期', - revoked: '已撤销', + revoked: '已撤销' }, columns: { user: '用户', @@ -753,13 +753,13 @@ export default { usage: '用量', expires: '到期时间', status: '状态', - actions: '操作', + actions: '操作' }, form: { user: '用户', group: '订阅分组', validityDays: '有效期(天)', - extendDays: '延长天数', + extendDays: '延长天数' }, selectUser: '选择用户', selectGroup: '选择订阅分组', @@ -781,7 +781,7 @@ export default { failedToAssign: '分配订阅失败', failedToExtend: '延长订阅失败', failedToRevoke: '撤销订阅失败', - revokeConfirm: "确定要撤销 '{user}' 的订阅吗?此操作无法撤销。", + revokeConfirm: "确定要撤销 '{user}' 的订阅吗?此操作无法撤销。" }, // Accounts Management @@ -838,23 +838,24 @@ export default { groups: '分组', usageWindows: '用量窗口', lastUsed: '最近使用', - actions: '操作', + actions: '操作' }, platforms: { claude: 'Claude', openai: 'OpenAI', anthropic: 'Anthropic', + gemini: 'Gemini' }, types: { oauth: 'OAuth', api_key: 'API Key', - cookie: 'Cookie', + cookie: 'Cookie' }, statuses: { active: '正常', inactive: '停用', error: '错误', - cooldown: '冷却中', + cooldown: '冷却中' }, form: { nameLabel: '账号名称', @@ -869,7 +870,7 @@ export default { priorityHint: '数值越高优先级越高', weightLabel: '权重', weightHint: '用于负载均衡的权重值', - statusLabel: '状态', + statusLabel: '状态' }, filters: { platform: '平台', @@ -877,7 +878,7 @@ export default { type: '类型', allTypes: '全部类型', status: '状态', - allStatuses: '全部状态', + allStatuses: '全部状态' }, saving: '保存中...', refreshing: '刷新中...', @@ -892,7 +893,7 @@ export default { selectCurrentPage: '本页全选', clear: '清除选择', edit: '批量编辑账号', - delete: '批量删除', + delete: '批量删除' }, bulkEdit: { title: '批量编辑账号', @@ -905,7 +906,7 @@ export default { partialSuccess: '部分更新成功:成功 {success} 个,失败 {failed} 个', failed: '批量更新失败', noSelection: '请选择要编辑的账号', - noFieldsSelected: '请至少选择一个要更新的字段', + noFieldsSelected: '请至少选择一个要更新的字段' }, bulkDeleteTitle: '批量删除账号', bulkDeleteConfirm: '确定要删除选中的 {count} 个账号吗?此操作无法撤销。', @@ -1034,13 +1035,44 @@ export default { authCode: '授权链接或 Code', authCodePlaceholder: '方式1:复制完整的链接\n(http://localhost:xxx/auth/callback?code=...)\n方式2:仅复制 code 参数的值', - authCodeHint: '您可以直接复制整个链接或仅复制 code 参数值,系统会自动识别', + authCodeHint: '您可以直接复制整个链接或仅复制 code 参数值,系统会自动识别' }, + // Gemini specific + gemini: { + title: 'Gemini 账户授权', + followSteps: '请按照以下步骤完成 Gemini 账户的授权:', + step1GenerateUrl: '先配置 Redirect URI,然后生成授权链接', + generateAuthUrl: '生成授权链接', + step2OpenUrl: '在浏览器中打开链接并完成授权', + openUrlDesc: '请在新标签页中打开授权链接,登录您的 Google 账户并授权。', + step3EnterCode: '输入回调链接或 Code', + authCodeDesc: + '授权完成后会跳转到 Redirect URI,并带上 codestate 参数。请粘贴完整链接或仅粘贴 code:', + authCode: '回调链接或 Code', + authCodePlaceholder: + '方式1:粘贴完整回调链接\n(https://your-domain/auth/callback?code=...&state=...)\n方式2:仅粘贴 code 参数的值', + authCodeHint: '如果粘贴完整链接,系统会自动提取 code/state', + redirectUri: 'Redirect URI', + redirectUriHint: '需要在 Google OAuth Client 中配置,且必须与此处完全一致。', + confirmRedirectUri: '我已在 Google OAuth Client 中配置了该 Redirect URI(必须完全一致)', + invalidRedirectUri: 'Redirect URI 必须是合法的 http(s) URL', + redirectUriNotConfirmed: '请确认 Redirect URI 已在 Google OAuth Client 中正确配置', + missingRedirectUri: '缺少 Redirect URI', + failedToGenerateUrl: '生成 Gemini 授权链接失败', + missingExchangeParams: '缺少 code / session_id / state / redirect_uri', + failedToExchangeCode: 'Gemini 授权码兑换失败', + modelPassthrough: 'Gemini 直接转发模型', + modelPassthroughDesc: '所有模型请求将直接转发至 Gemini API,不进行模型限制或映射。', + stateWarningTitle: '⚠️ 重要:Gemini 需要 code 和 state 参数', + stateWarningDesc: + '建议直接粘贴完整的回调链接,系统会自动提取 code 和 state。如果只粘贴 code,授权将会失败。' + } }, // Re-Auth Modal reAuthorizeAccount: '重新授权账号', claudeCodeAccount: 'Claude Code 账号', openaiAccount: 'OpenAI 账号', + geminiAccount: 'Gemini 账号', inputMethod: '输入方式', reAuthorizedSuccess: '账号重新授权成功', // Test Modal @@ -1092,8 +1124,8 @@ export default { todayTokens: '今日 Token', todayCost: '今日费用', usageTrend: '30天费用与请求趋势', - noData: '该账号暂无使用数据', - }, + noData: '该账号暂无使用数据' + } }, // Proxies Management @@ -1112,17 +1144,17 @@ export default { priority: '优先级', status: '状态', lastCheck: '最近检测', - actions: '操作', + actions: '操作' }, protocols: { http: 'HTTP', https: 'HTTPS', - socks5: 'SOCKS5', + socks5: 'SOCKS5' }, statuses: { active: '正常', inactive: '停用', - error: '错误', + error: '错误' }, form: { nameLabel: '名称', @@ -1138,13 +1170,13 @@ export default { passwordLabel: '密码(可选)', passwordPlaceholder: '请输入密码', priorityLabel: '优先级', - statusLabel: '状态', + statusLabel: '状态' }, filters: { protocol: '协议', allProtocols: '全部协议', status: '状态', - allStatuses: '全部状态', + allStatuses: '全部状态' }, // Additional keys used in ProxiesView allProtocols: '全部协议', @@ -1203,7 +1235,7 @@ export default { failedToCreate: '创建代理失败', failedToUpdate: '更新代理失败', failedToTest: '测试代理失败', - deleteConfirm: "确定要删除代理 '{name}' 吗?使用此代理的账号将被移除代理设置。", + deleteConfirm: "确定要删除代理 '{name}' 吗?使用此代理的账号将被移除代理设置。" }, // Redeem Codes Management @@ -1219,12 +1251,12 @@ export default { usedBy: '使用者', usedAt: '使用时间', createdAt: '创建时间', - actions: '操作', + actions: '操作' }, types: { balance: '余额', concurrency: '并发数', - subscription: '订阅', + subscription: '订阅' }, // 用于选择器和筛选器的直接键 balance: '余额', @@ -1267,7 +1299,7 @@ export default { unused: '未使用', used: '已使用', expired: '已过期', - disabled: '已禁用', + disabled: '已禁用' }, form: { typeLabel: '类型', @@ -1281,14 +1313,14 @@ export default { countHint: '要生成的兑换码数量', prefixLabel: '前缀(可选)', prefixPlaceholder: '例如:GIFT', - expiresLabel: '过期时间(可选)', + expiresLabel: '过期时间(可选)' }, filters: { type: '类型', allTypes: '全部类型', status: '状态', allStatuses: '全部状态', - search: '搜索兑换码', + search: '搜索兑换码' }, generating: '生成中...', copyCode: '复制', @@ -1306,7 +1338,7 @@ export default { failedToLoad: '加载兑换码列表失败', failedToGenerate: '生成兑换码失败', failedToUpdate: '更新兑换码失败', - failedToDelete: '删除兑换码失败', + failedToDelete: '删除兑换码失败' }, // Usage Records @@ -1317,7 +1349,7 @@ export default { searchUserPlaceholder: '按邮箱搜索用户...', selectedUser: '已选择', user: '用户', - failedToLoad: '加载使用记录失败', + failedToLoad: '加载使用记录失败' }, // Settings @@ -1330,7 +1362,7 @@ export default { enableRegistration: '开放注册', enableRegistrationHint: '允许新用户注册', emailVerification: '邮箱验证', - emailVerificationHint: '新用户注册时需要验证邮箱', + emailVerificationHint: '新用户注册时需要验证邮箱' }, turnstile: { title: 'Cloudflare Turnstile', @@ -1340,7 +1372,7 @@ export default { siteKey: '站点密钥', secretKey: '私密密钥', siteKeyHint: '从 Cloudflare Dashboard 获取', - secretKeyHint: '服务端验证密钥(请保密)', + secretKeyHint: '服务端验证密钥(请保密)' }, defaults: { title: '用户默认设置', @@ -1348,7 +1380,7 @@ export default { defaultBalance: '默认余额', defaultBalanceHint: '新用户的初始余额', defaultConcurrency: '默认并发数', - defaultConcurrencyHint: '新用户的最大并发请求数', + defaultConcurrencyHint: '新用户的最大并发请求数' }, site: { title: '站点设置', @@ -1370,7 +1402,7 @@ export default { logoHint: 'PNG、JPG 或 SVG 格式,最大 300KB。建议:80x80px 正方形图片。', logoSizeError: '图片大小超过 300KB 限制({size}KB)', logoTypeError: '请选择图片文件', - logoReadError: '读取图片文件失败', + logoReadError: '读取图片文件失败' }, smtp: { title: 'SMTP 设置', @@ -1385,7 +1417,7 @@ export default { fromEmail: '发件人邮箱', fromName: '发件人名称', useTls: '使用 TLS', - useTlsHint: '为 SMTP 连接启用 TLS 加密', + useTlsHint: '为 SMTP 连接启用 TLS 加密' }, testEmail: { title: '发送测试邮件', @@ -1393,7 +1425,7 @@ export default { recipientEmail: '收件人邮箱', sendTestEmail: '发送测试邮件', sending: '发送中...', - enterRecipientHint: '请输入收件人邮箱地址', + enterRecipientHint: '请输入收件人邮箱地址' }, adminApiKey: { title: '管理员 API Key', @@ -1415,7 +1447,7 @@ export default { keyCopied: '密钥已复制到剪贴板', keyWarning: '此密钥仅显示一次,请立即复制保存。', securityWarning: '警告:此密钥拥有完整的管理员权限,请妥善保管。', - usage: '使用方法:在请求头中添加 x-api-key: ', + usage: '使用方法:在请求头中添加 x-api-key: ' }, saveSettings: '保存设置', saving: '保存中...', @@ -1425,8 +1457,8 @@ export default { failedToLoad: '加载设置失败', failedToSave: '保存设置失败', failedToTestSmtp: 'SMTP 连接测试失败', - failedToSendTestEmail: '发送测试邮件失败', - }, + failedToSendTestEmail: '发送测试邮件失败' + } }, // Subscription Progress (Header component) @@ -1442,7 +1474,7 @@ export default { expiresToday: '今天到期', expiresTomorrow: '明天到期', viewAll: '查看全部订阅', - noSubscriptions: '暂无有效订阅', + noSubscriptions: '暂无有效订阅' }, // Version Badge @@ -1466,7 +1498,7 @@ export default { restartRequired: '请重启服务以应用更新', restartNow: '立即重启', restarting: '正在重启...', - retry: '重试', + retry: '重试' }, // User Subscriptions Page @@ -1478,7 +1510,7 @@ export default { status: { active: '有效', expired: '已过期', - revoked: '已撤销', + revoked: '已撤销' }, usage: '用量', expires: '到期时间', @@ -1491,6 +1523,6 @@ export default { expiresOn: '{date} 到期', resetIn: '{time} 后重置', windowNotActive: '等待首次使用', - usageOf: '已用 {used} / {limit}', - }, + usageOf: '已用 {used} / {limit}' + } }