1use serde::{Deserialize, Serialize};
2use std::collections::{HashMap, HashSet};
3use std::ops::Index;
4
5use crate::Language;
6
7#[derive(Serialize, Deserialize, Clone)]
9pub struct LanguageSet {
10 current: String,
11 fallback: String,
12 languages: HashMap<String, Language>,
13}
14
15impl LanguageSet {
16 pub fn new(fallback_language: &str, languages: &[Language]) -> Self {
22 Self {
23 current: fallback_language.to_string(),
24 fallback: fallback_language.to_string(),
25 languages: languages
26 .iter()
27 .map(|l| (l.short_name().to_string(), l.clone()))
28 .collect(),
29 }
30 }
31
32 pub fn all_languages(&self) -> Vec<Language> {
34 self.languages.values().cloned().collect()
35 }
36
37 pub fn fallback_language(&self) -> Option<&Language> {
39 self.languages.get(&self.fallback)
40 }
41
42 pub fn current_language(&self) -> Option<&Language> {
44 self.languages.get(&self.current)
45 }
46
47 pub fn add_language(&mut self, language: Language) {
52 self.languages
53 .insert(language.short_name().to_string(), language);
54 }
55
56 pub fn load_language(
61 &mut self,
62 filename: &str,
63 resources: HashMap<String, Vec<u8>>,
64 ) -> Result<(), String> {
65 match Language::new_from_file(filename, resources) {
66 Ok(lang) => {
67 self.add_language(lang);
68 Ok(())
69 }
70 Err(e) => Err(e),
71 }
72 }
73
74 pub fn verify(&self) -> HashMap<String, Vec<String>> {
77 if let Some(fallback) = self
78 .fallback_language()
79 .and_then(|l| Some(l.strings().keys().cloned().collect::<HashSet<String>>()))
80 {
81 self.languages
82 .iter()
83 .map(|l| {
84 (
85 l.0.clone(),
86 l.1.strings()
87 .keys()
88 .cloned()
89 .collect::<HashSet<String>>()
90 .difference(&fallback)
91 .cloned()
92 .collect(),
93 )
94 })
95 .collect::<HashMap<String, Vec<String>>>()
96 } else {
97 HashMap::default()
98 }
99 }
100
101 pub fn set_fallback_language(&mut self, language: &str) -> bool {
106 if self.languages.contains_key(language) {
107 self.fallback = language.to_string();
108 true
109 } else {
110 false
111 }
112 }
113
114 pub fn set_language(&mut self, language: &str) -> bool {
121 if self.languages.contains_key(language) {
122 self.current = language.to_string();
123 true
124 } else {
125 false
126 }
127 }
128
129 pub fn get_from_lang(&self, language: &str, name: &str) -> Option<&str> {
135 if let Some(lang) = self.languages.get(language) {
136 lang.get(name)
137 } else {
138 None
139 }
140 }
141
142 pub fn get(&self, name: &str) -> Option<&str> {
147 self.current_language()
148 .and_then(|l| l.get(name))
149 .or(self.fallback_language().and_then(|l| l.get(name)))
150 }
151
152 pub fn utf8_resource(&self, name: &str) -> Option<&str> {
154 self.current_language()
155 .and_then(|l| l.utf8_resource(name))
156 .or(self.fallback_language().and_then(|l| l.utf8_resource(name)))
157 }
158
159 pub fn binary_resource(&self, name: &str) -> Option<&[u8]> {
161 self.current_language()
162 .and_then(|l| l.binary_resource(name))
163 .or(self
164 .fallback_language()
165 .and_then(|l| l.binary_resource(name)))
166 }
167}
168
169impl Index<&str> for LanguageSet {
170 type Output = str;
171
172 fn index(&self, name: &str) -> &Self::Output {
173 self.get(name).unwrap_or_default()
174 }
175}
176
177#[cfg(test)]
178mod test_token {
179 use super::*;
180 use crate as embedded_lang;
181 use crate::embedded_language;
182
183 #[test]
184 fn test_current_language() {
185 let mut set = LanguageSet::new(
186 "fr",
187 &[
188 embedded_language!("../examples/en.lang.json"),
189 embedded_language!("../examples/fr.lang.json"),
190 ],
191 );
192
193 assert_eq!(set.current_language().unwrap().short_name(), "fr");
194 set.set_language("en");
195 assert_eq!(set.current_language().unwrap().short_name(), "en");
196 }
197
198 #[test]
199 fn test_fallback_language() {
200 let mut set = LanguageSet::new(
201 "fr",
202 &[
203 embedded_language!("../examples/en.lang.json"),
204 embedded_language!("../examples/fr.lang.json"),
205 ],
206 );
207
208 assert_eq!(set.fallback_language().unwrap().short_name(), "fr");
209 set.set_fallback_language("en");
210 assert_eq!(set.fallback_language().unwrap().short_name(), "en");
211 }
212
213 #[test]
214 fn test_add_language() {
215 let mut set = LanguageSet::new("fr", &[embedded_language!("../examples/fr.lang.json")]);
216
217 set.add_language(embedded_language!("../examples/en.lang.json"));
218
219 assert_eq!(set.set_language("en"), true);
220 }
221
222 #[test]
223 fn test_load_language() {
224 let mut set = LanguageSet::new("fr", &[embedded_language!("../examples/fr.lang.json")]);
225
226 assert_eq!(
227 set.load_language("examples/en.lang.json", HashMap::default())
228 .is_ok(),
229 true
230 );
231 assert_eq!(set.set_language("en"), true);
232 }
233
234 #[test]
235 fn test_set_fallback_language() {
236 let mut set = LanguageSet::new(
237 "fr",
238 &[
239 embedded_language!("../examples/en.lang.json"),
240 embedded_language!("../examples/fr.lang.json"),
241 ],
242 );
243
244 assert_eq!(set.set_fallback_language("en"), true);
245 assert_eq!(set.fallback_language().unwrap().short_name(), "en");
246
247 assert_eq!(set.set_fallback_language("foo"), false);
248 assert_eq!(set.fallback_language().unwrap().short_name(), "en");
249 }
250
251 #[test]
252 fn test_set_language() {
253 let mut set = LanguageSet::new(
254 "fr",
255 &[
256 embedded_language!("../examples/en.lang.json"),
257 embedded_language!("../examples/fr.lang.json"),
258 ],
259 );
260
261 assert_eq!(set.set_language("en"), true);
262 assert_eq!(set.current_language().unwrap().short_name(), "en");
263
264 assert_eq!(set.set_language("foo"), false);
265 assert_eq!(set.current_language().unwrap().short_name(), "en");
266 }
267
268 #[test]
269 fn test_get_from_lang() {
270 let mut set = LanguageSet::new(
271 "fr",
272 &[
273 embedded_language!("../examples/en.lang.json"),
274 embedded_language!("../examples/fr.lang.json"),
275 ],
276 );
277 set.set_fallback_language("en");
278
279 assert_eq!(set.get_from_lang("fr", "tree"), Some("arbre"));
280 assert_eq!(set.get_from_lang("fr", "mustard"), None);
281 assert_eq!(set.get_from_lang("en", "nope"), None);
282 }
283
284 #[test]
285 fn test_get() {
286 let mut set = LanguageSet::new(
287 "fr",
288 &[
289 embedded_language!("../examples/en.lang.json"),
290 embedded_language!("../examples/fr.lang.json"),
291 ],
292 );
293 set.set_fallback_language("en");
294
295 assert_eq!(set.get("tree"), Some("arbre"));
296 assert_eq!(set.get("mustard"), Some("mustard"));
297 assert_eq!(set.get("nope"), None);
298 }
299
300 #[test]
301 fn test_index() {
302 let mut set = LanguageSet::new(
303 "fr",
304 &[
305 embedded_language!("../examples/en.lang.json"),
306 embedded_language!("../examples/fr.lang.json"),
307 ],
308 );
309 set.set_fallback_language("en");
310
311 assert_eq!(set["tree"], "arbre".to_string());
312 assert_eq!(set["mustard"], "mustard".to_string());
313 assert_eq!(set["nope"], "".to_string());
314 }
315}