mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-24 10:09:32 -06:00
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:
@@ -7435,7 +7435,9 @@ mod tests {
|
|||||||
/// whose effect names come from the effect catalog instead.
|
/// whose effect names come from the effect catalog instead.
|
||||||
fn missing_menu_entries(code: &str) -> Vec<String> {
|
fn missing_menu_entries(code: &str) -> Vec<String> {
|
||||||
let catalog = menu_catalog(code).unwrap_or_default();
|
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 missing = Vec::new();
|
||||||
|
let mut seen = BTreeSet::new();
|
||||||
for line in TREE.lines() {
|
for line in TREE.lines() {
|
||||||
let line = line.trim().trim_start_matches("[mac] ").trim_start_matches("[!mac] ");
|
let line = line.trim().trim_start_matches("[mac] ").trim_start_matches("[!mac] ");
|
||||||
if line.is_empty() || line == "---" || line.starts_with('@') {
|
if line.is_empty() || line == "---" || line.starts_with('@') {
|
||||||
@@ -7444,7 +7446,7 @@ mod tests {
|
|||||||
let mut parts = line.split(" | ");
|
let mut parts = line.split(" | ");
|
||||||
let Some(en) = parts.next() else { continue };
|
let Some(en) = parts.next() else { continue };
|
||||||
let command = parts.next().and_then(|p| p.split_whitespace().next()).unwrap_or("");
|
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());
|
missing.push(en.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7459,11 +7461,7 @@ mod tests {
|
|||||||
println!("Missing translations (shown in English):");
|
println!("Missing translations (shown in English):");
|
||||||
let mut total = 0;
|
let mut total = 0;
|
||||||
for code in CATALOG_CODES {
|
for code in CATALOG_CODES {
|
||||||
let catalogs = [
|
let catalogs = [("menus", missing_menu_entries(code)), ("panels", ui::missing(code)), ("effects", effects::missing(code))];
|
||||||
("menus", missing_menu_entries(code)),
|
|
||||||
("panels", ui::missing(code).into_iter().map(str::to_string).collect()),
|
|
||||||
("effects", effects::missing(code)),
|
|
||||||
];
|
|
||||||
let count: usize = catalogs.iter().map(|(_, missing)| missing.len()).sum();
|
let count: usize = catalogs.iter().map(|(_, missing)| missing.len()).sum();
|
||||||
total += count;
|
total += count;
|
||||||
println!("{code}: {count}");
|
println!("{code}: {count}");
|
||||||
|
|||||||
@@ -80,13 +80,53 @@ fn catalog(language: &str) -> Option<&'static Index> {
|
|||||||
Some(index.get_or_init(|| rows.iter().copied().collect()))
|
Some(index.get_or_init(|| rows.iter().copied().collect()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The panel strings `language` has no row for (every English source any catalog lists), in
|
/// The panel strings `language` has no row for, for the missing-strings report: every English
|
||||||
/// catalog order, for the missing-strings report.
|
/// 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)]
|
#[cfg(test)]
|
||||||
pub(super) fn missing(language: &str) -> Vec<&'static str> {
|
pub(super) fn missing(language: &str) -> Vec<String> {
|
||||||
let table = catalog(language);
|
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();
|
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.
|
/// 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;
|
/// 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.
|
/// `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")),
|
("color_picker.rs", include_str!("../color_picker.rs")),
|
||||||
("credits.rs", include_str!("../credits.rs")),
|
("credits.rs", include_str!("../credits.rs")),
|
||||||
|
("dock.rs", include_str!("../dock.rs")),
|
||||||
("dock_ui.rs", include_str!("../dock_ui.rs")),
|
("dock_ui.rs", include_str!("../dock_ui.rs")),
|
||||||
("header.rs", include_str!("../header.rs")),
|
("header.rs", include_str!("../header.rs")),
|
||||||
("menus.rs", include_str!("../menus.rs")),
|
("menus.rs", include_str!("../menus.rs")),
|
||||||
|
|||||||
Reference in New Issue
Block a user