use wxdragon::{
translations::{Translations, TranslationsLoader},
widgets::choice::Choice,
};
use crate::{LanguageInfo, LanguageManager, best_available_language};
pub struct WxTranslationManager {
domain: String,
current_language: String,
available_languages: Vec<LanguageInfo>,
initialized: bool,
}
impl WxTranslationManager {
#[must_use]
pub fn new(domain: &str) -> Self {
Self {
domain: domain.to_string(),
current_language: "en".to_string(),
available_languages: vec![LanguageInfo { code: "en".to_string(), name: "English".to_string() }],
initialized: false,
}
}
pub fn initialize(&mut self, wxstd_loader: impl TranslationsLoader + 'static) {
if self.initialized {
return;
}
let translations = Translations::new();
translations.set_loader(wxstd_loader);
self.available_languages = LanguageManager::new(&self.domain).available();
self.current_language = best_available_language(&LanguageManager::system_language(), &self.available_languages)
.unwrap_or_else(|| "en".to_string());
if self.current_language != "en" {
translations.set_language_str(&self.current_language);
}
translations.add_std_catalog();
Translations::set_global(translations);
crate::set_default_domain(&self.domain);
crate::set_locale(&self.current_language);
self.initialized = true;
}
pub fn set_language(&mut self, language_code: &str, wxstd_loader: impl TranslationsLoader + 'static) -> bool {
if !self.initialized || !self.is_language_available(language_code) {
return false;
}
self.current_language = language_code.to_string();
let translations = Translations::new();
translations.set_loader(wxstd_loader);
translations.set_language_str(language_code);
translations.add_std_catalog();
Translations::set_global(translations);
crate::set_locale(language_code);
true
}
#[must_use]
pub fn current_language(&self) -> String {
self.current_language.clone()
}
#[must_use]
pub fn available_languages(&self) -> Vec<LanguageInfo> {
self.available_languages.clone()
}
#[must_use]
pub fn is_language_available(&self, language_code: &str) -> bool {
self.available_languages.iter().any(|lang| lang.code == language_code)
}
}
#[must_use]
pub fn populate_language_choice(combo: &Choice, languages: &[LanguageInfo]) -> Vec<String> {
let mut codes = Vec::with_capacity(languages.len());
for lang in languages {
combo.append(&lang.name);
codes.push(lang.code.clone());
}
codes
}
#[must_use]
pub fn resolve_language_choice(combo: &Choice, codes: &[String]) -> Option<String> {
combo.get_selection().and_then(|index| usize::try_from(index).ok()).and_then(|index| codes.get(index).cloned())
}
#[cfg(test)]
mod tests {
use std::borrow::Cow;
use super::*;
struct NoopLoader;
impl TranslationsLoader for NoopLoader {
fn load_catalog(&self, _domain: &str, _lang: &str) -> Option<Cow<'_, [u8]>> {
None
}
fn available_translations(&self, _domain: &str) -> Vec<String> {
Vec::new()
}
}
#[test]
fn new_manager_has_english_available_by_default() {
let manager = WxTranslationManager::new("test_domain");
assert_eq!(manager.current_language(), "en");
assert!(manager.is_language_available("en"));
assert!(!manager.is_language_available("zz"));
}
#[test]
fn set_language_fails_when_not_initialized() {
let mut manager = WxTranslationManager::new("test_domain");
assert!(!manager.set_language("en", NoopLoader));
assert_eq!(manager.current_language(), "en");
}
}