use crate::{domain_from_module, I18nAssets, I18nEmbedError, LanguageLoader};
pub use i18n_embed_impl::gettext_language_loader;
use gettext as gettext_system;
use parking_lot::RwLock;
use unic_langid::LanguageIdentifier;
#[derive(Debug)]
pub struct GettextLanguageLoader {
current_language: RwLock<LanguageIdentifier>,
module: &'static str,
fallback_language: LanguageIdentifier,
}
impl GettextLanguageLoader {
pub fn new(module: &'static str, fallback_language: unic_langid::LanguageIdentifier) -> Self {
Self {
current_language: RwLock::new(fallback_language.clone()),
module,
fallback_language,
}
}
fn load_src_language(&self) {
let catalog = gettext_system::Catalog::empty();
tr::internal::set_translator(self.module, catalog);
*(self.current_language.write()) = self.fallback_language().clone();
}
}
impl LanguageLoader for GettextLanguageLoader {
fn fallback_language(&self) -> &LanguageIdentifier {
&self.fallback_language
}
fn domain(&self) -> &'static str {
domain_from_module(self.module)
}
fn language_file_name(&self) -> String {
format!("{}.mo", self.domain())
}
fn current_language(&self) -> LanguageIdentifier {
self.current_language.read().clone()
}
#[allow(single_use_lifetimes)]
fn load_languages(
&self,
i18n_assets: &dyn I18nAssets,
language_ids: &[unic_langid::LanguageIdentifier],
) -> Result<(), I18nEmbedError> {
let language_id = language_ids
.iter()
.next()
.ok_or(I18nEmbedError::RequestedLanguagesEmpty)?;
if language_id == self.fallback_language() {
self.load_src_language();
return Ok(());
}
let (path, files) = self.language_files(language_id, i18n_assets);
let file = match files.as_slice() {
[first_file] => first_file,
[first_file, ..] => {
log::warn!(
"Gettext system does not yet support merging language files for {path:?}"
);
first_file
}
[] => {
log::error!(
target:"i18n_embed::gettext",
"{} Setting current_language to fallback locale: \"{}\".",
I18nEmbedError::LanguageNotAvailable(path, language_id.clone()),
self.fallback_language);
self.load_src_language();
return Ok(());
}
};
let catalog = gettext_system::Catalog::parse(&**file).expect("could not parse the catalog");
tr::internal::set_translator(self.module, catalog);
*(self.current_language.write()) = language_id.clone();
Ok(())
}
fn reload(&self, i18n_assets: &dyn I18nAssets) -> Result<(), I18nEmbedError> {
self.load_languages(i18n_assets, &[self.current_language()])
}
}