1
0
Fork 0

Return result from i18n

This commit is contained in:
Alex Kotov 2020-10-21 15:09:03 +05:00
parent c48781c40f
commit 67ee20d0bb
Signed by: kotovalexarian
GPG Key ID: 553C0EBBEB5D5F08
3 changed files with 70 additions and 22 deletions

View File

@ -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)
}
}

View File

@ -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 {

View File

@ -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)