use std::hash::{Hash, Hasher};
use std::{sync::Arc, fmt::Debug};
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use super::Region;
lazy_static! {
static ref LANGUAGE_DATA: HashMap<String, LanguageData> = {
serde_json::from_str::<HashMap<String, LanguageData>>(include_str!("../data/languages.json")).unwrap()
};
}
lazy_static! {
static ref INTERNED_LANGUAGES: HashMap<String, Language> = {
let mut r = HashMap::<String, Language>::new();
for (k, v) in LANGUAGE_DATA.iter() {
r.insert(k.clone(), Language {
_abbrev: k.clone(),
_data: Arc::new(v.clone()),
_region: None,
});
}
r
};
}
#[derive(Serialize, Deserialize, Clone)]
struct LanguageData {
n: String,
nn: String,
d: String,
}
#[derive(Clone)]
pub struct Language {
_abbrev: String,
_data: Arc<LanguageData>,
_region: Option<Region>,
}
impl Language {
fn parse_tag<T: ToString>(tag: T) -> Option<(String, String)> {
let tag = tag.to_string().to_lowercase().replace("_", "-");
let tag_split: Vec<&str> = tag.split("-").collect();
if tag_split.len() == 0 {
return None;
}
let mut language_abbrev = tag_split[0];
let mut region_abbrev = if tag_split.len() == 2 { Some(String::from(tag_split[1])) } else { None };
if region_abbrev.is_none() {
if language_abbrev == "en" || language_abbrev == "us" || language_abbrev == "usa" { language_abbrev = "en"; region_abbrev = Some(String::from("us")); }
if language_abbrev == "br" { language_abbrev = "pt"; region_abbrev = Some(String::from("br")); }
if language_abbrev == "jp" { language_abbrev = "ja"; region_abbrev = Some(String::from("jp")); }
}
if region_abbrev.is_none() {
let r = Region::parse(language_abbrev);
if let Some(a) = r {
region_abbrev = Some(a.to_string().to_lowercase());
}
}
if region_abbrev.is_none() {
return None;
}
Some((String::from(language_abbrev), region_abbrev.unwrap()))
}
pub fn parse<T: ToString>(tag: T) -> Option<Language> {
let tag = Language::parse_tag(tag);
if tag.is_none() {
return None;
}
let tag = tag.unwrap();
let lng = INTERNED_LANGUAGES.get(&tag.0);
let region = Region::parse(tag.1);
if lng.is_none() || region.is_none() {
return None;
}
Some(Language {
_abbrev: tag.0.clone(),
_data: lng.unwrap()._data.clone(),
_region: region.clone(),
})
}
pub fn international_name(&self) -> String {
self._data.n.clone()
}
pub fn native_name(&self) -> String {
self._data.nn.clone()
}
pub fn direction(&self) -> Direction {
if self._data.d == "ltr" { Direction::Ltr } else { Direction::Rtl }
}
pub fn tag(&self) -> String {
self._abbrev.clone() + "-" + self._region.as_ref().unwrap().to_string().to_uppercase().as_str()
}
pub fn region(&self) -> Region {
self._region.as_ref().unwrap().clone()
}
}
impl PartialEq for Language {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self._data, &other._data) && self._region.as_ref().unwrap() == other._region.as_ref().unwrap()
}
}
impl Eq for Language {
}
impl Hash for Language {
fn hash<H: Hasher>(&self, state: &mut H) {
self.tag().hash(state);
}
}
impl ToString for Language {
fn to_string(&self) -> String {
self._abbrev.clone() + "-" + self._region.as_ref().unwrap().to_string().to_uppercase().as_str()
}
}
impl Debug for Language {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_string())
}
}
#[derive(PartialEq, Eq, Debug, Hash)]
pub enum Direction {
Ltr,
Rtl,
}