mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-18 13:23:33 +08:00
Merge response language selector into main
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
99c964e0ca
@ -669,6 +669,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',
|
||||
|
||||
@ -671,6 +671,9 @@ export const zh: Record<TranslationKey, string> = {
|
||||
'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': '低',
|
||||
|
||||
@ -1368,6 +1368,8 @@ function GeneralSettings() {
|
||||
disableH5Access,
|
||||
regenerateH5AccessToken,
|
||||
updateH5AccessSettings,
|
||||
responseLanguage,
|
||||
setResponseLanguage,
|
||||
} = useSettingsStore()
|
||||
const t = useTranslation()
|
||||
const [webSearchDraft, setWebSearchDraft] = useState(webSearch)
|
||||
@ -1426,6 +1428,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') },
|
||||
@ -1577,6 +1604,21 @@ function GeneralSettings() {
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Response Language */}
|
||||
<h2 className="text-base font-semibold text-[var(--color-text-primary)] mb-1">{t('settings.general.responseLangTitle')}</h2>
|
||||
<p className="text-sm text-[var(--color-text-tertiary)] mb-3">{t('settings.general.responseLangDescription')}</p>
|
||||
<div className="flex gap-2 mb-8">
|
||||
<select
|
||||
value={responseLangDraft}
|
||||
onChange={(e) => void setResponseLanguage(e.target.value)}
|
||||
className="flex-1 px-3 py-2 text-sm rounded-lg border border-[var(--color-border)] bg-[var(--color-surface-container-low)] text-[var(--color-text-primary)] focus:outline-none focus:border-[var(--color-brand)] transition-colors cursor-pointer"
|
||||
>
|
||||
{RESPONSE_LANGUAGES.map(({ value, label }) => (
|
||||
<option key={value} value={value}>{label}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{/* Effort Level */}
|
||||
<h2 className="text-base font-semibold text-[var(--color-text-primary)] mb-1">{t('settings.general.effortTitle')}</h2>
|
||||
<p className="text-sm text-[var(--color-text-tertiary)] mb-3">{t('settings.general.effortDescription')}</p>
|
||||
|
||||
@ -32,6 +32,7 @@ type SettingsStore = {
|
||||
webSearch: WebSearchSettings
|
||||
h5Access: H5AccessSettings
|
||||
h5AccessError: string | null
|
||||
responseLanguage: string
|
||||
isLoading: boolean
|
||||
error: string | null
|
||||
|
||||
@ -53,6 +54,7 @@ type SettingsStore = {
|
||||
allowedOrigins?: string[]
|
||||
publicBaseUrl?: string | null
|
||||
}) => Promise<void>
|
||||
setResponseLanguage: (language: string) => Promise<void>
|
||||
}
|
||||
|
||||
const DEFAULT_H5_ACCESS_SETTINGS: H5AccessSettings = {
|
||||
@ -76,6 +78,7 @@ export const useSettingsStore = create<SettingsStore>((set, get) => ({
|
||||
webSearch: { mode: 'auto', tavilyApiKey: '', braveApiKey: '' },
|
||||
h5Access: DEFAULT_H5_ACCESS_SETTINGS,
|
||||
h5AccessError: null,
|
||||
responseLanguage: '',
|
||||
isLoading: false,
|
||||
error: null,
|
||||
|
||||
@ -106,6 +109,7 @@ export const useSettingsStore = create<SettingsStore>((set, get) => ({
|
||||
webSearch: normalizeWebSearchSettings(userSettings.webSearch),
|
||||
h5Access: h5AccessResult.settings,
|
||||
h5AccessError: h5AccessResult.error,
|
||||
responseLanguage: typeof userSettings.language === 'string' ? userSettings.language : '',
|
||||
isLoading: false,
|
||||
error: null,
|
||||
})
|
||||
@ -274,6 +278,16 @@ export const useSettingsStore = create<SettingsStore>((set, get) => ({
|
||||
throw error
|
||||
}
|
||||
},
|
||||
|
||||
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 {
|
||||
|
||||
@ -36,5 +36,6 @@ export type UserSettings = {
|
||||
skipWebFetchPreflight?: boolean
|
||||
desktopNotificationsEnabled?: boolean
|
||||
webSearch?: WebSearchSettings
|
||||
language?: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user