use topcoat::{
context::{Cx, try_context},
l10n::{Locale, accept_language, locale, negotiate, try_locale},
};
use super::Catalog;
use crate::cookie::request_cookie;
pub(crate) static ENGLISH: Locale = locale!("en");
const MAX_ACCEPTED: usize = 16;
pub(crate) fn entered(cx: &Cx, catalog: &Catalog) -> Cx {
let offered = catalog.locales();
if let Some(chosen) = chosen(cx, offered) {
return cx.with_many((chosen, Chosen));
}
let locale = match offered {
[only] => only,
_ => {
negotiate(accept_language(cx).iter().take(MAX_ACCEPTED), offered).unwrap_or(&offered[0])
}
};
cx.with(locale.clone())
}
pub(crate) const LOCALE_COOKIE: &str = "tablo_locale";
#[derive(Clone, Copy)]
pub(crate) struct Chosen;
pub(crate) fn chose_locale(cx: &Cx) -> bool {
try_context::<Chosen>(cx).is_some()
}
fn chosen(cx: &Cx, offered: &[Locale]) -> Option<Locale> {
matched(&request_cookie(cx, LOCALE_COOKIE)?, offered)
}
fn matched(tag: &str, offered: &[Locale]) -> Option<Locale> {
let picked: Locale = tag.parse().ok()?;
negotiate([&picked], offered).cloned()
}
pub(crate) fn offered(cx: &Cx) -> &[Locale] {
catalog(cx).map_or(&[], Catalog::locales)
}
pub(crate) fn offered_match(cx: &Cx, tag: &str) -> Option<Locale> {
matched(tag, offered(cx))
}
pub(crate) fn addressed_to(cx: &Cx, locale: Option<&Locale>) -> Cx {
let matched = locale
.zip(catalog(cx))
.and_then(|(locale, catalog)| negotiate([locale], catalog.locales()));
match matched {
Some(matched) => cx.with(matched.clone()),
None => cx.clone(),
}
}
pub(crate) fn catalog_and_locale(cx: &Cx) -> (&Catalog, &Locale) {
match catalog(cx) {
Some(catalog) => (catalog, try_locale(cx).unwrap_or(&catalog.locales()[0])),
None => (Catalog::english(), &ENGLISH),
}
}
fn catalog(cx: &Cx) -> Option<&Catalog> {
(try_context::<CatalogSource>(cx)?.0)(cx)
}
pub(crate) struct CatalogSource(pub(crate) for<'a> fn(&'a Cx) -> Option<&'a Catalog>);