use crate::prelude::types::LogString;
use crossbeam_channel::Sender;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::sync::Arc;
#[derive(Serialize, Debug)]
pub enum UpdateI18n {
Add((LogString, LogString)),
Remove(LogString),
Replace(I18nDataset),
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialOrd, PartialEq, Ord, Eq)]
pub enum Language {
ES,
#[default]
EN,
FR,
Other(&'static str),
}
impl Copy for Language {}
#[derive(Debug, Clone)]
pub struct I18nSynDataset {
dataset: Arc<I18nDataset>,
comm: Sender<UpdateI18n>,
}
impl I18nSynDataset {
pub fn new(dataset: Arc<I18nDataset>, comm: Sender<UpdateI18n>) -> Self {
Self { dataset, comm }
}
pub fn empty() -> Self {
let (sender, _) = crossbeam_channel::bounded(1);
Self {
dataset: Arc::new(I18nDataset::new()),
comm: sender,
}
}
pub fn insert<S>(&self, key: S, data: S)
where
S: Into<LogString>,
{
let _ = self
.comm
.try_send(UpdateI18n::Add((key.into(), data.into())));
}
pub fn remove<S>(&self, key: S)
where
S: Into<LogString>,
{
let _ = self.comm.try_send(UpdateI18n::Remove(key.into()));
}
pub fn update(&self, data: I18nDataset) {
let _ = self.comm.try_send(UpdateI18n::Replace(data));
}
pub fn get(&self, text: &LogString, language: &Language) -> Option<&LogString> {
self.dataset.get(text, language)
}
pub fn get_or_default(&self, text: &str, language: &Language) -> Option<&LogString> {
self.dataset.get_or_default(text, language)
}
}
#[derive(Serialize, Debug, Default)]
pub struct I18nDataset {
data: BTreeMap<LogString, BTreeMap<Language, LogString>>,
}
impl I18nDataset {
pub fn new() -> Self {
Self::default()
}
pub fn set_dictionary<M>(&mut self, language: Language, data: M)
where
M: Into<BTreeMap<LogString, LogString>>,
{
let new_data: BTreeMap<LogString, LogString> = data.into();
for (k, value) in new_data {
if self.data.contains_key(&k) {
let map = match self.data.get_mut(&k) {
Some(v) => v,
None => return,
};
map.insert(language, value);
} else {
let mut map = BTreeMap::new();
map.insert(language, value);
self.data.insert(k, map);
}
}
}
pub fn insert(&mut self, language: Language, text: LogString, value: LogString) {
if self.data.contains_key(&text) {
let map = match self.data.get_mut(&text) {
Some(v) => v,
None => return,
};
map.insert(language, value);
} else {
let mut map = BTreeMap::new();
map.insert(language, value);
self.data.insert(text, map);
}
}
pub fn get(&self, text: &str, language: &Language) -> Option<&LogString> {
self.data.get(text)?.get(language)
}
pub fn get_or_default(&self, text: &str, language: &Language) -> Option<&LogString> {
let langs = self.data.get(text)?;
match langs.get(language) {
Some(lang) => Some(lang),
None => {
match langs.get(&Language::EN) {
Some(lang) => Some(lang),
None => {
Some(langs.first_key_value()?.1)
}
}
}
}
}
pub fn internal_ref(&self) -> &BTreeMap<LogString, BTreeMap<Language, LogString>> {
&self.data
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_find_data_in_map() {
let mut dataset = I18nDataset::new();
dataset.insert(
Language::ES,
LogString::Borrowed("LocalIp"),
LogString::Borrowed("IP Local"),
);
dataset.insert(
Language::EN,
LogString::Borrowed("LocalIp"),
LogString::Borrowed("Local IP"),
);
assert_eq!(
dataset.get_or_default("LocalIp", &Language::ES),
Some(&LogString::Borrowed("IP Local"))
);
assert_eq!(
dataset.get_or_default("LocalIp", &Language::FR),
Some(&LogString::Borrowed("Local IP"))
);
}
}