i18n: add template override mechanism
This commit is contained in:
parent
069d332123
commit
6236d3bf40
43
src/mail.rs
43
src/mail.rs
|
@ -1,4 +1,4 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use failure;
|
||||
use handlebars::Handlebars;
|
||||
|
@ -10,10 +10,9 @@ use uuid::Uuid;
|
|||
use crate::counters;
|
||||
|
||||
use rocket_i18n::I18n;
|
||||
use gettext_macros::include_i18n;
|
||||
use gettext_macros::i18n;
|
||||
|
||||
use crate::i18n::I18NHelper;
|
||||
use crate::template_helpers;
|
||||
|
||||
use crate::database::types::Email;
|
||||
use crate::Result;
|
||||
|
@ -73,7 +72,7 @@ impl Service {
|
|||
|
||||
fn new(from: String, base_uri: String, template_dir: PathBuf, transport: Transport)
|
||||
-> Result<Self> {
|
||||
let templates = load_handlebars(template_dir)?;
|
||||
let templates = template_helpers::load_handlebars(template_dir)?;
|
||||
let domain =
|
||||
url::Url::parse(&base_uri)
|
||||
?.host_str().ok_or_else(|| failure::err_msg("No host in base-URI"))
|
||||
|
@ -167,7 +166,7 @@ impl Service {
|
|||
&self,
|
||||
template: &str,
|
||||
locale: &str,
|
||||
ctx: impl Serialize + Clone
|
||||
ctx: impl Serialize
|
||||
) -> Result<(String, String)> {
|
||||
let html = self.templates.render(&format!("{}/{}.htm", locale, template), &ctx)
|
||||
.or_else(|_| self.templates.render(&format!("{}.htm", template), &ctx))
|
||||
|
@ -185,7 +184,7 @@ impl Service {
|
|||
subject: &str,
|
||||
template: &str,
|
||||
locale: &str,
|
||||
ctx: impl Serialize + Clone
|
||||
ctx: impl Serialize
|
||||
) -> Result<()> {
|
||||
let (html, txt) = self.render_template(template, locale, ctx)?;
|
||||
|
||||
|
@ -221,35 +220,3 @@ impl Service {
|
|||
}
|
||||
}
|
||||
|
||||
fn load_handlebars(template_dir: PathBuf) -> Result<Handlebars> {
|
||||
let mut handlebars = Handlebars::new();
|
||||
|
||||
let i18ns = include_i18n!();
|
||||
let i18n_helper = I18NHelper::new(i18ns);
|
||||
handlebars.register_helper("text", Box::new(i18n_helper));
|
||||
|
||||
let mut glob_path = template_dir.join("**").join("*");
|
||||
glob_path.set_extension("hbs");
|
||||
let glob_path = glob_path.to_str().expect("valid glob path string");
|
||||
|
||||
for path in glob::glob(glob_path).unwrap().flatten() {
|
||||
let template_name = remove_extension(path.strip_prefix(&template_dir)?);
|
||||
handlebars.register_template_file(&template_name.to_string_lossy(), &path)?;
|
||||
}
|
||||
|
||||
Ok(handlebars)
|
||||
}
|
||||
|
||||
fn remove_extension<P: AsRef<Path>>(path: P) -> PathBuf {
|
||||
let path = path.as_ref();
|
||||
let stem = match path.file_stem() {
|
||||
Some(stem) => stem,
|
||||
None => return path.to_path_buf()
|
||||
};
|
||||
|
||||
match path.parent() {
|
||||
Some(parent) => parent.join(stem),
|
||||
None => PathBuf::from(stem)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ mod rate_limiter;
|
|||
mod dump;
|
||||
mod counters;
|
||||
mod i18n;
|
||||
mod template_helpers;
|
||||
mod gettext_strings;
|
||||
mod web;
|
||||
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::collections::HashSet;
|
||||
|
||||
use handlebars::Handlebars;
|
||||
|
||||
use gettext_macros::include_i18n;
|
||||
|
||||
use crate::Result;
|
||||
use crate::i18n::I18NHelper;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TemplateOverrides(String, HashSet<(String)>);
|
||||
|
||||
impl TemplateOverrides {
|
||||
pub fn load(template_path: &Path, localized_dir: &str) -> Result<Self> {
|
||||
load_localized_template_names(template_path, localized_dir)
|
||||
.map(|vec| Self(localized_dir.to_owned(), vec))
|
||||
}
|
||||
|
||||
pub fn get_template_override(&self, lang: &str, tmpl: &str) -> Option<String> {
|
||||
let template_name = format!("{}/{}/{}", self.0, lang, tmpl);
|
||||
if self.1.contains(&template_name) {
|
||||
println!("{}", &template_name);
|
||||
Some(template_name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn load_localized_template_names(template_path: &Path, localized_dir: &str) -> Result<HashSet<(String)>> {
|
||||
let language_glob = template_path.join(localized_dir).join("*");
|
||||
glob::glob(language_glob.to_str().expect("valid glob path string"))
|
||||
.unwrap()
|
||||
.flatten()
|
||||
.flat_map(|language_path| {
|
||||
let mut template_glob = language_path.join("**").join("*");
|
||||
template_glob.set_extension("hbs");
|
||||
glob::glob(template_glob.to_str().expect("valid glob path string"))
|
||||
.unwrap()
|
||||
.flatten()
|
||||
.map(move |path| {
|
||||
// TODO this is a hack
|
||||
let template_name = remove_extension(remove_extension(path.strip_prefix(&template_path)?));
|
||||
Ok(template_name.to_string_lossy().into_owned())
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn load_handlebars(template_dir: PathBuf) -> Result<Handlebars> {
|
||||
let mut handlebars = Handlebars::new();
|
||||
|
||||
let i18ns = include_i18n!();
|
||||
let i18n_helper = I18NHelper::new(i18ns);
|
||||
handlebars.register_helper("text", Box::new(i18n_helper));
|
||||
|
||||
let mut glob_path = template_dir.join("**").join("*");
|
||||
glob_path.set_extension("hbs");
|
||||
let glob_path = glob_path.to_str().expect("valid glob path string");
|
||||
|
||||
for path in glob::glob(glob_path).unwrap().flatten() {
|
||||
let template_name = remove_extension(path.strip_prefix(&template_dir)?);
|
||||
handlebars.register_template_file(&template_name.to_string_lossy(), &path)?;
|
||||
}
|
||||
|
||||
Ok(handlebars)
|
||||
}
|
||||
|
||||
fn remove_extension<P: AsRef<Path>>(path: P) -> PathBuf {
|
||||
let path = path.as_ref();
|
||||
let stem = match path.file_stem() {
|
||||
Some(stem) => stem,
|
||||
None => return path.to_path_buf()
|
||||
};
|
||||
|
||||
match path.parent() {
|
||||
Some(parent) => parent.join(stem),
|
||||
None => PathBuf::from(stem)
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ use std::path::PathBuf;
|
|||
use crate::mail;
|
||||
use crate::tokens;
|
||||
use crate::counters;
|
||||
use crate::template_helpers::TemplateOverrides;
|
||||
use crate::i18n::I18NHelper;
|
||||
use crate::rate_limiter::RateLimiter;
|
||||
|
||||
|
@ -48,9 +49,16 @@ impl Responder<'static> for HagridTemplate {
|
|||
fn respond_to(self, req: &rocket::Request) -> std::result::Result<Response<'static>, Status> {
|
||||
let HagridTemplate(tmpl, ctx) = self;
|
||||
let i18n: I18n = req.guard().expect("Error parsing language");
|
||||
let template_overrides: rocket::State<TemplateOverrides> = req.guard().expect("TemplateOverrides must be in managed state");
|
||||
let template_override = template_overrides.get_template_override(i18n.lang, tmpl);
|
||||
let origin: RequestOrigin = req.guard().expect("Error determining request origin");
|
||||
let layout_context = templates::HagridLayout::new(ctx, i18n, origin);
|
||||
Template::render(tmpl, layout_context).respond_to(req)
|
||||
|
||||
if let Some(template_override) = template_override {
|
||||
Template::render(template_override, layout_context)
|
||||
} else {
|
||||
Template::render(tmpl, layout_context)
|
||||
}.respond_to(req)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -410,6 +418,8 @@ fn rocket_factory(mut rocket: rocket::Rocket) -> Result<rocket::Rocket> {
|
|||
let mail_service = configure_mail_service(rocket.config())?;
|
||||
let rate_limiter = configure_rate_limiter(rocket.config())?;
|
||||
let maintenance_mode = configure_maintenance_mode(rocket.config())?;
|
||||
let localized_template_list = configure_localized_template_list(rocket.config())?;
|
||||
println!("{:?}", localized_template_list);
|
||||
|
||||
let prometheus = configure_prometheus(rocket.config());
|
||||
|
||||
|
@ -427,6 +437,7 @@ fn rocket_factory(mut rocket: rocket::Rocket) -> Result<rocket::Rocket> {
|
|||
.manage(mail_service)
|
||||
.manage(db_service)
|
||||
.manage(rate_limiter)
|
||||
.manage(localized_template_list)
|
||||
.mount("/", routes);
|
||||
|
||||
if let Some(prometheus) = prometheus {
|
||||
|
@ -514,6 +525,11 @@ fn configure_rate_limiter(config: &Config) -> Result<RateLimiter> {
|
|||
Ok(RateLimiter::new(timeout_secs))
|
||||
}
|
||||
|
||||
fn configure_localized_template_list(config: &Config) -> Result<TemplateOverrides> {
|
||||
let template_dir: PathBuf = config.get_str("template_dir")?.into();
|
||||
TemplateOverrides::load(&template_dir, "localized")
|
||||
}
|
||||
|
||||
fn configure_maintenance_mode(config: &Config) -> Result<MaintenanceMode> {
|
||||
let maintenance_file: PathBuf = config.get_str("maintenance_file")
|
||||
.unwrap_or("maintenance").into();
|
||||
|
|
Loading…
Reference in New Issue