From af36c56e7585e695535b0c75e66e37115dcbdb48 Mon Sep 17 00:00:00 2001 From: Nathaniel Ledford Date: Tue, 27 Oct 2026 23:04:23 -0400 Subject: [PATCH] i18n: the translation gaps report skips the tests.rs files of the new layout A file named tests.rs is the body of a #[cfg(test)] mod tests; line, so its strings are test code: the report listed them as app messages since the files moved out of their #[cfg(test)] blocks. source_files skips tests.rs as it skips tests_*.rs and tests/; the module doc says so. Test: a_file_named_tests_rs_is_test_code_and_is_not_read (failed before: tests.rs was listed). Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/i18n/gaps.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/crates/ui-egui/src/i18n/gaps.rs b/crates/ui-egui/src/i18n/gaps.rs index f14bd0a58..4bd6073d4 100644 --- a/crates/ui-egui/src/i18n/gaps.rs +++ b/crates/ui-egui/src/i18n/gaps.rs @@ -4,8 +4,8 @@ //! catalog and the report could not name it. This reads the source for them: every `tr("…")` / //! `.tr("…")` call in `crates/ui-egui/src` and `apps/lightcraft/src` whose argument is one string //! literal (a trailing comma, as rustfmt leaves in a wrapped call, is fine), or an `if`/`match` -//! whose branches are literals (`tr(if on { "On" } else { "Off" })`). Test code (`tests_*.rs` -//! files, `tests/` folders and items under exactly `#[cfg(test)]`) is skipped. The scanner lexes +//! whose branches are literals (`tr(if on { "On" } else { "Off" })`). Test code (`tests.rs` and +//! `tests_*.rs` files, `tests/` folders and items under exactly `#[cfg(test)]`) is skipped. The scanner lexes //! the source (comments, strings, raw strings and chars) rather than grepping it, so a `tr(` in a //! comment or a string is not a use. //! @@ -320,7 +320,7 @@ fn source_files(dir: &Path, out: &mut Vec) { if name != "tests" { source_files(&path, out); } - } else if name.ends_with(".rs") && !name.starts_with("tests_") { + } else if name.ends_with(".rs") && name != "tests.rs" && !name.starts_with("tests_") { out.push(path); } } @@ -351,6 +351,23 @@ pub(super) fn source_messages() -> BTreeSet { mod tests { use super::*; + #[test] + fn a_file_named_tests_rs_is_test_code_and_is_not_read() { + // Given a folder with a file of the app and the `tests.rs` of a `#[cfg(test)] mod tests;` + let dir = std::env::temp_dir().join(format!("lightcraft-gaps-{}", std::process::id())); + fs::create_dir_all(dir.join("sub")).unwrap(); + for file in ["app.rs", "sub/tests.rs", "sub/widget.rs"] { + fs::write(dir.join(file), "").unwrap(); + } + // When the source files are listed + let mut files = Vec::new(); + source_files(&dir, &mut files); + let names: Vec = files.iter().map(|path| path.strip_prefix(&dir).unwrap().display().to_string()).collect(); + fs::remove_dir_all(&dir).unwrap(); + // Then the tests.rs is not among them + assert_eq!(names, ["app.rs", "sub/widget.rs"]); + } + #[test] fn the_scanner_reads_literals_and_skips_comments_strings_and_tests() { let source = r##"