Translations report: count repeated menu entries once; list panel strings no catalog has yet (#2252)

* Translations report: count a repeated menu entry once; list panel strings no catalog has yet

* Translations report: scan the dock and dropped-file messages too
This commit is contained in:
aiongg
2026-10-23 19:19:43 -04:00
committed by GitHub
parent ffb147f3ed
commit 049070d65c
2 changed files with 50 additions and 11 deletions
+4 -6
View File
@@ -7435,7 +7435,9 @@ mod tests {
/// whose effect names come from the effect catalog instead.
fn missing_menu_entries(code: &str) -> Vec<String> {
let catalog = menu_catalog(code).unwrap_or_default();
// A label the tree repeats (one command in two menus) counts once.
let mut missing = Vec::new();
let mut seen = BTreeSet::new();
for line in TREE.lines() {
let line = line.trim().trim_start_matches("[mac] ").trim_start_matches("[!mac] ");
if line.is_empty() || line == "---" || line.starts_with('@') {
@@ -7444,7 +7446,7 @@ mod tests {
let mut parts = line.split(" | ");
let Some(en) = parts.next() else { continue };
let command = parts.next().and_then(|p| p.split_whitespace().next()).unwrap_or("");
if !catalog.iter().any(|(id, source, _)| *id == command && *source == en) {
if !catalog.iter().any(|(id, source, _)| *id == command && *source == en) && seen.insert((command, en)) {
missing.push(en.to_string());
}
}
@@ -7459,11 +7461,7 @@ mod tests {
println!("Missing translations (shown in English):");
let mut total = 0;
for code in CATALOG_CODES {
let catalogs = [
("menus", missing_menu_entries(code)),
("panels", ui::missing(code).into_iter().map(str::to_string).collect()),
("effects", effects::missing(code)),
];
let catalogs = [("menus", missing_menu_entries(code)), ("panels", ui::missing(code)), ("effects", effects::missing(code))];
let count: usize = catalogs.iter().map(|(_, missing)| missing.len()).sum();
total += count;
println!("{code}: {count}");
+46 -5
View File
@@ -80,13 +80,53 @@ fn catalog(language: &str) -> Option<&'static Index> {
Some(index.get_or_init(|| rows.iter().copied().collect()))
}
/// The panel strings `language` has no row for (every English source any catalog lists), in
/// catalog order, for the missing-strings report.
/// The panel strings `language` has no row for, for the missing-strings report: every English
/// source any catalog lists, in catalog order, then the literals the converted panels pass to `tr`
/// or `tr_args` that no catalog lists yet.
#[cfg(test)]
pub(super) fn missing(language: &str) -> Vec<&'static str> {
pub(super) fn missing(language: &str) -> Vec<String> {
let table = catalog(language);
let rows = ROWS.iter().flat_map(|(_, rows)| rows.iter().map(|(en, _)| en.to_string()));
let literals = tests::CONVERTED.iter().flat_map(|(_, src)| tr_literals(src));
let mut seen = std::collections::HashSet::new();
ROWS.iter().flat_map(|(_, rows)| rows.iter().map(|(en, _)| *en)).filter(|en| seen.insert(*en) && !table.is_some_and(|c| c.contains_key(en))).collect()
rows.chain(literals).filter(|en| !table.is_some_and(|c| c.contains_key(en.as_str())) && seen.insert(en.clone())).collect()
}
/// The string literals `src` passes to `tr(` and `tr_args(`.
#[cfg(test)]
fn tr_literals(src: &str) -> Vec<String> {
let mut out = Vec::new();
for call in ["tr(\"", "tr_args(\""] {
for (at, _) in src.match_indices(call) {
// `str("` or `attr("` is another call.
if src[..at].chars().next_back().is_some_and(|c| c.is_alphanumeric() || c == '_') {
continue;
}
out.extend(string_literal(&src[at + call.len()..]));
}
}
out
}
/// The text of the string literal `rest` starts inside (just after its opening quote), with the
/// common escapes resolved; `None` for an escape this doesn't resolve.
#[cfg(test)]
fn string_literal(rest: &str) -> Option<String> {
let mut out = String::new();
let mut chars = rest.chars();
while let Some(c) = chars.next() {
match c {
'"' => return Some(out),
'\\' => match chars.next()? {
'n' => out.push('\n'),
't' => out.push('\t'),
c @ ('\\' | '"' | '\'') => out.push(c),
_ => return None,
},
c => out.push(c),
}
}
None
}
/// Characters required by the fixed panel catalog, for system-font coverage selection.
@@ -5388,9 +5428,10 @@ mod tests {
/// The interface text that has moved into this catalog. Add a panel here when you convert it;
/// `every_row_is_used_by_a_converted_panel` then looks for its rows' English sources in it.
const CONVERTED: &[(&str, &str)] = &[
pub(super) const CONVERTED: &[(&str, &str)] = &[
("color_picker.rs", include_str!("../color_picker.rs")),
("credits.rs", include_str!("../credits.rs")),
("dock.rs", include_str!("../dock.rs")),
("dock_ui.rs", include_str!("../dock_ui.rs")),
("header.rs", include_str!("../header.rs")),
("menus.rs", include_str!("../menus.rs")),