From aca92482c29a6354de19439e04fb8d8fcc53d66c Mon Sep 17 00:00:00 2001 From: ByteColtX Date: Thu, 14 May 2026 13:53:13 +0800 Subject: [PATCH] =?UTF-8?q?fix(tray):=20=E8=AF=BB=E5=8F=96=20Windows=20?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E9=BB=98=E8=AE=A4=E5=8C=BA=E5=9F=9F=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 2 +- src/ui/tray/i18n.rs | 62 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 394e7e6..89f70ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,7 @@ native-dialog = "0.9.6" tray-icon = { version = "0.23.1", default-features = false } wasapi = "0.23.0" windows-registry = "0.6.1" -windows-sys = { version = "0.61.2", features = ["Win32_Foundation", "Win32_Storage_FileSystem", "Win32_System_Console"] } +windows-sys = { version = "0.61.2", features = ["Win32_Foundation", "Win32_Globalization", "Win32_Storage_FileSystem", "Win32_System_Console"] } winit = { version = "0.30.12", default-features = false } [build-dependencies] diff --git a/src/ui/tray/i18n.rs b/src/ui/tray/i18n.rs index 4ba7d8b..833ee1f 100644 --- a/src/ui/tray/i18n.rs +++ b/src/ui/tray/i18n.rs @@ -105,6 +105,48 @@ pub fn resolve_locale( } fn detected_system_locale() -> Option { + platform_system_locale().or_else(env_system_locale) +} + +#[cfg(target_os = "windows")] +fn platform_system_locale() -> Option { + windows_user_default_locale_name() +} + +#[cfg(not(target_os = "windows"))] +fn platform_system_locale() -> Option { + None +} + +#[cfg(target_os = "windows")] +#[allow(unsafe_code)] +fn windows_user_default_locale_name() -> Option { + use windows_sys::Win32::Globalization::GetUserDefaultLocaleName; + + const LOCALE_NAME_MAX_LENGTH: usize = 85; + + let mut locale_name = [0_u16; LOCALE_NAME_MAX_LENGTH]; + #[allow(unsafe_code)] + // SAFETY: `locale_name` is a valid writable UTF-16 buffer for the duration + // of the call, and the length passed matches the buffer capacity. + let length = unsafe { + GetUserDefaultLocaleName( + locale_name.as_mut_ptr(), + i32::try_from(locale_name.len()).ok()?, + ) + }; + + if length <= 1 { + return None; + } + + let length = usize::try_from(length).ok()?; + String::from_utf16(&locale_name[..length - 1]) + .ok() + .filter(|value| !value.trim().is_empty()) +} + +fn env_system_locale() -> Option { ["LANGUAGE", "LC_ALL", "LC_MESSAGES", "LANG"] .into_iter() .find_map(|key| { @@ -195,14 +237,34 @@ mod tests { resolve_locale(TrayLanguagePreference::System, Some("zh_CN.UTF-8")), TrayLocale::ZhCn ); + assert_eq!( + resolve_locale(TrayLanguagePreference::System, Some("zh-CN")), + TrayLocale::ZhCn + ); + assert_eq!( + resolve_locale(TrayLanguagePreference::System, Some("en-US")), + TrayLocale::EnUs + ); assert_eq!( resolve_locale(TrayLanguagePreference::System, Some("fr-FR")), TrayLocale::EnUs ); + assert_eq!( + resolve_locale(TrayLanguagePreference::System, None), + TrayLocale::EnUs + ); + } + + #[test] + fn explicit_language_preference_overrides_system_locale() { assert_eq!( resolve_locale(TrayLanguagePreference::EnUs, Some("zh-CN")), TrayLocale::EnUs ); + assert_eq!( + resolve_locale(TrayLanguagePreference::ZhCn, Some("en-US")), + TrayLocale::ZhCn + ); } #[test]