From 314f82eba02b0a58800a0a9388574b65cd9db868 Mon Sep 17 00:00:00 2001 From: Losminek <301412321+Losminek@users.noreply.github.com> Date: Sun, 11 Oct 2026 19:29:24 +0200 Subject: [PATCH] i18n (cs): translate status-bar messages The status line showed English for the messages the UI composes itself. Literal messages and templates now go through `tr` at their call sites ("Packaged {count} files into {dir}" and similar), the ": " messages share a small `DesignApp::status_error` helper that translates the feature name, and "Home" is translated too. Engine error texts stay as the engine wrote them. Adds the Czech strings, the stale-key allow-list entries and a test for the helper. Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/chrome.rs | 4 ++-- crates/ui-egui/src/dialogs.rs | 7 +++--- crates/ui-egui/src/i18n.rs | 13 ++++++++++++ crates/ui-egui/src/i18n/cs.rs | 18 ++++++++++++++++ crates/ui-egui/src/lib.rs | 27 ++++++++++++++++++++---- crates/ui-egui/src/menus.rs | 10 ++++----- crates/ui-egui/src/panel_docking.rs | 2 +- crates/ui-egui/src/panels/conditions.rs | 6 +++--- crates/ui-egui/src/panels/glyphs.rs | 2 +- crates/ui-egui/src/panels/interactive.rs | 16 +++++++------- crates/ui-egui/src/panels/library.rs | 22 +++++++++++-------- crates/ui-egui/src/panels/notes.rs | 2 +- crates/ui-egui/src/panels/properties.rs | 4 ++-- crates/ui-egui/src/panels/table.rs | 6 +++--- 14 files changed, 97 insertions(+), 42 deletions(-) diff --git a/crates/ui-egui/src/chrome.rs b/crates/ui-egui/src/chrome.rs index 2896fcdc4..bfc917945 100644 --- a/crates/ui-egui/src/chrome.rs +++ b/crates/ui-egui/src/chrome.rs @@ -121,7 +121,7 @@ pub fn app_bar(app: &mut DesignApp, ui: &mut egui::Ui) { ); ui.add_space(6.0); if icons::button(ui, "share", 22.0, false, crate::i18n::tr(&app.ui.language, "Share")).clicked() { - app.status("Export a PDF, IDML or package to share — no cloud account needed."); + app.status(crate::i18n::tr(&app.ui.language, "Export a PDF, IDML or package to share — no cloud account needed.")); } ui.add_space(8.0); // Always one click away: the ArtCraft community Discord. @@ -157,7 +157,7 @@ pub fn app_bar(app: &mut DesignApp, ui: &mut egui::Ui) { impl DesignApp { fn session_home(&mut self) { - self.ui.status = "Home".into(); + self.ui.status = crate::i18n::tr(&self.ui.language, "Home").into(); } } diff --git a/crates/ui-egui/src/dialogs.rs b/crates/ui-egui/src/dialogs.rs index 2ab7a3bad..371b5b6ac 100644 --- a/crates/ui-egui/src/dialogs.rs +++ b/crates/ui-egui/src/dialogs.rs @@ -140,7 +140,7 @@ fn user_dictionary(app: &mut DesignApp, ui: &mut egui::Ui, d: &mut Dialog) { Ok(_) => { d.fields.insert("word".into(), json!("")); } - Err(e) => app.status(format!("User Dictionary: {e}")), + Err(e) => app.status_error("User Dictionary", e), } } } @@ -1474,7 +1474,7 @@ pub fn show(app: &mut DesignApp, ctx: &egui::Context) { let f = app.session.execute("color.settings", &json!({})).unwrap_or_default(); d.fields.insert("profiles".into(), f["profiles"].clone()); } - Err(e) => app.status(format!("Color Settings: {e}")), + Err(e) => app.status_error("Color Settings", e), } } } @@ -1931,7 +1931,8 @@ pub fn confirm(app: &mut DesignApp) -> Result { json!({"printer": if printer.is_empty() { Value::Null } else { json!(printer) }, "copies": d.n("copies").unwrap_or(1.0).max(1.0) as u64, "pages": pages, "spreads": d.b("spreads"), "marks": d.b("marks"), "bleed": d.b("bleed")}), )?; - app.status(format!("Sent {} page(s) to {}", r["pages"], r["printer"].as_str().unwrap_or("the default printer"))); + let printer = r["printer"].as_str().unwrap_or_else(|| crate::i18n::tr(&app.ui.language, "the default printer")); + app.status(crate::i18n::tr(&app.ui.language, "Sent {count} page(s) to {printer}").replace("{count}", &r["pages"].to_string()).replace("{printer}", printer)); Ok(r) } "pdfExport" => { diff --git a/crates/ui-egui/src/i18n.rs b/crates/ui-egui/src/i18n.rs index 8bf06015b..e9809e9ee 100644 --- a/crates/ui-egui/src/i18n.rs +++ b/crates/ui-egui/src/i18n.rs @@ -3088,6 +3088,19 @@ mod tests { "Text:", "Unsaved Changes", "“{}” has changes that are not saved. Save them before closing?", + // Status-bar messages. + "Alternate layout", + "Couldn't write recovery data: {error}", + "Export a PDF, IDML or package to share — no cloud account needed.", + "Import cancelled: the originating document has closed", + "Invalid panel layout; restored the default dock", + "PDF import cancelled: the originating document has closed", + "Packaged {count} files into {dir}", + "Relinked {count}", + "Sent {count} page(s) to {printer}", + "the default printer", + "{name}: import cancelled while a dialog is open; choose the file again", + "{name}: {count} step(s) done", ]); // A new English string falls back to English until it is translated, so only stale // entries (keys nothing passes to `tr` any more) fail. diff --git a/crates/ui-egui/src/i18n/cs.rs b/crates/ui-egui/src/i18n/cs.rs index 7f261f879..7726b99df 100644 --- a/crates/ui-egui/src/i18n/cs.rs +++ b/crates/ui-egui/src/i18n/cs.rs @@ -1727,6 +1727,7 @@ pub(super) const TABLE: &[(&str, &str)] = &[ // Labels the code passes to `tr` that no other catalog has yet. ("Activate Panel", "Aktivovat panel"), ("Add Anchor Point Tool", "Nástroj Přidat kotevní bod"), + ("Alternate layout", "Alternativní rozvržení"), ("Cell Number:", "Číslo mobilu:"), ("Change fill to:", "Změnit výplň na:"), ("Change Panel Layout", "Změnit rozvržení panelů"), @@ -1737,6 +1738,7 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Content Collector Tool", "Nástroj Sběrač obsahu"), ("Content Placer Tool", "Nástroj Umísťovač obsahu"), ("Convert Direction Point Tool", "Nástroj Převést směrový bod"), + ("Couldn't write recovery data: {error}", "Nelze zapsat data pro obnovu: {error}"), ("Data Fields", "Datová pole"), ("Data Merge Options", "Možnosti sloučení dat"), ("Delete Anchor Point Tool", "Nástroj Odstranit kotevní bod"), @@ -1749,6 +1751,10 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Email Address:", "E-mailová adresa:"), ("Email:", "E-mail:"), ("Erase Tool", "Nástroj Guma"), + ( + "Export a PDF, IDML or package to share — no cloud account needed.", + "Ke sdílení exportujte PDF, IDML nebo balíček – cloudový účet není potřeba.", + ), ("Eyedropper Tool", "Nástroj Kapátko"), ("Find fill:", "Najít výplň:"), ("Free Transform Tool", "Nástroj Volná transformace"), @@ -1758,7 +1764,9 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Group with", "Seskupit s"), ("H:", "V:"), ("Hand Tool", "Nástroj Ruka"), + ("Import cancelled: the originating document has closed", "Import zrušen: původní dokument byl zavřen"), ("Insert Field", "Vložit pole"), + ("Invalid panel layout; restored the default dock", "Neplatné rozvržení panelů; obnoveno výchozí ukotvení"), ("Line Tool", "Nástroj Čára"), ("List Composite Fonts", "Vypsat složená písma"), ("Measure Tool", "Nástroj Měřidlo"), @@ -1767,7 +1775,9 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Note Tool", "Nástroj Poznámka"), ("Object & Layout", "Objekt a rozvržení"), ("Organization:", "Organizace:"), + ("Packaged {count} files into {dir}", "Sbaleno souborů: {count} do {dir}"), ("Page Tool", "Nástroj Stránka"), + ("PDF import cancelled: the originating document has closed", "Import PDF zrušen: původní dokument byl zavřen"), ("Pen Tool", "Nástroj Pero"), ("Pencil Tool", "Nástroj Tužka"), ("Phone:", "Telefon:"), @@ -1777,6 +1787,7 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Preview Record", "Náhled záznamu"), ("Rectangle Frame Tool", "Nástroj Obdélníkový rámeček"), ("Rectangle Tool", "Nástroj Obdélník"), + ("Relinked {count}", "Znovu propojeno: {count}"), ("Remove Data Source", "Odebrat zdroj dat"), ("Remove Field", "Odebrat pole"), ("Reset Bar Position", "Obnovit polohu lišty"), @@ -1786,12 +1797,14 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Scale Tool", "Nástroj Změna měřítka"), ("Scissors Tool", "Nástroj Nůžky"), ("Selection Tool", "Nástroj Výběr"), + ("Sent {count} page(s) to {printer}", "Odesláno stránek: {count} (tiskárna: {printer})"), ("Set Composite Font", "Nastavit složené písmo"), ("Shear Tool", "Nástroj Zkosení"), ("Smooth Tool", "Nástroj Vyhladit"), ("Stop Preview", "Ukončit náhled"), ("Subject:", "Předmět:"), ("Text:", "Text:"), + ("the default printer", "výchozí"), ("Type on a Path Tool", "Nástroj Text na cestě"), ("Type Tool", "Nástroj Text"), ("Unsaved Changes", "Neuložené změny"), @@ -1804,6 +1817,11 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("(any)", "(libovolná)"), ("(unchanged)", "(beze změny)"), ("[No Language]", "[Žádný jazyk]"), + ( + "{name}: import cancelled while a dialog is open; choose the file again", + "{name}: import byl zrušen, protože je otevřený dialog; vyberte soubor znovu", + ), + ("{name}: {count} step(s) done", "{name}: hotovo kroků: {count}"), ("“{}” has changes that are not saved. Save them before closing?", "„{}“ obsahuje neuložené změny. Uložit je před zavřením?"), ]; diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index c003154ad..6bcbf8c51 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -585,6 +585,12 @@ impl DesignApp { self.ui.status = s.into(); } + /// ": " in the status bar: the feature name is translated, the engine's own + /// error text stays as the engine wrote it. + pub fn status_error(&mut self, feature: &str, error: impl std::fmt::Display) { + self.ui.status = format!("{}: {error}", crate::i18n::tr(&self.ui.language, feature)); + } + /// THE entry point for every action (menus, shortcuts, palette, panels, control channel). pub fn run(&mut self, id: &str, params: Value) -> Result { if let Some(r) = menus::run_ui(self, id, ¶ms) { @@ -655,7 +661,7 @@ impl DesignApp { pub(crate) fn activate_import_target(&mut self, request: &ImportRequest) -> Result<(), String> { let Some(index) = request.target.and_then(|uid| self.session.documents().iter().position(|d| d.uid == uid)) else { let message = "Import cancelled: the originating document has closed"; - self.status(message); + self.status(crate::i18n::tr(&self.ui.language, message)); return Err(message.into()); }; self.run("file.activate", json!({"index": index}))?; @@ -688,7 +694,7 @@ impl DesignApp { if owns_dialog { self.ui.dialog = None; } - self.status("PDF import cancelled: the originating document has closed"); + self.status(crate::i18n::tr(&self.ui.language, "PDF import cancelled: the originating document has closed")); } } } @@ -696,7 +702,10 @@ impl DesignApp { let files = std::mem::take(&mut *inbox.lock().unwrap_or_else(|e| e.into_inner())); for file in files { if self.ui.dialog.is_some() { - self.status(format!("{}: import cancelled while a dialog is open; choose the file again", file.name)); + self.status( + crate::i18n::tr(&self.ui.language, "{name}: import cancelled while a dialog is open; choose the file again") + .replace("{name}", &file.name), + ); continue; } let name = file.name.clone(); @@ -775,7 +784,7 @@ impl DesignApp { if self.session.documents().iter().any(|d| d.is_dirty()) && let Err(e) = self.session.execute("file.recovery.save", &json!({})) { - self.status(format!("Couldn't write recovery data: {e}")); + self.status(crate::i18n::tr(&self.ui.language, "Couldn't write recovery data: {error}").replace("{error}", &e.to_string())); } } let dt = now - self.last_time; @@ -1265,6 +1274,16 @@ mod tests { } } + #[test] + fn status_messages_follow_the_interface_language_but_engine_errors_stay_english() { + let mut app = DesignApp::new(Session::new(), Services::default()); + app.status_error("Table", "No table selected"); + assert_eq!(app.ui.status, "Table: No table selected"); + app.ui.language = "cs".into(); + app.status_error("Table", "No table selected"); + assert_eq!(app.ui.status, "Tabulka: No table selected"); + } + #[test] fn dropping_an_unreadable_file_alerts() { // A document opens, so it says it can't be opened. diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs index 14a52b58f..aa91b45f3 100644 --- a/crates/ui-egui/src/menus.rs +++ b/crates/ui-egui/src/menus.rs @@ -848,11 +848,11 @@ pub fn run_ui(app: &mut DesignApp, id: &str, p: &Value) -> Option { let r = app.run("file.package", json!({"dir": dir})); if let Ok(v) = &r { - app.status(format!( - "Packaged {} files into {}", - v["files"].as_array().map_or(0, |f| f.len()), - v["dir"].as_str().unwrap_or("") - )); + app.status( + crate::i18n::tr(&app.ui.language, "Packaged {count} files into {dir}") + .replace("{count}", &v["files"].as_array().map_or(0, |f| f.len()).to_string()) + .replace("{dir}", v["dir"].as_str().unwrap_or("")), + ); } r } diff --git a/crates/ui-egui/src/panel_docking.rs b/crates/ui-egui/src/panel_docking.rs index e53986c5c..aff0fb86c 100644 --- a/crates/ui-egui/src/panel_docking.rs +++ b/crates/ui-egui/src/panel_docking.rs @@ -300,7 +300,7 @@ pub(crate) fn show(app: &mut DesignApp, ui: &mut egui::Ui) -> bool { let Some(layout) = app.ui.docking.as_ref() else { return false }; if !valid(layout) { app.ui.docking = None; - app.status("Invalid panel layout; restored the default dock"); + app.status(crate::i18n::tr(&app.ui.language, "Invalid panel layout; restored the default dock")); return false; } let mut layout = layout.clone(); diff --git a/crates/ui-egui/src/panels/conditions.rs b/crates/ui-egui/src/panels/conditions.rs index 6cb3cd3e5..45eddec20 100644 --- a/crates/ui-egui/src/panels/conditions.rs +++ b/crates/ui-egui/src/panels/conditions.rs @@ -58,10 +58,10 @@ pub fn show(app: &mut DesignApp, ui: &mut egui::Ui) { if has_text { let on = !applied.contains(&c.name); if let Err(e) = app.run("condition.apply", json!({"name": c.name, "on": on})) { - app.status(format!("Conditional Text: {e}")); + app.status_error("Conditional Text", e); } } else { - app.status("Select text to apply a condition".to_string()); + app.status(crate::i18n::tr(&app.ui.language, "Select text to apply a condition")); } } nr.context_menu(|ui| { @@ -83,7 +83,7 @@ pub fn show(app: &mut DesignApp, ui: &mut egui::Ui) { if ui.button(crate::rtl::widget(ui, crate::i18n::tr(&app.ui.language, "New"))).clicked() && !name.trim().is_empty() { match app.run("condition.new", json!({"name": name.trim()})) { Ok(_) => name.clear(), - Err(e) => app.status(format!("Conditional Text: {e}")), + Err(e) => app.status_error("Conditional Text", e), } } }); diff --git a/crates/ui-egui/src/panels/glyphs.rs b/crates/ui-egui/src/panels/glyphs.rs index 3fb9d00eb..5ca90b5ea 100644 --- a/crates/ui-egui/src/panels/glyphs.rs +++ b/crates/ui-egui/src/panels/glyphs.rs @@ -125,7 +125,7 @@ pub fn show(app: &mut DesignApp, ui: &mut egui::Ui) { st.recent.insert(0, c); st.recent.truncate(12); } - Err(e) => app.status(format!("Glyphs: {e}")), + Err(e) => app.status_error("Glyphs", e), } } crate::rtl::label( diff --git a/crates/ui-egui/src/panels/interactive.rs b/crates/ui-egui/src/panels/interactive.rs index 5b770aec8..ec0066133 100644 --- a/crates/ui-egui/src/panels/interactive.rs +++ b/crates/ui-egui/src/panels/interactive.rs @@ -34,7 +34,7 @@ pub fn hyperlinks(app: &mut DesignApp, ui: &mut egui::Ui) { { let p = if let Some(m) = url.strip_prefix("mailto:") { json!({"email": m}) } else { json!({"url": url}) }; if let Err(e) = app.run("hyperlink.create", p) { - app.status(format!("Hyperlinks: {e}")); + app.status_error("Hyperlinks", e); } } }); @@ -176,7 +176,7 @@ pub fn tags(app: &mut DesignApp, ui: &mut egui::Ui) { if ui.button(crate::rtl::widget(ui, crate::i18n::tr(&app.ui.language, "New"))).clicked() && !name.trim().is_empty() { match app.run("xml.newTag", json!({"name": name.trim()})) { Ok(_) => name.clear(), - Err(e) => app.status(format!("Tags: {e}")), + Err(e) => app.status_error("Tags", e), } } }); @@ -232,7 +232,7 @@ pub fn tags(app: &mut DesignApp, ui: &mut egui::Ui) { { match app.run("xml.loadDtd", json!({"path": path})) { Ok(_) => problems = None, - Err(e) => app.status(format!("Load DTD: {e}")), + Err(e) => app.status_error("Load DTD", e), } } let has_dtd = info["dtd"].as_bool().unwrap_or(false); @@ -281,7 +281,7 @@ pub fn tags(app: &mut DesignApp, ui: &mut egui::Ui) { && let Some(path) = app.services.pick_open.as_mut().and_then(|f| f("xml")) && let Err(e) = app.run("file.importXml", json!({"path": path})) { - app.status(format!("Import XML: {e}")); + app.status_error("Import XML", e); } }); } @@ -310,7 +310,7 @@ pub fn states(app: &mut DesignApp, ui: &mut egui::Ui) { .clicked() && let Err(e) = app.run("states.create", json!({})) { - app.status(format!("Object States: {e}")); + app.status_error("Object States", e); } return; } @@ -398,7 +398,7 @@ pub fn buttons(app: &mut DesignApp, ui: &mut egui::Ui) { if let Some(p) = params && let Err(e) = app.run("button.set", p) { - app.status(format!("Buttons: {e}")); + app.status_error("Buttons", e); } crate::rtl::label( ui, @@ -565,7 +565,7 @@ pub fn liquid(app: &mut DesignApp, ui: &mut egui::Ui) { if ui.button(crate::rtl::widget(ui, crate::i18n::tr(&app.ui.language, "Create"))).clicked() && let Err(e) = app.run("layout.createAlternate", json!({"name": name, "width": w, "height": h})) { - app.status(format!("Alternate layout: {e}")); + app.status_error("Alternate layout", e); } ui.data_mut(|x| x.insert_temp(key, (name, w, h))); } @@ -598,7 +598,7 @@ pub fn media(app: &mut DesignApp, ui: &mut egui::Ui) { && let Some(path) = app.services.pick_open.as_mut().and_then(|f| f("place")) && let Err(e) = app.run("media.options", json!({"poster": {"path": path}})) { - app.status(format!("Media: {e}")); + app.status_error("Media", e); } if !m["poster"].is_null() && ui.small_button(crate::rtl::widget(ui, crate::i18n::tr(&app.ui.language, "None"))).clicked() { let _ = app.run("media.options", json!({"poster": null})); diff --git a/crates/ui-egui/src/panels/library.rs b/crates/ui-egui/src/panels/library.rs index ccaa595dd..f659c7c1d 100644 --- a/crates/ui-egui/src/panels/library.rs +++ b/crates/ui-egui/src/panels/library.rs @@ -40,7 +40,7 @@ pub fn show(app: &mut DesignApp, ui: &mut egui::Ui) { && let Some(path) = app.services.pick_open.as_mut().and_then(|f| f("library")) && let Err(e) = app.run("library.open", json!({"path": path})) { - app.status(format!("Library: {e}")); + app.status_error("Library", e); } }); let Ok(items) = app.session.execute("library.list", &json!({})) else { @@ -51,7 +51,7 @@ pub fn show(app: &mut DesignApp, ui: &mut egui::Ui) { if ui.add_enabled(has_sel, egui::Button::new(crate::rtl::widget(ui, crate::i18n::tr(&app.ui.language, "Add Selection")))).clicked() && let Err(e) = app.run("library.add", json!({})) { - app.status(format!("Library: {e}")); + app.status_error("Library", e); } ui.separator(); let items = items.as_array().cloned().unwrap_or_default(); @@ -77,7 +77,7 @@ pub fn show(app: &mut DesignApp, ui: &mut egui::Ui) { if ui.small_button(crate::rtl::widget(ui, crate::i18n::tr(&app.ui.language, "Place"))).clicked() && let Err(e) = app.run("library.place", json!({"index": i})) { - app.status(format!("Library: {e}")); + app.status_error("Library", e); } }); }); @@ -93,13 +93,13 @@ pub fn book(app: &mut DesignApp, ui: &mut egui::Ui) { && let Some(path) = app.services.pick_save.as_mut().and_then(|f| f("Book.dcbook")) && let Err(e) = app.run("book.new", json!({"path": path})) { - app.status(format!("Book: {e}")); + app.status_error("Book", e); } if ui.button(crate::rtl::widget(ui, crate::i18n::tr(&app.ui.language, "Open…"))).clicked() && let Some(path) = app.services.pick_open.as_mut().and_then(|f| f("book")) && let Err(e) = app.run("book.open", json!({"path": path})) { - app.status(format!("Book: {e}")); + app.status_error("Book", e); } }); let Ok(info) = app.session.execute("book.list", &json!({})) else { @@ -145,7 +145,7 @@ pub fn book(app: &mut DesignApp, ui: &mut egui::Ui) { && let Some(path) = app.services.pick_open.as_mut().and_then(|f| f("open")) && let Err(e) = app.run("book.add", json!({"path": path})) { - app.status(format!("Book: {e}")); + app.status_error("Book", e); } if ui.button(crate::rtl::widget(ui, crate::i18n::tr(&app.ui.language, "Update Numbering"))).clicked() { let _ = app.run("book.paginate", json!({})); @@ -157,7 +157,7 @@ pub fn book(app: &mut DesignApp, ui: &mut egui::Ui) { && let Some(path) = app.services.pick_save.as_mut().and_then(|f| f("Book.pdf")) && let Err(e) = app.run("book.exportPdf", json!({"path": path})) { - app.status(format!("Book: {e}")); + app.status_error("Book", e); } }); } @@ -202,7 +202,7 @@ pub fn scripts(app: &mut DesignApp, ui: &mut egui::Ui) { app.ui.scripts.push((name, text)); sel = app.ui.scripts.len() - 1; } - Err(e) => app.status(format!("Scripts: {e}")), + Err(e) => app.status_error("Scripts", e), } } if ui @@ -222,7 +222,11 @@ pub fn scripts(app: &mut DesignApp, ui: &mut egui::Ui) { && let Some((name, text)) = app.ui.scripts.get(i).cloned() { match app.run("script.run", json!({"text": text})) { - Ok(r) => app.status(format!("{name}: {} step(s) done", r["steps"])), + Ok(r) => app.status( + crate::i18n::tr(&app.ui.language, "{name}: {count} step(s) done") + .replace("{name}", &name) + .replace("{count}", &r["steps"].to_string()), + ), Err(e) => app.status(format!("{name}: {e}")), } } diff --git a/crates/ui-egui/src/panels/notes.rs b/crates/ui-egui/src/panels/notes.rs index 5139a090d..6eebb7411 100644 --- a/crates/ui-egui/src/panels/notes.rs +++ b/crates/ui-egui/src/panels/notes.rs @@ -28,7 +28,7 @@ pub fn show(app: &mut DesignApp, ui: &mut egui::Ui) { { match app.run("note.new", json!({"text": draft.trim()})) { Ok(_) => draft.clear(), - Err(e) => app.status(format!("Notes: {e}")), + Err(e) => app.status_error("Notes", e), } } ui.data_mut(|d| d.insert_temp(id, draft)); diff --git a/crates/ui-egui/src/panels/properties.rs b/crates/ui-egui/src/panels/properties.rs index 49cb920f2..7478624a9 100644 --- a/crates/ui-egui/src/panels/properties.rs +++ b/crates/ui-egui/src/panels/properties.rs @@ -780,7 +780,7 @@ fn convert_shape_menu(app: &mut DesignApp, resp: &egui::Response) { ] { if ui.button(crate::rtl::widget(ui, crate::i18n::tr(&app.ui.language, label))).clicked() { if let Err(e) = app.run("object.convertShape", json!({"to": to})) { - app.status(format!("Convert Shape: {e}")); + app.status_error("Convert Shape", e); } ui.close(); } @@ -1908,7 +1908,7 @@ pub fn links_panel(app: &mut DesignApp, ui: &mut egui::Ui) { { let r = app.run("links.relinkFolder", json!({"dir": dir.to_string_lossy()})); if let Ok(v) = r { - app.status(format!("Relinked {}", v["relinked"])); + app.status(crate::i18n::tr(&app.ui.language, "Relinked {count}").replace("{count}", &v["relinked"].to_string())); } } }); diff --git a/crates/ui-egui/src/panels/table.rs b/crates/ui-egui/src/panels/table.rs index 0238d2960..ce3080612 100644 --- a/crates/ui-egui/src/panels/table.rs +++ b/crates/ui-egui/src/panels/table.rs @@ -36,7 +36,7 @@ pub fn show(app: &mut DesignApp, ui: &mut egui::Ui) { if ui.small_button(crate::rtl::widget(ui, crate::i18n::tr(&app.ui.language, "Graphic…"))).clicked() && let Err(e) = app.run("app.graphicCell", json!({})) { - app.status(format!("Table: {e}")); + app.status_error("Table", e); } if ui.small_button(crate::rtl::widget(ui, crate::i18n::tr(&app.ui.language, "Text"))).clicked() { let _ = app.run("table.textCell", json!({})); @@ -55,7 +55,7 @@ pub fn show(app: &mut DesignApp, ui: &mut egui::Ui) { if ui.add_enabled(ok, egui::Button::new(crate::rtl::widget(ui, label)).small()).clicked() && let Err(e) = app.run(id, json!({"from": from, "to": to})) { - app.status(format!("Table: {e}")); + app.status_error("Table", e); } } }); @@ -145,7 +145,7 @@ pub fn show(app: &mut DesignApp, ui: &mut egui::Ui) { .clicked() && let Err(e) = app.run("table.distributeRows", json!({})) { - app.status(format!("Table: {e}")); + app.status_error("Table", e); } divider(ui); caption(ui, crate::i18n::tr(&app.ui.language, "Cell Text"));