use i18n_embed::{
fluent::{fluent_language_loader, FluentLanguageLoader},
LanguageLoader,
};
use rust_embed::RustEmbed;
use std::sync::LazyLock;
use unic_langid::LanguageIdentifier;
#[derive(RustEmbed)]
#[folder = "locales/"]
pub struct Localizations;
pub static LANGUAGE_LOADER: LazyLock<FluentLanguageLoader> = LazyLock::new(|| {
let loader: FluentLanguageLoader = fluent_language_loader!();
loader
.load_languages(&Localizations, &[loader.fallback_language().clone()])
.expect("failed to load fallback language");
loader.set_use_isolating(false);
loader
});
pub fn set_language(lang: &LanguageIdentifier) {
let _ = i18n_embed::select(
&*LANGUAGE_LOADER,
&Localizations,
std::slice::from_ref(lang),
);
LANGUAGE_LOADER.set_use_isolating(false);
}
pub fn set_locale(tag: &str) {
if let Ok(lang) = tag.parse::<LanguageIdentifier>() {
set_language(&lang);
}
}
pub fn available_languages() -> Vec<LanguageIdentifier> {
let mut v = LANGUAGE_LOADER
.available_languages(&Localizations)
.unwrap_or_default();
v.sort_by_key(|l| l.to_string());
v
}
pub fn current_language() -> LanguageIdentifier {
LANGUAGE_LOADER
.current_languages()
.into_iter()
.next()
.unwrap_or_else(|| "en".parse().unwrap())
}
pub fn language_endonym(lang: &LanguageIdentifier) -> String {
match lang.language.as_str() {
"en" => "English",
"fr" => "Français",
"de" => "Deutsch",
"es" => "Español",
"it" => "Italiano",
"pt" => "Português",
"nl" => "Nederlands",
"ja" => "日本語",
_ => return lang.to_string(),
}
.to_owned()
}
#[cfg(not(target_arch = "wasm32"))]
pub fn detect_locale() -> LanguageIdentifier {
sys_locale::get_locale()
.and_then(|l| l.parse().ok())
.unwrap_or_else(|| "fr".parse().unwrap())
}
#[cfg(test)]
mod tests {
use super::*;
use i18n_embed_fl::fl;
#[test]
fn locales_load_and_negotiate() {
assert_eq!(available_languages().len(), 8);
let de: LanguageIdentifier = "de".parse().unwrap();
set_language(&de);
assert_eq!(fl!(LANGUAGE_LOADER, "meta-author"), "Autor");
let de_de: LanguageIdentifier = "de-DE".parse().unwrap();
set_language(&de_de);
assert_eq!(fl!(LANGUAGE_LOADER, "meta-author"), "Autor");
let ja: LanguageIdentifier = "ja".parse().unwrap();
set_language(&ja);
assert_eq!(fl!(LANGUAGE_LOADER, "meta-author"), "作者");
}
}