1use crate::{domain_from_module, I18nAssets, I18nEmbedError, LanguageLoader};
9
10pub use i18n_embed_impl::gettext_language_loader;
11
12use gettext as gettext_system;
13use parking_lot::RwLock;
14use unic_langid::LanguageIdentifier;
15
16#[derive(Debug)]
21pub struct GettextLanguageLoader {
22 current_language: RwLock<LanguageIdentifier>,
23 module: &'static str,
24 fallback_language: LanguageIdentifier,
25}
26
27impl GettextLanguageLoader {
28 pub fn new(module: &'static str, fallback_language: unic_langid::LanguageIdentifier) -> Self {
38 Self {
39 current_language: RwLock::new(fallback_language.clone()),
40 module,
41 fallback_language,
42 }
43 }
44
45 fn load_src_language(&self) {
46 let catalog = gettext_system::Catalog::empty();
47 tr::internal::set_translator(self.module, catalog);
48 *(self.current_language.write()) = self.fallback_language().clone();
49 }
50}
51
52impl LanguageLoader for GettextLanguageLoader {
53 fn fallback_language(&self) -> &LanguageIdentifier {
56 &self.fallback_language
57 }
58
59 fn domain(&self) -> &'static str {
61 domain_from_module(self.module)
62 }
63
64 fn language_file_name(&self) -> String {
66 format!("{}.mo", self.domain())
67 }
68
69 fn current_language(&self) -> LanguageIdentifier {
71 self.current_language.read().clone()
72 }
73
74 #[allow(single_use_lifetimes)]
85 fn load_languages(
86 &self,
87 i18n_assets: &dyn I18nAssets,
88 language_ids: &[unic_langid::LanguageIdentifier],
89 ) -> Result<(), I18nEmbedError> {
90 let language_id = language_ids
91 .iter()
92 .next()
93 .ok_or(I18nEmbedError::RequestedLanguagesEmpty)?;
94
95 if language_id == self.fallback_language() {
96 self.load_src_language();
97 return Ok(());
98 }
99 let (path, files) = self.language_files(language_id, i18n_assets);
100 let file = match files.as_slice() {
101 [first_file] => first_file,
102 [first_file, ..] => {
103 log::warn!(
104 "Gettext system does not yet support merging language files for {path:?}"
105 );
106 first_file
107 }
108 [] => {
109 log::error!(
110 target:"i18n_embed::gettext",
111 "{} Setting current_language to fallback locale: \"{}\".",
112 I18nEmbedError::LanguageNotAvailable(path, language_id.clone()),
113 self.fallback_language);
114 self.load_src_language();
115 return Ok(());
116 }
117 };
118
119 let catalog = gettext_system::Catalog::parse(&**file).expect("could not parse the catalog");
120 tr::internal::set_translator(self.module, catalog);
121 *(self.current_language.write()) = language_id.clone();
122
123 Ok(())
124 }
125
126 fn reload(&self, i18n_assets: &dyn I18nAssets) -> Result<(), I18nEmbedError> {
127 self.load_languages(i18n_assets, &[self.current_language()])
128 }
129}