use serde::{Deserialize, Deserializer, Serialize};
use std::collections::HashMap;
#[derive(Clone, Debug, Default)]
pub struct StaticTranslatableString {
pub translations: HashMap<String, String>,
pub lang: String,
}
impl StaticTranslatableString {
pub fn from_translations(
translations: HashMap<String, String>,
default_lang: Option<String>,
) -> Self {
let lang = default_lang.unwrap_or_else(|| "en".to_string());
let actual_lang = if translations.contains_key(&lang) {
lang
} else {
translations
.keys()
.next()
.cloned()
.unwrap_or_else(|| "en".to_string())
};
StaticTranslatableString {
translations,
lang: actual_lang,
}
}
pub fn from_string(s: &str) -> Self {
let mut translations = HashMap::new();
translations.insert("en".to_string(), s.to_string());
StaticTranslatableString {
translations,
lang: "en".to_string(),
}
}
pub fn empty() -> Self {
StaticTranslatableString {
translations: HashMap::new(),
lang: "en".to_string(),
}
}
pub fn get(&self, lang: &str) -> String {
self.translations
.get(lang)
.or_else(|| self.translations.get("en"))
.or_else(|| self.translations.values().next())
.cloned()
.unwrap_or_default()
}
pub fn to_string_default(&self) -> String {
self.get(&self.lang)
}
pub fn copy(&self) -> Self {
self.clone()
}
pub fn to_json(&self) -> serde_json::Value {
serde_json::to_value(&self.translations).unwrap_or(serde_json::Value::Null)
}
}
impl std::fmt::Display for StaticTranslatableString {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_string_default())
}
}
impl Serialize for StaticTranslatableString {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.translations.serialize(serializer)
}
}
impl<'de> Deserialize<'de> for StaticTranslatableString {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
use serde_json::Value;
let value = Value::deserialize(deserializer)?;
match value {
Value::Object(map) => {
let translations: HashMap<String, String> = map
.into_iter()
.filter_map(|(k, v)| v.as_str().map(|s| (k, s.to_string())))
.collect();
let lang = translations
.keys()
.next()
.cloned()
.unwrap_or_else(|| "en".to_string());
Ok(StaticTranslatableString { translations, lang })
}
Value::String(s) => {
let mut translations = HashMap::new();
translations.insert("en".to_string(), s);
Ok(StaticTranslatableString {
translations,
lang: "en".to_string(),
})
}
_ => {
let mut translations = HashMap::new();
translations.insert("en".to_string(), String::new());
Ok(StaticTranslatableString {
translations,
lang: "en".to_string(),
})
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_translatable_string_from_map() {
let mut translations = HashMap::new();
translations.insert("en".to_string(), "Hello".to_string());
translations.insert("de".to_string(), "Hallo".to_string());
let ts = StaticTranslatableString::from_translations(translations, None);
assert_eq!(ts.get("en"), "Hello");
assert_eq!(ts.get("de"), "Hallo");
}
#[test]
fn test_translatable_string_fallback() {
let mut translations = HashMap::new();
translations.insert("de".to_string(), "Hallo".to_string());
let ts = StaticTranslatableString::from_translations(translations, None);
assert_eq!(ts.get("en"), "Hallo");
}
}