leptos_use/
use_locale.rs

1use crate::{use_locales_with_options, UseLocalesOptions};
2use leptos::{logging::warn, prelude::*};
3use unic_langid::LanguageIdentifier;
4
5/// Reactive locale matching.
6///
7/// Returns the first matching locale given by [`fn@crate::use_locales`] that is also found in
8/// the `supported` list. In case there is no match, then the first locale in `supported` will be
9/// returned.
10///
11/// > If `supported` is empty, this function will panic!
12///
13/// Matching is done by using the [`fn@unic_langid::LanguageIdentifier::matches`] method.
14///
15/// ## Demo
16///
17/// [Link to Demo](https://github.com/Synphonyte/leptos-use/tree/main/examples/use_locale)
18///
19/// ## Usage
20///
21/// ```
22/// # use leptos::*;
23/// # use leptos_use::use_locale;
24/// use unic_langid::langid_slice;
25/// #
26/// # #[component]
27/// # fn Demo() -> impl IntoView {
28/// let locale = use_locale(langid_slice!["en", "de", "fr"]);
29/// #
30/// # view! { }
31/// # }
32/// ```
33///
34/// ## Server-Side Rendering
35///
36/// See [`fn@crate::use_locales`]
37pub fn use_locale<S>(supported: S) -> Signal<LanguageIdentifier>
38where
39    S: IntoIterator,
40    S::Item: AsRef<LanguageIdentifier>,
41{
42    use_locale_with_options(supported, UseLocaleOptions::default())
43}
44
45/// Version of [`fn@crate::use_locale`] that takes a `UseLocaleOptions`. See [`fn@crate::use_locale`] for how to use.
46pub fn use_locale_with_options<S>(
47    supported: S,
48    options: UseLocaleOptions,
49) -> Signal<LanguageIdentifier>
50where
51    S: IntoIterator,
52    S::Item: AsRef<LanguageIdentifier>,
53{
54    let client_locales = use_locales_with_options(options);
55
56    let supported = supported
57        .into_iter()
58        .map(|l| l.as_ref().clone())
59        .collect::<Vec<_>>();
60
61    const EMPTY_ERR_MSG: &str = "Empty supported list. You have to provide at least one locale in the `supported` parameter";
62
63    assert!(!supported.is_empty(), "{}", EMPTY_ERR_MSG);
64
65    Signal::derive(move || {
66        client_locales.with(|client_locales| {
67            let mut supported_iter = supported.iter().peekable();
68
69            // Checked it's not empty above.
70            let first_supported = *supported_iter.peek().unwrap();
71
72            for client_locale in client_locales {
73                let supported_iter = supported_iter.clone();
74
75                for s in supported_iter {
76                    let client_locale = client_locale.parse::<LanguageIdentifier>();
77
78                    if let Ok(client_locale) = client_locale {
79                        if client_locale.matches(s, true, true) {
80                            return (*s).clone();
81                        }
82                    } else {
83                        warn!("Received an invalid LanguageIdentifier")
84                    }
85                }
86            }
87
88            (*first_supported).clone()
89        })
90    })
91}
92
93pub type UseLocaleOptions = UseLocalesOptions;