diff --git a/ui/src/components/account/history-sync-learning-map.tsx b/ui/src/components/account/history-sync-learning-map.tsx index 4c941b47..cc8b31f5 100644 --- a/ui/src/components/account/history-sync-learning-map.tsx +++ b/ui/src/components/account/history-sync-learning-map.tsx @@ -171,8 +171,7 @@ export function HistorySyncLearningMap({ {legacyTargetCount > 0 && (
ccs doctor --fix を実行してください。',
+ details: '詳細',
+ syncNow: '今すぐ同期',
+ },
+ syncDialog: {
+ title: 'プロファイルをローカル CLIProxy に同期',
+ description: 'CCS の API プロファイルをローカルの CLIProxy config.yaml に同期します。',
+ noProfiles: '同期するプロファイルがありません。',
+ createProfilesFirst: '先にプロファイルタブで API プロファイルを作成してください。',
+ modelLabel: 'モデル:',
+ ready: '準備完了',
+ profilesToSync_one: '{{count}} 件のプロファイルを同期',
+ profilesToSync_other: '{{count}} 件のプロファイルを同期',
+ cancel: 'キャンセル',
+ syncing: '同期中...',
+ synced: '同期完了',
+ syncNow: '今すぐ同期',
+ },
+ errorLogs: {
+ title: 'エラーログ',
+ failedRequests_one: '{{count}} 件の失敗したリクエスト',
+ failedRequests_other: '{{count}} 件の失敗したリクエスト',
+ cliproxyDiagnostics: 'CLIProxy 診断',
+ showingCount: '{{total}} 件中 50 件のログを表示',
+ selectLog: '詳細を表示するログを選択してください',
+ failedLoadContent: 'ログ内容の読み込みに失敗しました',
+ copyAbsolutePath: '絶対パスをコピー',
+ copyRawContent: '生のログ内容をコピー',
+ tabOverview: '概要',
+ tabHeaders: 'ヘッダー',
+ tabRequest: 'リクエスト',
+ tabResponse: 'レスポンス',
+ tabRaw: '生データ',
+ modelLabel: 'モデル:',
+ quotaResetsIn: 'クォータのリセットまで ',
+ method: 'メソッド',
+ provider: 'プロバイダー',
+ version: 'バージョン',
+ endpoint: 'エンドポイント',
+ url: 'URL',
+ timestamp: 'タイムスタンプ',
+ na: '該当なし',
+ noHeaders: '利用可能なヘッダーはありません',
+ noRequestBody: 'リクエストボディなし',
+ noResponseBody: 'レスポンスボディなし',
+ rateLimitedMsg:
+ 'レート制限です。別のアカウントに切り替えるか、クォータのリセットを待ってください。モデル {{model}} のクォータは上限に達しています。',
+ rateLimitedMsgNoModel:
+ 'レート制限です。別のアカウントに切り替えるか、クォータのリセットを待ってください。',
+ authFailedMsg:
+ '認証に失敗しました。CLIProxy 設定で再認証するか、API キーを確認してください。',
+ notFoundMsg:
+ 'エンドポイントが見つかりません。このプロバイダーには存在しない可能性があります。',
+ serverErrorMsg:
+ '上流サーバーでエラーが発生しました。後でもう一度試すか、プロバイダーのステータスページを確認してください。',
+ timeoutMsg:
+ 'リクエストがタイムアウトしました。ネットワーク接続を確認するか、タイムアウト設定を延長してください。',
+ unknown: '不明',
+ },
+ editAccountContext: {
+ title: '履歴同期の設定',
+ description:
+ '"{{name}}" が他の CCS auth アカウントと履歴や継続性を共有する方法を設定します。',
+ syncMode: '同期モード',
+ selectContextMode: 'コンテキストモードを選択',
+ isolatedOption: '分離(同期なし)',
+ sharedOption: '共有(同期あり)',
+ sharedModeHint:
+ '共有モードでは、同じ履歴同期グループ内のアカウントでワークスペースコンテキストを再利用します。',
+ isolatedModeHint:
+ '分離モードでは、このアカウントを他の CCS auth アカウントから完全に切り離します。',
+ historySyncGroup: '履歴同期グループ',
+ groupPlaceholder: 'default',
+ groupHint:
+ '小文字に正規化されます(スペースはダッシュに変換)。使用可能: 英字、数字、_、-(最大 {{max}} 文字)。',
+ invalidGroup: '英字で始まる有効なグループ名を入力してください。',
+ continuityDepth: '継続性レベル',
+ selectContinuityDepth: '継続性レベルを選択',
+ standardOption: '標準(プロジェクトのみ)',
+ deeperOption: '拡張継続性(上級者向け)',
+ deeperHint:
+ '上級モードでは、session-env、file-history、shell-snapshots、todos も同期します。',
+ standardHint: '標準モードでは、プロジェクトのワークスペースコンテキストのみ同期します。',
+ credentialsIsolated:
+ 'どのモードでも、認証情報と .anthropic はアカウントごとに分離されます。',
+ cancel: 'キャンセル',
+ save: '保存',
+ saving: '保存中...',
+ },
+ historySyncLearningMap: {
+ title: '履歴同期の仕組み',
+ description: '分離 -> 共有 -> 拡張共有。変更は各行の「同期」から行います。',
+ learningMap: '概要図',
+ isolated: '分離',
+ shared: '共有',
+ deeper: '拡張共有',
+ cliproxyManaged_one:
+ '{{count}} 件の CLIProxy Claude Pool アカウントは、CLIProxy ページで管理します。',
+ cliproxyManaged_other:
+ '{{count}} 件の CLIProxy Claude Pool アカウントは、CLIProxy ページで管理します。',
+ showDetails: '詳細を表示: グループ、切り替え、レガシーポリシー',
+ modeSwitch: 'モード切り替え',
+ modeSwitchDesc:
+ '「同期」ダイアログでは、分離/共有の切り替えと、より深い継続性の選択ができます。',
+ historySyncGroup: '履歴同期グループ',
+ historySyncGroupDesc:
+ '同じグループのアカウントは、同じプロジェクトのコンテキストレーンを共有します。未設定時は default を使います。',
+ legacyConfirmation_one: '{{count}} 件のレガシーアカウントで明示的な確認がまだ必要です。',
+ legacyConfirmation_other: '{{count}} 件のレガシーアカウントで明示的な確認がまだ必要です。',
+ },
+ accountsTable: {
+ name: '名前',
+ type: '種別',
+ defaultBadge: '既定',
+ created: '作成日',
+ lastUsed: '最終使用',
+ historySync: '履歴同期',
+ actions: '操作',
+ syncTitle: '同期モード、グループ、継続性レベルを編集',
+ confirmLegacyTitle: 'このレガシーアカウントの現在のモードを明示的に確定する',
+ sync: '同期',
+ confirm: '確定',
+ active: '有効',
+ setDefault: '既定に設定',
+ deleteAccount: 'アカウントを削除',
+ cannotDeleteDefault: '既定のアカウントは削除できません',
+ noAccounts:
+ 'CCS auth アカウントが見つかりません。追加するには ccs auth create を使ってください。',
+ resetToDefault: 'CCS の既定値に戻す',
+ deleteDialogTitle: 'アカウントを削除',
+ deleteDialogDesc:
+ 'アカウント "{{name}}" を削除しますか? この操作でプロファイルと関連するすべてのセッションデータが削除されます。この操作は元に戻せません。',
+ cancel: 'キャンセル',
+ delete: '削除',
+ sharedGroupStandard: '共有({{group}}、標準)',
+ sharedGroupDeeper: '共有({{group}}、拡張)',
+ sharedGroupLegacy: '共有({{group}}、標準・レガシー)',
+ isolatedLegacy: '分離(旧既定値)',
+ isolated: '分離',
+ },
+ addAccountDialog: {
+ title: '{{displayName}} アカウントを追加',
+ descKiro:
+ 'Kiro の認証方法を選び、ブラウザーで認証するか Kiro IDE からインポートしてください。',
+ descDeviceCode:
+ '認証をクリックすると、プロバイダーのサイトで入力する確認コードが表示されます。',
+ descOauth:
+ '認証をクリックすると OAuth URL を取得します。任意のブラウザーで開いてサインインしてください。',
+ powerUserEnabled: '上級者モードが有効です',
+ powerUserSkipped:
+ '設定 > プロキシで AGY の責任確認チェックをスキップしています。OAuth / アカウントに関するリスクはすべて自己責任となります。',
+ authMethod: '認証方法',
+ selectKiroAuthMethod: 'Kiro の認証方法を選択',
+ nicknameRequired: 'ニックネーム(必須)',
+ nicknameOptional: 'ニックネーム(任意)',
+ nicknamePlaceholder: '例: work, personal',
+ nicknameRequiredHint:
+ 'このプロバイダーでは必須です。重複しないわかりやすい名前を付けてください(例: work, personal)。',
+ nicknameOptionalHint:
+ 'このアカウントを識別しやすい名前です。空欄ならメールアドレスから自動生成されます。',
+ waitingForAuth: '認証を待機中...',
+ deviceCodeHint:
+ '確認コードのダイアログがまもなく表示されます。プロバイダーのサイトでコードを入力してください。',
+ browserHint: 'ブラウザーで認証を完了してください。このダイアログは自動で閉じます。',
+ openUrlLabel: 'サインインするには、この URL を任意のブラウザーで開いてください:',
+ copied: 'コピー済み',
+ copy: 'コピー',
+ open: '開く',
+ popupBlocked:
+ 'ポップアップがブロックされました。上の URL をコピーして、ブラウザーで手動で開いてください。',
+ redirectPasteLabel:
+ 'リダイレクトが機能しない場合は、コールバック URL を貼り付けてください:',
+ callbackPlaceholder: 'リダイレクト URL をここに貼り付け...',
+ submitCallback: 'コールバックを送信',
+ submitting: '送信中...',
+ preparingUrl: 'サインイン URL を準備中...',
+ cancel: 'キャンセル',
+ importingToken: 'Kiro IDE からトークンをインポート中...',
+ authenticate: '認証',
+ importFromIde: 'IDE からインポート',
+ importing: 'インポート中...',
+ },
+ flowViz: {
+ backToProviders: 'プロバイダーに戻る',
+ showDetails: '詳細を表示',
+ hideDetails: '詳細を隠す',
+ resetLayout: 'レイアウトをリセット',
+ provider: 'プロバイダー',
+ totalRequests: '総リクエスト数',
+ accounts: 'アカウント',
+ connectionTimeline: '接続タイムライン',
+ noRecentConnections: '最近の接続はありません',
+ },
+ quickStats: {
+ totalRequests: '総リクエスト数',
+ successRate: '成功率',
+ totalTokens: '総トークン数',
+ activeModels: 'アクティブなモデル',
+ },
+ authMonitor: {
+ accounts: 'アカウント',
+ accountsCount: '{{count}} アカウント',
+ success: '成功',
+ failed: '失敗',
+ successRate: '成功率',
+ },
+ accountCard: {
+ resumeAccount: 'アカウントを再開',
+ pauseAccount: 'アカウントを一時停止',
+ quotaLoading: 'クォータ...',
+ quota: 'クォータ',
+ quotaUnavailable: 'クォータ上限を取得できません',
+ reauthNeeded: '再認証が必要',
+ failureLabelReauth: '再認証',
+ failureLabelWorkspace: 'ワークスペース',
+ failureLabelNoAccess: 'アクセス不可',
+ failureLabelRetry: '再試行',
+ failureLabelReconnect: '再接続',
+ failureLabelTemporary: '一時的',
+ failureLabelUnavailable: '利用不可',
+ failureHintReauth: 'このアカウントの認証フローをもう一度実行して更新してください。',
+ failureHintWorkspace:
+ 'このアカウントをアクティブなワークスペースに戻してから、削除して再追加してください。',
+ failureHintNoAccess:
+ 'このアカウントでは、プロバイダーのクォータエンドポイントにアクセスできません。',
+ failureHintRetry: 'しばらく待ってから、クォータリクエストを再試行してください。',
+ failureHintReconnect: '古いアカウントを削除し、再度認証してください。',
+ failureHintTemporary: '一時的な問題のようです。後でもう一度試してください。',
+ removeAndReadd: '削除して再追加',
+ autoRefreshFailed: '自動更新に失敗しました',
+ },
+ antigravityChecklist: {
+ title: 'Antigravity OAuth の責任確認',
+ subtitle: '認証する前に 4 ステップすべて完了してください。',
+ mandatory: '必須',
+ completion: '完了状況',
+ stepsCount: '{{current}}/4 ステップ',
+ },
+ accountSafetyWarning: {
+ title: 'OAuth アカウント安全性の警告',
+ subtitle: 'Issue #509 · Gemini + AGY OAuth リスク',
+ firstLine:
+ 'Issue #509 では、CCS AGY と、CCS Gemini と CCS AGY 間での共有アカウント利用に関連する停止・BAN 報告がまとめられています。',
+ secondLine:
+ 'OAuth とアカウントアクセスのリスクをすべて自己責任で負う場合のみ続行してください。',
+ issueLabel: 'Issue #509 を読む',
+ proxySettingsLabel: 'Gemini + AGY の設定: 設定 > プロキシ',
+ },
+ cliproxyDialog: {
+ name: '名前',
+ provider: 'プロバイダー',
+ account: 'アカウント',
+ accountOptional: 'アカウント(任意)',
+ model: 'モデル',
+ modelOptional: 'モデル(任意)',
+ defaultTarget: 'デフォルトターゲット',
+ defaultTier: 'デフォルトティア',
+ tierConfig: 'ティア設定',
+ selectProvider: 'プロバイダーを選択...',
+ useDefaultAccount: 'デフォルトのアカウントを使用',
+ defaultSuffix: '(デフォルト)',
+ opus: 'Opus',
+ sonnet: 'Sonnet',
+ haiku: 'Haiku',
+ claudeCode: 'Claude Code',
+ factoryDroid: 'Factory Droid',
+ cancel: 'キャンセル',
+ create: '作成',
+ creating: '作成中...',
+ saveChanges: '変更を保存',
+ saving: '保存中...',
+ placeholderName: 'my-gemini',
+ placeholderModel: 'gemini-2.5-pro',
+ placeholderComposite: 'my-composite',
+ placeholderModelId: 'model-id',
+ placeholderAccountId: 'account-id',
+ editCompositeTitle: '複合バリアントを編集: {{name}}',
+ editSingleTitle: '単一バリアントを編集: {{name}}',
+ },
+ profileEditor: {
+ profileInfo: 'プロファイル情報',
+ profileName: 'プロファイル名',
+ filePath: 'ファイルパス',
+ lastModified: '最終更新',
+ defaultTarget: 'デフォルトターゲット',
+ quickUsage: 'クイック実行',
+ runWithProfile: 'このプロファイルで実行',
+ runOnDroid: 'Droid で実行',
+ droidAliasExplicit: 'Droid エイリアス(明示)',
+ overrideToClaude: 'Claude に切り替え',
+ overrideToClaudeExplicit: 'Claude に切り替え(明示)',
+ setAsDefault: 'デフォルトに設定',
+ provider: 'プロバイダー',
+ custom: 'カスタム',
+ },
+ settings: {
+ sectionLoadFailed: 'セクションの読み込みに失敗しました',
+ unknownError: '不明なエラーが発生しました',
+ reloadPage: 'ページを再読み込み',
+ refresh: '更新',
+ copy: 'コピー',
+ copied: 'コピーしました',
+ saved: '保存しました',
+ loading: '読み込み中...',
+ configFileNotFound: '設定ファイルが見つかりません',
+ },
+ settingsTabs: {
+ web: 'Web検索',
+ env: '環境変数',
+ think: '思考',
+ proxy: 'プロキシ',
+ auth: '認証',
+ backup: 'バックアップ',
+ },
+ settingsAuth: {
+ failedFetchTokens: '認証トークンの取得に失敗しました',
+ failedSaveTokens: 'トークンの保存に失敗しました',
+ tokensUpdated: 'トークンを更新しました。反映するには CLIProxy を再起動してください。',
+ failedRegenerate: 'シークレットの再生成に失敗しました',
+ secretRegenerated:
+ '新しい Management Secret を生成しました。反映するには CLIProxy を再起動してください。',
+ failedReset: 'トークンのリセットに失敗しました',
+ tokensReset:
+ 'トークンをデフォルトに戻しました。反映するには CLIProxy を再起動してください。',
+ description:
+ 'CLIProxy の認証トークンを設定します。変更を反映するには CLIProxy の再起動が必要です。',
+ apiKey: 'API Key',
+ custom: 'カスタム',
+ apiKeyDesc: 'Claude Code が CLIProxy への認証に使用します',
+ apiKeyPlaceholder: 'API key',
+ managementSecret: 'Management Secret',
+ managementSecretDesc:
+ 'CCS ダッシュボードが CLIProxy の管理 API にアクセスするために使用します',
+ managementSecretPlaceholder: 'Management secret',
+ generateSecret: '新しい安全なシークレットを生成',
+ resetDefaults: 'デフォルトに戻す',
+ resetDesc: 'API Key と Management Secret の両方をデフォルト値に戻します。',
+ saving: '保存中...',
+ save: '保存',
+ },
+ settingsGlobalEnv: {
+ description:
+ 'Claude 以外のサブスクリプション型プロファイル(gemini、codex、agy、ghcp など)に注入する環境変数',
+ enabled: 'グローバル環境変数を有効化',
+ disabled: 'グローバル環境変数を無効化',
+ enabledDesc: '環境変数をサードパーティープロファイルに注入します',
+ disabledDesc: '環境変数は注入されません',
+ envVars: '環境変数',
+ noneConfigured: '環境変数は未設定です',
+ addNew: '変数を追加',
+ keyName: 'KEY_NAME',
+ value: '値',
+ add: '追加',
+ quickAdd: 'よく使う変数を追加',
+ allConfigured: '主要な変数はすべて設定済みです',
+ },
+ settingsBackups: {
+ failedFetch: 'バックアップの取得に失敗しました',
+ failedRestore: 'バックアップの復元に失敗しました',
+ restoreSuccess: 'バックアップを復元しました',
+ title: '設定バックアップ',
+ description:
+ 'settings.json の以前のバージョンを復元します。設定を変更するとバックアップが自動作成されます。',
+ none: '利用できるバックアップはありません',
+ noneHint: '設定を変更すると、ここにバックアップが表示されます',
+ latest: '最新',
+ restoring: '復元中...',
+ restore: '復元',
+ restoreConfirmTitle: 'バックアップを復元しますか?',
+ restoreConfirmPrefix: '現在の設定を次のバックアップで置き換えます:',
+ restoreConfirmSuffix: 'この操作は元に戻せません。',
+ cancel: 'キャンセル',
+ },
+ settingsWebsearch: {
+ description:
+ 'サードパーティープロファイル(gemini、codex、agy など)向けの CLI ベース Web 検索',
+ enabled: 'WebSearch を有効化',
+ disabled: 'WebSearch を無効化',
+ checking: '状態を確認中...',
+ providers: 'プロバイダー',
+ noneConfigured: 'プロバイダーが設定されていません',
+ noneConfiguredHint:
+ 'Web 検索プロバイダーを有効にするには CLI ツールをインストールしてください',
+ checkProviders: 'プロバイダーを確認',
+ installed: 'インストール済み',
+ notInstalled: '未インストール',
+ model: 'モデル:',
+ howInstall: '{{name}} CLI のインストール方法',
+ installGlobally: 'グローバルにインストール',
+ requiresKey: '(xAI API Key が必要)',
+ freeTier: '(無料枠あり)',
+ viewDocs: 'ドキュメントを見る',
+ },
+ settingsProxy: {
+ failedLoadAgyMode: 'AGY パワーユーザーモードの読み込みに失敗しました',
+ failedUpdateAgyMode: 'AGY パワーユーザーモードの更新に失敗しました',
+ failedVerifyAgyMode: 'AGY パワーユーザーモードの永続化確認に失敗しました',
+ notPersistedAgyMode:
+ 'AGY パワーユーザーモードが保存されませんでした。別のプロセスが設定を変更した可能性があります。',
+ agyModeEnabled: 'AGY パワーユーザーモードを有効にしました。',
+ agyModeDisabled: 'AGY パワーユーザーモードを無効にしました。',
+ typePhraseToContinue: '続行するには「{{value}}」と入力してください。',
+ description:
+ 'プロキシベースのプロファイル用に、ローカルまたはリモートの {{backend}} 接続を設定します',
+ backendPlus: 'CLIProxy Plus',
+ backend: 'CLIProxy',
+ instanceStatus: 'インスタンス状態',
+ connectionMode: '接続モード',
+ local: 'ローカル',
+ remote: 'リモート',
+ localDesc: 'このマシンで {{backend}} バイナリを実行します',
+ remoteDesc: 'リモートの {{backend}} サーバーに接続します',
+ backendBinary: 'バックエンドバイナリ',
+ stopProxyToSwitch:
+ 'バックエンドを切り替える前に、インスタンス状態から実行中のプロキシを停止してください。',
+ default: 'デフォルト',
+ plusDesc: 'Kiro と GitHub Copilot を含むすべてのプロバイダーをサポート',
+ originalDesc: '元のバイナリ(Gemini、Codex、Antigravity のみ)',
+ variantsIncompatible:
+ '既存の Kiro/Copilot バリアントは CLIProxyAPI では動作しません。CLIProxyAPIPlus に切り替えるか、それらのバリアントを削除してください。',
+ safety: '安全設定',
+ agyModeTitle: 'Antigravity パワーユーザーモード',
+ agyModeDesc:
+ 'アカウント追加画面と `ccs agy` フローで、AGY の責任確認チェックをスキップします。',
+ agyWarning:
+ 'OAuth の停止/BAN リスクパターン (#509) を十分理解している場合にのみ使用してください。CCS はアカウント喪失の責任を負いません。',
+ finalConfirm: '最終確認',
+ finalConfirmDesc:
+ '有効にすると、ダッシュボードと CLI の両方で AGY の安全チェックをスキップします。続行する前に issue #509 を確認し、正確なフレーズを入力してください。',
+ step1: 'ステップ 1',
+ readIssue: 'Issue #509 を読む',
+ step2: 'ステップ 2',
+ typePrefix: '有効にするには',
+ typeSuffix: 'と入力してください。',
+ typePhraseAria:
+ 'Antigravity パワーユーザーモードを有効にするには I ACCEPT RISK と入力してください',
+ exactPhrase: '完全一致で入力してください。',
+ enableAgyMode: 'パワーユーザーモードを有効にする',
+ toggleAgyMode: 'AGY パワーユーザーモードを切り替え',
+ fallbackSettings: 'フォールバック設定',
+ enableFallback: 'ローカルへのフォールバックを有効化',
+ enableFallbackDesc: 'リモートに接続できない場合はローカルプロキシを使用します',
+ autoStartLocal: 'ローカルプロキシを自動起動',
+ autoStartLocalDesc: 'フォールバック時にローカルプロキシを自動で起動します',
+ advanced: '詳細設定',
+ debugMode: 'デバッグモード',
+ debugModeDesc: 'ブラウザコンソールで開発者向け診断を有効にします',
+ debugModeEnabled:
+ 'デバッグモードを有効にしました。詳細ログはブラウザコンソールを確認してください。',
+ localProxy: 'ローカルプロキシ',
+ port: 'ポート',
+ autoStart: '自動起動',
+ localAutoStartDesc: '必要になったらローカルプロキシを自動起動します',
+ remoteConfigTitle: 'リモートサーバー設定',
+ host: 'ホスト',
+ hostPlaceholder: '192.168.1.100 または proxy.example.com',
+ defaultPort: 'デフォルト: {{value}}',
+ portPlaceholder: '{{value}} を使う場合は空欄',
+ protocol: 'プロトコル',
+ http: 'HTTP',
+ https: 'HTTPS',
+ apiKeyOptional: 'API Key(任意)',
+ apiKeyPlaceholder: '/v1/* API エンドポイント用',
+ apiKeyDesc: '/v1/chat/completions への API リクエストで使用します',
+ managementKeyOptional: 'Management Key(任意)',
+ managementKeyPlaceholder: '/v0/management/* エンドポイント用',
+ managementKeyDesc:
+ 'ダッシュボードの管理 API で使用します。未設定の場合は API Key を使用します。',
+ testing: 'テスト中...',
+ testConnection: '接続をテスト',
+ connectedLatency: '接続済み({{value}}ms)',
+ connectionFailed: '接続に失敗しました',
+ invalidPortOrEmpty:
+ 'ポートは 1〜65535 の整数で入力するか、デフォルトを使う場合は空欄にしてください',
+ invalidLocalPort: 'ローカルポートは 1〜65535 の整数で指定してください',
+ backendPlusApi: 'CLIProxyAPIPlus',
+ backendApi: 'CLIProxyAPI',
+ },
+ settingsThinking: {
+ description: '対応モデルの高度な思考 / 推論設定を行います。',
+ supportedProviders: '対応プロバイダー',
+ modeTitle: '思考モード',
+ modeAutoDesc: 'モデルのティアに応じて思考レベルを自動設定します',
+ modeOffDesc: '高度な思考を無効化します',
+ modeManualDesc: '永続的な上書きレベルを設定するか、実行ごとに CLI フラグを使います',
+ tierDefaults: 'ティア別デフォルト',
+ tierDefaultsDesc: '自動モード時に各モデルティアへ適用する既定の思考レベルです。',
+ persistentOverride: '永続オーバーライド',
+ persistentOverrideDesc: 'すべてのセッションに適用されます。CLI フラグが優先されます。',
+ enterCustomBudget: 'カスタム予算を入力',
+ apply: '適用',
+ providerOverrides: 'プロバイダー別オーバーライド({{count}})',
+ providerOverridesDesc:
+ '特定のプロバイダーに対してティア別デフォルトを上書きします。必要に応じてカスタムのプロバイダーキーを追加してください。',
+ addProviderPlaceholder: 'プロバイダーキーを追加(例: qwen)',
+ showWarnings: '警告を表示',
+ showWarningsDesc: '思考値が制限または調整された場合に警告を表示します',
+ cliEnvOverride: 'CLI / 環境変数の上書き',
+ supportLine1Prefix: '思考予算:',
+ supportLine1Suffix: '(トークンベース)',
+ supportLine2Prefix: '推論強度:',
+ supportLine2SuffixPrefix: '(サフィックス、または ',
+ supportLine2SuffixPostfix: ': medium/high/xhigh)',
+ supportLine3Prefix: 'Codex のサフィックスは推論強度を固定します(例: ',
+ supportLine3Suffix: ')。サフィックスなしのモデルは思考モードを使います。',
+ },
+ analytics: {
+ title: '分析',
+ subtitle: '利用状況とインサイトを確認',
+ month: '月',
+ allTime: '全期間',
+ updated: '最終更新: {{value}}',
+ },
+ analyticsSummary: {
+ totalTokens: '総トークン数',
+ totalTokensSubtitle: '入力 {{input}} / 出力 {{output}}',
+ totalCost: '総コスト',
+ totalCostSubtitle: '1日平均 ${{value}}',
+ cacheTokens: 'キャッシュトークン',
+ cacheTokensSubtitle: '${{cost}}(コストの{{percent}}%)',
+ inputCost: '入力コスト',
+ outputCost: '出力コスト',
+ tokensSubtitle: '{{value}} トークン',
+ },
+ apiProfiles: {
+ title: 'API プロファイル',
+ new: '新規',
+ searchPlaceholder: 'プロファイルを検索...',
+ loadingProfiles: 'プロファイルを読み込み中...',
+ failedLoadTitle: 'プロファイルを読み込めませんでした',
+ failedLoadDesc: 'API プロファイルを取得できませんでした。もう一度お試しください。',
+ retry: '再試行',
+ noProfilesYet: 'API プロファイルがまだありません',
+ noProfilesDesc: '最初のプロファイルを作成して、カスタム API エンドポイントに接続します',
+ createProfile: 'プロファイルを作成',
+ noProfileMatch: '"{{query}}" に一致するプロファイルはありません',
+ profileCount: '{{count}} 件のプロファイル',
+ profileCount_other: '{{count}} 件のプロファイル',
+ configuredCount: '{{count}} 件設定済み',
+ deleteProfileTitle: 'プロファイルを削除',
+ deleteProfileDesc:
+ '"{{name}}" を削除しますか?設定ファイルも削除され、この操作は元に戻せません。',
+ delete: '削除',
+ unsavedChangesTitle: '未保存の変更',
+ unsavedChangesDesc:
+ '"{{current}}" に未保存の変更があります。破棄して "{{next}}" に切り替えますか?',
+ discardSwitch: '破棄して切り替え',
+ },
+ accountsPage: {
+ title: 'アカウント',
+ managePrefix: '一つの画面で',
+ manageSuffix: 'のアカウント管理とプール導線をまとめて扱えます。',
+ mobileManageSuffix: 'の継続性設定をまとめて管理できます。',
+ primaryActions: '主要アクション',
+ createAccount: 'アカウントを作成',
+ authClaudeInPool: 'Pool で Claude を認証',
+ openClaudePoolSettings: 'Claude Pool の設定を開く',
+ openCliProxyClaudePool: 'CLIProxy Claude Pool を開く',
+ migrationFollowup: '移行フォローアップ',
+ legacyContextPending: '{{count}} 件のアカウントで初回モード確認がまだ必要です。',
+ legacyContextPending_other: '{{count}} 件のアカウントで初回モード確認がまだ必要です。',
+ legacyContinuityPending: '{{count}} 件の共有アカウントが標準のレガシー継続深度のままです。',
+ legacyContinuityPending_other:
+ '{{count}} 件の共有アカウントが標準のレガシー継続深度のままです。',
+ confirmingLegacy: 'レガシーポリシーを確認中...',
+ confirmLegacy: 'レガシーポリシーを確認({{count}})',
+ noLegacyFollowup: '保留中のレガシーフォローアップはありません。',
+ continuityGuide: '継続性ガイド',
+ expandWhenNeeded: '必要なときだけ展開。',
+ sharedStandard: '共有標準',
+ sharedStandardDesc:
+ 'プロジェクトワークスペースの同期のみ。ほとんどのチームに最適な既定値です。',
+ sharedDeeper: '共有拡張',
+ sharedDeeperPrefix: '追加で',
+ isolated: '分離',
+ isolatedDesc: 'リンクなし。厳密な分離に最適です。',
+ quickCommands: 'クイックコマンド',
+ quickCommandsDesc: 'コピーしてターミナルで実行します。',
+ workspaceBadge: 'ccs auth ワークスペース',
+ historySyncBadge: '履歴同期設定',
+ authAccounts: '認証アカウント',
+ tableScopePrefix: 'この表では',
+ tableScopeMiddle: 'のアカウントのみを表示します。モード/グループ/継続性の変更は',
+ tableScopeSuffix: 'を使ってください。',
+ accountMatrix: 'アカウント一覧',
+ sharedTotalDesc:
+ '共有アカウント合計: {{count}}。ここから同期設定とレガシー確認を行えます。',
+ loadingAccounts: 'アカウントを読み込み中...',
+ },
+ health: {
+ justNow: 'たった今',
+ secondsAgo: '{{count}}秒前',
+ minutesAgo: '{{count}}分前',
+ hoursAgo: '{{count}}時間前',
+ systemHealth: 'システムヘルス',
+ build: 'ビルド {{version}}',
+ lastScan: '最終スキャン:',
+ autoRefresh: '自動更新:',
+ refresh: '更新',
+ checks: 'チェック',
+ version: 'バージョン',
+ platform: 'プラットフォーム',
+ liveMonitoring: 'ライブ監視中',
+ copied: 'クリップボードにコピーしました',
+ refreshing: 'ヘルスチェックを更新中...',
+ fix: '修正',
+ applyFix: '修正を適用',
+ healthLabel: 'ヘルス',
+ },
+ updates: {
+ actionRequired: '対応が必要',
+ done: '完了',
+ all: 'すべて',
+ inboxTitle: '更新インボックス',
+ inboxSubtitle: '対応を優先し、その後で完了または非表示にします。',
+ needsAction: '要対応',
+ doneCount: '完了',
+ searchPlaceholder: '対応内容またはコマンドを検索',
+ noNotices: 'このビューに一致する通知はありません。',
+ noUpdates: '利用可能な更新はありません。',
+ published: '{{date}} 公開',
+ markDone: '完了にする',
+ dismiss: '非表示',
+ reopen: '再表示',
+ doNext: '次にやる',
+ impactedIntegrations: '影響を受ける連携',
+ impactedDesc: '更新範囲とルーティングに基づく関連領域です。',
+ whyMatters: '重要な理由',
+ whyMattersDesc: '長文のリリースノートではなく、要点だけを表示します。',
+ open: '開く',
+ progressNeedsAction: '要対応',
+ progressInReview: '確認中',
+ progressDone: '完了',
+ progressDismissed: '非表示',
+ statusNew: '新着',
+ statusStable: '安定',
+ statusPlanned: '予定',
+ dashboard: 'ダッシュボード',
+ cliUsage: 'CLI利用状況',
+ },
+ cliproxyPage: {
+ connected: '接続済み',
+ notConnected: '未接続',
+ variant: 'バリアント',
+ parentNotConnected: '親が未接続',
+ viaProvider: '{{provider}} 経由',
+ emptyTitle: 'CCS プロファイルマネージャー',
+ emptyDesc:
+ 'CLIProxy プロバイダー向けの OAuth 認証、アカウント設定、モデル選択を管理します。CCS が各 AI バックエンドへのリクエストをどうルーティングするかを設定できます。',
+ emptyControlPanelPrefix: 'ライブ利用統計とリアルタイム監視は',
+ controlPanel: 'コントロールパネルで確認できます',
+ quickSetup: 'クイックセットアップ',
+ accountManagement: 'CCSレベルのアカウント管理',
+ providers: 'プロバイダー',
+ variants: 'バリアント',
+ providerCount: '{{count}} 件のプロバイダー',
+ providerCount_other: '{{count}} 件のプロバイダー',
+ connectedCount: '{{count}} 件接続済み',
+ variantDisplay: '{{name}}({{provider}} バリアント)',
+ },
+ copilotPage: {
+ title: 'Copilot',
+ subtitle: 'GitHub Copilot プロキシ',
+ setup: 'セットアップ',
+ auth: '認証',
+ daemon: 'デーモン',
+ unofficialTitle: '非公式API: 自己責任で利用してください',
+ unofficialItem1:
+ 'リバースエンジニアリングされたAPIのため、いつでも動かなくなる可能性があります',
+ unofficialItem2: '過度な利用でアカウントに制限がかかる可能性があります',
+ unofficialItem3: 'CCSは保証も責任も負いません',
+ yes: 'はい',
+ no: 'いいえ',
+ installed: 'インストール済み',
+ missing: '未インストール',
+ integration: '連携',
+ enabled: '有効',
+ disabled: '無効',
+ github: 'GitHub',
+ connected: '接続済み',
+ notConnected: '未接続',
+ authenticate: '認証する',
+ authenticating: '認証中...',
+ status: 'ステータス',
+ running: '稼働中',
+ stopped: '停止',
+ port: 'ポート',
+ stopping: '停止中...',
+ stop: '停止',
+ starting: '起動中...',
+ start: '起動',
+ installing: 'インストール中...',
+ installCopilotApi: 'copilot-api をインストール',
+ proxy: 'プロキシ',
+ active: '有効',
+ inactive: '無効',
+ },
+ cursorPage: {
+ title: 'Cursor',
+ beta: 'ベータ',
+ subtitle: 'Cursor 専用の連携設定',
+ unofficialTitle: '非公式API - 自己責任で利用',
+ unofficialItem1:
+ 'リバースエンジニアリング連携のため、いつでも利用不能になる可能性があります',
+ unofficialItem2: '不正利用や過度な利用により、アカウントが制限されるおそれがあります',
+ unofficialItem3: 'CCSは保証も責任も負いません',
+ integration: '連携',
+ authentication: '認証',
+ daemon: 'デーモン',
+ enabled: '有効',
+ disabled: '無効',
+ expired: '期限切れ',
+ connected: '接続済み',
+ notConnected: '未接続',
+ running: '稼働中',
+ stopped: '停止中',
+ actions: '操作',
+ disableIntegration: '連携を無効化',
+ enableIntegration: '連携を有効化',
+ autoDetectAuth: '認証を自動検出',
+ manualAuthImport: '認証情報を手動インポート',
+ stopDaemon: 'デーモンを停止',
+ startDaemon: 'デーモンを起動',
+ port: 'ポート',
+ configuration: 'Cursor設定',
+ lastModified: '最終更新:',
+ neverSaved: '未保存',
+ saving: '保存中...',
+ save: '保存',
+ modelConfig: 'モデル設定',
+ settings: '設定',
+ info: '情報',
+ presets: 'プリセット',
+ presetsDesc: '事前設定済みのモデルマッピングを適用します',
+ modelMapping: 'モデルマッピング',
+ modelMappingDesc: '各ティアで使うモデルを設定します',
+ defaultModel: 'デフォルトモデル',
+ defaultModelDesc: '特定のティア指定がない場合に使われます。',
+ opusModel: 'Opus(最高性能)',
+ opusModelDesc: '複雑な推論と最高品質の応答向け。',
+ sonnetModel: 'Sonnet(バランス)',
+ sonnetModelDesc: '一般的なコーディングや日常的なチャット向け。',
+ haikuModel: 'Haiku(高速)',
+ haikuModelDesc: '低レイテンシで軽量なリクエスト向け。',
+ runtimeSettings: 'ランタイム設定',
+ autoStartDaemon: 'デーモンを自動起動',
+ autoStartDesc: '連携使用時にCursorデーモンを自動で起動します。',
+ ghostMode: 'ゴーストモード',
+ ghostModeDesc: 'テレメトリ削減のため x-ghost-mode を要求します。',
+ provider: 'プロバイダー',
+ filePath: 'ファイルパス',
+ availableModels: '利用可能なモデル',
+ loadingModels: 'モデルを読み込み中...',
+ noModels: 'モデルメタデータはまだありません。デーモンを起動して更新してください。',
+ default: 'デフォルト',
+ rawConfiguration: '生の設定(JSON)',
+ manualImportTitle: 'Cursor 認証情報の手動インポート',
+ manualImportDesc:
+ '自動検出できない場合は、CursorのアクセストークンとマシンIDを入力してください。',
+ accessToken: 'アクセストークン',
+ accessTokenPlaceholder: 'Cursorのアクセストークンを貼り付け',
+ machineId: 'マシンID',
+ machineIdPlaceholder: '32文字の16進数(ハイフンなしUUID)',
+ cancel: 'キャンセル',
+ import: 'インポート',
+ selectModel: 'モデルを選択',
+ useDefaultModel: 'デフォルトモデルを使用',
+ availableModelCount: '利用可能なモデル({{count}})',
+ invalidPort: 'ポートは1から65535の整数で指定してください',
+ defaultModelRequired: 'デフォルトモデルは必須です',
+ savedConfig: 'Cursor設定とモデルマッピングを保存しました',
+ failedSaveConfig: '設定の保存に失敗しました',
+ modelsLoadingWait: 'モデルの読み込み中です。プリセットの適用前にしばらくお待ちください。',
+ noModelsAvailable:
+ 'まだ利用可能なモデルがありません。先にデーモンを起動して更新してください。',
+ appliedCodexPreset: 'GPT-5.3 Codexプリセットを適用しました',
+ appliedClaudePreset: 'Claude 4.6プリセットを適用しました',
+ appliedGeminiPreset: 'Gemini 3プリセットを適用しました',
+ integrationEnabled: 'Cursor連携を有効化しました',
+ integrationDisabled: 'Cursor連携を無効化しました',
+ failedUpdateIntegration: '連携状態の更新に失敗しました',
+ credentialsImported: 'Cursor認証情報をインポートしました',
+ autoDetectFailed: '自動検出に失敗しました',
+ manualRequired: 'トークンとマシンIDは必須です',
+ manualImportFailed: '手動インポートに失敗しました',
+ failedStartDaemon: 'デーモンの起動に失敗しました',
+ daemonStarted: 'デーモンを起動しました',
+ daemonStartedWithPid: 'デーモンを起動しました(PID: {{pid}})',
+ failedStopDaemon: 'デーモンの停止に失敗しました',
+ daemonStopped: 'デーモンを停止しました',
+ rawLoading: '生の設定をまだ読み込み中です。しばらく待ってから再試行してください。',
+ invalidJson: 'JSONが不正です',
+ rawSaved: '生の設定を保存しました',
+ rawChanged: '生の設定が外部で変更されました。更新して再試行してください。',
+ failedSaveRaw: '生の設定の保存に失敗しました',
+ savedAll: 'Cursor設定を保存しました',
+ },
+ droidPage: {
+ loadingDiagnostics: 'Droid診断を読み込み中...',
+ failedDiagnostics: 'Droid診断の読み込みに失敗しました。',
+ overview: '概要',
+ byok: 'BYOK',
+ docs: 'ドキュメント',
+ runtimeInstall: 'ランタイムとインストール',
+ status: '状態',
+ detected: '検出済み',
+ notFound: '未検出',
+ detectionSource: '検出元',
+ binaryPath: 'バイナリパス',
+ installDirectory: 'インストール先',
+ version: 'バージョン',
+ overridePath: 'オーバーライド(CCS_DROID_PATH)',
+ configFiles: '設定ファイル',
+ path: 'パス',
+ resolved: '解決先',
+ size: 'サイズ',
+ lastModified: '最終更新',
+ parseWarning: '解析警告: {{value}}',
+ readWarning: '読み取り警告: {{value}}',
+ warnings: '警告',
+ byokSummary: 'BYOK概要',
+ activeModelSelector: '現在のモデルセレクター',
+ customModels: 'カスタムモデル',
+ ccsManaged: 'CCS管理',
+ userManaged: 'ユーザー管理',
+ malformedEntries: '不正なエントリ',
+ providers: 'プロバイダー',
+ none: 'なし',
+ customModelsTitle: 'カスタムモデル',
+ modelName: '名前 / モデル',
+ provider: 'プロバイダー',
+ baseUrl: 'ベース URL',
+ noCustomModels: 'カスタムモデルはありません',
+ docsAlignedNotes: 'ドキュメント整合メモ',
+ factoryDocs: 'Factory Docs',
+ providerFactCheckDocs: 'プロバイダー検証ドキュメント',
+ providerValues: 'プロバイダー値: {{value}}',
+ settingsHierarchy: '設定階層: {{value}}',
+ settingsTitle: 'Droid BYOK 設定',
+ fixJsonBeforeQuickSettings: 'クイック設定を使う前に JSON 構文を修正してください。',
+ fixJsonBeforeReasoning: 'BYOK 推論設定を更新する前に JSON 構文を修正してください。',
+ unableUpdateReasoning: '選択した BYOK モデルの推論設定を更新できません。',
+ fixJsonBeforeBudget: '思考予算を更新する前に JSON 構文を修正してください。',
+ anthropicOnlyBudget: '思考予算は Anthropic の BYOK モデルでのみ利用できます。',
+ invalidJson: 'JSON が不正です: {{value}}',
+ saved: 'Droid 設定を保存しました',
+ changedExternally: 'Droid 設定が外部で変更されました。更新して再試行してください。',
+ failedSave: 'Droid 設定の保存に失敗しました',
+ },
+ sharedPage: {
+ commands: 'コマンド',
+ skills: 'スキル',
+ agents: 'エージェント',
+ title: '共有データ',
+ subtitle: 'Claudeインスタンス間で共有されるコマンド、スキル、エージェント',
+ totalShared: '共有数',
+ visible: '表示中',
+ markdownDetail: 'Markdown詳細ビュー',
+ filterPrefix: 'フィルター:',
+ configurationRequired: '設定が必要です',
+ countsUnavailable: '件数を取得できません',
+ retryCounts: '件数を再取得',
+ filterPlaceholder: '{{tab}}を名前、説明、パスで絞り込み',
+ showing: '{{visible}} / {{total}} 件の{{tab}}を表示',
+ showingQuery: '(「{{query}}」で絞り込み)',
+ refreshing: '(更新中...)',
+ loadingShared: '共有{{tab}}を読み込み中...',
+ failedLoadShared: '共有{{tab}}の読み込みに失敗しました',
+ retry: '再試行',
+ noSharedFound:
+ '共有{{tab}}が見つかりません。`ccs sync` を実行するか、共有ディレクトリに項目を追加してください。',
+ noMatch: '{{tab}}で「{{query}}」に一致するものはありません。',
+ selectOne: '内容を表示する{{tab}}を選択してください。',
+ pathLabel: 'パス',
+ resolvedSource: '解決後ソース',
+ loadingMarkdown: 'Markdownコンテンツを読み込み中...',
+ failedLoadContent: 'コンテンツの読み込みに失敗しました',
+ retryContent: '再読み込み',
+ noMarkdown: 'Markdownコンテンツはありません。',
+ },
+ },
+ },
} as const;
if (!i18n.isInitialized) {
diff --git a/ui/src/lib/locales.ts b/ui/src/lib/locales.ts
index ca719231..c9f82d5e 100644
--- a/ui/src/lib/locales.ts
+++ b/ui/src/lib/locales.ts
@@ -1,6 +1,6 @@
export const LOCALE_STORAGE_KEY = 'ccs-ui-locale';
-export const SUPPORTED_LOCALES = ['en', 'zh-CN', 'vi'] as const;
+export const SUPPORTED_LOCALES = ['en', 'zh-CN', 'vi', 'ja'] as const;
export type AppLocale = (typeof SUPPORTED_LOCALES)[number];
@@ -10,6 +10,7 @@ export function isSupportedLocale(locale: string): locale is AppLocale {
export function normalizeLocale(locale: string | null | undefined): AppLocale {
if (!locale) return 'en';
+ if (locale.toLowerCase().startsWith('ja')) return 'ja';
if (locale.toLowerCase().startsWith('zh')) return 'zh-CN';
if (locale.toLowerCase().startsWith('vi')) return 'vi';
return 'en';
diff --git a/ui/src/pages/accounts.tsx b/ui/src/pages/accounts.tsx
index 6b517db5..877b04b4 100644
--- a/ui/src/pages/accounts.tsx
+++ b/ui/src/pages/accounts.tsx
@@ -232,7 +232,7 @@ export function AccountsPage() {
{t('accountsPage.tableScopePrefix')}
ccs auth
{t('accountsPage.tableScopeMiddle')}
- Sync
+ {t('accountsTable.sync')}
{t('accountsPage.tableScopeSuffix')}
diff --git a/ui/tests/unit/ui/i18n/language-switcher.test.tsx b/ui/tests/unit/ui/i18n/language-switcher.test.tsx
index 80f6ced7..fc0d08b0 100644
--- a/ui/tests/unit/ui/i18n/language-switcher.test.tsx
+++ b/ui/tests/unit/ui/i18n/language-switcher.test.tsx
@@ -2,12 +2,14 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
import { render, screen, userEvent, waitFor } from '@tests/setup/test-utils';
import i18n from '@/lib/i18n';
import { LanguageSwitcher } from '@/components/layout/language-switcher';
+import { HistorySyncLearningMap } from '@/components/account/history-sync-learning-map';
import { TabNavigation } from '@/pages/settings/components/tab-navigation';
import {
getInitialLocale,
LOCALE_STORAGE_KEY,
normalizeLocale,
persistLocale,
+ SUPPORTED_LOCALES,
} from '@/lib/locales';
function flattenKeys(node: unknown, prefix = '', out = new Set