alizarin_core/graph/
translatable.rs1use serde::{Deserialize, Deserializer, Serialize};
4use std::collections::HashMap;
5
6#[derive(Clone, Debug, Default)]
8pub struct StaticTranslatableString {
9 pub translations: HashMap<String, String>,
10 pub lang: String,
11}
12
13impl StaticTranslatableString {
14 pub fn from_translations(
16 translations: HashMap<String, String>,
17 default_lang: Option<String>,
18 ) -> Self {
19 let lang = default_lang.unwrap_or_else(|| "en".to_string());
20 let actual_lang = if translations.contains_key(&lang) {
21 lang
22 } else {
23 translations
24 .keys()
25 .next()
26 .cloned()
27 .unwrap_or_else(|| "en".to_string())
28 };
29 StaticTranslatableString {
30 translations,
31 lang: actual_lang,
32 }
33 }
34
35 pub fn from_string(s: &str) -> Self {
37 let mut translations = HashMap::new();
38 translations.insert("en".to_string(), s.to_string());
39 StaticTranslatableString {
40 translations,
41 lang: "en".to_string(),
42 }
43 }
44
45 pub fn empty() -> Self {
47 StaticTranslatableString {
48 translations: HashMap::new(),
49 lang: "en".to_string(),
50 }
51 }
52
53 pub fn get(&self, lang: &str) -> String {
55 self.translations
56 .get(lang)
57 .or_else(|| self.translations.get("en"))
58 .or_else(|| self.translations.values().next())
59 .cloned()
60 .unwrap_or_default()
61 }
62
63 pub fn to_string_default(&self) -> String {
65 self.get(&self.lang)
66 }
67
68 pub fn copy(&self) -> Self {
70 self.clone()
71 }
72
73 pub fn to_json(&self) -> serde_json::Value {
75 serde_json::to_value(&self.translations).unwrap_or(serde_json::Value::Null)
76 }
77}
78
79impl std::fmt::Display for StaticTranslatableString {
80 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81 write!(f, "{}", self.to_string_default())
82 }
83}
84
85impl Serialize for StaticTranslatableString {
86 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
87 where
88 S: serde::Serializer,
89 {
90 self.translations.serialize(serializer)
91 }
92}
93
94impl<'de> Deserialize<'de> for StaticTranslatableString {
95 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
96 where
97 D: Deserializer<'de>,
98 {
99 use serde_json::Value;
100 let value = Value::deserialize(deserializer)?;
101
102 match value {
103 Value::Object(map) => {
104 let translations: HashMap<String, String> = map
105 .into_iter()
106 .filter_map(|(k, v)| v.as_str().map(|s| (k, s.to_string())))
107 .collect();
108
109 let lang = translations
110 .keys()
111 .next()
112 .cloned()
113 .unwrap_or_else(|| "en".to_string());
114
115 Ok(StaticTranslatableString { translations, lang })
116 }
117 Value::String(s) => {
118 let mut translations = HashMap::new();
119 translations.insert("en".to_string(), s);
120 Ok(StaticTranslatableString {
121 translations,
122 lang: "en".to_string(),
123 })
124 }
125 _ => {
126 let mut translations = HashMap::new();
127 translations.insert("en".to_string(), String::new());
128 Ok(StaticTranslatableString {
129 translations,
130 lang: "en".to_string(),
131 })
132 }
133 }
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn test_translatable_string_from_map() {
143 let mut translations = HashMap::new();
144 translations.insert("en".to_string(), "Hello".to_string());
145 translations.insert("de".to_string(), "Hallo".to_string());
146
147 let ts = StaticTranslatableString::from_translations(translations, None);
148 assert_eq!(ts.get("en"), "Hello");
149 assert_eq!(ts.get("de"), "Hallo");
150 }
151
152 #[test]
153 fn test_translatable_string_fallback() {
154 let mut translations = HashMap::new();
155 translations.insert("de".to_string(), "Hallo".to_string());
156
157 let ts = StaticTranslatableString::from_translations(translations, None);
158 assert_eq!(ts.get("en"), "Hallo");
160 }
161}