use language_tags::LanguageTag;
const DEFAULT_LOCALE: &str = "en";
fn best_matching_locale<T1, T2>(available_locales: impl Iterator<Item = T1>, user_locales: impl Iterator<Item = T2>) -> Option<String>
where
T1: AsRef<str>,
T2: AsRef<str>
{
let available_tags = available_locales
.filter_map(|l| LanguageTag::parse(l.as_ref()).ok())
.collect::<Vec<LanguageTag>>();
user_locales
.filter_map(|locale| LanguageTag::parse(locale.as_ref()).ok())
.find_map(|user_tag|
available_tags.iter()
.rev() .filter(|aval_tag| aval_tag.primary_language() == user_tag.primary_language())
.max_by_key(|aval_tag| {
let mut score = 0;
for (aval, user, weight) in [
(aval_tag.extended_language(), user_tag.extended_language(), 32),
(aval_tag.script(), user_tag.script(), 16),
(aval_tag.region(), user_tag.region(), 8),
(aval_tag.variant(), user_tag.variant(), 4),
(aval_tag.extension(), user_tag.extension(), 2),
(aval_tag.private_use(), user_tag.private_use(), 1),
] {
match (aval, user) {
(Some(a), Some(u)) if a == u => score += weight,
_ => {} }
}
score
})
)
.map(|aval_tag| aval_tag.to_string())
}
pub fn set_rust_i18n_locale() {
rust_i18n::set_locale(&best_matching_locale(rust_i18n::available_locales!().iter(), sys_locale::get_locales()).unwrap_or(DEFAULT_LOCALE.to_string()));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_best_matching_locale() {
fn check_best_match(available_locales: &[&str], user_locales: &[&str], expected: Option<&str>) -> bool {
best_matching_locale(available_locales.iter(), user_locales.iter()).as_deref() == expected
}
assert!(check_best_match(&["en-US", "ru-RU"], &["ru", "en"], Some("ru-RU")));
assert!(check_best_match(&["en-US", "ru-RU"], &["en", "ru"], Some("en-US")));
assert!(check_best_match(&["en-US", "en-GB", "ru-UA", "fr-FR", "it"], &["ru-RU", "ru", "en-US", "en"], Some("ru-UA")));
assert!(check_best_match(&["en-US", "en-GB", "ru-UA", "fr-FR", "it"], &["en-US", "en", "ru-RU", "ru"], Some("en-US")));
assert!(check_best_match(&["en", "pt-BR", "pt-PT", "es"], &["pt", "en"], Some("pt-BR")));
assert!(check_best_match(&["kk"], &["en", "en-US", "fr-FR", "fr", "it", "pt", "ru-RU", "es-ES", "kk-KZ"], Some("kk")));
assert!(check_best_match(&["en", "en-US", "fr-FR", "fr", "it", "pt", "ru-RU", "es-ES", "kk-KZ", "pt"], &["pt-PT"], Some("pt")));
assert!(check_best_match(&["en", "en-US", "fr-FR", "fr", "it", "pt", "es-ES", "kk-KZ", "pt"], &["ru"], None));
assert!(check_best_match(&["en", "en-US", "fr-FR", "fr", "pt"], &["id"], None));
assert!(check_best_match(&["ru", "be", "uk", "kk"], &["en"], None));
assert!(check_best_match(&[], &["en", "fr", "it", "pt"], None));
assert!(check_best_match(&["en", "fr", "it", "pt"], &[], None));
assert!(check_best_match(&[], &[], None));
assert!(check_best_match(&["zh", "zh-cmn", "zh-cmn-Hans"], &["zh-cmn-SG"], Some("zh-cmn")));
assert!(check_best_match(&["zh", "zh-cmn", "zh-cmn-Hans", "zh-cmn-Hans-SG"], &["zh-cmn-SG"], Some("zh-cmn-Hans-SG")));
assert!(check_best_match(&["zh", "zh-cmn", "zh-cmn-Hans-SG"], &["zh-Hans"], Some("zh-cmn-Hans-SG")));
assert!(check_best_match(&["zh", "zh-cmn", "zh-cmn-Hans", "zh-cmn-Hans-SG"], &["zh-Hans"], Some("zh-cmn-Hans")));
assert!(check_best_match(&["zh", "zh-cmn", "zh-cmn-Hans", "zh-cmn-Hans-SG"], &["zh-SG"], Some("zh-cmn-Hans-SG")));
assert!(check_best_match(&["zh", "he"], &["he-IL-u-ca-hebrew-tz-jeruslm", "zh"], Some("he")));
assert!(check_best_match(&["zh", "he-IL-u-ca-hebrew-tz-jeruslm-nu-latn"], &["he", "zh"], Some("he-IL-u-ca-hebrew-tz-jeruslm-nu-latn")));
assert!(check_best_match(&["ar-u-nu-latn", "ar"], &["ar-u-no-latn", "ar", "en-US", "en"], Some("ar-u-nu-latn")));
assert!(check_best_match(&["fr-FR-u-em-text", "gsw-u-em-emoji"], &["gsw-u-em-text"], Some("gsw-u-em-emoji")));
assert!(check_best_match(&["en-US-SUS-BUS-VUS-GUS"], &["en"], None));
assert!(check_best_match(&["en-abcdefghijklmnopqrstuvwxyz"], &["en"], None));
assert!(check_best_match(&["ru-ЖЖЯЯ"], &["ru"], None));
assert!(check_best_match(&["ru--"], &["ru"], None));
assert!(check_best_match(&["", "@", "!!!", "721345"], &["en", "", "@", "!!!", "721345"], None));
assert!(check_best_match(&["en", "en", "en", "en"], &["ru-RU", "ru", "en-US", "en"], Some("en")));
assert!(check_best_match(&["en-US", "en-GB", "ru-UA", "fr-FR", "it"], &["kk", "ru", "pt", "ru"], Some("ru-UA")));
assert!(check_best_match(&["!!!!!!", "qwydgn12i6i", "ЖЖяяЖяЬЬЬ", "en-US", "!*&^^&*", "qweqweqweqwe-qweqwe", "ru-RU", "@@", "@"], &["ru", "en"], Some("ru-RU")));
assert!(check_best_match(&["", "", "", "zh", "", "", "", "", "", "he", "", ""], &["he-IL-u-ca-hebrew-tz-jeruslm", "", "", "zh"], Some("he")));
assert!(check_best_match(&["bla-!@#", "12345", "en-US", "en-GB", "ru-UA", "fr-FR", "it"], &["bla-!@#", "12345", "en-US", "en", "ru-RU", "ru"], Some("en-US")));
}
}