glossa_cli/
context.rs

1use std::sync::Arc;
2
3use glossa::{
4  LangID, LocaleContext, fallback::dbg_ref, misc::normalize_glossa_lang,
5  sys::new_once_lock, traits::ChainProvider,
6};
7use glossa_codegen::glossa_shared::{
8  ToCompactString,
9  load_bincode::{self, list_static_bincode_files, try_load_files},
10  tap::{Pipe, Tap},
11  type_aliases::L10nMaps,
12};
13
14use crate::{envs::static_glossa_lang, static_data::bincode_dir};
15
16pub(crate) trait GetL10nText: ChainProvider {
17  fn try_get_bincode<'t>(&self, map_name: &str, key: &str) -> Option<&'t str> {
18    let key_bytes = key.as_bytes();
19    let fallback_to_builtin =
20      || static_locale_context().try_get_bulitin_cli_data(key_bytes);
21
22    let lookup =
23      |(language, map_name, key)| match static_bincode_resource()?.get(language) {
24        Some(x) => x
25          .get(&(map_name, key))
26          .map(|x| x.as_str())
27          .or_else(fallback_to_builtin),
28        _ => {
29          log::trace!("fallback to builtin data");
30          fallback_to_builtin()
31        }
32      };
33
34    self
35      .provide_chain()?
36      .iter()
37      .map(|lang| (lang, map_name.to_compact_string(), key.to_compact_string()))
38      .find_map(lookup)
39  }
40
41  fn try_get_bulitin_cli_data<'t>(&self, key: &[u8]) -> Option<&'t str> {
42    let lookup = |language| match crate::l10n::router::map(language, key) {
43      "" => None,
44      s => Some(s),
45    };
46    self
47      .provide_chain()?
48      .iter()
49      .map(|lang| lang.as_bytes())
50      .find_map(lookup)
51  }
52
53  fn try_get<'t>(&self, map_name: &str, key: &str) -> Option<&'t str> {
54    match static_bincode_resource() {
55      Some(_) => self.try_get_bincode(map_name, key),
56      _ => self.try_get_bulitin_cli_data(key.as_bytes()),
57    }
58  }
59}
60
61impl GetL10nText for LocaleContext {}
62
63/// - exists => Some(())
64/// - _ => None
65pub fn bincode_exists() -> Option<()> {
66  bincode_dir()
67    .pipe(list_static_bincode_files)
68    .map(|_| ())
69}
70
71pub fn static_bincode_resource() -> Option<&'static Arc<L10nMaps>> {
72  bincode_exists()?;
73
74  new_once_lock!(L: Option<Arc<L10nMaps>>);
75
76  L.get_or_init(|| {
77    bincode_dir()
78      .pipe(list_static_bincode_files)
79      .map(try_load_files)
80      .and_then(|x| x.ok())
81      .map(Arc::new)
82  })
83  .as_ref()
84}
85
86fn compatible_with_gnu_language_colon_style(locale_context: &mut LocaleContext) {
87  let _ =
88    locale_context.try_push_front_with_colon_separated_str(static_glossa_lang());
89}
90
91pub fn static_bincode_context() -> Option<&'static LocaleContext> {
92  bincode_exists()?;
93  new_once_lock!(L: Option<LocaleContext>);
94
95  L.get_or_init(|| {
96    let locales = merge_locales()?;
97    dbg_ref!(locales);
98    LocaleContext::default()
99      .with_current_locale(normalize_glossa_lang(static_glossa_lang()))
100      .with_all_locales(locales)
101      .tap_mut(compatible_with_gnu_language_colon_style)
102      .pipe(Some)
103  })
104  .as_ref()
105}
106
107/// Merges locales from builtin & bincode sources
108pub(crate) fn merge_locales() -> Option<Box<[LangID]>> {
109  load_bincode::merge_locales(
110    static_bincode_resource().map(|v| v.as_ref()),
111    static_locale_context()
112      .get_all_locales()
113      .as_deref(),
114  )
115}
116
117pub(crate) fn static_locale_context() -> &'static LocaleContext {
118  new_once_lock!(L: LocaleContext);
119  L.get_or_init(|| {
120    LocaleContext::default()
121      .with_current_locale(normalize_glossa_lang(static_glossa_lang()))
122      .with_all_locales(crate::l10n::locale_registry::all_locales())
123      .tap_mut(compatible_with_gnu_language_colon_style)
124  })
125}
126
127pub fn get_text<'a>(key: &str, map_name: Option<&str>) -> &'a str {
128  let map_name = map_name.unwrap_or("cli");
129
130  match static_bincode_context() {
131    Some(ctx) => ctx,
132    _ => static_locale_context(),
133  }
134  .try_get(map_name, key)
135  .unwrap_or_else(|| {
136    log::warn!("{}", glossa::Error::new_map_text_not_found(map_name, key));
137    ""
138  })
139}