From b693aa53b47bad8c9d745616176bdc285461aef2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=91=98=E9=98=BF=E6=B1=9F=28Relakkes?= =?UTF-8?q?=29?= Date: Sun, 10 May 2026 11:54:17 +0800 Subject: [PATCH] feat: add response language selector in General settings Expose the CLI's `language` setting in the desktop app's General tab. Users can now pick from 21 pre-defined languages via a dropdown (value maps directly to CLI language names such as "chinese", "japanese"). Selecting a language writes it to ~/.claude/settings.json so the CLI injects the language instruction into every session's system prompt. Co-Authored-By: Claude Sonnet 4.6 --- desktop/src/i18n/locales/en.ts | 3 +++ desktop/src/i18n/locales/zh.ts | 3 +++ desktop/src/pages/Settings.tsx | 42 +++++++++++++++++++++++++++++ desktop/src/stores/settingsStore.ts | 14 ++++++++++ desktop/src/types/settings.ts | 1 + 5 files changed, 63 insertions(+) diff --git a/desktop/src/i18n/locales/en.ts b/desktop/src/i18n/locales/en.ts index bd824673..fe641a4c 100644 --- a/desktop/src/i18n/locales/en.ts +++ b/desktop/src/i18n/locales/en.ts @@ -643,6 +643,9 @@ export const en = { 'settings.general.appearance.dark': 'Dark', 'settings.general.languageTitle': 'Language', 'settings.general.languageDescription': 'Choose the display language for the application.', + 'settings.general.responseLangTitle': 'Response Language', + 'settings.general.responseLangDescription': 'Instruct Claude to always respond in a specific language.', + 'settings.general.responseLangDefault': 'Default (English)', 'settings.general.effortTitle': 'Effort Level', 'settings.general.effortDescription': 'Controls how much computation the model uses.', 'settings.general.effort.low': 'Low', diff --git a/desktop/src/i18n/locales/zh.ts b/desktop/src/i18n/locales/zh.ts index a6f3560c..1aea9846 100644 --- a/desktop/src/i18n/locales/zh.ts +++ b/desktop/src/i18n/locales/zh.ts @@ -645,6 +645,9 @@ export const zh: Record = { 'settings.general.appearance.dark': '暗色', 'settings.general.languageTitle': '语言', 'settings.general.languageDescription': '选择应用程序的显示语言。', + 'settings.general.responseLangTitle': '回复语言', + 'settings.general.responseLangDescription': '指定 Claude 始终以某种语言回复。', + 'settings.general.responseLangDefault': '默认(英语)', 'settings.general.effortTitle': '推理强度', 'settings.general.effortDescription': '控制模型使用的计算量。', 'settings.general.effort.low': '低', diff --git a/desktop/src/pages/Settings.tsx b/desktop/src/pages/Settings.tsx index 14177398..2e7ee88a 100644 --- a/desktop/src/pages/Settings.tsx +++ b/desktop/src/pages/Settings.tsx @@ -1355,6 +1355,8 @@ function GeneralSettings() { setDesktopNotificationsEnabled, webSearch, setWebSearch, + responseLanguage, + setResponseLanguage, } = useSettingsStore() const t = useTranslation() const [webSearchDraft, setWebSearchDraft] = useState(webSearch) @@ -1388,6 +1390,31 @@ function GeneralSettings() { { value: 'zh', label: '中文' }, ] + const RESPONSE_LANGUAGES: Array<{ value: string; label: string }> = [ + { value: '', label: t('settings.general.responseLangDefault') }, + { value: 'english', label: 'English' }, + { value: 'chinese', label: '中文 (Chinese)' }, + { value: 'japanese', label: '日本語 (Japanese)' }, + { value: 'korean', label: '한국어 (Korean)' }, + { value: 'spanish', label: 'Español (Spanish)' }, + { value: 'french', label: 'Français (French)' }, + { value: 'german', label: 'Deutsch (German)' }, + { value: 'portuguese', label: 'Português (Portuguese)' }, + { value: 'italian', label: 'Italiano (Italian)' }, + { value: 'russian', label: 'Русский (Russian)' }, + { value: 'dutch', label: 'Nederlands (Dutch)' }, + { value: 'polish', label: 'Polski (Polish)' }, + { value: 'turkish', label: 'Türkçe (Turkish)' }, + { value: 'hindi', label: 'हिन्दी (Hindi)' }, + { value: 'indonesian', label: 'Bahasa Indonesia' }, + { value: 'ukrainian', label: 'Українська (Ukrainian)' }, + { value: 'greek', label: 'Ελληνικά (Greek)' }, + { value: 'czech', label: 'Čeština (Czech)' }, + { value: 'danish', label: 'Dansk (Danish)' }, + { value: 'swedish', label: 'Svenska (Swedish)' }, + { value: 'norwegian', label: 'Norsk (Norwegian)' }, + ] + const THEMES: Array<{ value: ThemeMode; label: string }> = [ { value: 'light', label: t('settings.general.appearance.light') }, { value: 'dark', label: t('settings.general.appearance.dark') }, @@ -1493,6 +1520,21 @@ function GeneralSettings() { ))} + {/* Response Language */} +

{t('settings.general.responseLangTitle')}

+

{t('settings.general.responseLangDescription')}

+
+ +
+ {/* Effort Level */}

{t('settings.general.effortTitle')}

{t('settings.general.effortDescription')}

diff --git a/desktop/src/stores/settingsStore.ts b/desktop/src/stores/settingsStore.ts index df185a70..369ffddf 100644 --- a/desktop/src/stores/settingsStore.ts +++ b/desktop/src/stores/settingsStore.ts @@ -28,6 +28,7 @@ type SettingsStore = { skipWebFetchPreflight: boolean desktopNotificationsEnabled: boolean webSearch: WebSearchSettings + responseLanguage: string isLoading: boolean error: string | null @@ -41,6 +42,7 @@ type SettingsStore = { setSkipWebFetchPreflight: (enabled: boolean) => Promise setDesktopNotificationsEnabled: (enabled: boolean) => Promise setWebSearch: (settings: WebSearchSettings) => Promise + setResponseLanguage: (language: string) => Promise } export const useSettingsStore = create((set, get) => ({ @@ -55,6 +57,7 @@ export const useSettingsStore = create((set, get) => ({ skipWebFetchPreflight: true, desktopNotificationsEnabled: false, webSearch: { mode: 'auto', tavilyApiKey: '', braveApiKey: '' }, + responseLanguage: '', isLoading: false, error: null, @@ -81,6 +84,7 @@ export const useSettingsStore = create((set, get) => ({ skipWebFetchPreflight: userSettings.skipWebFetchPreflight !== false, desktopNotificationsEnabled: userSettings.desktopNotificationsEnabled === true, webSearch: normalizeWebSearchSettings(userSettings.webSearch), + responseLanguage: typeof userSettings.language === 'string' ? userSettings.language : '', isLoading: false, error: null, }) @@ -186,6 +190,16 @@ export const useSettingsStore = create((set, get) => ({ set({ webSearch: prev }) } }, + + setResponseLanguage: async (language) => { + const prev = get().responseLanguage + set({ responseLanguage: language }) + try { + await settingsApi.updateUser({ language: language || undefined }) + } catch { + set({ responseLanguage: prev }) + } + }, })) function normalizeWebSearchSettings(settings: WebSearchSettings | undefined): WebSearchSettings { diff --git a/desktop/src/types/settings.ts b/desktop/src/types/settings.ts index 188955b4..3ccfbd7e 100644 --- a/desktop/src/types/settings.ts +++ b/desktop/src/types/settings.ts @@ -29,5 +29,6 @@ export type UserSettings = { skipWebFetchPreflight?: boolean desktopNotificationsEnabled?: boolean webSearch?: WebSearchSettings + language?: string [key: string]: unknown }