diff --git a/src-tauri/src/app_update.rs b/src-tauri/src/app_update.rs index 70ddf99d..10b2dad6 100644 --- a/src-tauri/src/app_update.rs +++ b/src-tauri/src/app_update.rs @@ -170,9 +170,9 @@ pub(crate) async fn check_app_update( let unsupported_reason = if auto_update_supported { None } else if portable_support != Some(true) { - Some("当前程序不是支持自动升级的便携版,请手动下载首个支持版本".to_string()) + Some("Current application is not a portable build supporting automatic updates; please download manually".to_string()) } else { - Some("更新清单不包含当前平台或架构".to_string()) + Some("Update manifest does not include current platform or architecture".to_string()) }; let pending = if update_available && auto_update_supported { @@ -244,7 +244,7 @@ pub(crate) async fn fetch_portable_update_manifest( Err(error) => failures.push(format!("{}: {error}", candidate.display_name())), } } - Err(format!("所有软件版本检测源均失败: {}", failures.join("; "))) + Err(format!("All application version check sources failed: {}", failures.join("; "))) } pub(crate) async fn fetch_portable_update_manifest_from_gitcode( @@ -291,11 +291,11 @@ pub(crate) async fn fetch_portable_update_manifest_url( } pub(crate) fn configured_gitcode_gui_repository() -> Option<&'static str> { - configured_gitcode_repository(option_env!("GITCODE_GUI_REPOSITORY")) + configured_gitcode_repository(option_env!("GITCODE_GUI_REPOSITORY").or(Some("lzt404/EasyCLIProxyAPI"))) } pub(crate) fn configured_gitcode_core_repository() -> Option<&'static str> { - configured_gitcode_repository(option_env!("GITCODE_CORE_REPOSITORY")) + configured_gitcode_repository(option_env!("GITCODE_CORE_REPOSITORY").or(Some("lzt404/CLIProxyAPI"))) } pub(crate) fn configured_gitcode_repository( @@ -1072,7 +1072,7 @@ pub(crate) async fn download_portable_update_archive( Err(error) => failures.push(error), } } - Err(format!("所有应用更新下载源均失败: {}", failures.join("; "))) + Err(format!("All application update download sources failed: {}", failures.join("; "))) } pub(crate) fn portable_update_download_urls( diff --git a/src-tauri/src/core_runtime.rs b/src-tauri/src/core_runtime.rs index 2c0e6345..351f02f8 100644 --- a/src-tauri/src/core_runtime.rs +++ b/src-tauri/src/core_runtime.rs @@ -564,7 +564,7 @@ pub(crate) async fn fetch_release( Err(error) => failures.push(format!("{}: {error}", candidate.display_name())), } } - Err(format!("所有内核版本检测源均失败: {}", failures.join(";"))) + Err(format!("All core version check sources failed: {}", failures.join("; "))) } pub(crate) async fn fetch_release_from_github( @@ -1016,7 +1016,7 @@ pub(crate) async fn download_asset( let _ = fs::remove_file(archive_path); return Err("内核发行版没有可用的下载地址".to_string()); } - Err(format!("所有内核下载源均失败: {}", failures.join(";"))) + Err(format!("All core download sources failed: {}", failures.join("; "))) } pub(crate) fn core_download_source_name(url: &str) -> String { diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index cb0e3536..27becc63 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -125,8 +125,8 @@ const LEGACY_GUI_CONFIG_FILE: &str = "cpa-gui.yaml"; const MIN_MAIN_WINDOW_WIDTH: u32 = 640; const MIN_MAIN_WINDOW_HEIGHT: u32 = 600; const MAX_SAVED_WINDOW_DIMENSION: u32 = 16_384; -const DEFAULT_MAIN_WINDOW_WIDTH: u32 = 1280; -const DEFAULT_MAIN_WINDOW_HEIGHT: u32 = 800; +const DEFAULT_MAIN_WINDOW_WIDTH: u32 = 1400; +const DEFAULT_MAIN_WINDOW_HEIGHT: u32 = 860; const LEGACY_DEFAULT_MAIN_WINDOW_WIDTH: u32 = 1531; const LEGACY_DEFAULT_MAIN_WINDOW_HEIGHT: u32 = 891; const OAUTH_DIR_NAME: &str = "oauth"; diff --git a/src-tauri/src/tests/app_settings.rs b/src-tauri/src/tests/app_settings.rs index d005f8a1..e9bf6629 100644 --- a/src-tauri/src/tests/app_settings.rs +++ b/src-tauri/src/tests/app_settings.rs @@ -88,8 +88,8 @@ fn gui_config_defaults_are_stable() { assert!(content.contains("close-behavior = \"ask\"")); assert!(content.contains("default-terminal = \"auto\"")); assert_eq!(config.default_terminal, DEFAULT_AGENT_TERMINAL); - assert!(content.contains("window-width = 1280")); - assert!(content.contains("window-height = 800")); + assert!(content.contains("window-width = 1400")); + assert!(content.contains("window-height = 860")); assert!(content.contains("auth-dir = \"../oauth\"")); assert!(content.contains("[[api-keys]]")); assert!(content.contains("key = \"123456\"")); diff --git a/src-tauri/src/usage.rs b/src-tauri/src/usage.rs index 05cd3345..8ff673f5 100644 --- a/src-tauri/src/usage.rs +++ b/src-tauri/src/usage.rs @@ -3650,14 +3650,14 @@ fn api_key_category_label(remark: String, display: String) -> String { } else if !display.is_empty() { mask_api_key(&display) } else { - "未记录密钥".to_string() + "Unrecorded Key".to_string() } } fn usage_source_display(config: &GuiConfigFile, provider: &str, source: &str) -> String { let source = source.trim(); if source.is_empty() { - return "未知来源".to_string(); + return "Unknown Source".to_string(); } if let Some(remark) = config.api_access_remark_for_source(provider, source) { return remark.to_string(); diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 90140968..64a47d9c 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -13,8 +13,8 @@ { "label": "main", "title": "EasyCLIProxyAPI", - "width": 1280, - "height": 800, + "width": 1400, + "height": 860, "minWidth": 640, "minHeight": 600, "visible": false diff --git a/src/App.tsx b/src/App.tsx index bb26b7c5..dc7bbd3e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -189,7 +189,7 @@ function AppContent() { return; } } catch (error) { - console.error('读取关闭行为设置失败', error); + console.error('Failed to read close behavior settings', error); } setWindowsClosePrompt((current) => @@ -212,7 +212,7 @@ function AppContent() { } }) .catch((error) => { - console.error('监听 Windows 关闭确认事件失败', error); + console.error('Failed to listen for Windows close confirmation event', error); }); return () => { @@ -243,7 +243,7 @@ function AppContent() { try { await invoke('open_external_url', { url: CONTACT_URL }); } catch (error) { - console.error('打开联系我们链接失败', error); + console.error('Failed to open contact URL', error); } }; diff --git a/src/AppErrorBoundary.tsx b/src/AppErrorBoundary.tsx index ba0d9a80..a6944964 100644 --- a/src/AppErrorBoundary.tsx +++ b/src/AppErrorBoundary.tsx @@ -12,7 +12,7 @@ export class AppErrorBoundary extends Component { } componentDidCatch(error: Error, info: ErrorInfo) { - console.error('EasyCLIProxyAPI 渲染异常', error, info.componentStack); + console.error('EasyCLIProxyAPI render exception', error, info.componentStack); } render() { diff --git a/src/coreRuntime.tsx b/src/coreRuntime.tsx index 5f54c33e..8c6b5a10 100644 --- a/src/coreRuntime.tsx +++ b/src/coreRuntime.tsx @@ -98,7 +98,7 @@ export function CoreRuntimeProvider({ children }: { children: ReactNode }) { export function useCoreRuntime() { const context = useContext(CoreRuntimeContext); if (!context) { - throw new Error('useCoreRuntime 必须在 CoreRuntimeProvider 内使用'); + throw new Error('useCoreRuntime must be used within a CoreRuntimeProvider'); } return context; } diff --git a/src/i18n/index.tsx b/src/i18n/index.tsx index 9e86c947..a84d4cf8 100644 --- a/src/i18n/index.tsx +++ b/src/i18n/index.tsx @@ -3,6 +3,7 @@ import { invoke } from '@tauri-apps/api/core'; import { en, ja, zhCN, zhTW, type MessageKey, type MessageVariables } from './resources'; export type AppLocale = 'zh-CN' | 'zh-TW' | 'ja' | 'en'; +export type { MessageKey }; export const languageOptions: ReadonlyArray<{ value: AppLocale; diff --git a/src/i18n/ja.ts b/src/i18n/ja.ts index 763124f8..b1b96ddb 100644 --- a/src/i18n/ja.ts +++ b/src/i18n/ja.ts @@ -176,6 +176,76 @@ export const jaOverrides = { 'easyMode.guide.step3Description': '「利用可能なモデル」一覧からモデルを選び、インストール済みのエージェントクライアントを選択して設定を適用します。', 'easyMode.navigation.back': '前へ', 'easyMode.navigation.next': '次へ', + 'easyMode.subtitle': 'エージェントとモデルの簡単セットアップガイド', + 'easyMode.guide.button': '操作ガイド', + 'easyMode.guide.buttonActive': '操作ガイド(進行中)', + 'easyMode.guide.tooltipOpen': 'クリックして操作ガイドを開く', + 'easyMode.guide.tooltipClose': 'クリックして操作ガイドを閉じる', + 'easyMode.exit.button': 'ビギナーモードを終了', + 'easyMode.exit.tooltip': '通常ダッシュボードに戻る', + 'easyMode.oauth.loggedInCount': '{count} 個のアカウントがログイン中', + 'easyMode.oauth.recommended': 'おすすめ', + 'easyMode.oauth.supportedProviders': 'Codex、Claude、Antigravity、Kimi、xAI に対応', + 'easyMode.oauth.descCodex': 'OpenAI / ChatGPT アカウント認証ログイン', + 'easyMode.oauth.descClaude': 'Anthropic / Claude アカウント認証ログイン', + 'easyMode.oauth.descAntigravity': 'Antigravity アカウント認証ログイン', + 'easyMode.oauth.descKimi': 'Moonshot / Kimi アカウント認証ログイン', + 'easyMode.oauth.descXai': 'xAI / Grok アカウント認証ログイン', + 'easyMode.oauth.notLoggedIn': '未ログイン', + 'easyMode.oauth.startLogin': 'ログイン', + 'easyMode.oauth.errorGetStatus': '認証ステータスの取得に失敗しました。もう一度お試しください。', + 'easyMode.oauth.loginSuccess': 'ログインに成功しました!アカウントが認証され、利用枠が取得されました。', + 'easyMode.oauth.errorWithDetail': '認証に失敗しました: {error}', + 'easyMode.oauth.errorRetry': '認証に失敗しました。もう一度お試しください。', + 'easyMode.api.connectedCount': '{count} 個のプラットフォームを接続済み', + 'easyMode.api.supportedProviders': 'OpenAI、Anthropic、Codex、Gemini、DeepSeek に対応', + 'easyMode.api.formatOpenAi': 'OpenAI 形式', + 'easyMode.api.formatClaude': 'Anthropic 形式', + 'easyMode.api.formatGemini': 'Gemini 形式', + 'easyMode.api.remarkPlaceholder': '例: メイン DeepSeek V3、リレー API', + 'easyMode.api.saveAndConnect': '保存して接続', + 'easyMode.api.savedNotice': 'API 接続が正常に保存されました!', + 'easyMode.api.errorBaseUrl': '先に API Base URL を入力してください', + 'easyMode.api.errorApiKey': '先に API キーを入力してください', + 'easyMode.api.errorNoModels': 'モデルが見つかりませんでした。API Base URL とキーをご確認ください。', + 'easyMode.api.errorFetchModelsFirst': '先にモデル一覧を取得してください', + 'easyMode.steps.configureAgent': 'エージェントを設定', + 'easyMode.guide.badgeStep1': 'ステップ 1/4 · 接続方法の選択', + 'easyMode.guide.badgeStep2OAuth': 'ステップ 2/4 · アカウント認証ログイン', + 'easyMode.guide.badgeStep2Api': 'ステップ 2/4 · API 入力と接続', + 'easyMode.guide.badgeStep3': 'ステップ 3/4 · 接続ソースの確認と次へ', + 'easyMode.guide.badgeStep4': 'ステップ 4/4 · クライアント選択と設定適用', + 'easyMode.guide.closeTooltip': 'ガイドを閉じる', + 'easyMode.guide.finish': 'ガイド完了', + 'easyMode.guide.step1.heading': 'ステップ 1:接続方法を選択', + 'easyMode.guide.step1.oauthDesc': '一覧に表示されている OAuth プラットフォームに最適です。', + 'easyMode.guide.step1.apiDesc': 'API Base URL と API キーをお持ちのプロバイダーや中継サービスに最適です。', + 'easyMode.guide.step1.tipSelected': '接続方法を選択しました。「次へ」をクリックして続行してください。', + 'easyMode.guide.step1.tipUnselected': '上のいずれかの接続方法をクリックして進んでください。', + 'easyMode.guide.step2OAuth.heading': 'ステップ 2:OAuth 認証を完了', + 'easyMode.guide.step2OAuth.desc1': 'プラットフォームを選び、右側の「ログイン」または「再ログイン」をクリックしてブラウザーで認証を行ってください。', + 'easyMode.guide.step2OAuth.desc2': 'アプリに戻った後、プラットフォームが「ログイン済み」と表示されると完了です。', + 'easyMode.guide.step2OAuth.tipSuccess': '{provider} の認証に成功しました。「次へ」をクリックしてください。', + 'easyMode.guide.step2OAuth.tipPending': 'いずれかのプラットフォームのログインボタンをクリックし、認証完了をお待ちください。', + 'easyMode.guide.step2Api.heading': 'ステップ 2:API 情報を入力して保存', + 'easyMode.guide.step2Api.desc1': '1. インターフェース形式を確認します(デフォルトのままでも変更しても構いません)。', + 'easyMode.guide.step2Api.desc2': '2. API Base URL と API キーを入力します。', + 'easyMode.guide.step2Api.desc3': '3. 「モデル一覧を取得」をクリックし、取得されたモデルを確認して「保存して接続」をクリックします。', + 'easyMode.guide.step2Api.tipSaved': 'API 接続が保存されました。「次へ」をクリックして続行してください。', + 'easyMode.guide.step2Api.tipEmpty': 'モデルを取得する前に Base URL と API キーを入力してください。', + 'easyMode.guide.step2Api.tipFetch': '「モデル一覧を取得」をクリックし、結果をお待ちください。', + 'easyMode.guide.step2Api.tipNoSelected': 'モデルが選択されていません。少なくとも 1 つ選択して保存してください。', + 'easyMode.guide.step2Api.tipSelectedCount': 'デフォルトで {count} 個のモデルが選択されています。必要に応じて変更し、「保存して接続」をクリックしてください。', + 'easyMode.guide.step3.heading': 'ステップ 3:接続ソースの確認', + 'easyMode.guide.step3.desc1': '現在 {count} 個の接続ソースが確認されています。これはアカウントや API が接続されたことを意味し、クライアントの設定はまだ完了していません。', + 'easyMode.guide.step3.desc2': '下の強調表示された「次へ:エージェントを設定」をクリックして、クライアント選択とモデル設定に進んでください。', + 'easyMode.guide.step3.tipReady': '接続ソースが確認されました。「次へ:エージェントを設定」をクリックしてください。', + 'easyMode.guide.step3.tipWaiting': '前のステップで認証または API 保存を完了してください。', + 'easyMode.guide.step4.heading': 'ステップ 4:クライアントを選択して設定を適用', + 'easyMode.guide.step4.desc1': '左側の一覧に検出状況が表示されます。「検出済み」で対応しているクライアントを選び、右側の「使用するモデルを選択」でモデルを選んでください。', + 'easyMode.guide.step4.desc2': 'Pi 以外のクライアントでは「設定を適用」または「設定を更新」、Pi では「プロバイダーをインストール」または「プロバイダーを修復」をクリックします。成功するとガイド完了となります。', + 'easyMode.guide.step4.tipSuccess': '設定が正常に適用されました!操作ガイドを閉じるか、起動ボタンでクライアントを起動してください。', + 'easyMode.guide.step4.tipWaiting': '検出されたクライアントとモデルを選択し、設定ボタンをクリックして完了をお待ちください。', 'error.render.title': 'ページの描画中にエラーが発生しました', 'error.unknown': '不明なエラー', 'error.reload': 'ページを再読み込み', @@ -397,6 +467,9 @@ export const jaOverrides = { 'usage.column.total': '合計', 'usage.column.speed': '生成速度', 'usage.key.noRemark': 'メモなし', + 'usage.key.unrecorded': '未記録キー', + 'usage.source.unknown': '未知のソース', + 'usage.provider.unknown': '未知の Provider', 'usage.previous': '前へ', 'usage.next': '次へ', 'usage.empty': '現在のフィルター範囲に使用履歴はありません', @@ -946,6 +1019,7 @@ export const jaOverrides = { 'agents.clear.description': 'Codex 設定ディレクトリの auth.json と config.toml を完全に削除し、このアプリが記録した適用状態をリセットします。バックアップは作成されず、元に戻せません。', 'agents.clear.confirm': '設定を消去', 'agents.clear.success': 'Codex 設定を消去しました。', + 'apiAccess.provider.openaiCompatibility': 'OpenAI 互換', 'apiAccess.compatibleName': 'OpenAI 互換 {number}', 'apiAccess.error.headerMissingColon': 'カスタムヘッダーの {number} 行目にコロンがありません', 'apiAccess.error.headerInvalid': 'カスタムヘッダーの {number} 行目の形式が無効です', diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts index 9a942a83..c8105c39 100644 --- a/src/i18n/locales/en.ts +++ b/src/i18n/locales/en.ts @@ -163,6 +163,76 @@ export const en: Record = { 'easyMode.complete.title': 'Setup Complete!', 'easyMode.apiCopy.desc': 'You can also use the local proxy URL in any OpenAI / Claude / Gemini compatible tool.', 'easyMode.apiCopy.copied': 'Copied to clipboard', + 'easyMode.subtitle': 'Streamlined Agent and Model Setup Guide', + 'easyMode.guide.button': 'Walkthrough', + 'easyMode.guide.buttonActive': 'Walkthrough (Active)', + 'easyMode.guide.tooltipOpen': 'Click to open walkthrough', + 'easyMode.guide.tooltipClose': 'Click to close walkthrough', + 'easyMode.exit.button': 'Exit Beginner Mode', + 'easyMode.exit.tooltip': 'Return to standard dashboard', + 'easyMode.oauth.loggedInCount': '{count} account(s) signed in', + 'easyMode.oauth.recommended': 'Recommended', + 'easyMode.oauth.supportedProviders': 'Supports Codex, Claude, Antigravity, Kimi, xAI', + 'easyMode.oauth.descCodex': 'OpenAI / ChatGPT account authorization', + 'easyMode.oauth.descClaude': 'Anthropic / Claude account authorization', + 'easyMode.oauth.descAntigravity': 'Antigravity account authorization', + 'easyMode.oauth.descKimi': 'Moonshot / Kimi account authorization', + 'easyMode.oauth.descXai': 'xAI / Grok account authorization', + 'easyMode.oauth.notLoggedIn': 'Not Signed In', + 'easyMode.oauth.startLogin': 'Sign In', + 'easyMode.oauth.errorGetStatus': 'Failed to retrieve authorization status. Please try again.', + 'easyMode.oauth.loginSuccess': 'Login successful! Account authorized and quota loaded.', + 'easyMode.oauth.errorWithDetail': 'Authorization failed: {error}', + 'easyMode.oauth.errorRetry': 'Authorization failed. Please try again.', + 'easyMode.api.connectedCount': '{count} platform(s) connected', + 'easyMode.api.supportedProviders': 'Supports OpenAI, Anthropic, Codex, Gemini, DeepSeek', + 'easyMode.api.formatOpenAi': 'OpenAI Format', + 'easyMode.api.formatClaude': 'Anthropic Format', + 'easyMode.api.formatGemini': 'Gemini Format', + 'easyMode.api.remarkPlaceholder': 'e.g. Primary DeepSeek V3, Relay API', + 'easyMode.api.saveAndConnect': 'Save & Connect', + 'easyMode.api.savedNotice': 'API connection saved successfully!', + 'easyMode.api.errorBaseUrl': 'Please enter an API Base URL first', + 'easyMode.api.errorApiKey': 'Please enter an API Key first', + 'easyMode.api.errorNoModels': 'No models found. Please check your API Base URL and key.', + 'easyMode.api.errorFetchModelsFirst': 'Please fetch model list first', + 'easyMode.steps.configureAgent': 'Configure Agents', + 'easyMode.guide.badgeStep1': 'Step 1/4 · Choose connection method', + 'easyMode.guide.badgeStep2OAuth': 'Step 2/4 · Authorize account', + 'easyMode.guide.badgeStep2Api': 'Step 2/4 · Enter API & connect', + 'easyMode.guide.badgeStep3': 'Step 3/4 · Confirm source & proceed', + 'easyMode.guide.badgeStep4': 'Step 4/4 · Select client & apply config', + 'easyMode.guide.closeTooltip': 'Close walkthrough', + 'easyMode.guide.finish': 'Finish', + 'easyMode.guide.step1.heading': 'Step 1: Choose Connection Method', + 'easyMode.guide.step1.oauthDesc': 'Ideal for listed OAuth provider platforms.', + 'easyMode.guide.step1.apiDesc': 'Ideal if you already have an API Base URL and API Key from a provider or relay.', + 'easyMode.guide.step1.tipSelected': 'Connection method selected. Click "Next" to continue.', + 'easyMode.guide.step1.tipUnselected': 'Please click any connection method above to proceed.', + 'easyMode.guide.step2OAuth.heading': 'Step 2: Complete OAuth Authorization', + 'easyMode.guide.step2OAuth.desc1': 'Select a platform, click "Sign In" or "Re-login" on the right, and complete authorization in your browser.', + 'easyMode.guide.step2OAuth.desc2': 'After returning to the app, the platform must show "Signed In" to complete this step.', + 'easyMode.guide.step2OAuth.tipSuccess': '{provider} authorized successfully. Click "Next" to continue.', + 'easyMode.guide.step2OAuth.tipPending': 'Click a sign-in button and wait for the authorization result.', + 'easyMode.guide.step2Api.heading': 'Step 2: Enter & Save API Connection', + 'easyMode.guide.step2Api.desc1': '1. Confirm interface format (keep default or choose another format).', + 'easyMode.guide.step2Api.desc2': '2. Enter API Base URL and API Key.', + 'easyMode.guide.step2Api.desc3': '3. Click "Fetch model list" (returned models are selected by default); adjust selection if needed, then click "Save & Connect".', + 'easyMode.guide.step2Api.tipSaved': 'API connection saved successfully. Click "Next" to continue.', + 'easyMode.guide.step2Api.tipEmpty': 'Please enter Base URL and API Key before fetching models.', + 'easyMode.guide.step2Api.tipFetch': 'Click "Fetch model list" and wait for results.', + 'easyMode.guide.step2Api.tipNoSelected': 'No models selected. Please select at least one model before saving.', + 'easyMode.guide.step2Api.tipSelectedCount': '{count} model(s) selected by default. Adjust selection, then click "Save & Connect".', + 'easyMode.guide.step3.heading': 'Step 3: Confirm Connected Sources', + 'easyMode.guide.step3.desc1': 'Currently confirmed {count} connected source(s). Account or API credentials are ready, but client configuration is not yet complete.', + 'easyMode.guide.step3.desc2': 'Click the highlighted "Next: Configure Agents" below to proceed to client selection and model binding.', + 'easyMode.guide.step3.tipReady': 'Connected source confirmed. Click "Next: Configure Agents".', + 'easyMode.guide.step3.tipWaiting': 'Please complete authorization or API saving from the previous step first.', + 'easyMode.guide.step4.heading': 'Step 4: Select Client and Apply Configuration', + 'easyMode.guide.step4.desc1': 'The list on the left shows client detection status. Choose a client marked "Detected" that supports your system, then select a model under "Select Model" on the right.', + 'easyMode.guide.step4.desc2': 'For non-Pi clients, click "Apply Configuration" or "Update Configuration"; for Pi clients, click "Install Provider" or "Repair Provider". Success completes the walkthrough.', + 'easyMode.guide.step4.tipSuccess': 'Configuration applied successfully! You may close the walkthrough. Launch the client using its launch button.', + 'easyMode.guide.step4.tipWaiting': 'Please select a detected client and model, then click the configuration button and wait for completion.', 'error.render.title': 'Something went wrong while rendering this page', 'error.unknown': 'Unknown error', 'error.reload': 'Reload Page', @@ -385,6 +455,9 @@ export const en: Record = { 'usage.column.total': 'Total', 'usage.column.speed': 'Generation Speed', 'usage.key.noRemark': 'No remark', + 'usage.key.unrecorded': 'Unrecorded Key', + 'usage.source.unknown': 'Unknown Source', + 'usage.provider.unknown': 'Unknown Provider', 'usage.previous': 'Previous', 'usage.next': 'Next', 'usage.empty': 'No usage records match the current filters', @@ -946,6 +1019,7 @@ export const en: Record = { 'agents.clear.description': 'This permanently deletes auth.json and config.toml from the Codex configuration directory and resets the application state tracked by this app. No backup is created and the operation cannot be undone.', 'agents.clear.confirm': 'Clear Configuration', 'agents.clear.success': 'The Codex configuration has been cleared.', + 'apiAccess.provider.openaiCompatibility': 'OpenAI Compatible', 'apiAccess.compatibleName': 'OpenAI Compatible {number}', 'apiAccess.error.headerMissingColon': 'Custom header line {number} is missing a colon', 'apiAccess.error.headerInvalid': 'Custom header line {number} is invalid', diff --git a/src/i18n/locales/zh-CN.ts b/src/i18n/locales/zh-CN.ts index 363dcd90..70dc7fd0 100644 --- a/src/i18n/locales/zh-CN.ts +++ b/src/i18n/locales/zh-CN.ts @@ -162,6 +162,76 @@ export const zhCN = { 'easyMode.complete.title': '配置就绪!', 'easyMode.apiCopy.desc': '你也可以直接将本地代理地址填入任何支持 OpenAI / Claude / Gemini 协议的工具中。', 'easyMode.apiCopy.copied': '已复制到剪贴板', + 'easyMode.subtitle': '极简智能体与模型接入向导', + 'easyMode.guide.button': '操作指引', + 'easyMode.guide.buttonActive': '操作指引 (进行中)', + 'easyMode.guide.tooltipOpen': '点击开启操作指引', + 'easyMode.guide.tooltipClose': '点击关闭操作指引', + 'easyMode.exit.button': '退出新手模式', + 'easyMode.exit.tooltip': '返回常规控制台', + 'easyMode.oauth.loggedInCount': '已登录 {count} 个账号', + 'easyMode.oauth.recommended': '推荐', + 'easyMode.oauth.supportedProviders': '支持 Codex、Claude、Antigravity、Kimi、xAI', + 'easyMode.oauth.descCodex': 'OpenAI / ChatGPT 账号授权登录', + 'easyMode.oauth.descClaude': 'Anthropic / Claude 账号授权登录', + 'easyMode.oauth.descAntigravity': 'Antigravity 账号授权登录', + 'easyMode.oauth.descKimi': 'Moonshot / Kimi 账号授权登录', + 'easyMode.oauth.descXai': 'xAI / Grok 账号授权登录', + 'easyMode.oauth.notLoggedIn': '未登录', + 'easyMode.oauth.startLogin': '开始登录', + 'easyMode.oauth.errorGetStatus': '获取授权状态失败,请重试', + 'easyMode.oauth.loginSuccess': '登录成功!已成功授权并获取账号额度。', + 'easyMode.oauth.errorWithDetail': '授权失败: {error}', + 'easyMode.oauth.errorRetry': '授权失败,请重试', + 'easyMode.api.connectedCount': '已接入 {count} 个平台', + 'easyMode.api.supportedProviders': '支持 OpenAI、Anthropic、Codex、Gemini、DeepSeek', + 'easyMode.api.formatOpenAi': 'OpenAI 格式', + 'easyMode.api.formatClaude': 'Anthropic 格式', + 'easyMode.api.formatGemini': 'Gemini 格式', + 'easyMode.api.remarkPlaceholder': '例如:主力 DeepSeek V3、中转 API', + 'easyMode.api.saveAndConnect': '保存并接入', + 'easyMode.api.savedNotice': 'API 接入已保存成功!', + 'easyMode.api.errorBaseUrl': '请先填写 API Base URL', + 'easyMode.api.errorApiKey': '请先填写 API Key', + 'easyMode.api.errorNoModels': '未获取到任何模型,请检查 API Base URL 与密钥', + 'easyMode.api.errorFetchModelsFirst': '请先获取模型列表', + 'easyMode.steps.configureAgent': '配置智能体', + 'easyMode.guide.badgeStep1': '步骤 1/4 · 选择连接方式', + 'easyMode.guide.badgeStep2OAuth': '步骤 2/4 · 授权登录账号', + 'easyMode.guide.badgeStep2Api': '步骤 2/4 · 填写 API 与接入', + 'easyMode.guide.badgeStep3': '步骤 3/4 · 确认接入来源并进入下一步', + 'easyMode.guide.badgeStep4': '步骤 4/4 · 选择客户端并应用配置', + 'easyMode.guide.closeTooltip': '关闭指导', + 'easyMode.guide.finish': '完成指引', + 'easyMode.guide.step1.heading': '步骤 1:选择接入方式', + 'easyMode.guide.step1.oauthDesc': '适用于页面列出的 OAuth 平台。', + 'easyMode.guide.step1.apiDesc': '适用于你已有 API Base URL 和 API Key 的服务或中转平台。', + 'easyMode.guide.step1.tipSelected': '选择接入方式后,请点击『下一步』继续。', + 'easyMode.guide.step1.tipUnselected': '请点击上方任一接入方式;选择完成后才能继续。', + 'easyMode.guide.step2OAuth.heading': '步骤 2:完成 OAuth 授权', + 'easyMode.guide.step2OAuth.desc1': '请选择一个平台,点击它右侧的 『开始登录』 或 『重新登录』,并在浏览器中完成授权。', + 'easyMode.guide.step2OAuth.desc2': '返回应用后,平台显示为 『已登录』 才算完成本步骤;未成功授权不能继续。', + 'easyMode.guide.step2OAuth.tipSuccess': '{provider} 已授权成功,请点击『下一步』。', + 'easyMode.guide.step2OAuth.tipPending': '请先点击一个平台的登录按钮,并等待授权结果返回。', + 'easyMode.guide.step2Api.heading': '步骤 2:填写并保存 API 接入', + 'easyMode.guide.step2Api.desc1': '1. 确认接口格式,可保持默认选项或选择其他格式。', + 'easyMode.guide.step2Api.desc2': '2. 填写 API Base URL 和 API Key。', + 'easyMode.guide.step2Api.desc3': '3. 点击 『获取模型列表』,返回结果后会默认全选模型;确认或调整选择后,点击 『保存并接入』。', + 'easyMode.guide.step2Api.tipSaved': 'API 接入已保存成功,请点击『下一步』。', + 'easyMode.guide.step2Api.tipEmpty': '请填写 Base URL 和 API Key;填写完整后才能获取模型。', + 'easyMode.guide.step2Api.tipFetch': '请点击『获取模型列表』并等待结果返回。', + 'easyMode.guide.step2Api.tipNoSelected': '当前没有选中模型,请至少勾选一个模型后保存。', + 'easyMode.guide.step2Api.tipSelectedCount': '已默认选择 {count} 个模型;可调整选择,然后点击『保存并接入』。', + 'easyMode.guide.step3.heading': '步骤 3:确认接入来源', + 'easyMode.guide.step3.desc1': '当前已确认 {count} 个接入来源。这里表示账号或 API 配置已接入,不代表客户端已经完成配置。', + 'easyMode.guide.step3.desc2': '请点击下方高亮的 『下一步:配置智能体』,进入客户端选择和模型绑定。', + 'easyMode.guide.step3.tipReady': '接入来源已确认,请点击『下一步:配置智能体』。', + 'easyMode.guide.step3.tipWaiting': '请先完成上一步的授权或 API 保存。', + 'easyMode.guide.step4.heading': '步骤 4:选择客户端并应用配置', + 'easyMode.guide.step4.desc1': '左侧列表会显示客户端的检测状态。请选择一个显示为 『已检测到』 且支持当前系统的客户端,再在右侧 『使用模型』 中选择模型。', + 'easyMode.guide.step4.desc2': '非 Pi 客户端点击实际显示的 『应用配置』 或 『更新配置』;Pi 客户端点击 『安装提供方』 或 『修复提供方』。成功后才能完成指引。', + 'easyMode.guide.step4.tipSuccess': '配置已成功应用,可以关闭操作指引;启动客户端需要另行点击启动按钮。', + 'easyMode.guide.step4.tipWaiting': '请先选择已检测到的客户端和模型,再点击对应的配置按钮并等待成功结果。', 'error.render.title': '页面渲染出现异常', 'error.unknown': '未知错误', 'error.reload': '重新加载页面', @@ -384,6 +454,9 @@ export const zhCN = { 'usage.column.total': '总计', 'usage.column.speed': '生成速度', 'usage.key.noRemark': '未备注', + 'usage.key.unrecorded': '未记录密钥', + 'usage.source.unknown': '未知来源', + 'usage.provider.unknown': '未知 Provider', 'usage.previous': '上一页', 'usage.next': '下一页', 'usage.empty': '当前筛选范围没有使用记录', @@ -945,6 +1018,7 @@ export const zhCN = { 'agents.clear.description': '这会永久删除 Codex 配置目录中的 auth.json 和 config.toml,并重置软件记录的应用状态。该操作没有备份且无法恢复。', 'agents.clear.confirm': '确认清空配置', 'agents.clear.success': 'Codex 配置已清空。', + 'apiAccess.provider.openaiCompatibility': 'OpenAI 兼容', 'apiAccess.compatibleName': 'OpenAI 兼容 {number}', 'apiAccess.error.headerMissingColon': '自定义请求头第 {number} 行缺少冒号', 'apiAccess.error.headerInvalid': '自定义请求头第 {number} 行格式无效', diff --git a/src/pages/ApiAccessPage.tsx b/src/pages/ApiAccessPage.tsx index 69a09bcf..d59ac0d8 100644 --- a/src/pages/ApiAccessPage.tsx +++ b/src/pages/ApiAccessPage.tsx @@ -93,6 +93,7 @@ type ProviderDefinition = { openAi: boolean; }; + type ProviderRow = { section: ProviderSection; index: number; diff --git a/src/pages/EasyModePage.tsx b/src/pages/EasyModePage.tsx index 865eef6f..37ebb145 100644 --- a/src/pages/EasyModePage.tsx +++ b/src/pages/EasyModePage.tsx @@ -55,6 +55,7 @@ type OAuthProviderInfo = { id: OAuthProviderId; name: string; icon: string; + descriptionKey: MessageKey; }; @@ -149,7 +150,7 @@ export function EasyModePage({ const [guideApiModelsFetched, setGuideApiModelsFetched] = useState(false); const [guideAgentConfigured, setGuideAgentConfigured] = useState(false); - // 新手聚焦指导状态(默认关闭,点击开启) + // Guided walkthrough state (off by default, click to enable) const [guideActive, setGuideActive] = useState(false); const [guideStep, setGuideStep] = useState(1); const [spotlightRect, setSpotlightRect] = useState<{ @@ -434,7 +435,7 @@ export function EasyModePage({ } }; - // 获取当前聚焦点元素 ID (4 个稳定步骤) + // Current spotlight target element ID (4 stable steps) const currentTargetId = (() => { if (!guideActive) return null; if (activeStep === 1) { @@ -447,7 +448,7 @@ export function EasyModePage({ return null; })(); - // 计算聚光灯位置 + // Calculate spotlight position const updateSpotlightPosition = useCallback(() => { if (!guideActive || !currentTargetId) { setSpotlightRect(null); @@ -556,7 +557,7 @@ export function EasyModePage({ ? hasConnectedSource || guideOAuthCompleted || guideApiSaved : guideAgentConfigured; - // 指引步骤控制 + // Guide step controls const handleNextGuideStep = () => { if (!guideCanAdvance) return; if (guideStep === 1) { @@ -600,10 +601,10 @@ export function EasyModePage({ return (
- {/* 全灰色聚焦蒙层 (Dimmed Backdrop) */} + {/* Dimmed backdrop overlay */} {guideActive ?
: null} - {/* 顶部全宽导航栏 */} + {/* Full-width top navigation bar */}
@@ -616,7 +617,7 @@ export function EasyModePage({ {t("easyMode.brandSub")}
- {/* 新手聚焦指导开关 */} + {/* Guided setup toggle */}
- {/* 步骤条进度指示器 */} + {/* Step status progress indicator */} - {/* 第一步:接入模型 */} + {/* Step 1: Connect models */} {activeStep === 1 ? (
@@ -751,7 +752,7 @@ export function EasyModePage({
- {/* 连接方式选择卡片 */} + {/* Connection method choice cards */}
- {/* OAuth 平台列表 */} + {/* OAuth platform list */} {authMethod === "oauth" ? (
) : null} - {/* API 接入表单 */} + {/* API connection form */} {authMethod === "api" ? (
- {/* 平台格式切换 */} + {/* Platform format toggle */}
{apiSectionOptions.map((opt) => (
- {/* 模型拉取与选择 */} + {/* Model discovery and selection */}
{apiTestedModels.length === 0 ? (
@@ -994,7 +995,7 @@ export function EasyModePage({
) : null} - {/* 第一步底部操作栏 */} + {/* Step 1 footer actions */}