1use std::{fmt::Display, str::FromStr};
2
3use paste::paste;
4use serde::{Deserialize, Deserializer, Serialize};
5use thiserror::Error;
6
7#[derive(Debug, Error)]
8pub enum LangConvertError {
9 #[error("invalid language code {0}")]
10 InvalidLang(String),
11}
12
13type Result<T, E = LangConvertError> = core::result::Result<T, E>;
14
15macro_rules! generate_langs {
16 (
17 $(
18 ($code:literal, $desc:literal);
19 )+
20 ) => {
21 paste! {
22 #[allow(non_camel_case_types)]
24 #[derive(Clone, Debug, PartialEq, Eq, Serialize)]
25 #[serde(rename_all = "SCREAMING-KEBAB-CASE")]
26 pub enum Lang {
27 $(
28 #[doc = $desc]
29 [<$code>],
30 )+
31 }
32
33 impl Lang {
34 pub fn description(&self) -> String {
36 match self {
37 $(
38 Self::[<$code>] => $desc.to_string(),
39 )+
40 }
41 }
42 }
43
44 impl TryFrom<&str> for Lang {
45 type Error = LangConvertError;
46
47 fn try_from(value: &str) -> Result<Self, Self::Error> {
53 let lang = match value {
54 $(
55 $code => Self::[<$code>],
56 )+
57 _ => return Err(LangConvertError::InvalidLang(value.to_string())),
58 };
59
60 Ok(lang)
61 }
62 }
63
64 impl TryFrom<&String> for Lang {
65 type Error = LangConvertError;
66
67 fn try_from(value: &String) -> Result<Self, Self::Error> {
73 let lang = match value.as_ref() {
74 $(
75 $code => Self::[<$code>],
76 )+
77 _ => return Err(LangConvertError::InvalidLang(value.to_string())),
78 };
79
80 Ok(lang)
81 }
82 }
83
84 impl AsRef<str> for Lang {
85 fn as_ref(&self) -> &'static str {
86 match self {
87 $(
88 Self::[<$code>] => $code,
89 )+
90 }
91 }
92 }
93 }
94 };
95}
96
97generate_langs! {
98 ("AR", "Arabic");
99 ("BG", "Bulgarian");
100 ("CS", "Czech");
101 ("DA", "Danish");
102 ("DE", "German");
103 ("EL", "Greek");
104 ("EN", "English (Unspecified variant)");
105 ("EN-GB", "English (American)");
106 ("EN-US", "English (British)");
107 ("ES", "Spanish");
108 ("ET", "Estonian");
109 ("FI", "Finnish");
110 ("FR", "French");
111 ("HU", "Hungarian");
112 ("ID", "Indonesian");
113 ("IT", "Italian");
114 ("JA", "Japanese");
115 ("KO", "Korean");
116 ("LT", "Lithuanian");
117 ("LV", "Latvian");
118 ("NB", "Norwegian");
119 ("NL", "Dutch");
120 ("PL", "Polish");
121 ("PT", "Portuguese (all Portuguese varieties mixed)");
122 ("PT-BR", "Portuguese (Brazilian)");
123 ("PT-PT", "Portuguese (All Portuguese varieties excluding Brazilian)");
124 ("RO", "Romanian");
125 ("RU", "Russian");
126 ("SK", "Slovak");
127 ("SL", "Slovenian");
128 ("SV", "Swedish");
129 ("TR", "Turkish");
130 ("UK", "Ukrainian");
131 ("ZH", "Chinese");
132}
133
134impl<'de> Deserialize<'de> for Lang {
135 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
136 where
137 D: Deserializer<'de>,
138 {
139 let lang = String::deserialize(deserializer)?.to_uppercase();
140
141 let lang = Lang::try_from(&lang).map_err(|_| {
142 serde::de::Error::custom(
143 format!("invalid language code {lang}. This is an internal issue with the lib, please open issue")
144 )
145 })?;
146
147 Ok(lang)
148 }
149}
150
151impl FromStr for Lang {
152 type Err = LangConvertError;
153
154 fn from_str(s: &str) -> Result<Self, Self::Err> {
155 Lang::try_from(s)
156 }
157}
158
159impl Display for Lang {
160 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161 write!(f, "{}", self.as_ref())
162 }
163}