language_objects/
language.rs

1use std::hash::{Hash, Hasher};
2use std::{sync::Arc, fmt::Debug};
3use std::collections::HashMap;
4use serde::{Deserialize, Serialize};
5use super::Region;
6
7lazy_static! {
8    static ref LANGUAGE_DATA: HashMap<String, LanguageData> = {
9        serde_json::from_str::<HashMap<String, LanguageData>>(include_str!("../data/languages.json")).unwrap()
10    };
11}
12
13lazy_static! {
14    static ref INTERNED_LANGUAGES: HashMap<String, Language> = {
15        let mut r = HashMap::<String, Language>::new();
16        for (k, v) in LANGUAGE_DATA.iter() {
17            r.insert(k.clone(), Language {
18                _abbrev: k.clone(),
19                _data: Arc::new(v.clone()),
20                _region: None,
21            });
22        }
23        r
24    };
25}
26
27#[derive(Serialize, Deserialize, Clone)]
28struct LanguageData {
29    /// International name
30    n: String,
31    /// Native name
32    nn: String,
33    /// Direction
34    d: String,
35}
36
37#[derive(Clone)]
38pub struct Language {
39    _abbrev: String,
40    _data: Arc<LanguageData>,
41    _region: Option<Region>,
42}
43
44impl Language {
45    fn parse_tag<T: ToString>(tag: T) -> Option<(String, String)> {
46        let tag = tag.to_string().to_lowercase().replace("_", "-");
47        let tag_split: Vec<&str> = tag.split("-").collect();
48        if tag_split.len() == 0 {
49            return None;
50        }
51        let mut language_abbrev = tag_split[0];
52        let mut region_abbrev = if tag_split.len() == 2 { Some(String::from(tag_split[1])) } else { None };
53        if region_abbrev.is_none() {
54            if language_abbrev == "en" || language_abbrev == "us" || language_abbrev == "usa" { language_abbrev = "en"; region_abbrev = Some(String::from("us")); }
55            if language_abbrev == "br" { language_abbrev = "pt"; region_abbrev = Some(String::from("br")); }
56            if language_abbrev == "jp" { language_abbrev = "ja"; region_abbrev = Some(String::from("jp")); }
57        }
58        if region_abbrev.is_none() {
59            let r = Region::parse(language_abbrev);
60            if let Some(a) = r {
61                region_abbrev = Some(a.to_string().to_lowercase());
62            }
63        }
64        if region_abbrev.is_none() {
65            return None;
66        }
67        Some((String::from(language_abbrev), region_abbrev.unwrap()))
68    }
69
70    pub fn parse<T: ToString>(tag: T) -> Option<Language> {
71        let tag = Language::parse_tag(tag);
72        if tag.is_none() {
73            return None;
74        }
75        let tag = tag.unwrap();
76        let lng = INTERNED_LANGUAGES.get(&tag.0);
77        let region = Region::parse(tag.1);
78        if lng.is_none() || region.is_none() {
79            return None;
80        }
81        Some(Language {
82            _abbrev: tag.0.clone(),
83            _data: lng.unwrap()._data.clone(),
84            _region: region.clone(),
85        })
86    }
87
88    pub fn international_name(&self) -> String {
89        self._data.n.clone()
90    }
91    pub fn native_name(&self) -> String {
92        self._data.nn.clone()
93    }
94    pub fn direction(&self) -> Direction {
95        if self._data.d == "ltr" { Direction::Ltr } else { Direction::Rtl }
96    }
97    pub fn tag(&self) -> String {
98        self._abbrev.clone() + "-" + self._region.as_ref().unwrap().to_string().to_uppercase().as_str()
99    }
100    pub fn region(&self) -> Region {
101        self._region.as_ref().unwrap().clone()
102    }
103}
104
105impl PartialEq for Language {
106    fn eq(&self, other: &Self) -> bool {
107        Arc::ptr_eq(&self._data, &other._data) && self._region.as_ref().unwrap() == other._region.as_ref().unwrap()
108    }
109}
110
111impl Eq for Language {
112}
113
114impl Hash for Language {
115    fn hash<H: Hasher>(&self, state: &mut H) {
116        self.tag().hash(state);
117    }
118}
119
120impl ToString for Language {
121    fn to_string(&self) -> String {
122        self._abbrev.clone() + "-" + self._region.as_ref().unwrap().to_string().to_uppercase().as_str()
123    }
124}
125
126impl Debug for Language {
127    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128        write!(f, "{}", self.to_string())
129    }
130}
131
132#[derive(PartialEq, Eq, Debug, Hash)]
133pub enum Direction {
134    Ltr,
135    Rtl,
136}