Skip to content

Instantly share code, notes, and snippets.

@Kampfkarren
Created January 22, 2019 07:07
Show Gist options
  • Save Kampfkarren/a0332b035b80f27a2f1ae9f7f59e7b9d to your computer and use it in GitHub Desktop.
Save Kampfkarren/a0332b035b80f27a2f1ae9f7f59e7b9d to your computer and use it in GitHub Desktop.
use lazy_static::lazy_static;
use std::collections::{HashMap, HashSet};
use std::env;
use std::fs;
use std::path::{Component, Path};
use std::process;
use walkdir::WalkDir;
lazy_static! {
static ref SOURCE: &'static str = option_env!("SOURCE_LANGUAGE").unwrap_or("en-us");
}
fn escape(text: &str) -> String {
format!("\"{}\"", text.to_string().replace("\"", "\"\""))
}
#[test]
fn test_escape() {
assert_eq!(escape("hello"), "\"hello\"");
assert_eq!(
escape("doge said \"i am doge\""),
"\"doge said \"\"i am doge\"\"\""
);
assert_eq!(escape("comma, comma"), "\"comma, comma\"");
}
fn full_path(path: &Path) -> (String, String) {
let mut components = path.components();
let first = components
.next()
.expect("no directory?")
.as_os_str()
.to_string_lossy();
let last = &components
.next_back()
.expect("no file?")
.as_os_str()
.to_string_lossy();
let last = &last[0..last.len() - 5];
let full_name = components.fold(String::new(), |current, component| {
if let Component::Normal(normal) = &component {
current + &normal.to_string_lossy() + "."
} else {
unimplemented!();
}
});
(
if first == *SOURCE {
"Source".to_string()
} else {
first.to_string()
},
format!("{}{}", full_name, last),
)
}
#[test]
fn test_full_path() {
assert_eq!(
full_path(&Path::new("es-es/foo.toml")),
("es-es".to_string(), "foo".to_string()),
);
assert_eq!(
full_path(&Path::new("es-es/foo/bar/baz.toml")),
("es-es".to_string(), "foo.bar.baz".to_string()),
);
assert_eq!(
full_path(&Path::new("en-us/foo.toml")),
("Source".to_string(), "foo".to_string()),
);
}
type Language = String;
type TranslationPath = String;
fn main() {
println!("battle hats localization tool");
let directory = {
if let Some(directory) = env::args().nth(1) {
directory
} else {
eprintln!("No directory passed in.");
process::exit(1);
}
};
let mut langs: HashSet<Language> = HashSet::new();
let mut map: HashMap<TranslationPath, HashMap<String, HashMap<Language, String>>> =
HashMap::new();
for entry in WalkDir::new(&directory)
.min_depth(1)
.into_iter()
.filter_map(|x| x.ok())
.filter(|x| x.path().is_file())
{
if let Ok(path) = entry.path().strip_prefix(&directory) {
let contents: HashMap<String, String> =
toml::from_str(&fs::read_to_string(entry.path()).expect("couldn't read?")).unwrap();
let full_path = full_path(path);
langs.insert(full_path.0.clone());
let translation_path = map.entry(full_path.1).or_default();
for (key, text) in contents.into_iter() {
translation_path
.entry(key)
.or_default()
.insert(full_path.0.clone(), text);
}
}
}
// Collect langs in order
let langs = langs.into_iter().collect::<Vec<Language>>();
let mut csv = langs
.iter()
.fold("Key,Context,Example,".to_string(), |current, lang| {
current + &lang + ","
});
csv.pop();
for (translation_path, map) in map.into_iter() {
for (key, language_and_text) in map.into_iter() {
csv.push_str(&format!("\n{}.{},,,", translation_path, key));
for language in &langs {
csv.push_str(&format!(
"{},",
escape(language_and_text.get(language).unwrap_or(&"".to_string()))
));
}
csv.pop();
}
}
println!("{}", csv);
fs::write("./Localization.csv", csv).expect("couldn't write to Localization.csv");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment