diff --git a/crates/ui-egui/src/dialogs/show.rs b/crates/ui-egui/src/dialogs/show.rs
--- a/crates/ui-egui/src/dialogs/show.rs
+++ b/crates/ui-egui/src/dialogs/show.rs
@@ -291,27 +291,30 @@ pub fn show(app: &mut SheetApp, ctx: &egui::Context) {
                     }
                 }
                 "saveChanges" => {
-                    ui.label(format!("Do you want to save the changes you made to {}?", d.values.get("title").and_then(Json::as_str).unwrap_or("this workbook")));
+                    let lang = app.ui.language;
+                    let title = d.values.get("title").and_then(Json::as_str).unwrap_or_else(|| lang.tr("this workbook"));
+                    ui.label(lang.tr("Do you want to save the changes you made to {title}?").replace("{title}", title));
                     let quitting = d.values.get("quit").and_then(Json::as_bool) == Some(true);
                     ui.horizontal(|ui| {
                         for (label, answer) in
                             [("Don't Save", crate::SaveAnswer::DontSave), ("Cancel", crate::SaveAnswer::Cancel), ("Save", crate::SaveAnswer::Save)]
                         {
-                            if ui.button(label).clicked() && app.answer_save_changes(answer, quitting, ui.ctx()) {
+                            if ui.button(lang.tr(label)).clicked() && app.answer_save_changes(answer, quitting, ui.ctx()) {
                                 open = false;
                             }
                         }
                     });
                 }
                 "start" => {
-                    ui.heading("Start a new workbook");
+                    let lang = app.ui.language;
+                    ui.heading(lang.tr("Start a new workbook"));
                     ui.horizontal_wrapped(|ui| {
-                        if ui.button("Blank workbook").clicked() {
+                        if ui.button(lang.tr("Blank workbook")).clicked() {
                             app.run_or_alert("file.new", json!({}));
                             open = false;
                         }
                         for (n, t) in gridcraft_engine::sample::SAMPLES {
-                            if ui.button(*t).clicked() {
+                            if ui.button(lang.tr(t)).clicked() {
                                 app.run_or_alert("file.new", json!({"sample": n}));
                                 open = false;
                             }
diff --git a/crates/ui-egui/tests/it/file_menu.rs b/crates/ui-egui/tests/it/file_menu.rs
--- a/crates/ui-egui/tests/it/file_menu.rs
+++ b/crates/ui-egui/tests/it/file_menu.rs
@@ -254,6 +254,30 @@ fn closing_the_window_asks_about_every_unsaved_workbook() {
     assert!(!sent.contains(&egui::ViewportCommand::CancelClose), "the close that follows is let through");
 }
 
+/// The Save Changes question and its buttons follow the interface language, like every dialog.
+#[test]
+fn the_save_changes_dialog_is_translated() {
+    for language in [Language::It, Language::PtBr, Language::Ro] {
+        let mut h = harness(Services::default());
+        h.state_mut().run("app.language.set", serde_json::json!({"language": language.code()})).unwrap();
+        h.state_mut().run("cell.set", serde_json::json!({"cell": "A1", "input": "42"})).unwrap();
+        h.run_steps(2);
+        request_window_close(&mut h);
+        assert_eq!(h.state().dialog.as_ref().map(|d| d.name()), Some("saveChanges"));
+        h.run_steps(2);
+        for label in ["Don't Save", "Cancel", "Save"] {
+            let shown = language.tr(label);
+            assert_ne!(shown, label, "{language:?}: {label} has no translation");
+            assert!(h.query_by_role_and_label(egui::accesskit::Role::Button, shown).is_some(), "{language:?}: no {shown} button");
+        }
+        let question = language.tr("Do you want to save the changes you made to {title}?");
+        let before = question.split("{title}").next().unwrap_or(question).trim();
+        assert!(h.query_all_by_label_contains(before).next().is_some(), "{language:?}: the question is not translated");
+        click_commands(&mut h, language.tr("Cancel"));
+        assert!(h.state().dialog.is_none());
+    }
+}
+
 #[test]
 fn closing_the_window_can_save_first_and_a_saved_workbook_closes_at_once() {
     let dir = std::env::temp_dir().join(format!("gridcraft-close-window-{}", std::process::id()));
