Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,17 @@ The ribbon is translated into Japanese, Simplified Chinese, Korean, Brazilian Po
and German (266–268 labels each, ~12% of ~2,200 strings; merged 10-10 in #31, #104, #82, German
added 10-11), the
interface follows the system language, and CJK, Thai and Hebrew text falls back to system fonts
(#38). Dialogs, menus and messages are English; formulas and number formats are en-US only.
(#38). Dialogs and message boxes follow the interface language (Spanish translated in full;
other languages fall back to English per string); context menus, task panes and status messages
are still English. Spanish also has Spanish formula entry (`;` separators, decimal comma, 10 local
function names); number formats are en-US only.
Localized German formulas and numbers are in PR #163. Detail: [localization-parity.md](docs/localization-parity.md).

| Language | Code | Status | UI strings |
|---|---|---|---|
| English | en | full (source language) | 100% |
| Simplified Chinese | zh-Hans | menus only | ~12% |
| Spanish | es | none | 0% |
| Spanish | es | ribbon and dialogs | ~35% |
| Hindi | hi | none | 0% |
| Arabic | ar | none (no RTL layout, no shaping) | 0% |
| French | fr | none | 0% |
Expand Down
3 changes: 3 additions & 0 deletions contributors/people.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ sync_github_name = true
real_name = "James Symes"
sync_github_name = true

[people.manucarcor]
real_name = "Manuel Carmona"
display_name = "manucarcor"

[people.Silvertree2010]
display_name = "Netter"
Expand Down
308 changes: 168 additions & 140 deletions crates/ui-egui/src/dialogs.rs

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion crates/ui-egui/src/i18n.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,12 @@ impl Language {
/// A label that needs two translations (Home's text "Orientation" vs Page Layout's print
/// "Orientation") is keyed `context|label`: English shows only the part after the `|`.
pub fn tr(self, text: &str) -> &str {
let translated = match self {
self.translation(text).unwrap_or_else(|| text.rsplit_once('|').map_or(text, |(_, label)| label))
}

/// The catalog's entry for an interface label, if this language has one (`None` for English).
pub fn translation(self, text: &str) -> Option<&'static str> {
match self {
Self::En => None,
Self::Es => es::translate(text),
Self::Ja => JAPANESE.iter().find(|(english, _)| *english == text).map(|(_, translated)| *translated),
Expand Down
8 changes: 5 additions & 3 deletions crates/ui-egui/src/widgets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,13 +280,15 @@ pub fn message_box(app: &mut SheetApp, ctx: &egui::Context) {
ui.painter().circle_filled(r.center(), 16.0, Color32::from_rgb(0xF2, 0xC3, 0x2E));
ui.painter().text(r.center(), Align2::CENTER_CENTER, "!", theme::ui_bold(20.0), Color32::WHITE);
ui.vertical(|ui| {
ui.label(egui::RichText::new(title).strong());
ui.add(egui::Label::new(msg).wrap());
ui.label(egui::RichText::new(tr(ui, &title)).strong());
ui.add(egui::Label::new(tr(ui, &msg)).wrap());
});
});
ui.add_space(8.0);
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
if ui.button(" OK ").clicked() || ui.input(|i| i.key_pressed(egui::Key::Enter) || i.key_pressed(egui::Key::Escape)) {
if ui.button(format!(" {} ", tr(ui, "OK"))).clicked()
|| ui.input(|i| i.key_pressed(egui::Key::Enter) || i.key_pressed(egui::Key::Escape))
{
close = true;
}
});
Expand Down
29 changes: 29 additions & 0 deletions crates/ui-egui/tests/interaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,35 @@ fn dialogs_open_and_close() {
}
}

#[test]
fn dialogs_draw_in_the_interface_language() {
// Dialogs followed the interface language only in the formula language; their chrome was English.
let mut h = harness(blank());
h.state_mut().ui.language = gridcraft_ui_egui::i18n::Language::Es;
h.state_mut().open_dialog("find", json!({"replace": true}));
h.run_steps(3);
for label in ["Buscar y reemplazar", "Reemplazar con:", "Reemplazar todos", "Buscar siguiente", "Coincidir mayúsculas y minúsculas"] {
h.get_by_label(label);
}
assert!(h.query_by_label("Find Next").is_none(), "no English left in Find and Replace");
key(&mut h, Key::Escape, Modifiers::NONE);

h.state_mut().open_dialog("formatCells", json!({"tab": "Alignment"}));
h.run_steps(3);
for label in ["Formato de celdas", "Número", "Alineación", "Relleno", "Proteger", "Reducir hasta ajustar"] {
h.get_by_label(label);
}
// OK and Cancel carry padding in the label.
assert!(h.query_by_label_contains("Aceptar").is_some() && h.query_by_label_contains("Cancelar").is_some());
key(&mut h, Key::Escape, Modifiers::NONE);

h.state_mut().open_dialog("insertCells", json!({}));
h.run_steps(3);
h.get_by_label("Desplazar las celdas hacia abajo").click();
h.run_steps(2);
assert_eq!(h.state().dialog.as_ref().and_then(|d| d.values.get("shift")).and_then(|v| v.as_str()), Some("down"), "options keep their values");
}

#[test]
fn data_analysis_dialog_runs_a_tool_and_asks_before_overwriting() {
let mut s = blank();
Expand Down
8 changes: 7 additions & 1 deletion docs/localization-parity.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ right-to-left sheets and full complex-script support. Part of
dialog, every dialog title and the shared OK/Cancel buttons; the other dialogs, menus,
context menus, task panes, status messages, command labels and function descriptions are still
English literals. Untranslated labels fall back to English.
- **Dialogs follow the interface language** (2026-10-12): `dialogs.rs` keeps titles, tabs, field
labels and options English (they are ids for the control channel) and translates them when drawn,
as do message boxes. Spanish covers every dialog string, checked by
`dialogs::tests::spanish_translates_every_dialog_string`; other languages fall back to English
per string until their catalogs grow. Spanish now has 764 entries (~35%) and Spanish formula
entry (`docs/formula-input.md`).
- **About 2,200 user-visible strings** in all (heuristic source scan: ~1,700 UI and command
strings plus ~500 function descriptions), so each shipped language covers **~12%** (measured
count / estimated total).
Expand Down Expand Up @@ -45,7 +51,7 @@ separators, number/date formats, machine translation with agent review, and scri
|---|---|---|---|---|---|---|---|
| English | en | ~2,200 / ~2,200 (100%, source) | yes | Latin: yes | yes | full | — |
| Simplified Chinese (Mandarin) | zh-Hans | 266 (~12%) | no | CJK system-font fallback (#38); IME unverified; PDF can't export | no | menus only | 8–13 h |
| Spanish | es | 0 (0%) | no | Latin: yes | no | none | 6–10 h |
| Spanish | es | 764 (~35%) | dialogs: yes; tooltips partly; help no | Latin: yes | no | ribbon and dialogs | 4–7 h |
| Hindi | hi | 0 (0%) | no | Devanagari: **no shaping** | no | none | 12–18 h |
| Arabic | ar | 0 (0%) | no | **no shaping, no RTL UI**; Sheet Right-to-Left mirrors the grid (#146) | no | none | 25–35 h |
| French | fr | 0 (0%) | no | Latin: yes | no | none | 6–10 h |
Expand Down