1use crate::{I18nEmbedError, Localizer};
2use std::{collections::HashMap, sync::Weak};
3
4pub trait LanguageRequester<'a> {
7 fn add_listener(&mut self, listener: Weak<dyn Localizer>);
19 fn add_listener_ref(&mut self, listener: &'a dyn Localizer);
30 fn poll(&mut self) -> Result<(), I18nEmbedError>;
40 fn set_language_override(
43 &mut self,
44 language_override: Option<unic_langid::LanguageIdentifier>,
45 ) -> Result<(), I18nEmbedError>;
46 fn requested_languages(&self) -> Vec<unic_langid::LanguageIdentifier>;
48 fn available_languages(&self) -> Result<Vec<unic_langid::LanguageIdentifier>, I18nEmbedError>;
51 fn current_languages(&self) -> HashMap<String, unic_langid::LanguageIdentifier>;
54}
55
56pub struct LanguageRequesterImpl<'a> {
59 arc_listeners: Vec<Weak<dyn Localizer>>,
60 ref_listeners: Vec<&'a dyn Localizer>,
61 language_override: Option<unic_langid::LanguageIdentifier>,
62}
63
64impl<'a> LanguageRequesterImpl<'a> {
65 pub fn new() -> LanguageRequesterImpl<'a> {
67 LanguageRequesterImpl {
68 arc_listeners: Vec::new(),
69 ref_listeners: Vec::new(),
70 language_override: None,
71 }
72 }
73
74 pub fn set_language_override(
78 &mut self,
79 language_override: Option<unic_langid::LanguageIdentifier>,
80 ) -> Result<(), I18nEmbedError> {
81 self.language_override = language_override;
82 Ok(())
83 }
84
85 pub fn add_listener(&mut self, listener: Weak<dyn Localizer>) {
88 self.arc_listeners.push(listener);
89 }
90
91 pub fn add_listener_ref(&mut self, listener: &'a dyn Localizer) {
94 self.ref_listeners.push(listener);
95 }
96
97 pub fn poll_without_override(
101 &mut self,
102 requested_languages: Vec<unic_langid::LanguageIdentifier>,
103 ) -> Result<(), I18nEmbedError> {
104 let mut errors: Vec<I18nEmbedError> = Vec::new();
105
106 self.arc_listeners
107 .retain(|listener| match listener.upgrade() {
108 Some(arc_listener) => {
109 if let Err(error) = arc_listener.select(&requested_languages) {
110 errors.push(error);
111 }
112
113 true
114 }
115 None => false,
116 });
117
118 for boxed_listener in &self.ref_listeners {
119 if let Err(error) = boxed_listener.select(&requested_languages) {
120 errors.push(error);
121 }
122 }
123
124 if errors.is_empty() {
125 Ok(())
126 } else if errors.len() == 1 {
127 Err(errors.into_iter().next().unwrap())
128 } else {
129 Err(I18nEmbedError::Multiple(errors))
130 }
131 }
132
133 pub fn poll(
139 &mut self,
140 requested_languages: Vec<unic_langid::LanguageIdentifier>,
141 ) -> Result<(), I18nEmbedError> {
142 let languages = match &self.language_override {
143 Some(language) => {
144 log::debug!("Using language override: {}", language);
145 vec![language.clone()]
146 }
147 None => requested_languages,
148 };
149
150 self.poll_without_override(languages)
151 }
152
153 pub fn available_languages(
156 &self,
157 ) -> Result<Vec<unic_langid::LanguageIdentifier>, I18nEmbedError> {
158 let mut available_languages = std::collections::HashSet::new();
159
160 for weak_arc_listener in &self.arc_listeners {
161 if let Some(arc_listener) = weak_arc_listener.upgrade() {
162 arc_listener
163 .available_languages()?
164 .iter()
165 .for_each(|language| {
166 available_languages.insert(language.clone());
167 })
168 }
169 }
170
171 for boxed_listener in &self.ref_listeners {
172 boxed_listener
173 .available_languages()?
174 .iter()
175 .for_each(|language| {
176 available_languages.insert(language.clone());
177 })
178 }
179
180 Ok(available_languages.into_iter().collect())
181 }
182
183 pub fn current_languages(&self) -> HashMap<String, unic_langid::LanguageIdentifier> {
186 let mut current_languages = HashMap::new();
187 for weak_listener in &self.arc_listeners {
188 if let Some(localizer) = weak_listener.upgrade() {
189 let loader = localizer.language_loader();
190 current_languages.insert(loader.domain().to_string(), loader.current_language());
191 }
192 }
193
194 current_languages
195 }
196}
197
198impl Default for LanguageRequesterImpl<'_> {
199 fn default() -> Self {
200 LanguageRequesterImpl::new()
201 }
202}
203
204impl std::fmt::Debug for LanguageRequesterImpl<'_> {
205 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
206 let listeners_debug: String = self
207 .arc_listeners
208 .iter()
209 .map(|l| match l.upgrade() {
210 Some(l) => format!("{l:p}"),
211 None => "None".to_string(),
212 })
213 .collect::<Vec<String>>()
214 .join(", ");
215 write!(
216 f,
217 "LanguageRequesterImpl(listeners: {}, language_override: {:?})",
218 listeners_debug, self.language_override,
219 )
220 }
221}
222
223#[cfg(feature = "desktop-requester")]
230#[derive(Debug)]
231pub struct DesktopLanguageRequester<'a> {
232 implementation: LanguageRequesterImpl<'a>,
233}
234
235#[cfg(feature = "desktop-requester")]
236impl<'a> LanguageRequester<'a> for DesktopLanguageRequester<'a> {
237 fn requested_languages(&self) -> Vec<unic_langid::LanguageIdentifier> {
238 DesktopLanguageRequester::requested_languages()
239 }
240
241 fn add_listener(&mut self, listener: Weak<dyn Localizer>) {
242 self.implementation.add_listener(listener)
243 }
244
245 fn add_listener_ref(&mut self, listener: &'a dyn Localizer) {
246 self.implementation.add_listener_ref(listener)
247 }
248
249 fn set_language_override(
250 &mut self,
251 language_override: Option<unic_langid::LanguageIdentifier>,
252 ) -> Result<(), I18nEmbedError> {
253 self.implementation.set_language_override(language_override)
254 }
255
256 fn poll(&mut self) -> Result<(), I18nEmbedError> {
257 self.implementation.poll(self.requested_languages())
258 }
259
260 fn available_languages(&self) -> Result<Vec<unic_langid::LanguageIdentifier>, I18nEmbedError> {
261 self.implementation.available_languages()
262 }
263
264 fn current_languages(&self) -> HashMap<String, unic_langid::LanguageIdentifier> {
265 self.implementation.current_languages()
266 }
267}
268
269#[cfg(feature = "desktop-requester")]
270impl Default for DesktopLanguageRequester<'_> {
271 fn default() -> Self {
272 DesktopLanguageRequester::new()
273 }
274}
275
276#[cfg(feature = "desktop-requester")]
277impl DesktopLanguageRequester<'_> {
278 pub fn new() -> Self {
280 DesktopLanguageRequester {
281 implementation: LanguageRequesterImpl::new(),
282 }
283 }
284
285 pub fn requested_languages() -> Vec<unic_langid::LanguageIdentifier> {
289 let ids: Vec<unic_langid::LanguageIdentifier> = sys_locale::get_locales()
290 .filter_map(|tag| match tag.parse() {
291 Ok(tag) => Some(tag),
292 Err(err) => {
293 log::error!("Unable to parse your locale: {:?}", err);
294 None
295 }
296 })
297 .collect();
298
299 log::info!("Current Locale: {:?}", ids);
300
301 ids
302 }
303}
304
305#[cfg(feature = "web-sys-requester")]
309#[derive(Debug)]
310pub struct WebLanguageRequester<'a> {
311 implementation: LanguageRequesterImpl<'a>,
312}
313
314#[cfg(feature = "web-sys-requester")]
315impl WebLanguageRequester<'_> {
316 pub fn new() -> Self {
318 WebLanguageRequester {
319 implementation: LanguageRequesterImpl::new(),
320 }
321 }
322
323 pub fn requested_languages() -> Vec<unic_langid::LanguageIdentifier> {
325 use fluent_langneg::convert_vec_str_to_langids_lossy;
326 let window = web_sys::window().expect("no global `window` exists");
327 let navigator = window.navigator();
328 let languages = navigator.languages();
329
330 let requested_languages =
331 convert_vec_str_to_langids_lossy(languages.iter().map(|js_value| {
332 js_value
333 .as_string()
334 .expect("language value should be a string.")
335 }));
336
337 requested_languages
338 }
339}
340
341#[cfg(feature = "web-sys-requester")]
342impl Default for WebLanguageRequester<'_> {
343 fn default() -> Self {
344 WebLanguageRequester::new()
345 }
346}
347
348#[cfg(feature = "web-sys-requester")]
349impl<'a> LanguageRequester<'a> for WebLanguageRequester<'a> {
350 fn requested_languages(&self) -> Vec<unic_langid::LanguageIdentifier> {
351 Self::requested_languages()
352 }
353
354 fn add_listener(&mut self, listener: Weak<dyn Localizer>) {
355 self.implementation.add_listener(listener)
356 }
357
358 fn add_listener_ref(&mut self, listener: &'a dyn Localizer) {
359 self.implementation.add_listener_ref(listener)
360 }
361
362 fn poll(&mut self) -> Result<(), I18nEmbedError> {
363 self.implementation.poll(self.requested_languages())
364 }
365
366 fn set_language_override(
367 &mut self,
368 language_override: Option<unic_langid::LanguageIdentifier>,
369 ) -> Result<(), I18nEmbedError> {
370 self.implementation.set_language_override(language_override)
371 }
372
373 fn available_languages(&self) -> Result<Vec<unic_langid::LanguageIdentifier>, I18nEmbedError> {
374 self.implementation.available_languages()
375 }
376
377 fn current_languages(&self) -> HashMap<String, unic_langid::LanguageIdentifier> {
378 self.implementation.current_languages()
379 }
380}