fluent_template_helper/loader/
static_loader.rs1use std::collections::HashMap;
2
3use fluent_bundle::concurrent::FluentBundle;
4use fluent_bundle::{FluentResource, FluentValue};
5
6pub use unic_langid::{langid, langids, LanguageIdentifier};
7
8#[macro_export]
47macro_rules! static_loader {
48 ($constructor:ident, $location:expr, $fallback:expr) => {
49 $crate::lazy_static::lazy_static! {
50 static ref RESOURCES: std::collections::HashMap<$crate::loader::LanguageIdentifier, Vec<$crate::fluent_bundle::FluentResource>> = $crate::loader::build_resources($location);
51 static ref BUNDLES: std::collections::HashMap<$crate::loader::LanguageIdentifier, $crate::fluent_bundle::concurrent::FluentBundle<&'static $crate::fluent_bundle::FluentResource>> = $crate::loader::build_bundles(&&RESOURCES, None, |_bundle| {});
52 static ref LOCALES: Vec<$crate::loader::LanguageIdentifier> = RESOURCES.keys().cloned().collect();
53 static ref FALLBACKS: std::collections::HashMap<$crate::loader::LanguageIdentifier, Vec<$crate::loader::LanguageIdentifier>> = $crate::loader::build_fallbacks(&*LOCALES);
54 }
55
56 pub fn $constructor() -> $crate::loader::StaticLoader {
57 $crate::loader::StaticLoader::new(&*BUNDLES, &*FALLBACKS, $fallback.parse().expect("fallback language not valid"))
58 }
59 };
60 ($constructor:ident, $location:expr, $fallback:expr, core: $core:expr, customizer: $custom:expr) => {
61 $crate::lazy_static::lazy_static! {
62 static ref CORE_RESOURCE: $crate::fluent_bundle::FluentResource = $crate::loader::load_core_resource($core);
63 static ref RESOURCES: std::collections::HashMap<$crate::loader::LanguageIdentifier, Vec<$crate::fluent_bundle::FluentResource>> = $crate::loader::build_resources($location);
64 static ref BUNDLES: std::collections::HashMap<$crate::loader::LanguageIdentifier, $crate::fluent_bundle::concurrent::FluentBundle<&'static $crate::fluent_bundle::FluentResource>> = $crate::loader::build_bundles(&*RESOURCES, Some(&CORE_RESOURCE), $custom);
65 static ref LOCALES: Vec<$crate::loader::LanguageIdentifier> = RESOURCES.keys().cloned().collect();
66 static ref FALLBACKS: std::collections::HashMap<$crate::loader::LanguageIdentifier, Vec<$crate::loader::LanguageIdentifier>> = $crate::loader::build_fallbacks(&*LOCALES);
67 }
68
69 pub fn $constructor() -> $crate::loader::StaticLoader {
70 $crate::loader::StaticLoader::new(&*BUNDLES, &*FALLBACKS, $fallback.parse().expect("fallback language not valid"))
71 }
72 };
73}
74
75pub struct StaticLoader {
78 bundles: &'static HashMap<LanguageIdentifier, FluentBundle<&'static FluentResource>>,
79 fallbacks: &'static HashMap<LanguageIdentifier, Vec<LanguageIdentifier>>,
80 fallback: LanguageIdentifier,
81}
82
83impl StaticLoader {
84 pub fn new(
88 bundles: &'static HashMap<LanguageIdentifier, FluentBundle<&'static FluentResource>>,
89 fallbacks: &'static HashMap<LanguageIdentifier, Vec<LanguageIdentifier>>,
90 fallback: LanguageIdentifier,
91 ) -> Self {
92 Self {
93 bundles,
94 fallbacks,
95 fallback,
96 }
97 }
98
99 pub fn lookup_single_language(
101 &self,
102 lang: &LanguageIdentifier,
103 text_id: &str,
104 args: Option<&HashMap<&str, FluentValue>>,
105 ) -> Option<String> {
106 if let Some(bundle) = self.bundles.get(lang) {
107 if let Some(message) = bundle.get_message(text_id).and_then(|m| m.value) {
108 let mut errors = Vec::new();
109
110 let value = bundle.format_pattern(&message, dbg!(args), &mut errors);
111
112 if errors.is_empty() {
113 Some(value.into())
114 } else {
115 panic!(
116 "Failed to format a message for locale {} and id {}.\nErrors\n{:?}",
117 lang, text_id, errors
118 )
119 }
120 } else {
121 None
122 }
123 } else {
124 panic!("Unknown language {}", lang)
125 }
126 }
127
128 pub fn lookup_no_default_fallback(
130 &self,
131 lang: &LanguageIdentifier,
132 text_id: &str,
133 args: Option<&HashMap<&str, FluentValue>>,
134 ) -> Option<String> {
135 for l in self.fallbacks.get(lang).expect("language not found") {
136 if let Some(val) = self.lookup_single_language(l, text_id, args) {
137 return Some(val);
138 }
139 }
140
141 None
142 }
143}
144
145impl super::Loader for StaticLoader {
146 fn lookup(
148 &self,
149 lang: &LanguageIdentifier,
150 text_id: &str,
151 args: Option<&HashMap<&str, FluentValue>>,
152 ) -> String {
153 for l in self.fallbacks.get(lang).expect("language not found") {
154 if let Some(val) = self.lookup_single_language(l, text_id, args) {
155 return val;
156 }
157 }
158 if *lang != self.fallback {
159 if let Some(val) = self.lookup_single_language(&self.fallback, text_id, args) {
160 return val;
161 }
162 }
163 format!("Unknown localization {}", text_id)
164 }
165}
166
167