Add full set of locale translations
Generated using Claude Code / Codex so there may be errors
This commit is contained in:
112
src/i18n.rs
112
src/i18n.rs
@@ -1,7 +1,10 @@
|
||||
pub use rust_i18n::t;
|
||||
|
||||
/// Available UI locale codes. Separate from dictionary language support.
|
||||
pub const SUPPORTED_UI_LOCALES: &[&str] = &["en", "de"];
|
||||
pub const SUPPORTED_UI_LOCALES: &[&str] = &[
|
||||
"en", "de", "es", "fr", "it", "pt", "nl", "sv", "da", "nb", "fi", "pl", "cs", "ro", "hr",
|
||||
"hu", "lt", "lv", "sl", "et", "tr",
|
||||
];
|
||||
|
||||
pub fn set_ui_locale(locale: &str) {
|
||||
let effective = if SUPPORTED_UI_LOCALES.contains(&locale) {
|
||||
@@ -74,70 +77,85 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn catalog_parity_en_de() {
|
||||
fn catalog_parity_all_locales() {
|
||||
let en = locale_keys("en");
|
||||
let de = locale_keys("de");
|
||||
let mut errors = Vec::new();
|
||||
|
||||
let missing_in_de: Vec<_> = en.difference(&de).collect();
|
||||
let extra_in_de: Vec<_> = de.difference(&en).collect();
|
||||
for locale in SUPPORTED_UI_LOCALES {
|
||||
if *locale == "en" {
|
||||
continue;
|
||||
}
|
||||
let other = locale_keys(locale);
|
||||
let missing: Vec<_> = en.difference(&other).collect();
|
||||
let extra: Vec<_> = other.difference(&en).collect();
|
||||
|
||||
assert!(
|
||||
missing_in_de.is_empty(),
|
||||
"Keys in en.yml missing from de.yml:\n {}",
|
||||
missing_in_de
|
||||
.iter()
|
||||
.map(|k| k.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n ")
|
||||
);
|
||||
assert!(
|
||||
extra_in_de.is_empty(),
|
||||
"Keys in de.yml not present in en.yml:\n {}",
|
||||
extra_in_de
|
||||
.iter()
|
||||
.map(|k| k.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n ")
|
||||
);
|
||||
if !missing.is_empty() {
|
||||
errors.push(format!(
|
||||
"Keys in en.yml missing from {locale}.yml:\n {}",
|
||||
missing
|
||||
.iter()
|
||||
.map(|k| k.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n ")
|
||||
));
|
||||
}
|
||||
if !extra.is_empty() {
|
||||
errors.push(format!(
|
||||
"Keys in {locale}.yml not present in en.yml:\n {}",
|
||||
extra
|
||||
.iter()
|
||||
.map(|k| k.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n ")
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
assert!(errors.is_empty(), "Catalog parity errors:\n{}", errors.join("\n"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn placeholder_parity_en_de() {
|
||||
fn placeholder_parity_all_locales() {
|
||||
let en_content = std::fs::read_to_string("locales/en.yml").unwrap();
|
||||
let de_content = std::fs::read_to_string("locales/de.yml").unwrap();
|
||||
let en_root: serde_yaml::Value = serde_yaml::from_str(&en_content).unwrap();
|
||||
let de_root: serde_yaml::Value = serde_yaml::from_str(&de_content).unwrap();
|
||||
|
||||
let mut en_map = std::collections::BTreeMap::new();
|
||||
let mut de_map = std::collections::BTreeMap::new();
|
||||
collect_leaf_values(&en_root, "", &mut en_map);
|
||||
collect_leaf_values(&de_root, "", &mut de_map);
|
||||
|
||||
let placeholder_re = regex::Regex::new(r"%\{(\w+)\}").unwrap();
|
||||
let mut mismatches = Vec::new();
|
||||
let mut all_mismatches = Vec::new();
|
||||
|
||||
for (key, en_val) in &en_map {
|
||||
if let Some(de_val) = de_map.get(key) {
|
||||
let en_placeholders: BTreeSet<_> = placeholder_re
|
||||
.captures_iter(en_val)
|
||||
.map(|c| c[1].to_string())
|
||||
.collect();
|
||||
let de_placeholders: BTreeSet<_> = placeholder_re
|
||||
.captures_iter(de_val)
|
||||
.map(|c| c[1].to_string())
|
||||
.collect();
|
||||
if en_placeholders != de_placeholders {
|
||||
mismatches.push(format!(
|
||||
" {key}: en={en_placeholders:?} de={de_placeholders:?}"
|
||||
));
|
||||
for locale in SUPPORTED_UI_LOCALES {
|
||||
if *locale == "en" {
|
||||
continue;
|
||||
}
|
||||
let other_content = std::fs::read_to_string(format!("locales/{locale}.yml")).unwrap();
|
||||
let other_root: serde_yaml::Value = serde_yaml::from_str(&other_content).unwrap();
|
||||
let mut other_map = std::collections::BTreeMap::new();
|
||||
collect_leaf_values(&other_root, "", &mut other_map);
|
||||
|
||||
for (key, en_val) in &en_map {
|
||||
if let Some(other_val) = other_map.get(key) {
|
||||
let en_placeholders: BTreeSet<_> = placeholder_re
|
||||
.captures_iter(en_val)
|
||||
.map(|c| c[1].to_string())
|
||||
.collect();
|
||||
let other_placeholders: BTreeSet<_> = placeholder_re
|
||||
.captures_iter(other_val)
|
||||
.map(|c| c[1].to_string())
|
||||
.collect();
|
||||
if en_placeholders != other_placeholders {
|
||||
all_mismatches.push(format!(
|
||||
" {locale}/{key}: en={en_placeholders:?} {locale}={other_placeholders:?}"
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert!(
|
||||
mismatches.is_empty(),
|
||||
"Placeholder mismatches between en.yml and de.yml:\n{}",
|
||||
mismatches.join("\n")
|
||||
all_mismatches.is_empty(),
|
||||
"Placeholder mismatches:\n{}",
|
||||
all_mismatches.join("\n")
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user