Skip to content
Merged
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
18 changes: 17 additions & 1 deletion crates/ui-egui/src/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ pub fn handle(app: &mut SheetApp, ctx: &egui::Context, method: &str, p: &Json) -
}
"engine.commands" => {
let mut v: Vec<Json> = app.session.commands().into_iter().map(|c| serde_json::to_value(c).unwrap_or_default()).collect();
let language_params = format!("{{language: {}}} (alias: code)", crate::i18n::Language::code_list("|"));
for (id, label, params) in [
("ui.ribbonTab", "Ribbon Tab", ""),
("view.collapseRibbon", "Collapse Ribbon", ""),
Expand All @@ -195,7 +196,7 @@ pub fn handle(app: &mut SheetApp, ctx: &egui::Context, method: &str, p: &Json) -
"Submit Print Job",
"existing file.print sheet/pagination params → {printing,bytes,pending}; submits without opening a dialog",
),
("app.language.set", "Interface Language", "{language: \"en\"|\"zh\"|\"ja\"|\"ko\"|\"ru\"|\"pt\"|\"de\"|\"cs\"} (alias: code)"),
("app.language.set", "Interface Language", language_params.as_str()),
("app.language.english", "Interface Language: English", ""),
("app.language.japanese", "Interface Language: Japanese", ""),
] {
Expand Down Expand Up @@ -530,4 +531,19 @@ mod tests {
assert!(!app.printing.busy(), "discovery must not submit a job");
assert!(app.backstage.is_none(), "discovery must not open settings");
}

#[test]
fn language_command_docs_list_every_language() {
let mut session = gridcraft_engine::Session::new();
session.new_workbook();
let mut app = SheetApp::new(session, crate::Services::default());
let Outcome::Done(reply) = handle(&mut app, &egui::Context::default(), "engine.commands", &json!({"search":"language"})) else {
panic!("command discovery must return immediately");
};
let commands = reply["result"].as_array().unwrap();
let docs = commands.iter().find(|c| c["id"] == "app.language.set").unwrap()["params"].as_str().unwrap();
for l in crate::i18n::Language::ALL {
assert!(docs.contains(&format!("\"{}\"", l.code())), "app.language.set docs miss {:?}: {docs}", l.code());
}
}
}
10 changes: 10 additions & 0 deletions crates/ui-egui/src/i18n.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ impl Language {
Self::from_tag(code)
}

/// Every code `app.language.set` takes, quoted and joined (`"en"|"es"|…`), for command docs
/// and errors.
pub fn code_list(separator: &str) -> String {
Self::ALL.iter().map(|l| format!("\"{}\"", l.code())).collect::<Vec<_>>().join(separator)
}

fn from_tag(tag: &str) -> Option<Self> {
match tag.trim().split(['-', '_']).next()?.to_ascii_lowercase().as_str() {
"en" => Some(Self::En),
Expand Down Expand Up @@ -761,6 +767,10 @@ mod tests {
app.run("app.language.set", serde_json::json!({"code": "ja"})).unwrap();
assert_eq!(app.ui.language, Language::Ja, "`code` is an alias for `language`");
assert!(app.run("app.language.set", serde_json::json!({})).is_err(), "no language is an error, not a dialog");
let unknown = app.run("app.language.set", serde_json::json!({"language": "xx"})).unwrap_err().to_string();
for l in Language::ALL {
assert!(unknown.contains(&format!("\"{}\"", l.code())), "the error lists {:?}: {unknown}", l.code());
}
app.run("app.language.english", serde_json::json!({})).unwrap();
assert_eq!(app.ui.language, Language::En);
for l in Language::ALL {
Expand Down
2 changes: 1 addition & 1 deletion crates/ui-egui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,7 @@ impl SheetApp {
self.ui.language = l;
Ok(json!({"language": l}))
}
None => Err(format!("unknown language {code:?} (use \"en\", \"es\", \"zh\", \"ja\", \"ko\", \"ru\", \"pt\" or \"cs\")")),
None => Err(format!("unknown language {code:?} (use one of {})", i18n::Language::code_list(", "))),
}
}
"app.language.english" => {
Expand Down
5 changes: 3 additions & 2 deletions docs/control-protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,9 @@ the View ▸ Animations checkbox, saved with the other UI preferences and on by

`{command: "app.language.set", params: {language: "ja"}}` switches the interface language
(`code` is accepted as an alias for `language`); `app.language.english` and
`app.language.japanese` are shortcuts. Only interface chrome is translated, never command ids or
document text. The choice is saved in `ui.json`; with nothing saved the desktop app follows the
`app.language.japanese` are shortcuts. `engine.commands` lists every code it takes (`en`, `es`,
`zh`, `ja`, `ko`, `ru`, `pt`, `de`, `cs`, `fr`, `sr`), as does the error for an unknown one. Only
interface chrome is translated, never command ids or document text. The choice is saved in `ui.json`; with nothing saved the desktop app follows the
system language.

`{command: "file.open", params: {path: "Secret.xlsx", password: "…"}}` opens a password-protected
Expand Down