Adjustments after real-world testing

This commit is contained in:
Baptiste Gelez 2019-01-20 18:56:43 +01:00
parent 8d8a0ec8a8
commit 6b17e04ada

View file

@ -2,7 +2,7 @@
extern crate proc_macro; extern crate proc_macro;
use std::{env, io::{BufRead, Write}, fs::{create_dir_all, read, File, OpenOptions}, iter::FromIterator, path::Path, process::Command}; use std::{env, io::{BufRead, Write}, fs::{create_dir_all, read, File, OpenOptions}, iter::FromIterator, path::Path, process::Command};
use proc_macro::{Literal, Spacing, Punct, TokenStream, TokenTree, quote}; use proc_macro::{Delimiter, Literal, Spacing, Punct, TokenStream, TokenTree, quote};
fn is(t: &TokenTree, ch: char) -> bool { fn is(t: &TokenTree, ch: char) -> bool {
match t { match t {
@ -11,6 +11,29 @@ fn is(t: &TokenTree, ch: char) -> bool {
} }
} }
fn is_empty(t: &TokenTree) -> bool {
match t {
TokenTree::Literal(lit) => format!("{}", lit).len() == 2,
TokenTree::Group(grp) => if grp.delimiter() == Delimiter::None {
grp.stream().into_iter().next().map(|t| is_empty(&t)).unwrap_or(false)
} else {
false
},
_ => false,
}
}
fn trim(t: TokenTree) -> TokenTree {
match t {
TokenTree::Group(grp) => if grp.delimiter() == Delimiter::None {
grp.stream().into_iter().next().expect("Unexpected empty expression")
} else {
TokenTree::Group(grp)
},
x => x
}
}
#[proc_macro] #[proc_macro]
pub fn i18n(input: TokenStream) -> TokenStream { pub fn i18n(input: TokenStream) -> TokenStream {
let span = input.clone().into_iter().next().expect("Expected catalog").span(); let span = input.clone().into_iter().next().expect("Expected catalog").span();
@ -24,7 +47,11 @@ pub fn i18n(input: TokenStream) -> TokenStream {
let mut pot = OpenOptions::new().append(true).create(true).open(format!("po/{0}/{0}.pot", domain)).expect("Couldn't open .pot file"); let mut pot = OpenOptions::new().append(true).create(true).open(format!("po/{0}/{0}.pot", domain)).expect("Couldn't open .pot file");
for _ in 0..(catalog.len() + 1) { input.next(); } for _ in 0..(catalog.len() + 1) { input.next(); }
let message = input.next().unwrap(); let pot_reader = read(format!("po/{0}/{0}.pot", domain)).expect("Couldn't read .pot file");
let mut pot_lines = pot_reader.lines();
let message = trim(input.next().unwrap());
let msgid = format!("msgid {}", message);
let dont_write = is_empty(&message) || pot_lines.any(|l| l.map(|l| l == msgid).unwrap_or(false));
let plural = match input.clone().next() { let plural = match input.clone().next() {
Some(t) => if is(&t, ',') { Some(t) => if is(&t, ',') {
@ -61,24 +88,30 @@ pub fn i18n(input: TokenStream) -> TokenStream {
} }
let mut res = TokenStream::from_iter(catalog); let mut res = TokenStream::from_iter(catalog);
let code_path = if !file.is_absolute() {
format!("# {}:{}\n", file.to_str().unwrap(), line)
} else {
String::new()
};
if let Some(pl) = plural { if let Some(pl) = plural {
pot.write_all(&format!(r#" if !dont_write {
# {}:{} pot.write_all(&format!(r#"
msgid {} {}msgid {}
msgid_plural {} msgid_plural {}
msgstr[0] "" msgstr[0] ""
"#, file.to_str().unwrap(), line, message, pl).into_bytes()).expect("Couldn't write message to .pot (plural)"); "#, code_path, message, pl).into_bytes()).expect("Couldn't write message to .pot (plural)");
}
let count = format_args.clone().into_iter().next().expect("Item count should be specified").clone(); let count = format_args.clone().into_iter().next().expect("Item count should be specified").clone();
res.extend(quote!( res.extend(quote!(
.ngettext($message, $pl, $count) .ngettext($message, $pl, $count as u64)
)) ))
} else { } else {
pot.write_all(&format!(r#" if !dont_write {
# {}:{} pot.write_all(&format!(r#"
msgid {} {}msgid {}
msgstr "" msgstr ""
"#, file.to_str().unwrap(), line, message).into_bytes()).expect("Couldn't write message to .pot"); "#, code_path, message).into_bytes()).expect("Couldn't write message to .pot");
}
res.extend(quote!( res.extend(quote!(
.gettext($message) .gettext($message)
)) ))
@ -183,7 +216,7 @@ pub fn compile_i18n(_: TokenStream) -> TokenStream {
let pot_path = Path::new("po").join(domain.clone()).join(format!("{}.pot", domain)); let pot_path = Path::new("po").join(domain.clone()).join(format!("{}.pot", domain));
for lang in locales { for lang in locales {
let po_path = Path::new("po").join(format!("{}.po", lang.clone())); let po_path = Path::new("po").join(domain.clone()).join(format!("{}.po", lang.clone()));
if po_path.exists() && po_path.is_file() { if po_path.exists() && po_path.is_file() {
println!("Updating {}", lang.clone()); println!("Updating {}", lang.clone());
// Update it // Update it
@ -217,7 +250,6 @@ pub fn compile_i18n(_: TokenStream) -> TokenStream {
} }
// Generate .mo // Generate .mo
let po_path = Path::new("po").join(format!("{}.po", lang.clone()));
let mo_dir = Path::new("translations") let mo_dir = Path::new("translations")
.join(lang.clone()) .join(lang.clone())
.join("LC_MESSAGES"); .join("LC_MESSAGES");