1use std::string::ParseError;
2use std::{fmt::Display, str::FromStr};
3use std::{vec, vec::Vec};
4
5use serde::{Deserialize, Serialize};
6
7macro_rules! languages {
8 (
9 $(
10 $( #[$meta:meta] )*
11 $lang:ident => $code:literal,
12 )*
13 ) => {
14 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Serialize)]
16 #[non_exhaustive]
17 #[cfg_attr(feature = "specta", derive(specta::Type))]
18 #[cfg_attr(feature = "async-graphql", derive(async_graphql::Enum))]
19 pub enum Language {
20 $(
21 $( #[$meta] )*
22 #[serde(rename = $code)]
23 $lang,
24 )*
25 #[serde(other)]
26 Unknown,
27 }
28
29 impl Language {
30 pub fn code2(&self) -> &str {
32 match self {
33 $(
34 Self::$lang => $code,
35 )*
36 Self::Unknown => "Unknown",
37 }
38 }
39 pub fn get_langs() -> Vec<Self> {
40 vec![
41 $(
42 Self::$lang,
43 )*
44 Self::Unknown,
45 ]
46 }
47 }
48
49 impl From<&str> for Language {
50 fn from(value: &str) -> Self {
54 match value.to_lowercase().as_str() {
55 $(
56 $code => Self::$lang,
57 )*
58 _ => Self::Unknown,
59 }
60 }
61 }
62
63 impl FromStr for Language {
64 type Err = ParseError;
65
66 fn from_str(value: &str) -> Result<Self, ParseError> {
70 Ok(
71 match value.to_lowercase().as_str() {
72 $(
73 $code => Self::$lang,
74 )*
75 _ => Self::Unknown,
76 }
77 )
78 }
79 }
80
81 impl Default for Language {
82 fn default() -> Self{
83 Self::Unknown
84 }
85 }
86 };
87}
88
89languages! {
90 Arabic => "ar",
91 Azerbaijani => "az",
92 Afrikaans => "af",
93 Albanian => "sq",
94 Basque => "eu",
95 Belarusian => "be",
96 Bengali => "bn",
97 Bulgarian => "bg",
98 Burmese => "my",
99 Catalan => "ca",
100 ChineseRomanized => "zh-ro",
101 ChineseSimplified => "zh",
102 ChineseTraditional => "zh-hk",
103 Chuvash => "cv",
104 Croatian => "hr",
105 Czech => "cs",
106 Danish => "da",
107 Dutch => "nl",
108 English => "en",
109 Esperanto => "eo",
110 Estonian => "et",
111 Filipino => "tl",
112 Finnish => "fi",
113 French => "fr",
114 Georgian => "ka",
115 German => "de",
116 Greek => "el",
117 Hebrew => "he",
118 Hindi => "hi",
119 Hungarian => "hu",
120 Indonesian => "id",
121 Irish => "ga",
122 Italian => "it",
123 Japanese => "ja",
124 JapaneseRomanized => "ja-ro",
125 Javanese => "jv",
126 Jp => "jp",
127 Kazakh => "kk",
128 Korean => "ko",
129 KoreanRomanized => "ko-ro",
130 Latin => "la",
131 Lithuanian => "lt",
132 Malagasy => "mg",
133 Malay => "ms",
134 Mongolian => "mn",
135 Nepali => "ne",
136 NiloSaharan => "kr",
137 Norwegian => "no",
138 Persian => "fa",
139 Polish => "pl",
140 PortugueseBrazilian => "pt-br",
141 PortuguesePortugal => "pt",
142 Romansh => "rm",
143 Romanian => "ro",
144 Russian => "ru",
145 SerboCroatian => "sr",
146 Slovak => "sk",
147 Slovenian => "sl",
148 SpanishCastilian => "es",
149 SpanishLatinAmerican => "es-la",
150 Swedish => "sv",
151 Tamil => "ta",
152 Telugu => "te",
153 Thai => "th",
154 Turkish => "tr",
155 Ukrainian => "uk",
156 Urdu => "ur",
157 Uzbek => "uz",
158 Vietnamese => "vi",
159}
160
161impl Display for Language {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 f.write_str(self.code2())
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170
171 #[test]
172 fn string_produces_english_from_en() {
173 let lang = Language::from("en");
174 assert_eq!(lang, Language::English);
175 }
176
177 #[test]
178 fn string_produces_japanese_from_capitalized_ja() {
179 let lang = Language::from("JA");
180 assert_eq!(lang, Language::Japanese);
181 }
182
183 #[test]
184 fn string_produces_unknown_from_unknown_string() {
185 let test_cases = ["foo", "bar", "baz"];
186 for test in test_cases {
187 let lang = Language::from(test);
188 assert_eq!(lang, Language::Unknown);
189 }
190 }
191 #[test]
192 fn serde_produces_unknown_from_unknown_string() {
193 #[derive(Deserialize)]
194 struct TestStruct {
195 lang: Language,
196 }
197 let value = serde_json::json!({
198 "lang" : "jp"
199 });
200 let out: TestStruct = serde_json::from_value(value).unwrap();
201 assert_eq!(out.lang, Language::Jp);
202 }
203}