internationalization-rs/build.rs

83 lines
2.4 KiB
Rust

use glob::glob;
use proc_macro2::TokenStream;
use quote::quote;
use std::collections::HashMap;
use std::fs::File;
use std::io::prelude::*;
type Key = String;
type Locale = String;
type Value = String;
type Translations = HashMap<Key, HashMap<Locale, Value>>;
fn read_locales() -> Translations {
let mut translations: Translations = HashMap::new();
let build_directory = std::env::var("PWD").unwrap();
let locales = format!("{}/**/locales/**/*.json", build_directory);
println!("Reading {}", &locales);
for entry in glob(&locales).expect("Failed to read glob pattern") {
let entry = entry.unwrap();
println!("cargo:rerun-if-changed={}", entry.display());
let file = File::open(entry).expect("Failed to open the file");
let mut reader = std::io::BufReader::new(file);
let mut content = String::new();
reader
.read_to_string(&mut content)
.expect("Failed to read the file");
let res: HashMap<String, HashMap<String, String>> =
serde_json::from_str(&content).expect("Cannot parse locale file");
translations.extend(res);
}
translations
}
fn generate_code(translations: Translations) -> proc_macro2::TokenStream {
let mut branches = Vec::<TokenStream>::new();
for (key, trs) in translations {
let mut langs = Vec::<TokenStream>::new();
for (lang, tr) in trs {
let l = quote! {
#lang => #tr,
};
langs.push(l)
}
let branch = quote! {
(#key, $lang:expr) => {
match $lang.as_ref() {
#(#langs)*
e => panic!("Missing language: {}", e)
}
};
};
branches.push(branch);
}
quote! {
#[macro_export]
macro_rules! t {
#(#branches)*
($key:expr, $lang:expr) => {
compile_error!("Missing translation");
}
}
}
}
fn write_code(code: TokenStream) {
let dest = std::env::var("OUT_DIR").unwrap();
let mut output = File::create(&std::path::Path::new(&dest).join("i18n.rs")).unwrap();
output
.write(code.to_string().as_bytes())
.expect("Cannot write generated i18n code");
}
fn main() {
let translations = read_locales();
let code = generate_code(translations);
println!("{}", &code);
write_code(code);
}