Support for context (fixes #3)

pull/13/head
Baptiste Gelez 5 years ago
parent 3325c6b167
commit 203efc20f4

@ -1,7 +1,7 @@
#![feature(proc_macro_hygiene, proc_macro_quote, proc_macro_span, uniform_paths)]
extern crate proc_macro;
use proc_macro::{Delimiter, Literal, Spacing, Punct, TokenStream, TokenTree, quote};
use proc_macro::{Delimiter, Literal, Spacing, Punct, TokenStream, TokenTree, quote, token_stream::IntoIter as TokenIter};
use std::{
env,
fs::{create_dir_all, read, File, OpenOptions},
@ -41,6 +41,19 @@ fn trim(t: TokenTree) -> TokenTree {
}
}
fn named_arg(mut input: TokenIter, name: &'static str) -> Option<TokenStream> {
input.next().and_then(|t| match t {
TokenTree::Ident(ref i) if i.to_string() == name => {
input.next(); // skip "="
Some(input.take_while(|tok| match tok {
TokenTree::Punct(_) => false,
_ => true,
}).collect())
},
_ => None,
})
}
#[proc_macro]
pub fn i18n(input: TokenStream) -> TokenStream {
let span = input
@ -75,13 +88,19 @@ pub fn i18n(input: TokenStream) -> TokenStream {
for _ in 0..(catalog.len() + 1) {
input.next();
}
let context = named_arg(input.clone(), "context");
if let Some(c) = context.clone() {
for _ in 0..(c.into_iter().count() + 3) {
input.next();
}
}
let message = trim(input.next().expect("Expected a message to translate"));
let mut contents = String::new();
pot.read_to_string(&mut contents).expect("IO error while reading .pot file");
pot.seek(SeekFrom::End(0)).expect("IO error while seeking .pot file to end");
let already_exists = is_empty(&message) || contents.contains(&format!("msgid {}", message));
let already_exists = is_empty(&message) || contents.contains(&format!("{}msgid {}", context.clone().map(|c| format!("msgctxt {}\n", c)).unwrap_or_default(), message));
let plural = match input.clone().next() {
Some(t) => {
@ -121,9 +140,14 @@ pub fn i18n(input: TokenStream) -> TokenStream {
let mut res = TokenStream::from_iter(catalog);
let code_path = match file.to_str() {
Some(path) if !file.is_absolute() => format!("# {}:{}\n", path, line),
Some(path) if !file.is_absolute() => format!("#: {}:{}\n", path, line),
_ => String::new(),
};
let prefix = if let Some(c) = context.clone() {
format!("{}msgctxt {}\n", code_path, c)
} else {
code_path
};
if let Some(pl) = plural {
if !already_exists {
pot.write_all(
@ -133,7 +157,7 @@ pub fn i18n(input: TokenStream) -> TokenStream {
msgid_plural {}
msgstr[0] ""
"#,
code_path,
prefix,
message,
pl
)
@ -147,9 +171,15 @@ msgstr[0] ""
.next()
.expect("Item count should be specified")
.clone();
res.extend(quote!(
.ngettext($message, $pl, $count as u64)
))
if let Some(c) = context {
res.extend(quote!(
.npgettext($c, $message, $pl, $count as u64)
))
} else {
res.extend(quote!(
.ngettext($message, $pl, $count as u64)
))
}
} else {
if !already_exists {
pot.write_all(
@ -158,17 +188,22 @@ msgstr[0] ""
{}msgid {}
msgstr ""
"#,
code_path,
prefix,
message
)
.into_bytes(),
)
.expect("Couldn't write message to .pot");
}
res.extend(quote!(
.gettext($message)
))
if let Some(c) = context {
res.extend(quote!(
.pgettext($c, $message)
))
} else {
res.extend(quote!(
.gettext($message)
))
}
}
let mut args = vec![];
let mut first = true;

@ -10,6 +10,9 @@ fn main() {
let cat = &catalogs[0].1;
let x = i18n!(cat, "Hello");
let b = i18n!(cat, "Singular", "Plural"; 0);
i18n!(cat, context = "Test context", "Hello");
i18n!(cat, context = "Test context (plural)", "Hello", "Plural"; 2);
i18n!(cat, context = "Test context (format)", "Hello {}"; "world");
println!("{} {}", x, b);
println!("{}", i18n!(cat, "Woohoo, it {}"; "works"));
println!(i18n_domain!());

Loading…
Cancel
Save