1use std::fmt;
2use std::str::FromStr;
3
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
7pub enum Locale {
8 #[serde(rename = "en")]
9 En,
10 #[serde(rename = "zh_CN")]
11 ZhCn,
12}
13
14impl Default for Locale {
15 fn default() -> Self {
16 Locale::En
17 }
18}
19
20impl fmt::Display for Locale {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 match self {
23 Locale::En => write!(f, "en"),
24 Locale::ZhCn => write!(f, "zh_CN"),
25 }
26 }
27}
28
29impl FromStr for Locale {
30 type Err = String;
31
32 fn from_str(s: &str) -> Result<Self, Self::Err> {
33 match s.to_ascii_lowercase().as_str() {
34 "en" | "english" => Ok(Locale::En),
35 "zh" | "zh_cn" | "zh-cn" | "chinese" | "简体中文"
36 | "zh_tw" | "zh-tw" | "zh_hk" | "zh-hk" | "繁體中文" => Ok(Locale::ZhCn),
37 other => Err(format!("unsupported locale: {other}")),
38 }
39 }
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45
46 #[test]
47 fn display_round_trips_through_from_str() {
48 assert_eq!(Locale::En.to_string().parse::<Locale>().unwrap(), Locale::En);
49 assert_eq!(Locale::ZhCn.to_string().parse::<Locale>().unwrap(), Locale::ZhCn);
50 }
51
52 #[test]
53 fn from_str_accepts_common_aliases() {
54 assert_eq!("en".parse::<Locale>().unwrap(), Locale::En);
55 assert_eq!("English".parse::<Locale>().unwrap(), Locale::En);
56 assert_eq!("zh".parse::<Locale>().unwrap(), Locale::ZhCn);
57 assert_eq!("zh_CN".parse::<Locale>().unwrap(), Locale::ZhCn);
58 assert_eq!("zh-cn".parse::<Locale>().unwrap(), Locale::ZhCn);
59 assert_eq!("简体中文".parse::<Locale>().unwrap(), Locale::ZhCn);
60 assert_eq!("zh_TW".parse::<Locale>().unwrap(), Locale::ZhCn);
62 assert_eq!("zh-tw".parse::<Locale>().unwrap(), Locale::ZhCn);
63 assert_eq!("zh_HK".parse::<Locale>().unwrap(), Locale::ZhCn);
64 assert_eq!("zh-hk".parse::<Locale>().unwrap(), Locale::ZhCn);
65 assert_eq!("繁體中文".parse::<Locale>().unwrap(), Locale::ZhCn);
66 }
67
68 #[test]
69 fn from_str_rejects_unknown() {
70 assert!("fr".parse::<Locale>().is_err());
71 assert!("".parse::<Locale>().is_err());
72 }
73
74 #[test]
75 fn serde_uses_short_keys() {
76 let s = serde_json::to_string(&Locale::ZhCn).unwrap();
77 assert_eq!(s, r#""zh_CN""#);
78 let parsed: Locale = serde_json::from_str(r#""en""#).unwrap();
79 assert_eq!(parsed, Locale::En);
80 }
81}