pub const CLIENT_LANGS: &[&str] = &[
"en_us", "af_za", "ar_sa", "ast_es", "az_az", "ba_ru", "bar", "be_by", "be_latn", "bg_bg",
"br_fr", "brb", "bs_ba", "ca_es", "cs_cz", "cv_cu", "cy_gb", "da_dk", "de_at", "de_ch",
"de_de", "el_gr", "en_au", "en_ca", "en_gb", "en_nz", "en_pt", "en_ud", "enp", "enws", "eo_uy",
"es_ar", "es_cl", "es_ec", "es_es", "es_mx", "es_uy", "es_ve", "esan", "et_ee", "eu_es",
"fa_ir", "fi_fi", "fil_ph", "fo_fo", "fr_ca", "fr_ch", "fr_fr", "fra_de", "fur_it", "fy_nl",
"ga_ie", "gd_gb", "gl_es", "go_fr", "got_de", "hal_ua", "haw_us", "he_il", "hi_in", "hn_no",
"hr_hr", "hu_hu", "hy_am", "id_id", "ig_ng", "io_en", "is_is", "isv", "it_it", "ja_jp",
"jbo_en", "ka_ge", "kk_kz", "kn_in", "ko_kr", "ksh", "kw_gb", "ky_kg", "la_la", "lb_lu",
"li_li", "lmo", "lo_la", "lol_us", "lt_lt", "lv_lv", "lzh", "mk_mk", "mn_mn", "ms_my", "mt_mt",
"nah", "nds_de", "nl_be", "nl_nl", "nn_no", "no_no", "oc_fr", "ovd", "pl_pl", "pls", "pt_br",
"pt_pt", "qcb_es", "qid", "qya_aa", "ro_ro", "rpr", "ru_ru", "ry_ua", "sah_sah", "se_no",
"sk_sk", "sl_si", "so_so", "sq_al", "sr_cs", "sr_sp", "sv_se", "sxu", "szl", "ta_in", "th_th",
"tl_ph", "tlh_aa", "tok", "tr_tr", "tt_ru", "tzo_mx", "uk_ua", "uz_uz", "val_es", "vec_it",
"vi_vn", "vp_vl", "vro", "yi_de", "yo_ng", "zh_cn", "zh_hk", "zh_tw", "zlm_arab",
];
pub fn mc_lang_code(code: &str) -> Option<&'static str> {
let norm = code.to_ascii_lowercase().replace('-', "_");
if norm == "en" {
return Some("en_us");
}
if let Some(hit) = CLIENT_LANGS.iter().find(|c| **c == norm) {
return Some(hit);
}
if norm.contains('_') {
return None;
}
let prefix = format!("{norm}_");
let mut matches = CLIENT_LANGS.iter().filter(|c| c.starts_with(&prefix));
let first = matches.next()?;
let doubled = format!("{norm}_{norm}");
if let Some(hit) = CLIENT_LANGS.iter().find(|c| **c == doubled) {
return Some(hit);
}
match matches.next() {
None => Some(first),
Some(_) => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn table_is_the_derived_set() {
assert_eq!(CLIENT_LANGS[0], "en_us");
assert_eq!(
CLIENT_LANGS.len(),
143,
"142 asset-index language files + en_us from the jar"
);
let rest = &CLIENT_LANGS[1..];
assert!(
rest.windows(2).all(|w| w[0] < w[1]),
"the derived table must stay sorted and unique"
);
}
#[test]
fn superset_of_the_previous_hand_table() {
for (declared, mc) in [
("en", "en_us"),
("en-us", "en_us"),
("en-gb", "en_gb"),
("zh-cn", "zh_cn"),
("zh-tw", "zh_tw"),
("zh-hk", "zh_hk"),
("ja", "ja_jp"),
("ja-jp", "ja_jp"),
("ko", "ko_kr"),
("ko-kr", "ko_kr"),
("de", "de_de"),
("de-de", "de_de"),
("fr", "fr_fr"),
("fr-fr", "fr_fr"),
("es", "es_es"),
("es-es", "es_es"),
("es-mx", "es_mx"),
("pt-br", "pt_br"),
("pt", "pt_pt"),
("pt-pt", "pt_pt"),
("ru", "ru_ru"),
("ru-ru", "ru_ru"),
("it", "it_it"),
("it-it", "it_it"),
("pl", "pl_pl"),
("pl-pl", "pl_pl"),
("nl", "nl_nl"),
("nl-nl", "nl_nl"),
("tr", "tr_tr"),
("tr-tr", "tr_tr"),
("uk", "uk_ua"),
("uk-ua", "uk_ua"),
("cs", "cs_cz"),
("cs-cz", "cs_cz"),
("sv", "sv_se"),
("sv-se", "sv_se"),
("th", "th_th"),
("th-th", "th_th"),
("vi", "vi_vn"),
("vi-vn", "vi_vn"),
("id", "id_id"),
("id-id", "id_id"),
] {
assert_eq!(mc_lang_code(declared), Some(mc), "`{declared}`");
}
}
#[test]
fn ambiguity_and_invention_are_rejected() {
for bad in ["zh", "sr", "be", "xx", "de-xx", "klingon", ""] {
assert_eq!(mc_lang_code(bad), None, "`{bad}` must not resolve");
}
}
}