mod layer;
mod negotiate;
mod redirect;
mod serve;
use std::sync::OnceLock;
use mf2_catalog::Dir;
use crate::Corpus;
pub use layer::Negotiate;
pub(crate) use layer::RequestLocale;
#[cfg(all(feature = "ssr", any(feature = "leptos", feature = "leptos-0-8")))]
pub(crate) use negotiate::cookie as negotiate_cookie;
pub use negotiate::{
AcceptLanguage, CookieLocale, LocaleSink, LocaleSource, Negotiated, Negotiator, PathPrefix,
QueryParam,
};
pub use redirect::path_prefix_redirect;
pub use serve::{CATALOG_PREFIX, catalog_routes};
static INSTALLED: OnceLock<&'static Corpus> = OnceLock::new();
pub(crate) fn install(corpus: &'static Corpus) {
let _ = INSTALLED.set(corpus);
}
pub(crate) fn locales() -> &'static [(&'static str, Dir)] {
if let Some(corpus) = INSTALLED.get() {
return corpus.locales();
}
#[cfg(all(feature = "ssr", any(feature = "leptos", feature = "leptos-0-8")))]
{
crate::leptos::locales()
}
#[cfg(not(all(feature = "ssr", any(feature = "leptos", feature = "leptos-0-8"))))]
{
&[]
}
}
pub(crate) fn source_locale() -> &'static str {
if let Some(corpus) = INSTALLED.get() {
return corpus.source_locale();
}
#[cfg(all(feature = "ssr", any(feature = "leptos", feature = "leptos-0-8")))]
{
crate::leptos::source_locale()
}
#[cfg(not(all(feature = "ssr", any(feature = "leptos", feature = "leptos-0-8"))))]
{
""
}
}
pub(crate) fn catalog_name(tag: &str) -> Option<&'static str> {
if let Some(corpus) = INSTALLED.get() {
return corpus
.catalogs()
.iter()
.find(|file| file.tag() == tag && file.bytes().is_some())
.map(crate::CatalogFile::file_name);
}
#[cfg(all(feature = "ssr", any(feature = "leptos", feature = "leptos-0-8")))]
{
crate::leptos::catalog_name(tag)
}
#[cfg(not(all(feature = "ssr", any(feature = "leptos", feature = "leptos-0-8"))))]
{
None
}
}
pub(crate) fn catalog_file(name: &str) -> Option<(&'static str, &'static [u8])> {
if let Some(corpus) = INSTALLED.get() {
return corpus
.catalogs()
.iter()
.find(|file| file.file_name() == name)
.and_then(|file| Some((file.file_name(), file.bytes()?)));
}
#[cfg(all(feature = "ssr", any(feature = "leptos", feature = "leptos-0-8")))]
{
crate::leptos::catalog_entries()
.iter()
.find(|entry| entry.file == name)
.map(|entry| (entry.file, entry.bytes))
}
#[cfg(not(all(feature = "ssr", any(feature = "leptos", feature = "leptos-0-8"))))]
{
None
}
}
pub(crate) fn best_locale<'a>(
candidates: impl IntoIterator<Item = &'a str>,
locales: &[(&'static str, Dir)],
) -> Option<(&'static str, Dir)> {
let at = crate::LanguageMatching::cldr().best_match(candidates, locales)?;
locales.get(at).copied()
}
pub(crate) fn locale_index(
parts: &::http::request::Parts,
locales: &'static [(&'static str, Dir)],
source: &'static str,
) -> Option<usize> {
let tag = match parts.extensions.get::<RequestLocale>() {
Some(request) => request.read().tag,
None => {
Negotiator::over(locales, source)
.defaults()
.negotiate(parts)
.tag
}
};
locales.iter().position(|(t, _)| *t == tag)
}
#[cfg(all(feature = "ssr", any(feature = "leptos", feature = "leptos-0-8")))]
#[must_use]
pub fn negotiated() -> Option<Negotiated> {
crate::line::reactive_graph::owner::with_context::<::http::request::Parts, _>(|parts| {
parts
.extensions
.get::<RequestLocale>()
.map(|request| request.read().clone())
})
.flatten()
}