diff --git a/apps/desktop/src/features/settings/CommitSettingsCard.tsx b/apps/desktop/src/features/settings/CommitSettingsCard.tsx index e52d3a0..29bc3b2 100644 --- a/apps/desktop/src/features/settings/CommitSettingsCard.tsx +++ b/apps/desktop/src/features/settings/CommitSettingsCard.tsx @@ -1,5 +1,6 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import { api, pluginText, type CommitSettingsView } from "../../shared/api"; +import { commitPromptLocale } from "../../i18n/runtime"; import { useI18n } from "../../i18n/store"; import { useAppStore } from "../../shared/store/appStore"; import { Button } from "../../shared/ui/Button"; @@ -33,11 +34,12 @@ export function CommitSettingsCard() { void (async () => { try { let loaded = await api.commitSettings(locale); - if (!loaded.prompt.trim() && loaded.prompt_locale !== locale) { + const promptLocale = commitPromptLocale(locale); + if (!loaded.prompt.trim() && loaded.prompt_locale !== promptLocale) { loaded = await api.setCommitSettings({ model_id: loaded.model_id, prompt: "", - prompt_locale: locale, + prompt_locale: promptLocale, }); } if (active) { @@ -97,7 +99,7 @@ export function CommitSettingsCard() { return api.setCommitSettings({ model_id: modelId, prompt: normalizedPrompt, - prompt_locale: locale, + prompt_locale: commitPromptLocale(locale), }); }, [view, locale], diff --git a/apps/desktop/src/i18n/runtime.ts b/apps/desktop/src/i18n/runtime.ts index 98a458c..89c71b1 100644 --- a/apps/desktop/src/i18n/runtime.ts +++ b/apps/desktop/src/i18n/runtime.ts @@ -3,6 +3,12 @@ import enUS from "./locales/en-US.json"; import ptBR from "./locales/pt-BR.json"; export type Locale = "zh-CN" | "en-US" | "pt-BR"; +export type CommitPromptLocale = "zh-CN" | "en-US"; + +export function commitPromptLocale(locale: Locale): CommitPromptLocale { + return locale === "zh-CN" ? "zh-CN" : "en-US"; +} + export type TranslationValue = string | number; export type TranslationParams = Readonly>; diff --git a/apps/desktop/src/shared/api.ts b/apps/desktop/src/shared/api.ts index 5882a10..2642f2e 100644 --- a/apps/desktop/src/shared/api.ts +++ b/apps/desktop/src/shared/api.ts @@ -1,5 +1,5 @@ import type { AdRuntime } from "../shell/ads/types"; -import type { Locale } from "../i18n/runtime"; +import type { CommitPromptLocale, Locale } from "../i18n/runtime"; export type ModelType = "openai" | "anthropic"; @@ -154,7 +154,7 @@ export interface DesktopSettings { export interface CommitSettings { model_id: string; prompt: string; - prompt_locale: Locale; + prompt_locale: CommitPromptLocale; } export interface CommitSettingsView extends CommitSettings { diff --git a/server/src/control/settings.rs b/server/src/control/settings.rs index 9ade848..003c1c9 100644 --- a/server/src/control/settings.rs +++ b/server/src/control/settings.rs @@ -149,13 +149,11 @@ pub async fn update_pricing_settings( } fn requested_commit_locale(headers: &HeaderMap) -> CommitPromptLocale { - match headers + headers .get(header::ACCEPT_LANGUAGE) .and_then(|value| value.to_str().ok()) - { - Some(value) if value.eq_ignore_ascii_case("zh-CN") => CommitPromptLocale::ZhCn, - _ => CommitPromptLocale::EnUs, - } + .map(CommitPromptLocale::from_interface_language) + .unwrap_or(CommitPromptLocale::EnUs) } #[cfg(test)] @@ -170,5 +168,8 @@ mod tests { headers.insert(header::ACCEPT_LANGUAGE, "en-US".parse().unwrap()); assert_eq!(requested_commit_locale(&headers), CommitPromptLocale::EnUs); + + headers.insert(header::ACCEPT_LANGUAGE, "pt-BR".parse().unwrap()); + assert_eq!(requested_commit_locale(&headers), CommitPromptLocale::EnUs); } } diff --git a/server/src/store/settings.rs b/server/src/store/settings.rs index 2f842c3..1a2673c 100644 --- a/server/src/store/settings.rs +++ b/server/src/store/settings.rs @@ -1,5 +1,5 @@ //! Persists application settings. -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize}; use crate::Result; @@ -105,7 +105,7 @@ impl TabSettings { } } -#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq, Serialize)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize)] pub enum CommitPromptLocale { #[default] #[serde(rename = "zh-CN")] @@ -115,6 +115,14 @@ pub enum CommitPromptLocale { } impl CommitPromptLocale { + pub fn from_interface_language(value: &str) -> Self { + if value.eq_ignore_ascii_case("zh-CN") { + Self::ZhCn + } else { + Self::EnUs + } + } + pub fn default_prompt(self) -> &'static str { match self { Self::ZhCn => DEFAULT_COMMIT_PROMPT_ZH_CN.trim(), @@ -123,6 +131,13 @@ impl CommitPromptLocale { } } +impl<'de> Deserialize<'de> for CommitPromptLocale { + fn deserialize>(deserializer: D) -> Result { + let value = String::deserialize(deserializer)?; + Ok(Self::from_interface_language(&value)) + } +} + /// User preferences for Git commit message generation. /// /// Empty `model_id` means 直连: forward the original Cursor RPC unchanged. @@ -490,6 +505,26 @@ mod tests { const LEGACY_PROXY_ROW: &str = r#"{"mode":"system","address":"","auth_enabled":false,"username":"","password":""}"#; + #[test] + fn commit_prompt_locale_maps_unknown_interface_languages_to_english() { + assert_eq!( + serde_json::from_str::(r#""zh-CN""#).unwrap(), + CommitPromptLocale::ZhCn + ); + assert_eq!( + serde_json::from_str::(r#""en-US""#).unwrap(), + CommitPromptLocale::EnUs + ); + assert_eq!( + serde_json::from_str::(r#""pt-BR""#).unwrap(), + CommitPromptLocale::EnUs + ); + assert_eq!( + serde_json::to_string(&CommitPromptLocale::EnUs).unwrap(), + r#""en-US""# + ); + } + #[test] fn default_commit_prompt_follows_its_saved_locale() { for (prompt_locale, expected) in [