fluent_templates/loader/
static_loader.rs

1use std::borrow::Cow;
2use std::collections::HashMap;
3
4use crate::{error::LookupError, languages::negotiate_languages, FluentBundle};
5use fluent_bundle::{FluentResource, FluentValue};
6
7pub use unic_langid::LanguageIdentifier;
8
9/// A simple Loader implementation, with statically-loaded fluent data.
10/// Typically created with the [`static_loader!`] macro
11///
12/// [`static_loader!`]: ./macro.static_loader.html
13pub struct StaticLoader {
14    bundles: &'static HashMap<LanguageIdentifier, FluentBundle<&'static FluentResource>>,
15    fallbacks: &'static HashMap<LanguageIdentifier, Vec<LanguageIdentifier>>,
16    fallback: LanguageIdentifier,
17}
18
19impl StaticLoader {
20    /// Construct a new `StaticLoader`.
21    ///
22    /// This is exposed as publicly so that it can be used inside the
23    /// `static_loader!` macro. it's not meant to be called directly.
24    #[doc(hidden)]
25    pub fn new(
26        bundles: &'static HashMap<LanguageIdentifier, FluentBundle<&'static FluentResource>>,
27        fallbacks: &'static HashMap<LanguageIdentifier, Vec<LanguageIdentifier>>,
28        fallback: LanguageIdentifier,
29    ) -> Self {
30        Self {
31            bundles,
32            fallbacks,
33            fallback,
34        }
35    }
36
37    /// Convenience function to look up a string for a single language
38    pub fn lookup_single_language<S: AsRef<str>>(
39        &self,
40        lang: &LanguageIdentifier,
41        text_id: &str,
42        args: Option<&HashMap<S, FluentValue>>,
43    ) -> Result<String, LookupError> {
44        super::shared::lookup_single_language(self.bundles, lang, text_id, args)
45    }
46
47    /// Convenience function to look up a string without falling back to the
48    /// default fallback language
49    pub fn lookup_no_default_fallback<S: AsRef<str>>(
50        &self,
51        lang: &LanguageIdentifier,
52        text_id: &str,
53        args: Option<&HashMap<S, FluentValue>>,
54    ) -> Option<String> {
55        super::shared::lookup_no_default_fallback(self.bundles, self.fallbacks, lang, text_id, args)
56    }
57
58    /// Return the fallback language
59    pub fn fallback(&self) -> &LanguageIdentifier {
60        &self.fallback
61    }
62}
63
64impl super::Loader for StaticLoader {
65    // Traverse the fallback chain,
66    fn lookup_complete(
67        &self,
68        lang: &LanguageIdentifier,
69        text_id: &str,
70        args: Option<&HashMap<Cow<'static, str>, FluentValue>>,
71    ) -> String {
72        for lang in negotiate_languages(&[lang], &self.bundles.keys().collect::<Vec<_>>(), None) {
73            if let Ok(val) = self.lookup_single_language(lang, text_id, args) {
74                return val;
75            }
76        }
77
78        if *lang != self.fallback {
79            if let Ok(val) = self.lookup_single_language(&self.fallback, text_id, args) {
80                return val;
81            }
82        }
83        format!("Unknown localization key: {text_id:?}")
84    }
85
86    // Traverse the fallback chain,
87    fn try_lookup_complete(
88        &self,
89        lang: &LanguageIdentifier,
90        text_id: &str,
91        args: Option<&HashMap<Cow<'static, str>, FluentValue>>,
92    ) -> Option<String> {
93        for lang in negotiate_languages(&[lang], &self.bundles.keys().collect::<Vec<_>>(), None) {
94            if let Ok(val) = self.lookup_single_language(lang, text_id, args) {
95                return Some(val);
96            }
97        }
98
99        if *lang != self.fallback {
100            if let Ok(val) = self.lookup_single_language(&self.fallback, text_id, args) {
101                return Some(val);
102            }
103        }
104        None
105    }
106
107    fn locales(&self) -> Box<dyn Iterator<Item = &LanguageIdentifier> + '_> {
108        Box::new(self.fallbacks.keys())
109    }
110}