use fluent_bundle::{FluentArgs, FluentValue};
use fluent_langneg::{negotiate_languages, LanguageIdentifier, NegotiationStrategy};
use fluent_resmgr::resource_manager::ResourceManager;
use std::collections::HashMap;
use std::fs;
use std::sync::Arc;
use std::path::{Path, PathBuf};
pub struct I18n {
resource_manager: ResourceManager,
bundles: HashMap<String, Arc<FluentBundle<FluentResource>>>,
}
impl I18n {
pub fn new(locales_path: &str, service_locales_path: Option<&str>) -> Self {
let resource_manager = ResourceManager::new(locales_path);
let mut bundles = HashMap::new();
for lang in &["en", "es"] {
let mut resources = resource_manager
.get_resources(lang, &["messages.ftl"])
.expect("Failed to load general resources.");
if let Some(service_path) = service_locales_path {
let service_resources = ResourceManager::new(service_path)
.get_resources(lang, &["messages.ftl"])
.expect("Failed to load service-specific resources.");
resources.extend(service_resources);
}
let mut bundle = FluentBundle::new(vec![lang.to_string()]);
for resource in resources {
bundle.add_resource(resource).expect("Failed to add resource.");
}
bundles.insert(lang.to_string(), Arc::new(bundle));
}
I18n {
resource_manager,
bundles,
}
}
fn get_available_locales() -> Result<Vec<LanguageIdentifier>, io::Error> {
let mut locales = vec![];
let res_path = PathBuf::from(std::env!("CARGO_MANIFEST_DIR"))
.join("examples")
.join("resources");
let res_dir = fs::read_dir(res_path)?;
for entry in res_dir.flatten() {
let path = entry.path();
if path.is_dir() {
if let Some(name) = path.file_name() {
if let Some(name) = name.to_str() {
let langid: LanguageIdentifier = name.parse().expect("Parsing failed.");
locales.push(langid);
}
}
}
}
Ok(locales)
}
pub fn translate(&self, lang: &str, key: &str, args: Option<&HashMap<&str, &str>>) -> String {
let lang = negotiate_languages(
&[lang],
&self.bundles.keys().map(|k| k.as_str()).collect::<Vec<_>>(),
None,
fluent_langneg::NegotiationStrategy::Filtering,
)[0];
let bundle = self.bundles.get(lang).expect("Bundle not found.");
let msg = bundle.get_message(key).expect("Message not found.");
let pattern = msg.value().expect("Message has no value.");
let mut errors = vec![];
let value = bundle.format_pattern(pattern, args, &mut errors);
value.to_string()
}
}