diff --git a/src/i18n.rs b/src/i18n.rs index fdf7a37..2eb479f 100644 --- a/src/i18n.rs +++ b/src/i18n.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use fluent_bundle::FluentResource; +use fluent_bundle::{FluentError, FluentResource}; use fluent_bundle::concurrent::FluentBundle; use unic_langid::LanguageIdentifier; @@ -8,19 +8,40 @@ pub struct I18n(HashMap>); pub struct L10n<'a>(&'a FluentBundle); +#[derive(Debug)] +pub enum I18nError { + // For `I18n::new` + InvalidLocale(String), + InvalidPath, + CantReadFile(String), + CantBuildResource(String), + CantAddResource(String), + + // For `I18n.l10n` + NoSuchLocale(String), + + // For `L10n.translate` + NoSuchTranslation(String), + InvalidTranslation(String), + FormattingFailed(Vec), +} + impl I18n { - pub fn new(path: &str, locales: &[&str]) -> Result { - let lang_ids: Vec> = + pub fn new(path: &str, locales: &[&str]) -> Result { + let locales_and_lang_ids: Vec<(&str, Result)> = locales.iter().map(|locale| { - locale.parse::() + (*locale, locale.parse::()) }).collect(); - if let Some(_) = lang_ids.iter().find(|lang_id| lang_id.is_err()) { - return Err(()); + if let Some((locale, _)) = + locales_and_lang_ids.iter().find(|(_, lang_id)| lang_id.is_err()) + { + return Err(I18nError::InvalidLocale(locale.to_string())); } - let lang_ids: Vec<&LanguageIdentifier> = - lang_ids.iter().map(|lang_id| lang_id.as_ref().unwrap()).collect(); + let lang_ids: Vec<&LanguageIdentifier> = locales_and_lang_ids.iter() + .map(|(_, lang_id)| lang_id.as_ref().unwrap()) + .collect(); let mut hash_map = HashMap::new(); @@ -31,20 +52,29 @@ impl I18n { path_buf.push(&locale); path_buf.set_extension("ftl"); - let data = match std::fs::read_to_string(path_buf) { + let path_str = match path_buf.to_str() { + Some(path_str) => path_str, + None => return Err(I18nError::InvalidPath), + }; + + let data = match std::fs::read_to_string(path_str) { Ok(data) => data, - Err(_) => return Err(()), + Err(_) => return Err(I18nError::CantReadFile( + path_str.to_string(), + )), }; let resource = match FluentResource::try_new(data) { Ok(resource) => resource, - Err(_) => return Err(()), + Err(_) => return Err(I18nError::CantBuildResource( + path_str.to_string(), + )), }; let mut bundle = FluentBundle::default(); if let Err(_) = bundle.add_resource(resource) { - return Err(()); + return Err(I18nError::CantAddResource(path_str.to_string())); }; hash_map.insert(locale, bundle); @@ -53,19 +83,34 @@ impl I18n { Ok(Self(hash_map)) } - pub fn l10n<'a>(&'a self, locale: &'a str) -> Option> { + pub fn l10n<'a>(&'a self, locale: &'a str) -> Result, I18nError> { match self.0.get(locale) { - None => None, - Some(bundle) => Some(L10n(bundle)), + None => Err(I18nError::NoSuchLocale(locale.to_string())), + Some(bundle) => Ok(L10n(bundle)), } } } impl L10n<'_> { - pub fn dummy_translate(&self, key: &str) -> String { - let msg = self.0.get_message(key).unwrap(); - let val = msg.value.unwrap(); + pub fn translate(&self, key: &str) -> Result { + let msg = match self.0.get_message(key) { + None => return Err(I18nError::NoSuchTranslation(key.to_string())), + Some(msg) => msg, + }; + + let val = match msg.value { + None => return Err(I18nError::InvalidTranslation(key.to_string())), + Some(val) => val, + }; + let mut errors = vec![]; - self.0.format_pattern(val, None, &mut errors).to_string() + + let out = self.0.format_pattern(val, None, &mut errors).to_string(); + + if !errors.is_empty() { + return Err(I18nError::FormattingFailed(errors)); + } + + Ok(out) } } diff --git a/src/routes/home.rs b/src/routes/home.rs index 85ddaec..f8a15c5 100644 --- a/src/routes/home.rs +++ b/src/routes/home.rs @@ -17,8 +17,8 @@ pub fn index( let l10n = i18n.l10n("en").unwrap(); let page_context = views::home::Index { - i18n_fedihub: l10n.dummy_translate("fedihub"), - i18n_federated_services_without_censorship: l10n.dummy_translate("federated-services-without-censorship"), + i18n_fedihub: l10n.translate("fedihub").unwrap(), + i18n_federated_services_without_censorship: l10n.translate("federated-services-without-censorship").unwrap(), }; let context = views::Site { diff --git a/src/web.rs b/src/web.rs index 553be65..3be9277 100644 --- a/src/web.rs +++ b/src/web.rs @@ -12,7 +12,10 @@ pub fn rocket(config: &config::Config) -> Result { let public_path = config.public_path()?; let locales_path = config.locales_path()?; - let i18n = I18n::new(&locales_path, &["en", "ru"])?; + let i18n = match I18n::new(&locales_path, &["en", "ru"]) { + Err(_) => return Err(()), + Ok(i18n) => i18n, + }; let result = rocket::custom(rocket_config) .manage(i18n)