1pub mod translate;
3
4#[cfg(feature = "schema")]
5use schemars::JsonSchema;
6use serde::{Deserialize, Serialize};
7
8#[allow(missing_docs)]
10#[derive(Deserialize, Serialize, Copy, Clone, Eq, PartialEq, Debug, Hash)]
11#[cfg_attr(feature = "schema", derive(JsonSchema))]
12#[serde(rename_all = "snake_case")]
13pub enum Language {
14 Afrikaans,
15 Arabic,
16 Asturian,
17 Azerbaijani,
18 Bashkir,
19 Bavarian,
20 Belarusian,
21 Bulgarian,
22 Breton,
23 Brabantian,
24 Bosnian,
25 Catalan,
26 Czech,
27 Welsh,
28 Danish,
29 AustrianGerman,
30 SwissGerman,
31 German,
32 Greek,
33 AustralianEnglish,
34 CanadianEnglish,
35 BritishEnglish,
36 NewZealandEnglish,
37 PirateSpeak,
38 UpsideDown,
39 AmericanEnglish,
40 Anglish,
41 Shakespearean,
42 Esperanto,
43 ArgentinianSpanish,
44 ChileanSpanish,
45 EcuadorianSpanish,
46 EuropeanSpanish,
47 MexicanSpanish,
48 UruguayanSpanish,
49 VenezuelanSpanish,
50 Andalusian,
51 Estonian,
52 Basque,
53 Persian,
54 Finnish,
55 Filipino,
56 Faroese,
57 CanadianFrench,
58 EuropeanFrench,
59 EastFranconian,
60 Friulian,
61 Frisian,
62 Irish,
63 ScottishGaelic,
64 Galician,
65 Hawaiian,
66 Hebrew,
67 Hindi,
68 Croatian,
69 Hungarian,
70 Armenian,
71 Indonesian,
72 Igbo,
73 Ido,
74 Icelandic,
75 Interslavic,
76 Italian,
77 Japanese,
78 Lojban,
79 Georgian,
80 Kazakh,
81 Kannada,
82 Korean,
83 Kolsch,
84 Cornish,
85 Latin,
86 Luxembourgish,
87 Limburgish,
88 Lombard,
89 Lolcat,
90 Lithuanian,
91 Latvian,
92 ClassicalChinese,
93 Macedonian,
94 Mongolian,
95 Malay,
96 Maltese,
97 Nahuatl,
98 LowGerman,
99 DutchFlemish,
100 Dutch,
101 NorwegianNynorsk,
102 NorwegianBokmal,
103 Occitan,
104 Elfdalian,
105 Polish,
106 BrazilianPortuguese,
107 EuropeanPortuguese,
108 Quenya,
109 Romanian,
110 RussianPreRevolutionary,
111 Russian,
112 Rusyn,
113 NorthernSami,
114 Slovak,
115 Slovenian,
116 Somali,
117 Albanian,
118 Serbian,
119 Swedish,
120 UpperSaxonGerman,
121 Silesian,
122 Tamil,
123 Thai,
124 Tagalog,
125 Klingon,
126 TokiPona,
127 Turkish,
128 Tatar,
129 Ukrainian,
130 Valencian,
131 Venetian,
132 Vietnamese,
133 Yiddish,
134 Yoruba,
135 ChineseSimplified,
136 ChineseTraditionalHongKong,
137 ChineseTraditionalTaiwan,
138 MalayJawi,
139}
140
141impl Default for Language {
142 fn default() -> Self {
143 match sys_locale::get_locale() {
144 Some(locale) => extract_locale_language(&locale).unwrap_or(Self::AmericanEnglish),
145 None => Self::AmericanEnglish,
146 }
147 }
148}
149
150impl Language {
151 pub fn parse_from_str(string: &str) -> Option<Self> {
153 match string {
154 "afrikaans" => Some(Self::Afrikaans),
155 "arabic" => Some(Self::Arabic),
156 "asturian" => Some(Self::Asturian),
157 "azerbaijani" => Some(Self::Azerbaijani),
158 "bashkir" => Some(Self::Bashkir),
159 "bavarian" => Some(Self::Bavarian),
160 "belarusian" => Some(Self::Belarusian),
161 "bulgarian" => Some(Self::Bulgarian),
162 "breton" => Some(Self::Breton),
163 "brabantian" => Some(Self::Brabantian),
164 "bosnian" => Some(Self::Bosnian),
165 "catalan" => Some(Self::Catalan),
166 "czech" => Some(Self::Czech),
167 "welsh" => Some(Self::Welsh),
168 "danish" => Some(Self::Danish),
169 "austrian_german" => Some(Self::AustrianGerman),
170 "swiss_german" => Some(Self::SwissGerman),
171 "german" => Some(Self::German),
172 "greek" => Some(Self::Greek),
173 "australian_english" => Some(Self::AustralianEnglish),
174 "canadian_english" => Some(Self::CanadianEnglish),
175 "british_english" => Some(Self::BritishEnglish),
176 "new_zealand_english" => Some(Self::NewZealandEnglish),
177 "pirate_speak" => Some(Self::PirateSpeak),
178 "upside_down" => Some(Self::UpsideDown),
179 "american_english" => Some(Self::AmericanEnglish),
180 "anglish" => Some(Self::Anglish),
181 "shakespearean" => Some(Self::Shakespearean),
182 "esperanto" => Some(Self::Esperanto),
183 "argentinian_spanish" => Some(Self::ArgentinianSpanish),
184 "chilean_spanish" => Some(Self::ChileanSpanish),
185 "ecuadorian_spanish" => Some(Self::EcuadorianSpanish),
186 "european_spanish" => Some(Self::EuropeanSpanish),
187 "mexican_spanish" => Some(Self::MexicanSpanish),
188 "uruguayan_spanish" => Some(Self::UruguayanSpanish),
189 "venezuelan_spanish" => Some(Self::VenezuelanSpanish),
190 "andalusian" => Some(Self::Andalusian),
191 "estonian" => Some(Self::Estonian),
192 "basque" => Some(Self::Basque),
193 "persian" => Some(Self::Persian),
194 "finnish" => Some(Self::Finnish),
195 "filipino" => Some(Self::Filipino),
196 "faroese" => Some(Self::Faroese),
197 "canadian_french" => Some(Self::CanadianFrench),
198 "european_french" => Some(Self::EuropeanFrench),
199 "east_franconian" => Some(Self::EastFranconian),
200 "friulian" => Some(Self::Friulian),
201 "frisian" => Some(Self::Frisian),
202 "irish" => Some(Self::Irish),
203 "scottish_gaelic" => Some(Self::ScottishGaelic),
204 "galician" => Some(Self::Galician),
205 "hawaiian" => Some(Self::Hawaiian),
206 "hebrew" => Some(Self::Hebrew),
207 "hindi" => Some(Self::Hindi),
208 "croatian" => Some(Self::Croatian),
209 "hungarian" => Some(Self::Hungarian),
210 "armenian" => Some(Self::Armenian),
211 "indonesian" => Some(Self::Indonesian),
212 "igbo" => Some(Self::Igbo),
213 "ido" => Some(Self::Ido),
214 "icelandic" => Some(Self::Icelandic),
215 "interslavic" => Some(Self::Interslavic),
216 "italian" => Some(Self::Italian),
217 "japanese" => Some(Self::Japanese),
218 "lojban" => Some(Self::Lojban),
219 "georgian" => Some(Self::Georgian),
220 "kazakh" => Some(Self::Kazakh),
221 "kannada" => Some(Self::Kannada),
222 "korean" => Some(Self::Korean),
223 "kolsch" => Some(Self::Kolsch),
224 "cornish" => Some(Self::Cornish),
225 "latin" => Some(Self::Latin),
226 "luxembourgish" => Some(Self::Luxembourgish),
227 "limburgish" => Some(Self::Limburgish),
228 "lombard" => Some(Self::Lombard),
229 "lolcat" => Some(Self::Lolcat),
230 "lithuanian" => Some(Self::Lithuanian),
231 "latvian" => Some(Self::Latvian),
232 "classical_chinese" => Some(Self::ClassicalChinese),
233 "macedonian" => Some(Self::Macedonian),
234 "mongolian" => Some(Self::Mongolian),
235 "malay" => Some(Self::Malay),
236 "maltese" => Some(Self::Maltese),
237 "nahuatl" => Some(Self::Nahuatl),
238 "low_german" => Some(Self::LowGerman),
239 "dutch_flemish" => Some(Self::DutchFlemish),
240 "dutch" => Some(Self::Dutch),
241 "norwegian_nynorsk" => Some(Self::NorwegianNynorsk),
242 "norwegian_bokmal" => Some(Self::NorwegianBokmal),
243 "occitan" => Some(Self::Occitan),
244 "elfdalian" => Some(Self::Elfdalian),
245 "polish" => Some(Self::Polish),
246 "brazilian_portuguese" => Some(Self::BrazilianPortuguese),
247 "european_portuguese" => Some(Self::EuropeanPortuguese),
248 "quenya" => Some(Self::Quenya),
249 "romanian" => Some(Self::Romanian),
250 "russian_pre_revolutionary" => Some(Self::RussianPreRevolutionary),
251 "russian" => Some(Self::Russian),
252 "rusyn" => Some(Self::Rusyn),
253 "northern_sami" => Some(Self::NorthernSami),
254 "slovak" => Some(Self::Slovak),
255 "slovenian" => Some(Self::Slovenian),
256 "somali" => Some(Self::Somali),
257 "albanian" => Some(Self::Albanian),
258 "serbian" => Some(Self::Serbian),
259 "swedish" => Some(Self::Swedish),
260 "upper_saxon_german" => Some(Self::UpperSaxonGerman),
261 "silesian" => Some(Self::Silesian),
262 "tamil" => Some(Self::Tamil),
263 "thai" => Some(Self::Thai),
264 "tagalog" => Some(Self::Tagalog),
265 "klingon" => Some(Self::Klingon),
266 "toki_pona" => Some(Self::TokiPona),
267 "turkish" => Some(Self::Turkish),
268 "tatar" => Some(Self::Tatar),
269 "ukrainian" => Some(Self::Ukrainian),
270 "valencian" => Some(Self::Valencian),
271 "venetian" => Some(Self::Venetian),
272 "vietnamese" => Some(Self::Vietnamese),
273 "yiddish" => Some(Self::Yiddish),
274 "yoruba" => Some(Self::Yoruba),
275 "chinese_simplified" => Some(Self::ChineseSimplified),
276 "chinese_traditional_hong_kong" => Some(Self::ChineseTraditionalHongKong),
277 "chinese_traditional_taiwan" => Some(Self::ChineseTraditionalTaiwan),
278 "malay_jawi" => Some(Self::MalayJawi),
279 _ => None,
280 }
281 }
282}
283
284pub fn extract_locale_language(locale: &str) -> Option<Language> {
286 let locale = canonicalize_locale(locale);
287 match locale.as_str() {
288 "de_AT" => Some(Language::AustrianGerman),
289 "de_CH" => Some(Language::SwissGerman),
290 "en_AU" => Some(Language::AustralianEnglish),
291 "en_CA" => Some(Language::CanadianEnglish),
292 "en_GB" => Some(Language::BritishEnglish),
293 "en_NZ" => Some(Language::NewZealandEnglish),
294 "en_US" | "C" | "POSIX" => Some(Language::AmericanEnglish),
295 "es_AR" => Some(Language::ArgentinianSpanish),
296 "es_CL" => Some(Language::ChileanSpanish),
297 "es_EC" => Some(Language::EcuadorianSpanish),
298 "es_ES" => Some(Language::EuropeanSpanish),
299 "es_MX" => Some(Language::MexicanSpanish),
300 "es_UY" => Some(Language::UruguayanSpanish),
301 "es_VE" => Some(Language::VenezuelanSpanish),
302 "fr_CA" => Some(Language::CanadianFrench),
303 "fr_FR" => Some(Language::EuropeanFrench),
304 "nl_BE" => Some(Language::DutchFlemish),
305 "nl_NL" => Some(Language::Dutch),
306 "pt_BR" => Some(Language::BrazilianPortuguese),
307 "pt_PT" => Some(Language::EuropeanPortuguese),
308 "zh_CN" => Some(Language::ChineseSimplified),
309 "zh_HK" => Some(Language::ChineseTraditionalHongKong),
310 "zh_TW" => Some(Language::ChineseTraditionalTaiwan),
311 other => {
313 let first_part = extract_locale_first_part(other);
314 match first_part {
315 "af" => Some(Language::Afrikaans),
316 "ar" => Some(Language::Arabic),
317 "az" => Some(Language::Azerbaijani),
318 "be" => Some(Language::Belarusian),
319 "bg" => Some(Language::Bulgarian),
320 "bs" => Some(Language::Bosnian),
321 "ca" => Some(Language::Catalan),
322 "cs" => Some(Language::Czech),
323 "da" => Some(Language::Danish),
324 "de" => Some(Language::German),
325 "el" => Some(Language::Greek),
326 "en" => Some(Language::AmericanEnglish),
327 "es" => Some(Language::EuropeanSpanish),
328 "et" => Some(Language::Estonian),
329 "fi" => Some(Language::Finnish),
330 "fr" => Some(Language::EuropeanFrench),
331 "he" => Some(Language::Hebrew),
332 "hi" => Some(Language::Hindi),
333 "hr" => Some(Language::Croatian),
334 "hu" => Some(Language::Hungarian),
335 "hy" => Some(Language::Armenian),
336 "id" => Some(Language::Indonesian),
337 "is" => Some(Language::Icelandic),
338 "it" => Some(Language::Italian),
339 "ja" => Some(Language::Japanese),
340 "ka" => Some(Language::Georgian),
341 "kk" => Some(Language::Kazakh),
342 "kn" => Some(Language::Kannada),
343 "ko" => Some(Language::Korean),
344 "lt" => Some(Language::Lithuanian),
345 "lv" => Some(Language::Latvian),
346 "mk" => Some(Language::Macedonian),
347 "ms" => Some(Language::Malay),
348 "mt" => Some(Language::Maltese),
349 "nb" => Some(Language::NorwegianBokmal),
350 "nl" => Some(Language::Dutch),
351 "nn" => Some(Language::NorwegianNynorsk),
352 "pl" => Some(Language::Polish),
353 "pt" => Some(Language::EuropeanPortuguese),
354 "ro" => Some(Language::Romanian),
355 "ru" => Some(Language::Russian),
356 "sk" => Some(Language::Slovak),
357 "sl" => Some(Language::Slovenian),
358 "sq" => Some(Language::Albanian),
359 "sr" => Some(Language::Serbian),
360 "sv" => Some(Language::Swedish),
361 "ta" => Some(Language::Tamil),
362 "th" => Some(Language::Thai),
363 "tr" => Some(Language::Turkish),
364 "uk" => Some(Language::Ukrainian),
365 "vi" => Some(Language::Vietnamese),
366 "zh" => Some(Language::ChineseSimplified),
367 _ => None,
368 }
369 }
370 }
371}
372
373pub fn extract_locale_first_part(locale: &str) -> &str {
376 if let Some(underscore_location) = locale.find('_') {
377 locale.split_at(underscore_location).0
378 } else {
379 locale
380 }
381}
382
383pub fn canonicalize_locale(locale: &str) -> String {
385 let mut locale = strip_locale(locale).to_string();
386 locale = locale.replace('-', "_");
387 locale
388}
389
390pub fn strip_locale(locale: &str) -> &str {
392 if let Some(dot_location) = locale.find('.') {
393 locale.split_at(dot_location).0
394 } else {
395 locale
396 }
397}
398
399#[cfg(test)]
400mod tests {
401 use super::*;
402
403 #[test]
404 fn test_locale_canonicalization() {
405 assert_eq!(canonicalize_locale("az"), "az".to_string());
406 assert_eq!(canonicalize_locale("az-ZA"), "az_ZA".to_string());
407 assert_eq!(canonicalize_locale("az-ZA.UTF-8"), "az_ZA".to_string());
408 }
409
410 #[test]
411 fn test_language_extraction() {
412 assert_eq!(
413 extract_locale_language("C"),
414 Some(Language::AmericanEnglish)
415 );
416 assert_eq!(extract_locale_language("af-ZA"), Some(Language::Afrikaans));
417 assert_eq!(
418 extract_locale_language("de-CH"),
419 Some(Language::SwissGerman)
420 );
421 assert_eq!(extract_locale_language("de_FOO"), Some(Language::German));
422 }
423}