diff --git a/README.md b/README.md index 6cf659b..4b881c9 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ rust-i18n = "2" Load macro and init translations in `lib.rs` or `main.rs`: -```rust,no_run +```rust,compile_fail,no_run // Load I18n macro, for allow you use `t!` macro in anywhere. #[macro_use] extern crate rust_i18n; diff --git a/crates/macro/src/lib.rs b/crates/macro/src/lib.rs index 448e50c..2426537 100644 --- a/crates/macro/src/lib.rs +++ b/crates/macro/src/lib.rs @@ -181,6 +181,17 @@ fn generate_code( static _RUST_I18N_FALLBACK_LOCALE: Option<&'static str> = #fallback; + /// Lookup fallback locales + /// + /// For example: `"zh-Hant-CN-x-private1-private2"` -> `"zh-Hant-CN-x-private1"` -> `"zh-Hant-CN"` -> `"zh-Hant"` -> `"zh"`. + /// + /// https://datatracker.ietf.org/doc/html/rfc4647#section-3.4 + #[inline] + #[allow(missing_docs)] + pub fn _rust_i18n_lookup_fallback(locale: &str) -> Option<&str> { + locale.rfind('-').map(|n| locale[..n].trim_end_matches("-x")) + } + /// Get I18n text by locale and key #[inline] #[allow(missing_docs)] @@ -189,6 +200,13 @@ fn generate_code( return value.to_string(); } + let mut current_locale = locale; + while let Some(fallback_locale) = _rust_i18n_lookup_fallback(current_locale) { + if let Some(value) = _RUST_I18N_BACKEND.translate(fallback_locale, key) { + return value.to_string(); + } + current_locale = fallback_locale; + } if let Some(fallback) = _RUST_I18N_FALLBACK_LOCALE { if let Some(value) = _RUST_I18N_BACKEND.translate(fallback, key) { diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 2ec5d00..e7bb3d2 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -98,7 +98,7 @@ mod tests { fn test_available_locales() { assert_eq!( rust_i18n::available_locales!(), - &["en", "ja", "pt", "zh-CN"] + &["en", "ja", "pt", "zh", "zh-CN"] ); } @@ -287,4 +287,16 @@ mod tests { "こんにちは test3" ); } + + #[test] + fn test_lookup_fallback() { + assert_eq!( + t!("missing.lookup-fallback", locale = "zh-CN"), + "在 zh-XXX 中缺失的的翻译。" + ); + assert_eq!( + t!("missing.default", locale = "zh-CN", fallback = "en"), + "This is missing key fallbacked to en." + ); + } } diff --git a/tests/locales/zh.yml b/tests/locales/zh.yml new file mode 100644 index 0000000..c436097 --- /dev/null +++ b/tests/locales/zh.yml @@ -0,0 +1,2 @@ +missing: + lookup-fallback: 在 zh-XXX 中缺失的的翻译。 \ No newline at end of file