language_objects/
language.rs1use 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 n: String,
31 nn: String,
33 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}