Menu
Public repository / master
AkurAI-Framework / crates/i18n/tests/load_dir.rs
Latest change 4310a8373c9b2e01b559c8a42bd21b36b0fb950e - prefer 'is' as the default locale when present in i18n catalogs by Ólafur Búi Ólafsson
//! Integration tests that exercise `Catalogs::load_dir` against real files.
//! Uses `CARGO_TARGET_TMPDIR` (set by Cargo for integration test binaries).
use akurai_i18n::Catalogs;
use std::path::{Path, PathBuf};
fn tmp_dir(name: &str) -> PathBuf {
// `env!` reads the compile-time env var set by Cargo when compiling
// integration tests — this is the idiomatic way to get CARGO_TARGET_TMPDIR.
let dir = PathBuf::from(env!("CARGO_TARGET_TMPDIR")).join(name);
std::fs::create_dir_all(&dir).unwrap();
dir
}
fn write(dir: &Path, filename: &str, content: &str) {
std::fs::write(dir.join(filename), content).unwrap();
}
// ── basic load ────────────────────────────────────────────────────────────────
#[test]
fn loads_en_and_is_catalogs() {
let dir = tmp_dir("load_basic");
write(
&dir,
"en.json",
r#"{"hello":"Hello","greeting":"Hello, {name}!"}"#,
);
write(
&dir,
"is.json",
r#"{"hello":"Halló","greeting":"Halló, {name}!"}"#,
);
let cats = Catalogs::load_dir(&dir).unwrap();
assert_eq!(cats.translate("en", "hello"), "Hello");
assert_eq!(cats.translate("is", "hello"), "Halló");
assert_eq!(cats.default_locale(), "is");
}
// ── translate hit ─────────────────────────────────────────────────────────────
#[test]
fn translate_hit_in_requested_locale() {
let dir = tmp_dir("translate_hit");
write(&dir, "en.json", r#"{"key":"English"}"#);
write(&dir, "is.json", r#"{"key":"Íslenska"}"#);
let cats = Catalogs::load_dir(&dir).unwrap();
assert_eq!(cats.translate("is", "key"), "Íslenska");
}
// ── translate miss → fallback to default locale ───────────────────────────────
#[test]
fn translate_miss_falls_back_to_default_locale() {
let dir = tmp_dir("translate_fallback_locale");
write(&dir, "is.json", r#"{"only_in_is":"Icelandic only"}"#);
write(&dir, "en.json", r#"{}"#); // key absent
let cats = Catalogs::load_dir(&dir).unwrap();
assert_eq!(cats.translate("en", "only_in_is"), "Icelandic only");
}
// ── translate miss → fallback to key ─────────────────────────────────────────
#[test]
fn translate_miss_falls_back_to_key() {
let dir = tmp_dir("translate_fallback_key");
write(&dir, "en.json", r#"{}"#);
let cats = Catalogs::load_dir(&dir).unwrap();
assert_eq!(cats.translate("en", "app.title"), "app.title");
assert_eq!(cats.translate("fr", "app.title"), "app.title");
}
// ── placeholder interpolation ─────────────────────────────────────────────────
#[test]
fn translate_args_interpolates_placeholder() {
let dir = tmp_dir("translate_args");
write(
&dir,
"en.json",
r#"{"greeting":"Hello, {name}! You have {count} messages."}"#,
);
let cats = Catalogs::load_dir(&dir).unwrap();
let result = cats.translate_args("en", "greeting", &[("name", "Óli"), ("count", "5")]);
assert_eq!(result, "Hello, Óli! You have 5 messages.");
}
#[test]
fn translate_args_unknown_placeholder_left_verbatim() {
let dir = tmp_dir("translate_args_unknown");
write(&dir, "en.json", r#"{"msg":"Hello, {name}!"}"#);
let cats = Catalogs::load_dir(&dir).unwrap();
// no args supplied → placeholder is preserved
let result = cats.translate_args("en", "msg", &[]);
assert_eq!(result, "Hello, {name}!");
}
// ── default locale selection ──────────────────────────────────────────────────
#[test]
fn default_locale_is_en_when_present() {
let dir = tmp_dir("default_en");
write(&dir, "en.json", r#"{"x":"X"}"#);
write(&dir, "fr.json", r#"{"x":"X-fr"}"#);
let cats = Catalogs::load_dir(&dir).unwrap();
assert_eq!(cats.default_locale(), "en");
}
#[test]
fn default_locale_is_first_alphabetically_when_no_en_or_is() {
let dir = tmp_dir("default_alpha");
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
write(&dir, "de.json", r#"{"x":"X-de"}"#);
write(&dir, "fr.json", r#"{"x":"X-fr"}"#);
let cats = Catalogs::load_dir(&dir).unwrap();
// "de" < "fr" alphabetically
assert_eq!(cats.default_locale(), "de");
}
// ── non-json files are ignored ────────────────────────────────────────────────
#[test]
fn ignores_non_json_files() {
let dir = tmp_dir("ignore_non_json");
write(&dir, "en.json", r#"{"hello":"Hello"}"#);
write(&dir, "README.txt", "not a catalog");
let cats = Catalogs::load_dir(&dir).unwrap();
assert_eq!(cats.translate("en", "hello"), "Hello");
}
// ── error cases ───────────────────────────────────────────────────────────────
#[test]
fn empty_dir_returns_error() {
let dir = tmp_dir("empty_dir");
let err = Catalogs::load_dir(&dir).unwrap_err();
assert!(err.message.contains("no *.json"), "got: {}", err.message);
}
#[test]
fn invalid_json_returns_error() {
let dir = tmp_dir("bad_json");
write(&dir, "en.json", r#"not json"#);
assert!(Catalogs::load_dir(&dir).is_err());
}
#[test]
fn non_string_value_returns_error() {
let dir = tmp_dir("bad_value");
write(&dir, "en.json", r#"{"key": 42}"#);
let err = Catalogs::load_dir(&dir).unwrap_err();
assert!(
err.message.contains("must be a JSON string"),
"got: {}",
err.message
);
}