diff --git a/README_i18n.md b/README_i18n.md
index eef75a77..662892f9 100644
--- a/README_i18n.md
+++ b/README_i18n.md
@@ -4,7 +4,7 @@
1. **安装依赖**:添加了 `react-i18next` 和 `i18next` 包
2. **配置国际化**:在 `src/i18n/` 目录下创建了配置文件
-3. **翻译文件**:创建了英文和中文翻译文件
+3. **翻译文件**:创建了英文、中文、日文翻译文件
4. **组件更新**:替换了主要组件中的硬编码文案
5. **语言切换器**:添加了语言切换按钮
@@ -16,6 +16,7 @@ src/
│ ├── index.ts # 国际化配置文件
│ └── locales/
│ ├── en.json # 英文翻译
+│ ├── ja.json # 日文翻译
│ └── zh.json # 中文翻译
├── components/
│ └── LanguageSwitcher.tsx # 语言切换组件
@@ -24,7 +25,7 @@ src/
## 默认语言设置
-- **默认语言**:英文 (en)
+- **默认语言**:中文 (zh)(无首选时根据浏览器/系统语言选择 zh/en/ja)
- **回退语言**:英文 (en)
## 使用方式
@@ -57,7 +58,7 @@ src/
## 测试功能
-应用已添加了语言切换按钮(地球图标),点击可以在中英文之间切换,验证国际化功能是否正常工作。
+应用已添加了语言切换按钮,支持中文、英文、日文三种语言切换,验证国际化功能是否正常工作。
## 已更新的组件
diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs
index cd8cbc9f..fbfc96f9 100644
--- a/src-tauri/src/lib.rs
+++ b/src-tauri/src/lib.rs
@@ -69,6 +69,11 @@ impl TrayTexts {
no_provider_hint: " (No providers yet, please add them from the main window)",
quit: "Quit",
},
+ "ja" => Self {
+ show_main: "メインウィンドウを開く",
+ no_provider_hint: " (プロバイダーがまだありません。メイン画面から追加してください)",
+ quit: "終了",
+ },
_ => Self {
show_main: "打开主界面",
no_provider_hint: " (无供应商,请在主界面添加)",
diff --git a/src-tauri/src/settings.rs b/src-tauri/src/settings.rs
index b078d83a..bd239b5e 100644
--- a/src-tauri/src/settings.rs
+++ b/src-tauri/src/settings.rs
@@ -118,7 +118,7 @@ impl AppSettings {
.language
.as_ref()
.map(|s| s.trim())
- .filter(|s| matches!(*s, "en" | "zh"))
+ .filter(|s| matches!(*s, "en" | "zh" | "ja"))
.map(|s| s.to_string());
}
diff --git a/src/components/settings/LanguageSettings.tsx b/src/components/settings/LanguageSettings.tsx
index dd86400b..8ef2cb13 100644
--- a/src/components/settings/LanguageSettings.tsx
+++ b/src/components/settings/LanguageSettings.tsx
@@ -2,9 +2,11 @@ import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { useTranslation } from "react-i18next";
+type LanguageOption = "zh" | "en" | "ja";
+
interface LanguageSettingsProps {
- value: "zh" | "en";
- onChange: (value: "zh" | "en") => void;
+ value: LanguageOption;
+ onChange: (value: LanguageOption) => void;
}
export function LanguageSettings({ value, onChange }: LanguageSettingsProps) {
@@ -25,6 +27,9 @@ export function LanguageSettings({ value, onChange }: LanguageSettingsProps) {
onChange("en")}>
{t("settings.languageOptionEnglish")}
+ onChange("ja")}>
+ {t("settings.languageOptionJapanese")}
+
);
diff --git a/src/hooks/useSettings.ts b/src/hooks/useSettings.ts
index 280d5aec..d6dd7458 100644
--- a/src/hooks/useSettings.ts
+++ b/src/hooks/useSettings.ts
@@ -12,7 +12,7 @@ import {
} from "./useDirectorySettings";
import { useSettingsMetadata } from "./useSettingsMetadata";
-type Language = "zh" | "en";
+type Language = "zh" | "en" | "ja";
interface SaveResult {
requiresRestart: boolean;
diff --git a/src/hooks/useSettingsForm.ts b/src/hooks/useSettingsForm.ts
index 742e735d..c823992b 100644
--- a/src/hooks/useSettingsForm.ts
+++ b/src/hooks/useSettingsForm.ts
@@ -3,7 +3,7 @@ import { useTranslation } from "react-i18next";
import { useSettingsQuery } from "@/lib/query";
import type { Settings } from "@/types";
-type Language = "zh" | "en";
+type Language = "zh" | "en" | "ja";
export type SettingsFormState = Omit & {
language: Language;
@@ -11,7 +11,8 @@ export type SettingsFormState = Omit & {
const normalizeLanguage = (lang?: string | null): Language => {
if (!lang) return "zh";
- return lang === "en" ? "en" : "zh";
+ const normalized = lang.toLowerCase();
+ return normalized === "en" || normalized === "ja" ? normalized : "zh";
};
const sanitizeDir = (value?: string | null): string | undefined => {
@@ -51,8 +52,8 @@ export function useSettingsForm(): UseSettingsFormResult {
const readPersistedLanguage = useCallback((): Language => {
if (typeof window !== "undefined") {
const stored = window.localStorage.getItem("language");
- if (stored === "en" || stored === "zh") {
- return stored;
+ if (stored === "en" || stored === "zh" || stored === "ja") {
+ return stored as Language;
}
}
return normalizeLanguage(i18n.language);
diff --git a/src/i18n/index.ts b/src/i18n/index.ts
index 5002f0c3..81c55275 100644
--- a/src/i18n/index.ts
+++ b/src/i18n/index.ts
@@ -2,15 +2,18 @@ import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import en from "./locales/en.json";
+import ja from "./locales/ja.json";
import zh from "./locales/zh.json";
-const DEFAULT_LANGUAGE: "zh" | "en" = "zh";
+type Language = "zh" | "en" | "ja";
-const getInitialLanguage = (): "zh" | "en" => {
+const DEFAULT_LANGUAGE: Language = "zh";
+
+const getInitialLanguage = (): Language => {
if (typeof window !== "undefined") {
try {
const stored = window.localStorage.getItem("language");
- if (stored === "zh" || stored === "en") {
+ if (stored === "zh" || stored === "en" || stored === "ja") {
return stored;
}
} catch (error) {
@@ -28,6 +31,10 @@ const getInitialLanguage = (): "zh" | "en" => {
return "zh";
}
+ if (navigatorLang?.startsWith("ja")) {
+ return "ja";
+ }
+
if (navigatorLang?.startsWith("en")) {
return "en";
}
@@ -39,6 +46,9 @@ const resources = {
en: {
translation: en,
},
+ ja: {
+ translation: ja,
+ },
zh: {
translation: zh,
},
diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json
index 0e9073ac..92d6b678 100644
--- a/src/i18n/locales/en.json
+++ b/src/i18n/locales/en.json
@@ -165,6 +165,7 @@
"autoReload": "Data will refresh automatically in 2 seconds...",
"languageOptionChinese": "中文",
"languageOptionEnglish": "English",
+ "languageOptionJapanese": "日本語",
"windowBehavior": "Window Behavior",
"windowBehaviorHint": "Configure window minimize and Claude plugin integration policies.",
"launchOnStartup": "Launch on Startup",
diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json
new file mode 100644
index 00000000..ed099ff5
--- /dev/null
+++ b/src/i18n/locales/ja.json
@@ -0,0 +1,837 @@
+{
+ "app": {
+ "title": "CC Switch",
+ "description": "Claude Code・Codex・Gemini CLI のためのオールインワンアシスタント"
+ },
+ "common": {
+ "add": "追加",
+ "edit": "編集",
+ "delete": "削除",
+ "save": "保存",
+ "saving": "保存中...",
+ "cancel": "キャンセル",
+ "confirm": "確認",
+ "close": "閉じる",
+ "done": "完了",
+ "settings": "設定",
+ "about": "バージョン情報",
+ "version": "バージョン",
+ "loading": "読み込み中...",
+ "success": "成功",
+ "error": "エラー",
+ "unknown": "不明",
+ "enterValidValue": "有効な値を入力してください",
+ "clear": "クリア",
+ "toggleTheme": "テーマを切り替え",
+ "format": "フォーマット",
+ "formatSuccess": "整形しました",
+ "formatError": "整形に失敗しました: {{error}}",
+ "copy": "コピー",
+ "view": "表示",
+ "back": "戻る"
+ },
+ "apiKeyInput": {
+ "placeholder": "API Key を入力",
+ "show": "API Key を表示",
+ "hide": "API Key を隠す"
+ },
+ "jsonEditor": {
+ "mustBeObject": "設定はオブジェクト形式の JSON で入力してください(配列や他の型は不可)",
+ "invalidJson": "JSON 形式が正しくありません"
+ },
+ "claudeConfig": {
+ "configLabel": "Claude Code settings.json (JSON) *",
+ "writeCommonConfig": "共通設定を書き込む",
+ "editCommonConfig": "共通設定を編集",
+ "editCommonConfigTitle": "共通設定スニペットを編集",
+ "commonConfigHint": "「共通設定を書き込む」がオンのとき settings.json にマージされます",
+ "fullSettingsHint": "Claude Code の settings.json 全文"
+ },
+ "header": {
+ "viewOnGithub": "GitHub で見る",
+ "toggleDarkMode": "ダークモードに切り替え",
+ "toggleLightMode": "ライトモードに切り替え",
+ "addProvider": "プロバイダーを追加",
+ "switchToChinese": "中国語に切り替え",
+ "switchToEnglish": "英語に切り替え",
+ "enterEditMode": "編集モードに入る",
+ "exitEditMode": "編集モードを終了"
+ },
+ "provider": {
+ "noProviders": "まだプロバイダーがありません",
+ "noProvidersDescription": "右上の「プロバイダーを追加」を押して最初の API プロバイダーを登録してください",
+ "currentlyUsing": "現在使用中",
+ "enable": "有効化",
+ "inUse": "使用中",
+ "editProvider": "プロバイダーを編集",
+ "editProviderHint": "保存すると現在のプロバイダーにすぐ反映されます。",
+ "deleteProvider": "プロバイダーを削除",
+ "addNewProvider": "新しいプロバイダーを追加",
+ "addClaudeProvider": "Claude Code プロバイダーを追加",
+ "addCodexProvider": "Codex プロバイダーを追加",
+ "addGeminiProvider": "Gemini プロバイダーを追加",
+ "addProviderHint": "一覧にすばやく切り替えられるよう、ここに情報を入力してください。",
+ "editClaudeProvider": "Claude Code プロバイダーを編集",
+ "editCodexProvider": "Codex プロバイダーを編集",
+ "configError": "設定エラー",
+ "notConfigured": "公式サイト用に未設定",
+ "applyToClaudePlugin": "Claude プラグインに適用",
+ "removeFromClaudePlugin": "Claude プラグインから解除",
+ "dragToReorder": "ドラッグで並べ替え",
+ "dragHandle": "ドラッグで並べ替え",
+ "duplicate": "複製",
+ "sortUpdateFailed": "並び順の更新に失敗しました",
+ "configureUsage": "利用状況を設定",
+ "name": "プロバイダー名",
+ "namePlaceholder": "例: Claude Official",
+ "websiteUrl": "Web サイト URL",
+ "notes": "メモ",
+ "notesPlaceholder": "例: 会社用アカウント",
+ "configJson": "Config JSON",
+ "writeCommonConfig": "共通設定を書き込む",
+ "editCommonConfigButton": "共通設定を編集",
+ "configJsonHint": "Claude Code の設定をすべて入力してください",
+ "editCommonConfigTitle": "共通設定スニペットを編集",
+ "editCommonConfigHint": "共通設定スニペットは、この機能をオンにしたすべてのプロバイダーへマージされます",
+ "addProvider": "プロバイダーを追加",
+ "sortUpdated": "並び順を更新しました",
+ "usageSaved": "利用状況の設定を保存しました",
+ "usageSaveFailed": "利用状況設定の保存に失敗しました",
+ "geminiConfig": "Gemini 設定",
+ "geminiConfigHint": ".env 形式で Gemini を設定してください",
+ "form": {
+ "gemini": {
+ "model": "モデル",
+ "oauthTitle": "OAuth 認証モード",
+ "oauthHint": "Google 公式は OAuth 個人認証を使用するため API Key は不要です。初回利用時にブラウザが開きます。",
+ "apiKeyPlaceholder": "Gemini API Key を入力"
+ }
+ }
+ },
+ "notifications": {
+ "providerAdded": "プロバイダーを追加しました",
+ "providerSaved": "プロバイダー設定を保存しました",
+ "providerDeleted": "プロバイダーを削除しました",
+ "switchSuccess": "切り替え成功! {{appName}} ターミナルを再起動すると反映されます",
+ "switchFailedTitle": "切り替えに失敗しました",
+ "switchFailed": "切り替えに失敗しました: {{error}}",
+ "autoImported": "既存設定からデフォルトプロバイダーを自動作成しました",
+ "addFailed": "プロバイダーの追加に失敗しました: {{error}}",
+ "saveFailed": "保存に失敗しました: {{error}}",
+ "saveFailedGeneric": "保存に失敗しました。もう一度お試しください",
+ "appliedToClaudePlugin": "Claude プラグインに適用しました",
+ "removedFromClaudePlugin": "Claude プラグインから削除しました",
+ "syncClaudePluginFailed": "Claude プラグインとの同期に失敗しました",
+ "updateSuccess": "プロバイダーを更新しました",
+ "updateFailed": "プロバイダーの更新に失敗しました: {{error}}",
+ "deleteSuccess": "プロバイダーを削除しました",
+ "deleteFailed": "プロバイダーの削除に失敗しました: {{error}}",
+ "settingsSaved": "設定を保存しました",
+ "settingsSaveFailed": "設定の保存に失敗しました: {{error}}"
+ },
+ "confirm": {
+ "deleteProvider": "プロバイダーを削除",
+ "deleteProviderMessage": "プロバイダー「{{name}}」を削除してもよろしいですか?この操作は元に戻せません。"
+ },
+ "settings": {
+ "title": "設定",
+ "general": "一般",
+ "tabGeneral": "一般",
+ "tabAdvanced": "詳細",
+ "language": "言語",
+ "languageHint": "切り替えるとすぐにプレビューされ、保存後に永続化されます。",
+ "theme": "テーマ",
+ "themeHint": "アプリのテーマを選択します。すぐに反映されます。",
+ "themeLight": "ライト",
+ "themeDark": "ダーク",
+ "themeSystem": "システム",
+ "importExport": "SQL インポート/エクスポート",
+ "importExportHint": "移行や復元用にデータベースの SQL バックアップをインポート/エクスポートします。",
+ "exportConfig": "SQL バックアップをエクスポート",
+ "selectConfigFile": "SQL ファイルを選択",
+ "noFileSelected": "ファイルが選択されていません。",
+ "import": "インポート",
+ "importing": "インポート中...",
+ "importSuccess": "インポート成功!",
+ "importFailed": "インポート失敗",
+ "syncLiveFailed": "インポートしましたが、現在のプロバイダーへの同期に失敗しました。手動で再選択してください。",
+ "importPartialSuccess": "設定はインポートされましたが、現在のプロバイダーへの同期に失敗しました。",
+ "importPartialHint": "ライブ設定を更新するため、もう一度プロバイダーを選択してください。",
+ "configExported": "設定をエクスポートしました:",
+ "exportFailed": "エクスポートに失敗しました",
+ "selectFileFailed": "有効な SQL バックアップファイルを選択してください",
+ "configCorrupted": "SQL ファイルが壊れているか形式が無効な可能性があります",
+ "backupId": "バックアップ ID",
+ "autoReload": "2 秒後に自動で再読み込みします...",
+ "languageOptionChinese": "中文",
+ "languageOptionEnglish": "English",
+ "languageOptionJapanese": "日本語",
+ "windowBehavior": "ウィンドウ動作",
+ "windowBehaviorHint": "最小化動作や Claude プラグイン連携を設定します。",
+ "launchOnStartup": "起動時に自動実行",
+ "launchOnStartupDescription": "システム起動時に CC Switch を自動起動します",
+ "autoLaunchFailed": "自動起動の設定に失敗しました",
+ "minimizeToTray": "閉じるときトレイへ最小化",
+ "minimizeToTrayDescription": "チェックすると閉じるボタンでトレイに隠し、オフならアプリを終了します。",
+ "enableClaudePluginIntegration": "Claude Code 拡張に適用",
+ "enableClaudePluginIntegrationDescription": "オンにすると VS Code の Claude Code 拡張のプロバイダーも同期します",
+ "configDirectoryOverride": "設定ディレクトリの上書き(詳細)",
+ "configDirectoryDescription": "WSL などで Claude Code や Codex を使う場合、ここで設定ディレクトリを WSL 側に合わせるとデータを揃えられます。",
+ "appConfigDir": "CC Switch 設定ディレクトリ",
+ "appConfigDirDescription": "CC Switch の保存場所をカスタマイズします(クラウド同期フォルダを指定すると設定を同期できます)",
+ "browsePlaceholderApp": "例: C:\\\\Users\\\\Administrator\\\\.cc-switch",
+ "claudeConfigDir": "Claude Code 設定ディレクトリ",
+ "claudeConfigDirDescription": "Claude の設定ディレクトリ(settings.json)を上書きし、claude.json(MCP)も同じ場所に置きます。",
+ "codexConfigDir": "Codex 設定ディレクトリ",
+ "codexConfigDirDescription": "Codex の設定ディレクトリを上書きします。",
+ "geminiConfigDir": "Gemini 設定ディレクトリ",
+ "geminiConfigDirDescription": "Gemini の設定ディレクトリ(.env)を上書きします。",
+ "browsePlaceholderClaude": "例: /home//.claude",
+ "browsePlaceholderCodex": "例: /home//.codex",
+ "browsePlaceholderGemini": "例: /home//.gemini",
+ "browseDirectory": "ディレクトリを選択",
+ "resetDefault": "デフォルトに戻す(保存後に反映)",
+ "checkForUpdates": "アップデートを確認",
+ "updateTo": "v{{version}} に更新",
+ "updating": "更新中...",
+ "checking": "確認中...",
+ "upToDate": "最新バージョンです",
+ "aboutHint": "バージョン情報と更新状況を表示します。",
+ "portableMode": "ポータブルモード: 更新は手動ダウンロードが必要です。",
+ "updateAvailable": "新しいバージョンがあります: {{version}}",
+ "updateFailed": "更新のインストールに失敗しました。ダウンロードページを開こうとしました。",
+ "checkUpdateFailed": "更新の確認に失敗しました。時間をおいて再試行してください。",
+ "openReleaseNotesFailed": "リリースノートの表示に失敗しました",
+ "releaseNotes": "リリースノート",
+ "viewReleaseNotes": "このバージョンのリリースノートを見る",
+ "viewCurrentReleaseNotes": "現在のバージョンのリリースノートを見る",
+ "importFailedError": "設定のインポートに失敗しました: {{message}}",
+ "exportFailedError": "設定のエクスポートに失敗しました:",
+ "restartRequired": "再起動が必要です",
+ "restartRequiredMessage": "CC Switch の設定ディレクトリを変更すると再起動が必要です。今すぐ再起動しますか?",
+ "restartNow": "今すぐ再起動",
+ "restartLater": "後で再起動",
+ "restartFailed": "アプリの再起動に失敗しました。手動で閉じて再度開いてください。",
+ "devModeRestartHint": "開発モードでは自動再起動をサポートしていません。手動で再起動してください。",
+ "saving": "保存中..."
+ },
+ "apps": {
+ "claude": "Claude Code",
+ "codex": "Codex",
+ "gemini": "Gemini"
+ },
+ "console": {
+ "providerSwitchReceived": "プロバイダー切り替えイベントを受信:",
+ "setupListenerFailed": "プロバイダー切り替えリスナーの設定に失敗:",
+ "updateProviderFailed": "プロバイダー更新に失敗:",
+ "autoImportFailed": "デフォルト設定の自動インポートに失敗:",
+ "openLinkFailed": "リンクを開けませんでした:",
+ "getVersionFailed": "バージョン情報の取得に失敗:",
+ "loadSettingsFailed": "設定の読み込みに失敗:",
+ "getConfigPathFailed": "設定パスの取得に失敗:",
+ "getConfigDirFailed": "設定ディレクトリの取得に失敗:",
+ "detectPortableFailed": "ポータブルモードの検出に失敗:",
+ "saveSettingsFailed": "設定の保存に失敗:",
+ "updateFailed": "更新に失敗:",
+ "checkUpdateFailed": "更新確認に失敗:",
+ "openConfigFolderFailed": "設定フォルダを開けませんでした:",
+ "selectConfigDirFailed": "設定ディレクトリの選択に失敗:",
+ "getDefaultConfigDirFailed": "デフォルト設定ディレクトリの取得に失敗:",
+ "openReleaseNotesFailed": "リリースノートを開けませんでした:"
+ },
+ "providerForm": {
+ "supplierName": "プロバイダー名",
+ "supplierNameRequired": "プロバイダー名 *",
+ "supplierNamePlaceholder": "例: Anthropic Official",
+ "websiteUrl": "Web サイト URL",
+ "websiteUrlPlaceholder": "https://example.com(任意)",
+ "apiEndpoint": "API エンドポイント",
+ "apiEndpointPlaceholder": "https://your-api-endpoint.com",
+ "codexApiEndpointPlaceholder": "https://your-api-endpoint.com/v1",
+ "manageAndTest": "管理・テスト",
+ "configContent": "設定内容",
+ "officialNoApiKey": "公式ログインは API Key 不要です。そのまま保存できます",
+ "codexOfficialNoApiKey": "公式は API Key 不要です。そのまま保存してください",
+ "codexApiKeyAutoFill": "ここに入力すれば auth.json も自動で埋まります",
+ "apiKeyAutoFill": "ここに入力すれば下の設定も自動で埋まります",
+ "cnOfficialApiKeyHint": "💡 API Key のみ入力すれば OK。エンドポイントはプリセット済みです",
+ "aggregatorApiKeyHint": "💡 API Key のみ入力すれば OK。エンドポイントはプリセット済みです",
+ "thirdPartyApiKeyHint": "💡 API Key のみ入力すれば OK。エンドポイントはプリセット済みです",
+ "customApiKeyHint": "💡 カスタム設定では必要な項目をすべて手動で入力してください",
+ "officialHint": "💡 公式プロバイダーはブラウザログインで、API Key は不要です",
+ "getApiKey": "API Key を取得",
+ "partnerPromotion": {
+ "zhipu": "Zhipu GLM は CC Switch の公式パートナーです。リンク経由でチャージすると 10% 割引",
+ "packycode": "PackyCode は CC Switch の公式パートナーです。登録後チャージ時に \"cc-switch\" を入力すると 10% オフ",
+ "minimax": "MiniMax Coding Plan Black Friday、Starter が月額 $2(80% OFF)"
+ },
+ "parameterConfig": "パラメーター設定 - {{name}} *",
+ "mainModel": "メインモデル(任意)",
+ "mainModelPlaceholder": "例: GLM-4.6",
+ "fastModel": "高速モデル(任意)",
+ "fastModelPlaceholder": "例: GLM-4.5-Air",
+ "modelHint": "💡 空欄ならプロバイダーのデフォルトモデルを使用します",
+ "apiHint": "💡 Claude API 互換サービスのエンドポイントを入力してください",
+ "codexApiHint": "💡 OpenAI Response 互換のサービスエンドポイントを入力してください",
+ "fillSupplierName": "プロバイダー名を入力してください",
+ "fillConfigContent": "設定内容を入力してください",
+ "fillParameter": "{{label}} を入力してください",
+ "fillTemplateValue": "{{label}} を入力してください",
+ "endpointRequired": "公式以外は API エンドポイントが必須です",
+ "apiKeyRequired": "公式以外は API Key が必須です",
+ "configJsonError": "Config JSON の形式が正しくありません。構文を確認してください",
+ "authJsonRequired": "auth.json は JSON オブジェクトで入力してください",
+ "authJsonError": "auth.json の形式が正しくありません。JSON を確認してください",
+ "fillAuthJson": "auth.json の設定を入力してください",
+ "fillApiKey": "OPENAI_API_KEY を入力してください",
+ "visitWebsite": "{{url}} を開く",
+ "anthropicModel": "メインモデル",
+ "anthropicSmallFastModel": "高速モデル",
+ "anthropicDefaultHaikuModel": "既定 Haiku モデル",
+ "anthropicDefaultSonnetModel": "既定 Sonnet モデル",
+ "anthropicDefaultOpusModel": "既定 Opus モデル",
+ "modelPlaceholder": "",
+ "smallModelPlaceholder": "",
+ "haikuModelPlaceholder": "",
+ "modelHelper": "任意: 既定で使いたい Claude モデルを指定。空欄ならシステム既定を使用します。",
+ "categoryOfficial": "公式",
+ "categoryCnOfficial": "オープンソース公式",
+ "categoryAggregation": "アグリゲーター",
+ "categoryThirdParty": "サードパーティ"
+ },
+ "endpointTest": {
+ "title": "API エンドポイント管理",
+ "endpoints": "エンドポイント",
+ "autoSelect": "自動選択",
+ "testSpeed": "テスト",
+ "testing": "テスト中",
+ "addEndpointPlaceholder": "https://api.example.com",
+ "done": "完了",
+ "noEndpoints": "エンドポイントがありません",
+ "failed": "失敗",
+ "enterValidUrl": "有効な URL を入力してください",
+ "invalidUrlFormat": "URL 形式が正しくありません",
+ "onlyHttps": "HTTP/HTTPS のみサポートします",
+ "urlExists": "この URL はすでに存在します",
+ "saveFailed": "保存に失敗しました。もう一度お試しください",
+ "loadEndpointsFailed": "カスタムエンドポイントの読み込みに失敗:",
+ "addEndpointFailed": "カスタムエンドポイントの追加に失敗:",
+ "removeEndpointFailed": "カスタムエンドポイントの削除に失敗:",
+ "removeFailed": "削除に失敗しました: {{error}}",
+ "updateLastUsedFailed": "エンドポイントの最終使用時間の更新に失敗しました",
+ "pleaseAddEndpoint": "まずエンドポイントを追加してください",
+ "testUnavailable": "速度テストを実行できません",
+ "noResult": "結果がありません",
+ "testFailed": "速度テストに失敗しました: {{error}}",
+ "status": "ステータス: {{code}}"
+ },
+ "codexConfig": {
+ "authJson": "auth.json (JSON) *",
+ "authJsonPlaceholder": "{\n \"OPENAI_API_KEY\": \"sk-your-api-key-here\"\n}",
+ "authJsonHint": "Codex の auth.json 設定内容",
+ "configToml": "config.toml (TOML)",
+ "configTomlHint": "Codex の config.toml 設定内容",
+ "writeCommonConfig": "共通設定を書き込む",
+ "editCommonConfig": "共通設定を編集",
+ "editCommonConfigTitle": "Codex 共通設定スニペットを編集",
+ "commonConfigHint": "「共通設定を書き込む」がオンの場合、config.toml の末尾に追記されます",
+ "apiUrlLabel": "API リクエスト URL"
+ },
+ "geminiConfig": {
+ "envFile": "環境変数 (.env)",
+ "envFileHint": ".env 形式で Gemini の環境変数を設定",
+ "configJson": "設定ファイル (config.json)",
+ "configJsonHint": "Gemini 拡張パラメーターを JSON 形式で設定(任意)",
+ "writeCommonConfig": "共通設定を書き込む",
+ "editCommonConfig": "共通設定を編集",
+ "editCommonConfigTitle": "Gemini 共通設定スニペットを編集",
+ "commonConfigHint": "共通設定スニペットは、この機能をオンにしたすべての Gemini プロバイダーへマージされます"
+ },
+ "providerPreset": {
+ "label": "プロバイダータイプ",
+ "custom": "カスタム設定",
+ "other": "その他",
+ "hint": "プリセットを選んだ後でも、下のフィールドで調整できます。"
+ },
+ "usage": {
+ "queryFailed": "照会に失敗しました",
+ "refreshUsage": "利用状況を更新",
+ "planUsage": "プラン利用状況",
+ "invalid": "期限切れ",
+ "total": "合計:",
+ "used": "使用:",
+ "remaining": "残り:",
+ "justNow": "たった今",
+ "minutesAgo": "{{count}} 分前",
+ "hoursAgo": "{{count}} 時間前",
+ "daysAgo": "{{count}} 日前"
+ },
+ "usageScript": {
+ "title": "利用状況を設定",
+ "enableUsageQuery": "利用状況照会を有効にする",
+ "presetTemplate": "プリセットテンプレート",
+ "requestUrl": "リクエスト URL",
+ "requestUrlPlaceholder": "例: https://api.example.com",
+ "method": "HTTP メソッド",
+ "templateCustom": "カスタム",
+ "templateGeneral": "General",
+ "templateNewAPI": "NewAPI",
+ "credentialsConfig": "認証情報",
+ "baseUrl": "Base URL",
+ "accessToken": "Access Token",
+ "accessTokenPlaceholder": "「Security Settings」で生成",
+ "userId": "ユーザー ID",
+ "userIdPlaceholder": "例: 114514",
+ "defaultPlan": "デフォルトプラン",
+ "queryFailedMessage": "照会に失敗しました",
+ "queryScript": "照会スクリプト (JavaScript)",
+ "timeoutSeconds": "タイムアウト(秒)",
+ "headers": "ヘッダー",
+ "body": "ボディ",
+ "timeoutHint": "範囲: 2〜30 秒",
+ "timeoutMustBeInteger": "タイムアウトは整数で入力してください(小数は切り捨て)",
+ "timeoutCannotBeNegative": "タイムアウトは負の値にできません",
+ "autoIntervalMinutes": "自動照会間隔(分、0 で無効)",
+ "autoQueryInterval": "自動照会間隔(分)",
+ "autoQueryIntervalHint": "0 で無効。推奨 5〜60 分",
+ "intervalMustBeInteger": "間隔は整数で入力してください(小数は切り捨て)",
+ "intervalCannotBeNegative": "間隔は負の値にできません",
+ "intervalAdjusted": "間隔を {{value}} 分に調整しました",
+ "scriptHelp": "スクリプトの書き方:",
+ "configFormat": "設定の形式:",
+ "commentOptional": "任意",
+ "commentResponseIsJson": "response は API から返る JSON データです",
+ "extractorFormat": "抽出関数の返却形式(すべて任意):",
+ "tips": "💡 ヒント:",
+ "testing": "テスト中...",
+ "testScript": "スクリプトをテスト",
+ "format": "整形",
+ "saveConfig": "設定を保存",
+ "scriptEmpty": "スクリプト設定は空にできません",
+ "mustHaveReturn": "スクリプトには return 文が必要です",
+ "testSuccess": "テスト成功!",
+ "testFailed": "テストに失敗しました",
+ "formatSuccess": "整形に成功しました",
+ "formatFailed": "整形に失敗しました",
+ "variablesHint": "使用可能な変数: {{apiKey}}, {{baseUrl}} | extractor 関数には API 応答の JSON オブジェクトが渡されます",
+ "scriptConfig": "リクエスト設定",
+ "extractorCode": "抽出コード",
+ "extractorHint": "戻り値のオブジェクトに残り枠の項目を含めてください",
+ "fieldIsValid": "• isValid: Boolean。プランが有効かどうか",
+ "fieldInvalidMessage": "• invalidMessage: String。無効時の理由(isValid が false のとき表示)",
+ "fieldRemaining": "• remaining: Number。残り枠",
+ "fieldUnit": "• unit: String。単位(例: \"USD\")",
+ "fieldPlanName": "• planName: String。プラン名",
+ "fieldTotal": "• total: Number。総枠",
+ "fieldUsed": "• used: Number。使用量",
+ "fieldExtra": "• extra: String。自由記述の追加テキスト",
+ "tip1": "• 変数 {{apiKey}} と {{baseUrl}} は自動で置換されます",
+ "tip2": "• 抽出関数はサンドボックスで実行され、ES2020+ の構文を使えます",
+ "tip3": "• 全体を () で囲み、オブジェクトリテラル式にしてください"
+ },
+ "errors": {
+ "usage_query_failed": "利用状況の取得に失敗しました"
+ },
+ "presetSelector": {
+ "title": "設定タイプを選択",
+ "custom": "カスタム",
+ "customDescription": "手動で設定。完全な構成が必要",
+ "officialDescription": "公式ログイン。API Key 不要",
+ "presetDescription": "プリセットを使用。API Key だけ入力すれば OK"
+ },
+ "mcp": {
+ "title": "MCP 管理",
+ "claudeTitle": "Claude Code MCP 管理",
+ "codexTitle": "Codex MCP 管理",
+ "geminiTitle": "Gemini MCP 管理",
+ "unifiedPanel": {
+ "title": "MCP サーバー管理",
+ "addServer": "サーバーを追加",
+ "editServer": "サーバーを編集",
+ "deleteServer": "サーバーを削除",
+ "deleteConfirm": "サーバー「{{id}}」を削除しますか?この操作は元に戻せません。",
+ "noServers": "まだサーバーがありません",
+ "enabledApps": "有効なアプリ",
+ "apps": {
+ "claude": "Claude",
+ "codex": "Codex",
+ "gemini": "Gemini"
+ }
+ },
+ "userLevelPath": "ユーザーレベルの MCP パス",
+ "serverList": "サーバー一覧",
+ "loading": "読み込み中...",
+ "empty": "MCP サーバーがありません",
+ "emptyDescription": "右上のボタンから最初の MCP サーバーを追加してください",
+ "add": "MCP を追加",
+ "addServer": "MCP を追加",
+ "editServer": "MCP を編集",
+ "addClaudeServer": "Claude Code MCP を追加",
+ "editClaudeServer": "Claude Code MCP を編集",
+ "addCodexServer": "Codex MCP を追加",
+ "editCodexServer": "Codex MCP を編集",
+ "configPath": "設定パス",
+ "serverCount": "MCP サーバー: {{count}} 件",
+ "enabledCount": "{{count}} 件が有効",
+ "template": {
+ "fetch": "クイックテンプレート: mcp-fetch"
+ },
+ "form": {
+ "title": "MCP ID(ユニーク)",
+ "titlePlaceholder": "my-mcp-server",
+ "name": "表示名",
+ "namePlaceholder": "例: @modelcontextprotocol/server-time",
+ "enabledApps": "適用するアプリ",
+ "noAppsWarning": "少なくとも 1 つ選択してください",
+ "description": "説明",
+ "descriptionPlaceholder": "任意の説明",
+ "tags": "タグ(カンマ区切り)",
+ "tagsPlaceholder": "stdio, time, utility",
+ "homepage": "ホームページ",
+ "homepagePlaceholder": "https://example.com",
+ "docs": "ドキュメント",
+ "docsPlaceholder": "https://example.com/docs",
+ "additionalInfo": "追加情報",
+ "jsonConfig": "JSON 全設定",
+ "jsonConfigOrPrefix": "JSON 全設定、または",
+ "tomlConfigOrPrefix": "TOML 全設定、または",
+ "jsonPlaceholder": "{\n \"type\": \"stdio\",\n \"command\": \"uvx\",\n \"args\": [\"mcp-server-fetch\"]\n}",
+ "tomlConfig": "TOML 全設定",
+ "tomlPlaceholder": "type = \"stdio\"\ncommand = \"uvx\"\nargs = [\"mcp-server-fetch\"]",
+ "useWizard": "設定ウィザード",
+ "syncOtherSide": "{{target}} にも反映",
+ "syncOtherSideHint": "{{target}} に同じ設定を書き込みます。既存の同一 ID は上書きされます。",
+ "willOverwriteWarning": "{{target}} の既存設定を上書きします"
+ },
+ "wizard": {
+ "title": "MCP 設定ウィザード",
+ "hint": "MCP サーバーを素早く設定し JSON を自動生成します",
+ "type": "タイプ",
+ "typeStdio": "stdio",
+ "typeHttp": "http",
+ "typeSse": "sse",
+ "command": "コマンド",
+ "commandPlaceholder": "npx または uvx",
+ "args": "引数",
+ "argsPlaceholder": "arg1\narg2",
+ "env": "環境変数",
+ "envPlaceholder": "KEY1=value1\nKEY2=value2",
+ "url": "URL",
+ "urlPlaceholder": "https://api.example.com/mcp",
+ "urlRequired": "URL を入力してください",
+ "headers": "ヘッダー(任意)",
+ "headersPlaceholder": "Authorization: Bearer your_token_here\nContent-Type: application/json",
+ "preview": "設定プレビュー",
+ "apply": "設定を反映"
+ },
+ "id": "識別子(ユニーク)",
+ "type": "タイプ",
+ "command": "コマンド",
+ "validateCommand": "コマンドを検証",
+ "args": "引数",
+ "argsPlaceholder": "例: mcp-server-fetch --help",
+ "env": "環境変数(1 行に 1 件、KEY=VALUE)",
+ "envPlaceholder": "FOO=bar\nHELLO=world",
+ "reset": "リセット",
+ "notice": {
+ "restartClaude": "書き込みました。Claude を再起動すると反映されます。"
+ },
+ "msg": {
+ "saved": "保存しました",
+ "deleted": "削除しました",
+ "enabled": "有効化しました",
+ "disabled": "無効化しました",
+ "templateAdded": "テンプレートを追加しました"
+ },
+ "error": {
+ "idRequired": "識別子を入力してください",
+ "idExists": "この識別子は既に存在します。別のものを選んでください。",
+ "jsonInvalid": "JSON 形式が無効です",
+ "tomlInvalid": "TOML 形式が無効です",
+ "commandRequired": "コマンドを入力してください",
+ "singleServerObjectRequired": "単一の MCP サーバーオブジェクトを貼り付けてください(トップレベルの mcpServers は不要)",
+ "saveFailed": "保存に失敗しました",
+ "deleteFailed": "削除に失敗しました"
+ },
+ "validation": {
+ "ok": "コマンドが見つかりました",
+ "fail": "コマンドが見つかりません"
+ },
+ "confirm": {
+ "deleteTitle": "MCP サーバーを削除",
+ "deleteMessage": "MCP サーバー「{{id}}」を削除してもよろしいですか?この操作は元に戻せません。"
+ },
+ "presets": {
+ "title": "MCP タイプを選択",
+ "enable": "有効化",
+ "enabled": "有効",
+ "installed": "インストール済み",
+ "docs": "ドキュメント",
+ "requiresEnv": "環境変数が必要",
+ "fetch": {
+ "name": "mcp-server-fetch",
+ "description": "汎用 HTTP リクエストツール。GET/POST などに対応し、API テストや Web データ取得に最適です"
+ },
+ "time": {
+ "name": "@modelcontextprotocol/server-time",
+ "description": "現在時刻、タイムゾーン変換、日付計算を提供する時間クエリツール"
+ },
+ "memory": {
+ "name": "@modelcontextprotocol/server-memory",
+ "description": "エンティティ・関係・観測を扱うナレッジグラフ型メモリ。会話の重要情報を AI に記憶させます"
+ },
+ "sequential-thinking": {
+ "name": "@modelcontextprotocol/server-sequential-thinking",
+ "description": "複雑な問題をステップに分解して深く考えるためのシーケンシャル思考ツール"
+ },
+ "context7": {
+ "name": "@upstash/context7-mcp",
+ "description": "最新のライブラリドキュメントとコード例を提供する Context7 ドキュメント検索ツール。キー設定で上限が拡張されます"
+ }
+ }
+ },
+ "prompts": {
+ "manage": "プロンプト",
+ "title": "{{appName}} プロンプト管理",
+ "claudeTitle": "Claude プロンプト管理",
+ "codexTitle": "Codex プロンプト管理",
+ "add": "プロンプトを追加",
+ "edit": "プロンプトを編集",
+ "addTitle": "{{appName}} プロンプトを追加",
+ "editTitle": "{{appName}} プロンプトを編集",
+ "import": "既存をインポート",
+ "count": "{{count}} 件のプロンプト",
+ "enabled": "有効",
+ "enable": "有効化",
+ "enabledName": "有効: {{name}}",
+ "noneEnabled": "有効なプロンプトがありません",
+ "currentFile": "現在の {{filename}} の内容",
+ "empty": "まだプロンプトがありません",
+ "emptyDescription": "上のボタンからプロンプトを追加またはインポートしてください",
+ "loading": "読み込み中...",
+ "name": "名前",
+ "namePlaceholder": "例: デフォルトプロジェクトプロンプト",
+ "description": "説明",
+ "descriptionPlaceholder": "任意の説明",
+ "content": "内容",
+ "contentPlaceholder": "# {{filename}}\n\nここにプロンプト内容を入力...",
+ "loadFailed": "プロンプトの読み込みに失敗しました",
+ "saveSuccess": "保存しました",
+ "saveFailed": "保存に失敗しました",
+ "deleteSuccess": "削除しました",
+ "deleteFailed": "削除に失敗しました",
+ "enableSuccess": "有効化しました",
+ "enableFailed": "有効化に失敗しました",
+ "disableSuccess": "無効化しました",
+ "disableFailed": "無効化に失敗しました",
+ "importSuccess": "インポートしました",
+ "importFailed": "インポートに失敗しました",
+ "confirm": {
+ "deleteTitle": "削除の確認",
+ "deleteMessage": "プロンプト「{{name}}」を削除してもよろしいですか?"
+ }
+ },
+ "env": {
+ "warning": {
+ "title": "競合する環境変数を検出しました",
+ "description": "設定を上書きする可能性のある環境変数を {{count}} 件見つけました"
+ },
+ "actions": {
+ "expand": "詳細を表示",
+ "collapse": "折りたたむ",
+ "selectAll": "すべて選択",
+ "clearSelection": "選択を解除",
+ "deleteSelected": "選択 {{count}} 件を削除",
+ "deleting": "削除中..."
+ },
+ "field": {
+ "value": "値",
+ "source": "ソース"
+ },
+ "source": {
+ "userRegistry": "ユーザー環境変数(レジストリ)",
+ "systemRegistry": "システム環境変数(レジストリ)",
+ "systemEnv": "システム環境変数"
+ },
+ "delete": {
+ "success": "環境変数を削除しました",
+ "error": "環境変数の削除に失敗しました"
+ },
+ "backup": {
+ "location": "バックアップ場所: {{path}}"
+ },
+ "confirm": {
+ "title": "環境変数を削除しますか?",
+ "message": "{{count}} 件の環境変数を削除してもよろしいですか?",
+ "backupNotice": "削除前に自動バックアップを作成します。後で復元できます。再起動またはターミナル再起動後に反映されます。",
+ "confirm": "削除を確認"
+ },
+ "error": {
+ "noSelection": "削除する環境変数を選択してください"
+ }
+ },
+ "skills": {
+ "manage": "Skills",
+ "title": "Claude スキル管理",
+ "description": "人気リポジトリから Claude Skills を探してインストールし、Claude Code/Codex を拡張",
+ "refresh": "更新",
+ "refreshing": "更新中...",
+ "repoManager": "リポジトリ管理",
+ "count": "{{count}} 個のスキル",
+ "empty": "スキルがありません",
+ "emptyDescription": "スキルリポジトリを追加して探索してください",
+ "addRepo": "スキルリポジトリを追加",
+ "loading": "読み込み中...",
+ "installed": "インストール済み",
+ "install": "インストール",
+ "installing": "インストール中...",
+ "uninstall": "アンインストール",
+ "uninstalling": "アンインストール中...",
+ "view": "表示",
+ "noDescription": "説明なし",
+ "loadFailed": "読み込みに失敗しました",
+ "installSuccess": "スキル {{name}} をインストールしました",
+ "installFailed": "インストールに失敗しました",
+ "uninstallSuccess": "スキル {{name}} をアンインストールしました",
+ "uninstallFailed": "アンインストールに失敗しました",
+ "error": {
+ "skillNotFound": "スキルが見つかりません: {{directory}}",
+ "missingRepoInfo": "リポジトリ情報(owner または name)が不足しています",
+ "downloadTimeout": "リポジトリ {{owner}}/{{name}} のダウンロードがタイムアウトしました({{timeout}} 秒)",
+ "downloadTimeoutHint": "ネットワークを確認するか、時間をおいて再試行してください",
+ "skillPathNotFound": "リポジトリ {{owner}}/{{name}} にスキルパス '{{path}}' がありません",
+ "skillDirNotFound": "スキルディレクトリが見つかりません: {{path}}",
+ "emptyArchive": "ダウンロードしたアーカイブが空です",
+ "downloadFailed": "ダウンロードに失敗しました: HTTP {{status}}",
+ "allBranchesFailed": "すべてのブランチで失敗しました。試行: {{branches}}",
+ "httpError": "HTTP エラー {{status}}",
+ "http403": "GitHub へのアクセスが制限されています(レート制限の可能性)",
+ "http404": "リポジトリまたはブランチが見つかりません。URL を確認してください",
+ "http429": "リクエストが多すぎます。時間をおいて再試行してください",
+ "parseMetadataFailed": "スキルメタデータの解析に失敗しました",
+ "getHomeDirFailed": "ユーザーのホームディレクトリを取得できません",
+ "networkError": "ネットワークエラー",
+ "fsError": "ファイルシステムエラー",
+ "unknownError": "不明なエラー",
+ "suggestion": {
+ "checkNetwork": "ネットワーク接続を確認してください",
+ "checkProxy": "HTTP プロキシの設定を検討してください",
+ "retryLater": "時間をおいて再試行してください",
+ "checkRepoUrl": "リポジトリ URL とブランチ名を確認してください",
+ "checkDiskSpace": "ディスク容量を確認してください",
+ "checkPermission": "ディレクトリの権限を確認してください"
+ }
+ },
+ "repo": {
+ "title": "スキルリポジトリを管理",
+ "description": "GitHub のスキルリポジトリソースを追加または削除します",
+ "url": "リポジトリ URL",
+ "urlPlaceholder": "owner/name または https://github.com/owner/name",
+ "branch": "ブランチ",
+ "branchPlaceholder": "main",
+ "path": "スキルパス",
+ "pathPlaceholder": "skills(任意。空欄はルート)",
+ "add": "リポジトリを追加",
+ "list": "追加済みリポジトリ",
+ "empty": "リポジトリがありません",
+ "invalidUrl": "リポジトリ URL の形式が無効です",
+ "addSuccess": "リポジトリ {{owner}}/{{name}} を追加しました。検出スキル: {{count}} 件",
+ "addFailed": "追加に失敗しました",
+ "removeSuccess": "リポジトリ {{owner}}/{{name}} を削除しました",
+ "removeFailed": "削除に失敗しました",
+ "skillCount": "{{count}} 件のスキルを検出"
+ },
+ "search": "スキルを検索",
+ "searchPlaceholder": "スキル名または説明で検索...",
+ "filter": {
+ "placeholder": "状態で絞り込み",
+ "all": "すべて",
+ "installed": "インストール済み",
+ "uninstalled": "未インストール"
+ },
+ "noResults": "一致するスキルが見つかりませんでした"
+ },
+ "deeplink": {
+ "confirmImport": "プロバイダーのインポートを確認",
+ "confirmImportDescription": "次の設定をディープリンクから CC Switch へインポートします",
+ "importPrompt": "プロンプトをインポート",
+ "importPromptDescription": "このシステムプロンプトをインポートするか確認してください",
+ "importMcp": "MCP サーバーをインポート",
+ "importMcpDescription": "これらの MCP サーバーをインポートするか確認してください",
+ "importSkill": "スキルリポジトリを追加",
+ "importSkillDescription": "このスキルリポジトリを追加するか確認してください",
+ "promptImportSuccess": "プロンプトをインポートしました",
+ "promptImportSuccessDescription": "インポートされたプロンプト: {{name}}",
+ "mcpImportSuccess": "MCP サーバーをインポートしました",
+ "mcpImportSuccessDescription": "{{count}} 件のサーバーをインポートしました",
+ "mcpPartialSuccess": "一部のみインポート成功",
+ "mcpPartialSuccessDescription": "成功: {{success}}、失敗: {{failed}}",
+ "skillImportSuccess": "スキルリポジトリを追加しました",
+ "skillImportSuccessDescription": "追加したリポジトリ: {{repo}}",
+ "app": "アプリ種別",
+ "providerName": "プロバイダー名",
+ "homepage": "ホームページ",
+ "endpoint": "API エンドポイント",
+ "apiKey": "API Key",
+ "icon": "アイコン",
+ "model": "モデル",
+ "haikuModel": "Haiku モデル",
+ "sonnetModel": "Sonnet モデル",
+ "opusModel": "Opus モデル",
+ "multiModel": "マルチモーダルモデル",
+ "notes": "メモ",
+ "import": "インポート",
+ "importing": "インポート中...",
+ "warning": "インポート前に内容を確認してください。後から一覧で編集・削除できます。",
+ "parseError": "ディープリンクの解析に失敗しました",
+ "importSuccess": "インポート成功",
+ "importSuccessDescription": "プロバイダー「{{name}}」をインポートしました",
+ "importError": "インポートに失敗しました",
+ "configSource": "設定ソース",
+ "configEmbedded": "埋め込み設定",
+ "configRemote": "リモート設定",
+ "configDetails": "設定の詳細",
+ "configUrl": "設定ファイル URL",
+ "configMergeError": "設定ファイルのマージに失敗しました",
+ "mcp": {
+ "title": "MCP サーバーを一括インポート",
+ "targetApps": "ターゲットアプリ",
+ "serverCount": "MCP サーバー({{count}} 件)",
+ "enabledWarning": "インポート後、指定したすべてのアプリに即座に書き込まれます"
+ },
+ "prompt": {
+ "title": "システムプロンプトをインポート",
+ "app": "アプリ",
+ "name": "名前",
+ "description": "説明",
+ "contentPreview": "内容プレビュー",
+ "enabledWarning": "インポート後すぐにこのプロンプトが有効になり、他は無効になります"
+ },
+ "skill": {
+ "title": "Claude スキルリポジトリを追加",
+ "repo": "GitHub リポジトリ",
+ "directory": "対象ディレクトリ",
+ "branch": "ブランチ",
+ "skillsPath": "スキルパス",
+ "hint": "この操作でスキルリポジトリが一覧に追加されます。",
+ "hintDetail": "追加後、スキル管理ページから個別のスキルをインストールできます。"
+ }
+ },
+ "iconPicker": {
+ "search": "アイコンを検索",
+ "searchPlaceholder": "アイコン名を入力...",
+ "noResults": "一致するアイコンが見つかりません",
+ "category": {
+ "aiProvider": "AI プロバイダー",
+ "cloud": "クラウドプラットフォーム",
+ "tool": "開発ツール",
+ "other": "その他"
+ }
+ },
+ "providerIcon": {
+ "label": "アイコン",
+ "colorLabel": "アイコンカラー",
+ "selectIcon": "アイコンを選択",
+ "preview": "プレビュー"
+ }
+}
diff --git a/src/i18n/locales/zh.json b/src/i18n/locales/zh.json
index d00d5bc5..e379bfcc 100644
--- a/src/i18n/locales/zh.json
+++ b/src/i18n/locales/zh.json
@@ -165,6 +165,7 @@
"autoReload": "数据将在2秒后自动刷新...",
"languageOptionChinese": "中文",
"languageOptionEnglish": "English",
+ "languageOptionJapanese": "日本語",
"windowBehavior": "窗口行为",
"windowBehaviorHint": "配置窗口最小化与 Claude 插件联动策略。",
"launchOnStartup": "开机自启",
diff --git a/src/lib/schemas/settings.ts b/src/lib/schemas/settings.ts
index e754e34e..61e6b9da 100644
--- a/src/lib/schemas/settings.ts
+++ b/src/lib/schemas/settings.ts
@@ -13,7 +13,7 @@ export const settingsSchema = z.object({
minimizeToTrayOnClose: z.boolean(),
enableClaudePluginIntegration: z.boolean().optional(),
launchOnStartup: z.boolean().optional(),
- language: z.enum(["en", "zh"]).optional(),
+ language: z.enum(["en", "zh", "ja"]).optional(),
// 设备级目录覆盖
claudeConfigDir: directorySchema.nullable().optional(),
diff --git a/src/types.ts b/src/types.ts
index ad8e59d0..bdf46fcf 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -109,7 +109,7 @@ export interface Settings {
// 是否开机自启
launchOnStartup?: boolean;
// 首选语言(可选,默认中文)
- language?: "en" | "zh";
+ language?: "en" | "zh" | "ja";
// ===== 设备级目录覆盖 =====
// 覆盖 Claude Code 配置目录(可选)
diff --git a/tests/hooks/useSettingsForm.test.tsx b/tests/hooks/useSettingsForm.test.tsx
index 4a84c9eb..f6dbd96b 100644
--- a/tests/hooks/useSettingsForm.test.tsx
+++ b/tests/hooks/useSettingsForm.test.tsx
@@ -58,6 +58,29 @@ describe("useSettingsForm Hook", () => {
expect(changeLanguageSpy).toHaveBeenCalledWith("en");
});
+ it("should support japanese language preference from server data", async () => {
+ useSettingsQueryMock.mockReturnValue({
+ data: {
+ showInTray: true,
+ minimizeToTrayOnClose: true,
+ enableClaudePluginIntegration: false,
+ claudeConfigDir: "/Users/demo",
+ codexConfigDir: null,
+ language: "ja",
+ },
+ isLoading: false,
+ });
+
+ const { result } = renderHook(() => useSettingsForm());
+
+ await waitFor(() => {
+ expect(result.current.settings?.language).toBe("ja");
+ });
+
+ expect(result.current.initialLanguage).toBe("ja");
+ expect(changeLanguageSpy).toHaveBeenCalledWith("ja");
+ });
+
it("should prioritize reading language from local storage in readPersistedLanguage", () => {
useSettingsQueryMock.mockReturnValue({
data: null,