Skip to main content

mux_media/types/lang/
new.rs

1use super::{Lang, LangCode};
2use crate::{IsDefault, MuxError, Result};
3use std::{env, str::FromStr};
4
5/// Returns a [`Lang::Code`].
6#[macro_export]
7macro_rules! lang {
8    ($x:ident) => {
9        $crate::Lang::Code($crate::LangCode::$x)
10    };
11}
12
13impl Lang {
14    pub(crate) fn new(s: impl AsRef<str>) -> Lang {
15        let s = s.as_ref();
16        match get_code(s) {
17            Some(c) => Lang::Code(c),
18            None => Lang::Other(s.into()),
19        }
20    }
21}
22
23impl LangCode {
24    pub(crate) fn init() -> Self {
25        Self::get_from_system_locale().unwrap_or_default()
26    }
27
28    pub(crate) fn get(s: &str) -> Option<LangCode> {
29        get_code(s)
30    }
31
32    fn get_from_system_locale() -> Option<Self> {
33        let locale = env::var("LC_ALL")
34            .ok()
35            .or_else(|| env::var("LANG").ok())
36            .or_else(|| env::var("LC_MESSAGES").ok())
37            .or_else(|| get_system_locale_fallback())?;
38
39        return get_code(&locale);
40
41        fn get_system_locale_fallback() -> Option<String> {
42            #[cfg(windows)]
43            {
44                use std::ffi::OsString;
45                use std::os::windows::ffi::OsStringExt;
46                use winapi::um::winnls::GetUserDefaultLocaleName;
47
48                const LOCALE_NAME_MAX_LENGTH: usize = 85;
49                let mut buffer = [0u16; LOCALE_NAME_MAX_LENGTH];
50
51                let len = unsafe {
52                    GetUserDefaultLocaleName(buffer.as_mut_ptr(), LOCALE_NAME_MAX_LENGTH as i32)
53                };
54
55                if len > 0 {
56                    let os_str = OsString::from_wide(&buffer[..(len as usize - 1)]);
57                    os_str.into_string().ok()
58                } else {
59                    None
60                }
61            }
62
63            #[cfg(unix)]
64            {
65                None
66            }
67        }
68    }
69}
70
71impl Default for Lang {
72    fn default() -> Lang {
73        Lang::Code(LangCode::default())
74    }
75}
76impl IsDefault for Lang {
77    fn is_default(&self) -> bool {
78        matches!(self, Lang::Code(c) if c.is_default())
79    }
80}
81
82impl FromStr for Lang {
83    type Err = MuxError;
84
85    fn from_str(s: &str) -> Result<Lang> {
86        Ok(Lang::new(s))
87    }
88}
89impl FromStr for LangCode {
90    type Err = MuxError;
91
92    fn from_str(s: &str) -> Result<LangCode> {
93        get_code(s).ok_or_else(|| err!("Not found a valid language code"))
94    }
95}
96
97fn get_code(s: &str) -> Option<LangCode> {
98    fn str_to_ascii_words(s: &str) -> impl Iterator<Item = &str> {
99        use lazy_regex::{Lazy, Regex, regex};
100        static REGEX_ASCII_WORD: &Lazy<Regex> = regex!(r"[a-zA-Z]+");
101        REGEX_ASCII_WORD.find_iter(s).map(|mat| mat.as_str())
102    }
103
104    let mut buf = [0u8; 3];
105    str_to_ascii_words(s).find_map(|s| {
106        let len = s.len();
107        if !matches!(len, 2 | 3) {
108            return None;
109        }
110        for (dst, src) in buf[..len].iter_mut().zip(s.bytes()) {
111            *dst = src.to_ascii_lowercase();
112        }
113
114        let code = match &buf[..len] {
115            b"und" => LangCode::Und,
116            b"aa" | b"aar" => LangCode::Aar,
117            b"ab" | b"abk" => LangCode::Abk,
118            b"af" | b"afr" => LangCode::Afr,
119            b"ak" | b"aka" => LangCode::Aka,
120            b"sq" | b"sqi" | b"alb" => LangCode::Alb,
121            b"am" | b"amh" => LangCode::Amh,
122            b"ar" | b"ara" => LangCode::Ara,
123            b"an" | b"arg" => LangCode::Arg,
124            b"hy" | b"hye" | b"arm" => LangCode::Arm,
125            b"as" | b"asm" => LangCode::Asm,
126            b"av" | b"ava" => LangCode::Ava,
127            b"ae" | b"ave" => LangCode::Ave,
128            b"ay" | b"aym" => LangCode::Aym,
129            b"az" | b"aze" => LangCode::Aze,
130            b"ba" | b"bak" => LangCode::Bak,
131            b"bm" | b"bam" => LangCode::Bam,
132            b"eu" | b"eus" | b"baq" => LangCode::Baq,
133            b"be" | b"bel" => LangCode::Bel,
134            b"bn" | b"ben" => LangCode::Ben,
135            b"bi" | b"bis" => LangCode::Bis,
136            b"bs" | b"bos" => LangCode::Bos,
137            b"br" | b"bre" => LangCode::Bre,
138            b"bg" | b"bul" => LangCode::Bul,
139            b"my" | b"mya" | b"bur" => LangCode::Bur,
140            b"ca" | b"cat" => LangCode::Cat,
141            b"ch" | b"cha" => LangCode::Cha,
142            b"ce" | b"che" => LangCode::Che,
143            b"zh" | b"zho" | b"chi" => LangCode::Chi,
144            b"cu" | b"chu" => LangCode::Chu,
145            b"cv" | b"chv" => LangCode::Chv,
146            b"kw" | b"cor" => LangCode::Cor,
147            b"co" | b"cos" => LangCode::Cos,
148            b"cr" | b"cre" => LangCode::Cre,
149            b"cs" | b"ces" | b"cze" => LangCode::Cze,
150            b"da" | b"dan" => LangCode::Dan,
151            b"dv" | b"div" => LangCode::Div,
152            b"nl" | b"nld" | b"dut" => LangCode::Dut,
153            b"dz" | b"dzo" => LangCode::Dzo,
154            b"en" | b"eng" => LangCode::Eng,
155            b"eo" | b"epo" => LangCode::Epo,
156            b"et" | b"est" => LangCode::Est,
157            b"ee" | b"ewe" => LangCode::Ewe,
158            b"fo" | b"fao" => LangCode::Fao,
159            b"fj" | b"fij" => LangCode::Fij,
160            b"fi" | b"fin" => LangCode::Fin,
161            b"fr" | b"fra" | b"fre" => LangCode::Fre,
162            b"fy" | b"fry" => LangCode::Fry,
163            b"ff" | b"ful" => LangCode::Ful,
164            b"ka" | b"kat" | b"geo" => LangCode::Geo,
165            b"de" | b"der" | b"ger" => LangCode::Ger,
166            b"gd" | b"gla" => LangCode::Gla,
167            b"ga" | b"gle" => LangCode::Gle,
168            b"gl" | b"glg" => LangCode::Glg,
169            b"gb" | b"glv" => LangCode::Glv,
170            b"el" | b"ell" | b"gre" => LangCode::Gre,
171            b"gn" | b"grn" => LangCode::Grn,
172            b"gu" | b"guj" => LangCode::Guj,
173            b"ht" | b"hat" => LangCode::Hat,
174            b"ha" | b"hau" => LangCode::Hau,
175            b"sh" | b"hbs" => LangCode::Hbs,
176            b"he" | b"heb" => LangCode::Heb,
177            b"hz" | b"her" => LangCode::Her,
178            b"hi" | b"hin" => LangCode::Hin,
179            b"ho" | b"hmo" => LangCode::Hmo,
180            b"hr" | b"hrv" => LangCode::Hrv,
181            b"hu" | b"hun" => LangCode::Hun,
182            b"ig" | b"ibo" => LangCode::Ibo,
183            b"is" | b"isl" | b"ice" => LangCode::Ice,
184            b"io" | b"ido" => LangCode::Ido,
185            b"ii" | b"iii" => LangCode::Iii,
186            b"iu" | b"iku" => LangCode::Iku,
187            b"ie" | b"ile" => LangCode::Ile,
188            b"ia" | b"ina" => LangCode::Ina,
189            b"id" | b"ind" => LangCode::Ind,
190            b"ik" | b"ipk" => LangCode::Ipk,
191            b"it" | b"ita" => LangCode::Ita,
192            b"jv" | b"jav" => LangCode::Jav,
193            b"ja" | b"jpn" => LangCode::Jpn,
194            b"kl" | b"kal" => LangCode::Kal,
195            b"kn" | b"kan" => LangCode::Kan,
196            b"ks" | b"kas" => LangCode::Kas,
197            b"kr" | b"kau" => LangCode::Kau,
198            b"kk" | b"kaz" => LangCode::Kaz,
199            b"km" | b"khm" => LangCode::Khm,
200            b"ki" | b"kik" => LangCode::Kik,
201            b"rw" | b"kin" => LangCode::Kin,
202            b"ky" | b"kir" => LangCode::Kir,
203            b"kv" | b"kom" => LangCode::Kom,
204            b"kg" | b"kon" => LangCode::Kon,
205            b"ko" | b"kor" => LangCode::Kor,
206            b"kj" | b"kua" => LangCode::Kua,
207            b"ku" | b"kur" => LangCode::Kur,
208            b"lo" | b"lao" => LangCode::Lao,
209            b"la" | b"lat" => LangCode::Lat,
210            b"lv" | b"lav" => LangCode::Lav,
211            b"li" | b"lim" => LangCode::Lim,
212            b"ln" | b"lin" => LangCode::Lin,
213            b"lt" | b"lit" => LangCode::Lit,
214            b"lb" | b"ltz" => LangCode::Ltz,
215            b"lu" | b"lub" => LangCode::Lub,
216            b"lg" | b"lug" => LangCode::Lug,
217            b"mk" | b"mkd" | b"mac" => LangCode::Mac,
218            b"mh" | b"mah" => LangCode::Mah,
219            b"ml" | b"mal" => LangCode::Mal,
220            b"mi" | b"mri" | b"mao" => LangCode::Mao,
221            b"mr" | b"mar" => LangCode::Mar,
222            b"ms" | b"msa" | b"may" => LangCode::May,
223            b"mg" | b"mlg" => LangCode::Mlg,
224            b"mt" | b"mlt" => LangCode::Mlt,
225            b"mn" | b"mon" => LangCode::Mon,
226            b"na" | b"nau" => LangCode::Nau,
227            b"nv" | b"nav" => LangCode::Nav,
228            b"nr" | b"nbl" => LangCode::Nbl,
229            b"nd" | b"nde" => LangCode::Nde,
230            b"ng" | b"ndo" => LangCode::Ndo,
231            b"ne" | b"nep" => LangCode::Nep,
232            b"nn" | b"nno" => LangCode::Nno,
233            b"nb" | b"nob" => LangCode::Nob,
234            b"no" | b"nor" => LangCode::Nor,
235            b"ny" | b"nya" => LangCode::Nya,
236            b"oc" | b"oci" => LangCode::Oci,
237            b"oj" | b"oji" => LangCode::Oji,
238            b"or" | b"ori" => LangCode::Ori,
239            b"om" | b"orm" => LangCode::Orm,
240            b"os" | b"oss" => LangCode::Oss,
241            b"pa" | b"pan" => LangCode::Pan,
242            b"fa" | b"fas" | b"per" => LangCode::Per,
243            b"pi" | b"pli" => LangCode::Pli,
244            b"pl" | b"pol" => LangCode::Pol,
245            b"pt" | b"por" => LangCode::Por,
246            b"ps" | b"pus" => LangCode::Pus,
247            b"qu" | b"que" => LangCode::Que,
248            b"rm" | b"roh" => LangCode::Roh,
249            b"ro" | b"ron" | b"rum" => LangCode::Rum,
250            b"rn" | b"run" => LangCode::Run,
251            b"ru" | b"rus" => LangCode::Rus,
252            b"sg" | b"sag" => LangCode::Sag,
253            b"sa" | b"san" => LangCode::San,
254            b"si" | b"sin" => LangCode::Sin,
255            b"sk" | b"slk" | b"slo" => LangCode::Slo,
256            b"sl" | b"slv" => LangCode::Slv,
257            b"se" | b"sme" => LangCode::Sme,
258            b"sm" | b"smo" => LangCode::Smo,
259            b"sn" | b"sna" => LangCode::Sna,
260            b"sd" | b"snd" => LangCode::Snd,
261            b"so" | b"som" => LangCode::Som,
262            b"st" | b"sot" => LangCode::Sot,
263            b"es" | b"spa" => LangCode::Spa,
264            b"sc" | b"srd" => LangCode::Srd,
265            b"sr" | b"srp" => LangCode::Srp,
266            b"ss" | b"ssw" => LangCode::Ssw,
267            b"su" | b"sun" => LangCode::Sun,
268            b"sw" | b"swa" => LangCode::Swa,
269            b"sv" | b"swe" => LangCode::Swe,
270            b"ty" | b"tah" => LangCode::Tah,
271            b"ta" | b"tam" => LangCode::Tam,
272            b"tt" | b"tat" => LangCode::Tat,
273            b"te" | b"tel" => LangCode::Tel,
274            b"tg" | b"tgk" => LangCode::Tgk,
275            b"tl" | b"tgl" => LangCode::Tgl,
276            b"th" | b"tha" => LangCode::Tha,
277            b"bo" | b"bod" | b"tib" => LangCode::Tib,
278            b"ti" | b"tir" => LangCode::Tir,
279            b"to" | b"ton" => LangCode::Ton,
280            b"tn" | b"tsn" => LangCode::Tsn,
281            b"ts" | b"tso" => LangCode::Tso,
282            b"tk" | b"tuk" => LangCode::Tuk,
283            b"tr" | b"tur" => LangCode::Tur,
284            b"tw" | b"twi" => LangCode::Twi,
285            b"ug" | b"uig" => LangCode::Uig,
286            b"uk" | b"ukr" => LangCode::Ukr,
287            b"ur" | b"urd" => LangCode::Urd,
288            b"uz" | b"uzb" => LangCode::Uzb,
289            b"ve" | b"ven" => LangCode::Ven,
290            b"vi" | b"vie" => LangCode::Vie,
291            b"vo" | b"vol" => LangCode::Vol,
292            b"cy" | b"cym" | b"wel" => LangCode::Wel,
293            b"wa" | b"wln" => LangCode::Wln,
294            b"wo" | b"wol" => LangCode::Wol,
295            b"xh" | b"xho" => LangCode::Xho,
296            b"yi" | b"yid" => LangCode::Yid,
297            b"yo" | b"yor" => LangCode::Yor,
298            b"za" | b"zha" => LangCode::Zha,
299            b"zu" | b"zul" => LangCode::Zul,
300            _ => return None,
301        };
302
303        Some(code)
304    })
305}