#[cfg(feature = "i18n")]
mod fluent_impl {
use i18n_embed::fluent::{FluentLanguageLoader, fluent_language_loader};
use i18n_embed::{DesktopLanguageRequester, LanguageLoader};
use rust_embed::RustEmbed;
use std::sync::LazyLock;
#[derive(RustEmbed)]
#[folder = "i18n/"]
struct Localizations;
pub static LOADER: LazyLock<FluentLanguageLoader> = LazyLock::new(|| {
let loader = fluent_language_loader!();
loader
.load_fallback_language(&Localizations)
.expect("fallback language must be present");
loader.set_use_isolating(false);
loader
});
pub fn init() {
let requested = DesktopLanguageRequester::requested_languages();
let _ = i18n_embed::select(&*LOADER, &Localizations, &requested);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_catalog_loads() {
let loader = fluent_language_loader!();
let langs = loader
.available_languages(&Localizations)
.expect("list languages");
assert!(
langs.len() >= 13,
"expected ≥13 languages, got {}",
langs.len()
);
for lang in langs {
loader
.load_languages(&Localizations, std::slice::from_ref(&lang))
.unwrap_or_else(|e| panic!("catalog {lang} failed to load: {e}"));
}
}
}
}
#[cfg(feature = "i18n")]
pub use fluent_impl::{LOADER, init};
#[cfg(not(feature = "i18n"))]
mod fallback_impl {
include!(concat!(env!("OUT_DIR"), "/i18n_fallback.rs"));
pub fn init() {}
}
#[cfg(not(feature = "i18n"))]
pub use fallback_impl::{fallback, init};
#[cfg(feature = "i18n")]
#[macro_export]
macro_rules! tr {
($id:literal) => {
$crate::i18n::LOADER.get($id)
};
($id:literal, $($name:ident = $value:expr),+ $(,)?) => {{
let mut args = ::std::collections::HashMap::new();
$( args.insert(::std::stringify!($name), $value); )+
$crate::i18n::LOADER.get_args($id, args)
}};
}
#[cfg(not(feature = "i18n"))]
#[macro_export]
macro_rules! tr {
($id:literal) => {
$crate::i18n::fallback($id, &[])
};
($id:literal, $($name:ident = $value:expr),+ $(,)?) => {
$crate::i18n::fallback(
$id,
&[ $( (::std::stringify!($name), ::std::format!("{}", $value)) ),+ ],
)
};
}