Implement i18n backend
This commit is contained in:
parent
1de0633833
commit
76e359ea89
10 changed files with 152 additions and 12 deletions
55
src/i18n.rs
Normal file
55
src/i18n.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
use std::{collections::HashMap, fs::{self, File}, io::BufReader, process::Command};
|
||||
use derive_more::From;
|
||||
use rocket_dyn_templates::tera::{self, Value};
|
||||
|
||||
use gettext::Catalog;
|
||||
|
||||
#[derive(From, Debug)]
|
||||
pub enum LoadCatalogsError {
|
||||
Io(std::io::Error),
|
||||
Parse(gettext::Error),
|
||||
MissingDefaultLanguage,
|
||||
}
|
||||
|
||||
const DEFAULT: &str = "ja";
|
||||
|
||||
pub fn load_catalogs() -> Result<HashMap<String, Catalog>, LoadCatalogsError> {
|
||||
let mut catalogs = HashMap::new();
|
||||
for file in fs::read_dir("i18n")? {
|
||||
let file = file?;
|
||||
let path = file.path();
|
||||
if !file.file_type()?.is_file() || !path.extension().map(|extension| extension.eq("po")).unwrap_or(false) {
|
||||
continue;
|
||||
}
|
||||
let language_code = path
|
||||
.file_stem()
|
||||
.expect("Invalid translation file name")
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
let po_file_path = path;
|
||||
let mo_file_path = format!("i18n/{}.mo", language_code);
|
||||
Command::new("msgfmt")
|
||||
.arg(&po_file_path)
|
||||
.arg("-o")
|
||||
.arg(&mo_file_path)
|
||||
.output()?;
|
||||
catalogs.insert(language_code, Catalog::parse(BufReader::new(File::open(mo_file_path)?))?);
|
||||
}
|
||||
if !catalogs.contains_key(DEFAULT) {
|
||||
return Err(LoadCatalogsError::MissingDefaultLanguage);
|
||||
}
|
||||
Ok(catalogs)
|
||||
}
|
||||
|
||||
pub fn i18n_filter(value: &Value, _args: &HashMap<String, Value>, catalogs: &HashMap<String, Catalog>) -> tera::Result<Value> {
|
||||
let key = value.as_str().ok_or_else(|| {
|
||||
tera::Error::msg("The translation key must be a string")
|
||||
})?;
|
||||
|
||||
let translation = catalogs
|
||||
.get(DEFAULT)
|
||||
.expect("Missing catalog")
|
||||
.gettext(key);
|
||||
|
||||
Ok(Value::String(translation.to_owned()))
|
||||
}
|
17
src/main.rs
17
src/main.rs
|
@ -3,9 +3,9 @@ extern crate rocket;
|
|||
|
||||
use poise::serenity_prelude::Http;
|
||||
use rocket::fs::{relative, FileServer};
|
||||
use rocket_dyn_templates::Template;
|
||||
use rocket_dyn_templates::{Template, tera};
|
||||
use sass_rocket_fairing::SassFairing;
|
||||
use std::env;
|
||||
use std::{env, collections::HashMap};
|
||||
|
||||
mod models;
|
||||
use models::Settings;
|
||||
|
@ -17,6 +17,9 @@ mod cookies;
|
|||
mod routes;
|
||||
use routes::*;
|
||||
|
||||
mod i18n;
|
||||
use i18n::{load_catalogs, i18n_filter};
|
||||
|
||||
mod prelude;
|
||||
|
||||
#[launch]
|
||||
|
@ -40,6 +43,12 @@ async fn rocket() -> _ {
|
|||
routes![get_challenge, login, post_login, success, logout, testing],
|
||||
)
|
||||
.mount("/css", FileServer::from(relative!("styles/css")))
|
||||
.attach(Template::fairing())
|
||||
.attach(Template::custom(|engines| {
|
||||
use tera::Value;
|
||||
let catalogs = load_catalogs().unwrap();
|
||||
engines.tera.register_filter("i18n", move |value: &Value, args: &HashMap<String, Value>| {
|
||||
i18n_filter(value, args, &catalogs)
|
||||
})
|
||||
}))
|
||||
.attach(SassFairing::default())
|
||||
}
|
||||
}
|
|
@ -7,12 +7,6 @@ use crate::models::{Challenge, User, Settings};
|
|||
|
||||
#[get("/<challenge>")]
|
||||
pub async fn get_challenge(challenge: u32, cookies: &CookieJar<'_>, settings: &State<Settings>) -> Template {
|
||||
println!(
|
||||
"{:?}",
|
||||
cookies
|
||||
.get_private("user_name")
|
||||
.map(|cookie| cookie.value().to_owned())
|
||||
);
|
||||
Template::render(
|
||||
"index",
|
||||
context! {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue