1use std::sync::RwLock;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub enum Locale {
5 Zh,
6 En,
7}
8
9static LOCALE: RwLock<Option<Locale>> = RwLock::new(None);
10
11fn detect_locale() -> Locale {
12 let locale_str = std::env::var("LC_ALL")
13 .ok()
14 .filter(|s| !s.is_empty())
15 .or_else(|| std::env::var("LANG").ok().filter(|s| !s.is_empty()))
16 .unwrap_or_default();
17
18 if locale_str.to_lowercase().starts_with("zh") {
19 Locale::Zh
20 } else {
21 Locale::En
22 }
23}
24
25pub fn locale() -> Locale {
26 if let Ok(guard) = LOCALE.read()
27 && let Some(loc) = *guard
28 {
29 return loc;
30 }
31
32 let detected = detect_locale();
33 if let Ok(mut guard) = LOCALE.write()
34 && guard.is_none()
35 {
36 *guard = Some(detected);
37 }
38 detected
39}
40
41#[doc(hidden)]
42pub fn set_locale(loc: Locale) {
43 if let Ok(mut guard) = LOCALE.write() {
44 *guard = Some(loc);
45 }
46}
47
48pub fn t(key: &str) -> &'static str {
49 let loc = locale();
50 match (loc, key) {
51 (Locale::Zh, "copy_button") => "复制内容",
52 (Locale::Zh, "open_editor") => "打开编辑器",
53 (Locale::Zh, "copy_success") => "已复制到剪贴板!",
54 (Locale::Zh, "copy_failed") => "复制失败,请手动选择内容复制",
55 (Locale::Zh, "slides_ready") => "张图片已准备好上传",
56 (Locale::Zh, "preview_suffix") => "预览",
57
58 (Locale::En, "copy_button") => "Copy",
59 (Locale::En, "open_editor") => "Open Editor",
60 (Locale::En, "copy_success") => "Copied!",
61 (Locale::En, "copy_failed") => "Copy failed. Please select and copy manually.",
62 (Locale::En, "slides_ready") => "slides ready for upload",
63 (Locale::En, "preview_suffix") => "Preview",
64
65 _ => "[missing translation]",
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 #![allow(clippy::expect_used)]
72
73 use super::*;
74
75 #[test]
76 fn test_t_returns_translation() {
77 let result = t("copy_button");
78 assert!(!result.is_empty());
79 assert!(result == "复制内容" || result == "Copy");
80 }
81
82 #[test]
83 fn test_t_unknown_key_returns_placeholder() {
84 assert_eq!(t("unknown_key_xyz"), "[missing translation]");
85 }
86}