Return result from i18n
This commit is contained in:
parent
c48781c40f
commit
67ee20d0bb
83
src/i18n.rs
83
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<String, FluentBundle<FluentResource>>);
|
|||
|
||||
pub struct L10n<'a>(&'a FluentBundle<FluentResource>);
|
||||
|
||||
#[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<FluentError>),
|
||||
}
|
||||
|
||||
impl I18n {
|
||||
pub fn new(path: &str, locales: &[&str]) -> Result<Self, ()> {
|
||||
let lang_ids: Vec<Result<LanguageIdentifier, _>> =
|
||||
pub fn new(path: &str, locales: &[&str]) -> Result<Self, I18nError> {
|
||||
let locales_and_lang_ids: Vec<(&str, Result<LanguageIdentifier, _>)> =
|
||||
locales.iter().map(|locale| {
|
||||
locale.parse::<LanguageIdentifier>()
|
||||
(*locale, locale.parse::<LanguageIdentifier>())
|
||||
}).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<L10n<'a>> {
|
||||
pub fn l10n<'a>(&'a self, locale: &'a str) -> Result<L10n<'a>, 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<String, I18nError> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -12,7 +12,10 @@ pub fn rocket(config: &config::Config) -> Result<rocket::Rocket, ()> {
|
|||
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)
|
||||
|
|
Reference in New Issue