Browser rows that are names someone gave (bodies, sketches, components, joints, views...) show as typed instead of being translated as UI labels; default names like Sketch1 are still translated. Fixes #1228.
This commit is contained in:
1 parent
c008addae2
commit
b1695873f5
3 files changed
+65
-8
No files matched your search
@@ -268,6 +268,9 @@ pub(crate) struct Row<'a> {
|
||||
pub(crate) eye: Option<bool>,
|
||||
pub(crate) icon: &'a str,
|
||||
pub(crate) label: &'a str,
|
||||
/// The label is a name someone gave (a body, sketch, component, …): it is shown as typed,
|
||||
/// not translated when it happens to match a UI label.
|
||||
pub(crate) name: bool,
|
||||
pub(crate) selected: bool,
|
||||
pub(crate) dim: bool,
|
||||
pub(crate) color: Option<Color32>,
|
||||
@@ -375,7 +378,7 @@ pub(crate) fn draw_row(ui: &mut egui::Ui, id: egui::Id, row: &Row) -> RowResp {
|
||||
x += 21.0;
|
||||
}
|
||||
let col = row.color.unwrap_or(if row.dim { t.text_dim } else { t.text });
|
||||
let label_display = crate::i18n::tr_dyn(row.label);
|
||||
let label_display = if row.name { crate::i18n::tr_name(row.label) } else { crate::i18n::tr_dyn(row.label) };
|
||||
let galley = ui.painter().layout_no_wrap(label_display, FontId::proportional(12.5), col);
|
||||
let lw = galley.size().x;
|
||||
ui.painter().galley(pos2(x, cy - galley.size().y / 2.0), galley, col);
|
||||
@@ -596,6 +599,7 @@ fn component_rows(app: &mut SolveApp, ui: &mut egui::Ui, id: u64, depth: usize,
|
||||
eye: (id != 0).then_some(visible),
|
||||
icon: "component",
|
||||
label: &name,
|
||||
name: true,
|
||||
selected: app.tree.picked_components.contains(&id),
|
||||
dim: faded,
|
||||
radio: Some(active),
|
||||
@@ -699,6 +703,7 @@ fn occurrence_rows(app: &mut SolveApp, ui: &mut egui::Ui, path: Vec<u64>, depth:
|
||||
eye: Some(own_visible),
|
||||
icon: "component",
|
||||
label: &placement.name,
|
||||
name: true,
|
||||
selected,
|
||||
dim: faded || !visible,
|
||||
radio: Some(active),
|
||||
@@ -891,7 +896,11 @@ fn named_view_rows(app: &mut SolveApp, ui: &mut egui::Ui, depth: usize, acts: &m
|
||||
}
|
||||
let names: Vec<String> = app.session.doc.named_views.iter().map(|v| v.name.clone()).collect();
|
||||
for name in names {
|
||||
let r = draw_row(ui, ui.id().with(("view", &name)), &Row { depth: depth + 1, icon: "perspective", label: &name, ..Default::default() });
|
||||
let r = draw_row(
|
||||
ui,
|
||||
ui.id().with(("view", &name)),
|
||||
&Row { depth: depth + 1, icon: "perspective", label: &name, name: true, ..Default::default() },
|
||||
);
|
||||
if r.double {
|
||||
restore_view(app, &name);
|
||||
}
|
||||
@@ -1031,7 +1040,7 @@ fn canvas_rows(app: &mut SolveApp, ui: &mut egui::Ui, depth: usize, acts: &mut A
|
||||
let r = draw_row(
|
||||
ui,
|
||||
ui.id().with(("canvas", id)),
|
||||
&Row { depth: depth + 1, eye: Some(visible), icon: "canvas", label: &name, selected, dim: !visible, ..Default::default() },
|
||||
&Row { depth: depth + 1, eye: Some(visible), icon: "canvas", label: &name, name: true, selected, dim: !visible, ..Default::default() },
|
||||
);
|
||||
if r.eye {
|
||||
let _ = app.run("canvas.edit", json!({ "canvas": id, "visible": !visible }));
|
||||
@@ -1461,7 +1470,16 @@ fn folder_rows_at(app: &mut SolveApp, ui: &mut egui::Ui, comp: u64, path: Option
|
||||
let r = draw_row(
|
||||
ui,
|
||||
ui.id().with(&gkey),
|
||||
&Row { depth: depth + 1, fold: Some(gopen), eye: Some(gvis), icon: "folder", label: &label, dim: !gvis, ..Default::default() },
|
||||
&Row {
|
||||
depth: depth + 1,
|
||||
fold: Some(gopen),
|
||||
eye: Some(gvis),
|
||||
icon: "folder",
|
||||
label: &label,
|
||||
name: true,
|
||||
dim: !gvis,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
if r.fold || r.clicked {
|
||||
toggle(app, &gkey, true);
|
||||
@@ -1517,6 +1535,7 @@ fn entry_row(
|
||||
eye: Some(e.visible),
|
||||
icon: e.icon,
|
||||
label: &e.label,
|
||||
name: true,
|
||||
selected: e.selected,
|
||||
dim: !e.visible,
|
||||
color: e.color,
|
||||
|
||||
@@ -1119,7 +1119,16 @@ pub fn browser_joints(app: &mut SolveApp, ui: &mut egui::Ui, depth: usize) {
|
||||
let r = draw_row(
|
||||
ui,
|
||||
ui.id().with(("joint", id)),
|
||||
&Row { depth: depth + 1, eye: Some(visible), icon: "joint", label: &name, selected, dim: suppressed || !visible, ..Default::default() },
|
||||
&Row {
|
||||
depth: depth + 1,
|
||||
eye: Some(visible),
|
||||
icon: "joint",
|
||||
label: &name,
|
||||
name: true,
|
||||
selected,
|
||||
dim: suppressed || !visible,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
if let Some(resp) = &r.resp {
|
||||
resp.clone().on_hover_text(format!("{kind:?} joint"));
|
||||
|
||||
@@ -77,16 +77,30 @@ impl Locale {
|
||||
interpolate(self.text(id), args)
|
||||
}
|
||||
|
||||
/// Translate generated browser names and labels, preserving custom names otherwise.
|
||||
pub fn dynamic(self, text: &str) -> String {
|
||||
/// The default names SolidCraft gives (`Sketch1`, `Body2`, `Component3`), translated.
|
||||
fn default_name(self, text: &str) -> Option<String> {
|
||||
for (prefix, id) in [("Sketch", "browser.sketch_name"), ("Body", "browser.body_name"), ("Component", "browser.component_name")] {
|
||||
if let Some(number) = text.strip_prefix(prefix)
|
||||
&& !number.is_empty()
|
||||
&& number.chars().all(|c| c.is_ascii_digit())
|
||||
{
|
||||
return self.format(id, &[("number", number)]);
|
||||
return Some(self.format(id, &[("number", number)]));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// A name someone gave (a body, sketch, component, …): shown as typed, even when it matches
|
||||
/// a UI label ("Fillet", "Boss"); only the default names are translated.
|
||||
pub fn given_name(self, text: &str) -> String {
|
||||
self.default_name(text).unwrap_or_else(|| text.to_string())
|
||||
}
|
||||
|
||||
/// Translate generated browser names and labels, preserving custom names otherwise.
|
||||
pub fn dynamic(self, text: &str) -> String {
|
||||
if let Some(name) = self.default_name(text) {
|
||||
return name;
|
||||
}
|
||||
for (prefix, id, arg) in [("Units: ", "browser.units", "units"), ("Precision: ", "browser.precision", "precision")] {
|
||||
if let Some(value) = text.strip_prefix(prefix) {
|
||||
return self.format(id, &[(arg, value)]);
|
||||
@@ -166,6 +180,9 @@ pub fn format(id: &str, args: &[(&str, &str)]) -> String {
|
||||
pub fn tr_dyn(text: &str) -> String {
|
||||
CURRENT.with(|current| current.get().dynamic(text))
|
||||
}
|
||||
pub fn tr_name(text: &str) -> String {
|
||||
CURRENT.with(|current| current.get().given_name(text))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
@@ -402,6 +419,18 @@ mod tests {
|
||||
assert_eq!(Locale::for_language("en").dynamic("Sketch1"), "Sketch1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn given_names_are_not_translated_as_labels() {
|
||||
let de = Locale::for_language("de");
|
||||
// "Boss" and "Fillet" are also UI labels, which `dynamic` translates.
|
||||
assert_ne!(de.dynamic("Boss"), "Boss");
|
||||
assert_ne!(de.dynamic("Fillet"), "Fillet");
|
||||
assert_eq!(de.given_name("Boss"), "Boss");
|
||||
assert_eq!(de.given_name("Fillet"), "Fillet");
|
||||
assert_eq!(de.given_name("Sketch3"), de.dynamic("Sketch3"));
|
||||
assert_ne!(de.given_name("Sketch3"), "Sketch3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn korean_catalog_translates_keys_labels_and_browser_patterns() {
|
||||
let ko = Locale::for_language("ko");
|
||||
|
||||
Reference in new issue
Block a user