diff --git a/Cargo.toml b/Cargo.toml index fb1ae38..fa9de50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ license = "MIT" name = "rust-i18n" readme = "README.md" repository = "https://github.com/longbridgeapp/rust-i18n" -version = "1.0.1" +version = "1.1.0" [dependencies] anyhow = {version = "1", optional = true} @@ -18,8 +18,8 @@ clap = {version = "2.32", optional = true} itertools = {version = "0.10.3", optional = true} once_cell = "1.10.0" quote = {version = "1", optional = true} -rust-i18n-extract = {path = "./crates/extract", version = ">=1.0", optional = true} -rust-i18n-macro = {path = "./crates/macro", version = ">=0.4"} +rust-i18n-extract = {path = "./crates/extract", version = ">=1.1", optional = true} +rust-i18n-macro = {path = "./crates/macro", version = ">=1.1"} serde = "1" serde_derive = "1" toml = "0.5.8" diff --git a/README.md b/README.md index ef2d3e1..be48cba 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,9 @@ rust_i18n::i18n!("locales"); fn main() { println!("{}", t!("hello")); + + // Use `available_locales` method to get all available locales. + println!("{:?}", available_locales()); } ``` diff --git a/crates/extract/Cargo.toml b/crates/extract/Cargo.toml index 1ed9614..1e2ac02 100644 --- a/crates/extract/Cargo.toml +++ b/crates/extract/Cargo.toml @@ -5,7 +5,7 @@ license = "MIT" name = "rust-i18n-extract" readme = "../../README.md" repository = "https://github.com/longbridgeapp/rust-i18n" -version = "1.0.0" +version = "1.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -15,7 +15,7 @@ ignore = "0.4" proc-macro2 = {version = "1", features = ["span-locations"]} quote = "1" regex = "1" -rust-i18n-support = {path = "../support", version = ">= 0.3"} +rust-i18n-support = {path = "../support", version = ">= 1.1"} serde = "1" serde_json = "1" serde_yaml = "0.8" diff --git a/crates/extract/src/generator.rs b/crates/extract/src/generator.rs index 3b8cfa6..02b5321 100644 --- a/crates/extract/src/generator.rs +++ b/crates/extract/src/generator.rs @@ -18,7 +18,7 @@ pub fn generate<'a, P: AsRef>( let output_path = output.as_ref().display().to_string(); let ignore_file = |fname: &str| fname.ends_with(&filename); - let old_translations = load_locales(&output_path, ignore_file); + let data = load_locales(&output_path, ignore_file); let mut new_values: HashMap = HashMap::new(); @@ -31,7 +31,7 @@ pub fn generate<'a, P: AsRef>( } } - if old_translations.get(&key).is_some() { + if data.translations.get(&key).is_some() { continue; } diff --git a/crates/macro/Cargo.toml b/crates/macro/Cargo.toml index 9788fa5..9a90a11 100644 --- a/crates/macro/Cargo.toml +++ b/crates/macro/Cargo.toml @@ -5,7 +5,7 @@ license = "MIT" name = "rust-i18n-macro" readme = "../../README.md" repository = "https://github.com/longbridgeapp/rust-i18n" -version = "0.4.0" +version = "1.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/crates/macro/src/lib.rs b/crates/macro/src/lib.rs index 92e630c..9635d09 100644 --- a/crates/macro/src/lib.rs +++ b/crates/macro/src/lib.rs @@ -34,43 +34,68 @@ pub fn i18n(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let current_dir = std::path::PathBuf::from(cargo_dir); let locales_path = current_dir.join(option.locales_path); - let translations = load_locales(&locales_path.display().to_string(), |_| false); - let code = generate_code(translations); + let data = load_locales(&locales_path.display().to_string(), |_| false); + let code = generate_code(data.translations, data.locales); if is_debug() { println!("{}", code.to_string()); - // panic!("Debug mode, show codegen."); } code.into() } -fn generate_code(translations: HashMap) -> proc_macro2::TokenStream { - let mut locales = Vec::::new(); +fn generate_code( + translations: HashMap, + locales: Vec, +) -> proc_macro2::TokenStream { + let mut all_translations = Vec::::new(); + let mut all_locales = Vec::::new(); + // For keep locales unique + let mut locale_names = HashMap::::new(); translations.iter().for_each(|(k, v)| { let k = k.to_string(); let v = v.to_string(); - locales.push(quote! { + all_translations.push(quote! { #k => #v, }); }); + locales.iter().for_each(|l| { + if locale_names.contains_key(l) { + return; + } + + locale_names.insert(l.to_string(), l.to_string()); + all_locales.push(quote! { + #l, + }); + }); + // result quote! { - static LOCALES: once_cell::sync::Lazy> = once_cell::sync::Lazy::new(|| rust_i18n::map! [ - #(#locales)* + static ALL_TRANSLATIONS: once_cell::sync::Lazy> = once_cell::sync::Lazy::new(|| rust_i18n::map! [ + #(#all_translations)* "" => "" ]); + static AVAILABLE_LOCALES: &[&'static str] = &[ + #(#all_locales)* + ]; + /// Get I18n text by locale and key pub fn translate(locale: &str, key: &str) -> String { let key = format!("{}.{}", locale, key); - match LOCALES.get(key.as_str()) { + match ALL_TRANSLATIONS.get(key.as_str()) { Some(value) => value.to_string(), None => key.to_string(), } } + + /// Return all available locales, for example: `&["en", "zh-CN"]` + pub fn available_locales() -> &'static [&'static str] { + AVAILABLE_LOCALES + } } } diff --git a/crates/support/Cargo.toml b/crates/support/Cargo.toml index f890300..9ce547a 100644 --- a/crates/support/Cargo.toml +++ b/crates/support/Cargo.toml @@ -5,7 +5,7 @@ license = "MIT" name = "rust-i18n-support" readme = "../../README.md" repository = "https://github.com/longbridgeapp/rust-i18n" -version = "1.0.0" +version = "1.1.0" [dependencies] glob = "0.3" diff --git a/crates/support/src/lib.rs b/crates/support/src/lib.rs index c5e6752..7c98a5e 100644 --- a/crates/support/src/lib.rs +++ b/crates/support/src/lib.rs @@ -25,12 +25,18 @@ pub fn merge_value(a: &mut Value, b: &Value) { } } +pub struct LocaleData { + pub translations: HashMap, + pub locales: Vec, +} + // Load locales into flatten key, value HashMap -pub fn load_locales bool>( - locales_path: &str, - ignore_if: F, -) -> HashMap { +pub fn load_locales bool>(locales_path: &str, ignore_if: F) -> LocaleData { let mut translations: Translations = HashMap::new(); + let mut data = LocaleData { + translations: HashMap::new(), + locales: Vec::new(), + }; let path_pattern = format!("{}/**/*.yml", locales_path); @@ -55,6 +61,8 @@ pub fn load_locales bool>( .unwrap() .to_string(); + data.locales.push(locale.clone()); + let file = File::open(entry).expect("Failed to open the YAML file"); let mut reader = std::io::BufReader::new(file); let mut content = String::new(); @@ -76,13 +84,12 @@ pub fn load_locales bool>( }); } - let mut locale_vars = HashMap::::new(); translations.iter().for_each(|(locale, trs)| { let new_vars = extract_vars(locale.as_str(), &trs); - locale_vars.extend(new_vars); + data.translations.extend(new_vars); }); - locale_vars + data } pub fn extract_vars(prefix: &str, trs: &Value) -> HashMap { diff --git a/tests/intergartion_test.rs b/tests/intergartion_test.rs index 3e6b62b..d21501c 100644 --- a/tests/intergartion_test.rs +++ b/tests/intergartion_test.rs @@ -5,7 +5,17 @@ mod tests { use rust_i18n::t; #[test] - fn test_foo_title() { + fn test_translate() { + assert_eq!(crate::translate("en", "hello"), "Bar - Hello, World!"); + } + + #[test] + fn test_available_locales() { + assert_eq!(crate::available_locales(), &["de", "en"]); + } + + #[test] + fn it_foo_title() { rust_i18n::set_locale("en"); assert_eq!(foo::t("hello"), "Foo - Hello, World!"); }