use mf2_catalog::Dir;
macro_rules! forward {
($d:tt $name:ident, $($cfg:tt)*) => {
#[cfg($($cfg)*)]
#[doc(hidden)]
#[macro_export]
macro_rules! $name {
($d($d t:tt)*) => { $d($d t)* };
}
#[cfg(not($($cfg)*))]
#[doc(hidden)]
#[macro_export]
macro_rules! $name {
($d($d t:tt)*) => {};
}
};
}
forward!($ __if_host_std, feature = "host-std");
forward!($ __if_native, feature = "native");
forward!($ __if_ssr, all(feature = "ssr", any(feature = "leptos", feature = "leptos-0-8")));
forward!($ __if_client, all(any(feature = "hydrate", feature = "csr"), any(feature = "leptos", feature = "leptos-0-8")));
forward!($ __if_csr, all(feature = "csr", any(feature = "leptos", feature = "leptos-0-8")));
forward!($ __if_leptos, all(any(feature = "ssr", feature = "hydrate", feature = "csr"), any(feature = "leptos", feature = "leptos-0-8")));
forward!($ __if_mode, any(feature = "native", all(any(feature = "ssr", feature = "hydrate", feature = "csr"), any(feature = "leptos", feature = "leptos-0-8"))));
forward!($ __if_clap, feature = "clap");
forward!($ __if_axum, feature = "axum");
forward!($ __if_format, any(feature = "native", feature = "axum", all(feature = "ssr", any(feature = "leptos", feature = "leptos-0-8"))));
forward!($ __if_install, any(feature = "native", feature = "axum", all(any(feature = "ssr", feature = "hydrate", feature = "csr"), any(feature = "leptos", feature = "leptos-0-8"))));
forward!($ __if_ratatui, feature = "ratatui");
#[cfg(feature = "host-std")]
#[doc(hidden)]
#[macro_export]
macro_rules! __use_host {
($($dates:ident)?) => {
pub use $crate::host_std::HOST;
};
}
#[cfg(all(
not(feature = "host-std"),
feature = "host-web",
feature = "datetime-intl"
))]
#[doc(hidden)]
#[macro_export]
macro_rules! __use_host {
() => {
pub use $crate::host_web::HOST;
};
(dates) => {
pub use $crate::host_web::INTL_HOST as HOST;
};
}
#[cfg(all(
not(feature = "host-std"),
feature = "host-web",
not(feature = "datetime-intl"),
feature = "datetime-icu"
))]
#[doc(hidden)]
#[macro_export]
macro_rules! __use_host {
() => {
pub use $crate::host_web::HOST;
};
(dates) => {
pub use $crate::host_web::ZONES_HOST as HOST;
};
}
#[cfg(all(
not(feature = "host-std"),
feature = "host-web",
not(feature = "datetime-intl"),
not(feature = "datetime-icu")
))]
#[doc(hidden)]
#[macro_export]
macro_rules! __use_host {
($($dates:ident)?) => {
pub use $crate::host_web::HOST;
};
}
#[cfg(not(any(feature = "host-std", feature = "host-web")))]
#[doc(hidden)]
#[macro_export]
macro_rules! __use_host {
($($dates:ident)?) => {};
}
#[cfg(any(feature = "host-std", not(feature = "hydrate")))]
#[doc(hidden)]
#[macro_export]
macro_rules! __best_locale {
($matching:ident, $locales:ident, $tag:expr) => {
$matching.best_match([$tag], $locales)
};
}
#[cfg(all(feature = "hydrate", not(feature = "host-std")))]
#[doc(hidden)]
#[macro_export]
macro_rules! __best_locale {
($matching:ident, $locales:ident, $tag:expr) => {
$crate::__generated::exact_locale($locales, $tag)
};
}
#[must_use]
pub fn exact_locale(locales: &[(&str, Dir)], tag: &str) -> Option<usize> {
locales
.iter()
.position(|(t, _)| t.eq_ignore_ascii_case(tag))
}
#[cfg(any(
feature = "native",
all(
any(feature = "ssr", feature = "hydrate", feature = "csr"),
any(feature = "leptos", feature = "leptos-0-8")
)
))]
fn position(locales: &[(&str, Dir)], tag: &str) -> Option<usize> {
locales.iter().position(|(t, _)| *t == tag)
}
#[cfg(all(
any(feature = "ssr", feature = "hydrate", feature = "csr"),
any(feature = "leptos", feature = "leptos-0-8")
))]
#[must_use]
pub fn current_locale(locales: &[(&str, Dir)]) -> Option<usize> {
#[cfg(not(feature = "ssr"))]
crate::leptos::track_locale();
if let Some(catalog) = crate::leptos::active() {
return position(locales, catalog.locale());
}
#[cfg(feature = "native")]
if let Some(tag) = crate::native::store::try_locale() {
return position(locales, tag);
}
None
}
#[cfg(all(
feature = "native",
not(all(
any(feature = "ssr", feature = "hydrate", feature = "csr"),
any(feature = "leptos", feature = "leptos-0-8")
))
))]
#[must_use]
pub fn current_locale(locales: &[(&str, Dir)]) -> Option<usize> {
position(locales, crate::native::locale())
}
#[cfg(any(
feature = "native",
all(
any(feature = "ssr", feature = "hydrate", feature = "csr"),
any(feature = "leptos", feature = "leptos-0-8")
)
))]
pub fn set_locale(tag: &'static str) {
#[cfg(feature = "native")]
let _ = crate::native::set_locale(tag);
#[cfg(all(
any(feature = "hydrate", feature = "csr"),
any(feature = "leptos", feature = "leptos-0-8")
))]
wasm_bindgen_futures::spawn_local(async move {
if let Err(error) = crate::leptos::set_locale(tag).await {
crate::leptos::components::switch_failed(&error);
}
});
let _ = tag;
}
#[cfg(all(
any(feature = "ssr", feature = "hydrate", feature = "csr"),
any(feature = "leptos", feature = "leptos-0-8")
))]
pub fn preload_locale(tag: &'static str) {
#[cfg(any(feature = "hydrate", feature = "csr"))]
wasm_bindgen_futures::spawn_local(async move {
if crate::leptos::preload_locale(tag).await.is_err() {
web_sys::console::error_1(&wasm_bindgen::JsValue::from_str(
"mf2: the locale could not be preloaded",
));
}
});
let _ = tag;
}
#[cfg(all(feature = "ssr", any(feature = "leptos", feature = "leptos-0-8")))]
pub fn install_server(
setup: crate::leptos::Setup,
catalogs: &'static [(&'static str, &'static str, &'static [u8])],
) {
crate::leptos::install(setup);
if let Err(error) = crate::leptos::install_catalogs(catalogs) {
refused(&error);
}
}
#[cfg(all(feature = "ssr", any(feature = "leptos", feature = "leptos-0-8")))]
#[cold]
#[inline(never)]
#[allow(
clippy::panic,
reason = "server only: install() returns nothing, and an embedded catalog that does not load means a corrupt executable (plans/19 §10)"
)]
fn refused(error: &crate::leptos::LoadError) -> ! {
panic!("mf2: install(): {error}")
}
#[cfg(feature = "native")]
#[must_use]
pub fn format_in(
corpus: &'static crate::Corpus,
locale: &str,
message: &impl crate::Message,
) -> alloc::string::String {
crate::native::store::format_in(corpus, locale, message)
}
#[cfg(all(
not(feature = "native"),
any(
feature = "axum",
all(feature = "ssr", any(feature = "leptos", feature = "leptos-0-8"))
)
))]
#[must_use]
pub fn format_in(
corpus: &'static crate::Corpus,
locale: &str,
message: &impl crate::Message,
) -> alloc::string::String {
server::format_in(corpus, locale, message)
}
#[cfg(all(
not(feature = "native"),
any(
feature = "axum",
all(feature = "ssr", any(feature = "leptos", feature = "leptos-0-8"))
)
))]
mod server {
use alloc::string::String;
use alloc::vec::Vec;
use std::sync::OnceLock;
use mf2_catalog::{Catalog, CatalogError};
use mf2_runtime::{FormatContext, Formatter, NoErrors};
use crate::{Corpus, Message};
struct Loaded {
corpus: &'static Corpus,
catalogs: Vec<Option<Catalog>>,
}
static LOADED: OnceLock<Loaded> = OnceLock::new();
fn load(corpus: &'static Corpus) -> Vec<Option<Catalog>> {
corpus
.catalogs()
.iter()
.map(|file| {
let bytes = file.bytes()?;
match Catalog::new(Vec::from(bytes), corpus.manifest_hash()) {
Ok(catalog) => Some(catalog),
Err(error) => refused(error),
}
})
.collect()
}
pub(super) fn format_in(
corpus: &'static Corpus,
locale: &str,
message: &impl Message,
) -> String {
let loaded = LOADED.get_or_init(|| Loaded {
corpus,
catalogs: load(corpus),
});
let other;
let catalogs = if core::ptr::eq(loaded.corpus, corpus) {
&loaded.catalogs
} else {
other = load(corpus);
&other
};
let at = |tag: &str| {
let index = corpus
.catalogs()
.iter()
.position(|file| file.tag() == tag)?;
catalogs.get(index)?.as_ref()
};
let mut out = String::new();
if let Some(catalog) = at(locale).or_else(|| at(corpus.source_locale())) {
let cx = FormatContext::new(&mf2_host_std::HOST);
let f = Formatter::new(catalog, corpus.registry(), &cx);
message.write(&f, &mut out, &mut NoErrors);
}
out
}
#[cold]
#[inline(never)]
#[allow(
clippy::panic,
reason = "server only: Locale::format returns text, and an embedded catalog that does not load means a corrupt executable"
)]
fn refused(error: CatalogError) -> ! {
panic!("mf2: Locale::format(): {error}")
}
}
#[cfg(feature = "axum")]
pub fn install_axum(corpus: &'static crate::Corpus) {
crate::axum::install(corpus);
}
#[cfg(feature = "axum")]
pub mod axum {
pub use ::axum::extract::FromRequestParts;
pub use ::http::request::Parts;
use mf2_catalog::Dir;
#[must_use]
pub fn locale_index(
parts: &Parts,
locales: &'static [(&'static str, Dir)],
source: &'static str,
) -> Option<usize> {
crate::axum::locale_index(parts, locales, source)
}
}
#[cfg(feature = "native")]
pub fn with_locale_in<R>(
corpus: &'static crate::Corpus,
locale: &str,
body: impl FnOnce() -> R,
) -> R {
crate::native::store::with_locale_in(corpus, locale, body)
}
#[cfg(any(
feature = "native",
feature = "axum",
all(feature = "ssr", any(feature = "leptos", feature = "leptos-0-8"))
))]
pub use alloc::string::String;
#[cfg(feature = "native")]
pub use std::path::Path;
#[cfg(feature = "clap")]
pub mod clap {
use alloc::boxed::Box;
use std::ffi::OsStr;
pub use ::clap::builder::ValueParserFactory;
use ::clap::builder::{PossibleValue, TypedValueParser};
use mf2_catalog::Dir;
use crate::UnknownLocale;
pub struct LocaleParser<L> {
locales: &'static [(&'static str, Dir)],
parse: fn(&str) -> Result<L, UnknownLocale>,
}
impl<L> LocaleParser<L> {
#[must_use]
pub const fn new(
locales: &'static [(&'static str, Dir)],
parse: fn(&str) -> Result<L, UnknownLocale>,
) -> Self {
LocaleParser { locales, parse }
}
}
impl<L> core::fmt::Debug for LocaleParser<L> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("LocaleParser")
.field("locales", &self.locales)
.finish_non_exhaustive()
}
}
impl<L> Clone for LocaleParser<L> {
fn clone(&self) -> Self {
LocaleParser {
locales: self.locales,
parse: self.parse,
}
}
}
impl<L: Clone + Send + Sync + 'static> TypedValueParser for LocaleParser<L> {
type Value = L;
fn parse_ref(
&self,
cmd: &::clap::Command,
arg: Option<&::clap::Arg>,
value: &OsStr,
) -> Result<L, ::clap::Error> {
self.parse.parse_ref(cmd, arg, value)
}
fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> {
Some(Box::new(
self.locales.iter().map(|(tag, _)| PossibleValue::new(*tag)),
))
}
}
}