Use the rocket_i18n crate
This commit is contained in:
		
							parent
							
								
									14c3fd5c8f
								
							
						
					
					
						commit
						cafb0e2277
					
				
							
								
								
									
										13
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										13
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -1014,6 +1014,7 @@ dependencies = [ | ||||
|  "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_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_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)", | ||||
| @ -1269,6 +1270,17 @@ dependencies = [ | ||||
|  "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]] | ||||
| name = "rustc-demangle" | ||||
| 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_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_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 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" | ||||
|  | ||||
| @ -45,3 +45,7 @@ rev = "df7111143e466c18d1f56377a8d9530a5a306aba" | ||||
| features = ["tera_templates", "json"] | ||||
| git = "https://github.com/SergioBenitez/Rocket" | ||||
| 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 rocket; | ||||
| extern crate rocket_contrib; | ||||
| extern crate rocket_i18n; | ||||
| extern crate serde; | ||||
| #[macro_use] | ||||
| extern crate serde_derive; | ||||
| @ -40,7 +41,6 @@ use std::env; | ||||
| 
 | ||||
| mod activity_pub; | ||||
| mod db_conn; | ||||
| mod i18n; | ||||
| mod models; | ||||
| mod schema; | ||||
| mod routes; | ||||
| @ -130,8 +130,8 @@ fn main() { | ||||
|         ]) | ||||
|         .manage(init_pool()) | ||||
|         .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(); | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user