Use the rocket_i18n crate
This commit is contained in:
parent
14c3fd5c8f
commit
cafb0e2277
|
@ -1014,6 +1014,7 @@ dependencies = [
|
||||||
"rocket 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
|
"rocket 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
|
||||||
"rocket_codegen 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
|
"rocket_codegen 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
|
||||||
"rocket_contrib 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
|
"rocket_contrib 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
|
||||||
|
"rocket_i18n 0.1.1 (git+https://github.com/BaptisteGelez/rocket_i18n?rev=457b88c59ec31905a9193df43df58bee55b4b83d)",
|
||||||
"serde 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_json 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1269,6 +1270,17 @@ dependencies = [
|
||||||
"time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rocket_i18n"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "git+https://github.com/BaptisteGelez/rocket_i18n?rev=457b88c59ec31905a9193df43df58bee55b4b83d#457b88c59ec31905a9193df43df58bee55b4b83d"
|
||||||
|
dependencies = [
|
||||||
|
"gettext-rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rocket 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)",
|
||||||
|
"serde_json 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tera 0.11.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
|
@ -2085,6 +2097,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum rocket_codegen_next 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)" = "<none>"
|
"checksum rocket_codegen_next 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)" = "<none>"
|
||||||
"checksum rocket_contrib 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)" = "<none>"
|
"checksum rocket_contrib 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)" = "<none>"
|
||||||
"checksum rocket_http 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)" = "<none>"
|
"checksum rocket_http 0.4.0-dev (git+https://github.com/SergioBenitez/Rocket?rev=df7111143e466c18d1f56377a8d9530a5a306aba)" = "<none>"
|
||||||
|
"checksum rocket_i18n 0.1.1 (git+https://github.com/BaptisteGelez/rocket_i18n?rev=457b88c59ec31905a9193df43df58bee55b4b83d)" = "<none>"
|
||||||
"checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb"
|
"checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb"
|
||||||
"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f"
|
"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f"
|
||||||
"checksum schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "85fd9df495640643ad2d00443b3d78aae69802ad488debab4f1dd52fc1806ade"
|
"checksum schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "85fd9df495640643ad2d00443b3d78aae69802ad488debab4f1dd52fc1806ade"
|
||||||
|
|
|
@ -45,3 +45,7 @@ rev = "df7111143e466c18d1f56377a8d9530a5a306aba"
|
||||||
features = ["tera_templates", "json"]
|
features = ["tera_templates", "json"]
|
||||||
git = "https://github.com/SergioBenitez/Rocket"
|
git = "https://github.com/SergioBenitez/Rocket"
|
||||||
rev = "df7111143e466c18d1f56377a8d9530a5a306aba"
|
rev = "df7111143e466c18d1f56377a8d9530a5a306aba"
|
||||||
|
|
||||||
|
[dependencies.rocket_i18n]
|
||||||
|
git = "https://github.com/BaptisteGelez/rocket_i18n"
|
||||||
|
rev = "457b88c59ec31905a9193df43df58bee55b4b83d"
|
||||||
|
|
130
src/i18n.rs
130
src/i18n.rs
|
@ -1,130 +0,0 @@
|
||||||
use gettextrs::*;
|
|
||||||
use rocket::{Data, Request, Rocket, fairing::{Fairing, Info, Kind}};
|
|
||||||
use serde_json;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::env;
|
|
||||||
use std::fs;
|
|
||||||
use std::io::{BufRead, BufReader};
|
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
use std::process::Command;
|
|
||||||
use tera::{Tera, Error as TeraError};
|
|
||||||
|
|
||||||
const ACCEPT_LANG: &'static str = "Accept-Language";
|
|
||||||
|
|
||||||
pub struct I18n {
|
|
||||||
domain: &'static str
|
|
||||||
}
|
|
||||||
|
|
||||||
impl I18n {
|
|
||||||
pub fn new(domain: &'static str) -> I18n {
|
|
||||||
I18n {
|
|
||||||
domain: domain
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Fairing for I18n {
|
|
||||||
fn info(&self) -> Info {
|
|
||||||
Info {
|
|
||||||
name: "Gettext I18n",
|
|
||||||
kind: Kind::Attach | Kind::Request
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_attach(&self, rocket: Rocket) -> Result<Rocket, Rocket> {
|
|
||||||
update_po(self.domain);
|
|
||||||
compile_po(self.domain);
|
|
||||||
|
|
||||||
bindtextdomain(self.domain, fs::canonicalize(&PathBuf::from("./translations/")).unwrap().to_str().unwrap());
|
|
||||||
textdomain(self.domain);
|
|
||||||
Ok(rocket)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_request(&self, request: &mut Request, _: &Data) {
|
|
||||||
let lang = request
|
|
||||||
.headers()
|
|
||||||
.get_one(ACCEPT_LANG)
|
|
||||||
.unwrap_or("en")
|
|
||||||
.split(",")
|
|
||||||
.nth(0)
|
|
||||||
.unwrap_or("en");
|
|
||||||
|
|
||||||
// We can't use setlocale(LocaleCategory::LcAll, lang), because it only accepts system-wide installed
|
|
||||||
// locales (and most of the time there are only a few of them).
|
|
||||||
// But, when we set the LANGUAGE environment variable, and an empty string as a second parameter to
|
|
||||||
// setlocale, gettext will be smart enough to find a matching locale in the locally installed ones.
|
|
||||||
env::set_var("LANGUAGE", lang);
|
|
||||||
setlocale(LocaleCategory::LcAll, "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_po(domain: &str) {
|
|
||||||
let pot_path = Path::new("po").join(format!("{}.pot", domain));
|
|
||||||
|
|
||||||
for lang in get_locales() {
|
|
||||||
let po_path = Path::new("po").join(format!("{}.po", lang.clone()));
|
|
||||||
if po_path.exists() && po_path.is_file() {
|
|
||||||
println!("Updating {}", lang.clone());
|
|
||||||
// Update it
|
|
||||||
Command::new("msgmerge")
|
|
||||||
.arg("-U")
|
|
||||||
.arg(po_path.to_str().unwrap())
|
|
||||||
.arg(pot_path.to_str().unwrap())
|
|
||||||
.spawn()
|
|
||||||
.expect("Couldn't update PO file");
|
|
||||||
} else {
|
|
||||||
println!("Creating {}", lang.clone());
|
|
||||||
// Create it from the template
|
|
||||||
Command::new("msginit")
|
|
||||||
.arg(format!("--input={}", pot_path.to_str().unwrap()))
|
|
||||||
.arg(format!("--output-file={}", po_path.to_str().unwrap()))
|
|
||||||
.arg("-l")
|
|
||||||
.arg(lang)
|
|
||||||
.arg("--no-translator")
|
|
||||||
.spawn()
|
|
||||||
.expect("Couldn't init PO file");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compile_po(domain: &str) {
|
|
||||||
for lang in get_locales() {
|
|
||||||
let po_path = Path::new("po").join(format!("{}.po", lang.clone()));
|
|
||||||
let mo_dir = Path::new("translations")
|
|
||||||
.join(lang.clone())
|
|
||||||
.join("LC_MESSAGES");
|
|
||||||
fs::create_dir_all(mo_dir.clone()).expect("Couldn't create MO directory");
|
|
||||||
let mo_path = mo_dir.join(format!("{}.mo", domain));
|
|
||||||
|
|
||||||
Command::new("msgfmt")
|
|
||||||
.arg(format!("--output-file={}", mo_path.to_str().unwrap()))
|
|
||||||
.arg(po_path)
|
|
||||||
.spawn()
|
|
||||||
.expect("Couldn't compile translations");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_locales() -> Vec<String> {
|
|
||||||
let linguas_file = fs::File::open(Path::new("po").join("LINGUAS")).expect("Couldn't find po/LINGUAS file");
|
|
||||||
let linguas = BufReader::new(&linguas_file);
|
|
||||||
linguas.lines().map(Result::unwrap).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tera_gettext(msg: serde_json::Value, ctx: HashMap<String, serde_json::Value>) -> Result<serde_json::Value, TeraError> {
|
|
||||||
let trans = gettext(msg.as_str().unwrap());
|
|
||||||
Ok(serde_json::Value::String(Tera::one_off(trans.as_ref(), &ctx, false).unwrap_or(String::from(""))))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tera_ngettext(msg: serde_json::Value, ctx: HashMap<String, serde_json::Value>) -> Result<serde_json::Value, TeraError> {
|
|
||||||
let trans = ngettext(
|
|
||||||
ctx.get("singular").unwrap().as_str().unwrap(),
|
|
||||||
msg.as_str().unwrap(),
|
|
||||||
ctx.get("count").unwrap().as_u64().unwrap() as u32
|
|
||||||
);
|
|
||||||
Ok(serde_json::Value::String(Tera::one_off(trans.as_ref(), &ctx, false).unwrap_or(String::from(""))))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tera(t: &mut Tera) {
|
|
||||||
t.register_filter("_", tera_gettext);
|
|
||||||
t.register_filter("_n", tera_ngettext);
|
|
||||||
}
|
|
|
@ -25,6 +25,7 @@ extern crate openssl;
|
||||||
extern crate reqwest;
|
extern crate reqwest;
|
||||||
extern crate rocket;
|
extern crate rocket;
|
||||||
extern crate rocket_contrib;
|
extern crate rocket_contrib;
|
||||||
|
extern crate rocket_i18n;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
@ -40,7 +41,6 @@ use std::env;
|
||||||
|
|
||||||
mod activity_pub;
|
mod activity_pub;
|
||||||
mod db_conn;
|
mod db_conn;
|
||||||
mod i18n;
|
|
||||||
mod models;
|
mod models;
|
||||||
mod schema;
|
mod schema;
|
||||||
mod routes;
|
mod routes;
|
||||||
|
@ -130,8 +130,8 @@ fn main() {
|
||||||
])
|
])
|
||||||
.manage(init_pool())
|
.manage(init_pool())
|
||||||
.attach(Template::custom(|engines| {
|
.attach(Template::custom(|engines| {
|
||||||
i18n::tera(&mut engines.tera);
|
rocket_i18n::tera(&mut engines.tera);
|
||||||
}))
|
}))
|
||||||
.attach(i18n::I18n::new("plume"))
|
.attach(rocket_i18n::I18n::new("plume"))
|
||||||
.launch();
|
.launch();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue