Complete application localization across all supported languages

This commit is contained in:
Hakan Seven committed 2026-09-07 01:05:02 +03:00
1 parent 96c794c072
commit d66e89ca19
78 files changed
+26043 -877

No files matched your search

+8 -8
View File
@@ -555,11 +555,11 @@ impl OpenCADStudio {
_ => return None,
};
if add.is_empty() {
self.command_line.push_info(match kw.as_str() {
self.command_line.push_info(crate::t!(match kw.as_str() {
"P" | "PREVIOUS" => "No previous selection set.",
"ALL" => "Nothing to select.",
_ => "No last object.",
});
}).as_ref());
return Some(Task::none());
}
let count = add.len();
@@ -1103,7 +1103,7 @@ impl OpenCADStudio {
});
if !valid {
self.command_line.push_error(
"MVIEW Object: select a closed paper-space circle, ellipse, or polyline.",
crate::t!("MVIEW Object: select a closed paper-space circle, ellipse, or polyline.").as_ref(),
);
if let Some(prompt) =
self.tabs[i].active_cmd.as_ref().map(|command| command.prompt())
@@ -2140,11 +2140,11 @@ impl OpenCADStudio {
if self.tabs[i].scene.reassociate_center_mark(target, source, point) {
self.tabs[i].dirty = true;
self.command_line.push_output(
"CENTERREASSOCIATE: center mark associated.",
crate::t!("CENTERREASSOCIATE: center mark associated.").as_ref(),
);
} else {
self.command_line.push_error(
"CENTERREASSOCIATE: the selected source is not circular.",
crate::t!("CENTERREASSOCIATE: the selected source is not circular.").as_ref(),
);
}
self.tabs[i].active_cmd = None;
@@ -2414,11 +2414,11 @@ impl OpenCADStudio {
self.tabs[i].active_cmd = None;
self.tabs[i].snap_result = None;
self.restore_pre_cmd_tangent();
self.command_line.push_info(if space_changed {
self.command_line.push_info(crate::t!(if space_changed {
"Command cancelled because the active drawing space changed."
} else {
"Command cancelled."
});
}).as_ref());
}
CmdResult::SelectByPath {
path,
@@ -3200,7 +3200,7 @@ impl OpenCADStudio {
self.tabs[i].scene.clear_preview_wire();
self.restore_pre_cmd_tangent();
self.command_line.push_error(
"JOIN: objects don't form a single connected chain, or contain an unsupported type / tilted arc.",
crate::t!("JOIN: objects don't form a single connected chain, or contain an unsupported type / tilted arc.").as_ref(),
);
}
}
+1 -1
View File
@@ -529,7 +529,7 @@ impl OpenCADStudio {
let sel: Vec<_> = self.tabs[i].scene.selected.iter().copied().collect();
if sel.is_empty() {
self.command_line.push_error(
"WBLOCK Select entities first, or: WBLOCK <block name> or WBLOCK *",
crate::t!("WBLOCK Select entities first, or: WBLOCK <block name> or WBLOCK *").as_ref(),
);
} else {
return Some(Task::done(Message::WblockSave("*".to_string())));
+3 -3
View File
@@ -130,7 +130,7 @@ impl OpenCADStudio {
}
if opt.is_empty() {
self.command_line.push_info(
"Usage: JUSTIFYTEXT <Left|Center|Right|Middle|TL|TC|TR|ML|MC|MR|BL|BC|BR>",
crate::t!("Usage: JUSTIFYTEXT <Left|Center|Right|Middle|TL|TC|TR|ML|MC|MR|BL|BC|BR>").as_ref(),
);
return Some(Task::none());
}
@@ -401,7 +401,7 @@ impl OpenCADStudio {
Some(v) if v > 0.0 => v,
_ => {
self.command_line.push_info(
"Usage: TEXTFIT <target width> (fits selected text to that width)",
crate::t!("Usage: TEXTFIT <target width> (fits selected text to that width)").as_ref(),
);
return Some(Task::none());
}
@@ -1311,7 +1311,7 @@ impl OpenCADStudio {
let text = cmd.strip_prefix("ARCTEXT").unwrap_or("").trim().to_string();
if text.is_empty() {
self.command_line.push_info(
"Usage: ARCTEXT <text> (select an arc first; the text follows it)",
crate::t!("Usage: ARCTEXT <text> (select an arc first; the text follows it)").as_ref(),
);
return None;
}
+16 -16
View File
@@ -429,11 +429,11 @@ impl OpenCADStudio {
self.tabs[i].scene.set_drawing_limit_check(enabled);
self.tabs[i].dirty = true;
}
self.command_line.push_output(if enabled {
self.command_line.push_output(crate::t!(if enabled {
"Limits checking ON."
} else {
"Limits checking OFF."
});
}).as_ref());
}
cmd if cmd.starts_with("LIMITS SET ") => {
let tokens: Vec<&str> = cmd["LIMITS SET ".len()..].split_whitespace().collect();
@@ -492,14 +492,14 @@ impl OpenCADStudio {
"REDRAW" => {
use crate::scene::ViewportRefreshScope;
self.tabs[i].scene.request_refresh(ViewportRefreshScope::Active);
self.command_line.push_output("REDRAW: viewport refreshed.");
self.command_line.push_output(crate::t!("REDRAW: viewport refreshed.").as_ref());
return Some(Task::none());
}
// REDRAWALL — force re-rasterize of every generated viewport.
"REDRAWALL" => {
use crate::scene::ViewportRefreshScope;
self.tabs[i].scene.request_refresh(ViewportRefreshScope::All);
self.command_line.push_output("REDRAWALL: viewports refreshed.");
self.command_line.push_output(crate::t!("REDRAWALL: viewports refreshed.").as_ref());
return Some(Task::none());
}
// REGEN — full model regeneration (bump_geometry: geometry_epoch AND
@@ -509,7 +509,7 @@ impl OpenCADStudio {
// REGENALL is functionally identical (C5).
"REGEN" | "REGENALL" => {
self.tabs[i].scene.bump_geometry();
self.command_line.push_output("REGEN: regenerated model.");
self.command_line.push_output(crate::t!("REGEN: regenerated model.").as_ref());
return Some(Task::none());
}
@@ -877,8 +877,8 @@ impl OpenCADStudio {
let active = self
.active_plot_style
.as_ref()
.map(|t| format!("Active: {}", t.name))
.unwrap_or_else(|| "No plot style loaded.".into());
.map(|t| crate::tf!("Active: {}", t.name).into_owned())
.unwrap_or_else(|| crate::t!("No plot style loaded.").into_owned());
self.command_line.push_info(&active);
return Some(Task::done(Message::PlotStyleLoad));
}
@@ -887,13 +887,13 @@ impl OpenCADStudio {
.active_plot_style
.as_ref()
.map(|t| {
format!(
crate::tf!(
"Plot style: {} ({} color overrides)",
t.name,
t.aci_entries.iter().filter(|e| e.color.is_some()).count()
)
).into_owned()
})
.unwrap_or_else(|| "No plot style table loaded.".into());
.unwrap_or_else(|| crate::t!("No plot style table loaded.").into_owned());
self.command_line.push_output(&msg);
}
_ => {
@@ -1215,7 +1215,7 @@ impl OpenCADStudio {
.push_output(crate::tf!("ADJUST: {action} = {v} on {changed} image(s).").as_ref());
} else {
self.command_line.push_error(
"ADJUST: no raster images selected, or unknown property (use BRIGHTNESS|CONTRAST|FADE).",
crate::t!("ADJUST: no raster images selected, or unknown property (use BRIGHTNESS|CONTRAST|FADE).").as_ref(),
);
}
} else {
@@ -1274,7 +1274,7 @@ impl OpenCADStudio {
match value.parse::<i8>() {
Ok(mode @ -4..=4) => self.annotation_auto_scale = mode,
_ => self.command_line.push_error(
"ANNOAUTOSCALE: enter an integer from -4 through 4.",
crate::t!("ANNOAUTOSCALE: enter an integer from -4 through 4.").as_ref(),
),
}
}
@@ -1461,7 +1461,7 @@ impl OpenCADStudio {
let path = cmd.trim_start_matches("DATALINK").trim();
if path.is_empty() {
self.command_line.push_info(
"Usage: DATALINK <path-to-.csv>",
crate::t!("Usage: DATALINK <path-to-.csv>").as_ref(),
);
return Some(Task::none());
}
@@ -1574,7 +1574,7 @@ impl OpenCADStudio {
}
if jobs.is_empty() {
self.command_line
.push_error("DATALINKUPDATE: no linked tables found.");
.push_error(crate::t!("DATALINKUPDATE: no linked tables found.").as_ref());
return Some(Task::none());
}
if write_back {
@@ -1606,7 +1606,7 @@ impl OpenCADStudio {
.collect();
if updates.is_empty() {
self.command_line
.push_error("DATALINKUPDATE: linked sources could not be read.");
.push_error(crate::t!("DATALINKUPDATE: linked sources could not be read.").as_ref());
return Some(Task::none());
}
self.push_undo_snapshot(i, "DATALINKUPDATE");
@@ -1675,7 +1675,7 @@ impl OpenCADStudio {
let path = cmd.trim_start_matches("LANDXMLIMPORT").trim();
if path.is_empty() {
self.command_line.push_info(
"Usage: LANDXMLIMPORT <path-to-.xml> (imports CgPoint survey points)",
crate::t!("Usage: LANDXMLIMPORT <path-to-.xml> (imports CgPoint survey points)").as_ref(),
);
return Some(Task::none());
}
+8 -8
View File
@@ -526,7 +526,7 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
}
self.command_line
.push_output(&format!("CENTERRESET: {count} center object(s) updated."));
.push_output(&crate::tf!("CENTERRESET: {count} center object(s) updated."));
}
"CENTERREASSOCIATE" => {
@@ -549,7 +549,7 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
}
self.command_line
.push_output(&format!("CENTERREASSOCIATE: {count} center object(s) associated."));
.push_output(&crate::tf!("CENTERREASSOCIATE: {count} center object(s) associated."));
}
"CENTERDISASSOCIATE" => {
@@ -561,7 +561,7 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
}
self.command_line
.push_output(&format!("CENTERDISASSOCIATE: {count} center object(s) detached."));
.push_output(&crate::tf!("CENTERDISASSOCIATE: {count} center object(s) detached."));
}
"DIMCENTER" => {
@@ -1159,7 +1159,7 @@ impl OpenCADStudio {
match parts.get(val_idx).and_then(|s| s.parse::<f64>().ok()) {
Some(v) => return Some(self.solid_section(axis, v)),
None => self.command_line.push_info(
"Usage: SECTION [X|Y|Z] <value> (cross-sections the selected solid)",
crate::t!("Usage: SECTION [X|Y|Z] <value> (cross-sections the selected solid)").as_ref(),
),
}
}
@@ -1185,7 +1185,7 @@ impl OpenCADStudio {
return Some(self.solid_align3d(src, dst));
}
self.command_line.push_info(
"Usage: 3DALIGN <sx1 sy1 sz1 … sx3 sy3 sz3 dx1 dy1 dz1 … dx3 dy3 dz3> (18 numbers: 3 source then 3 destination points)",
crate::t!("Usage: 3DALIGN <sx1 sy1 sz1 … sx3 sy3 sz3 dx1 dy1 dz1 … dx3 dy3 dz3> (18 numbers: 3 source then 3 destination points)").as_ref(),
);
}
@@ -1214,7 +1214,7 @@ impl OpenCADStudio {
Some("Z") => 2,
_ => {
self.command_line.push_info(
"Usage: 3DMIRROR [X|Y|Z] (mirrors the selected solid across that plane)",
crate::t!("Usage: 3DMIRROR [X|Y|Z] (mirrors the selected solid across that plane)").as_ref(),
);
return None;
}
@@ -1254,7 +1254,7 @@ impl OpenCADStudio {
match angle {
Some(a) => return Some(self.solid_rotate3d(axis, a)),
None => self.command_line.push_info(
"Usage: 3DROTATE [X|Y|Z] <angle> (rotates the selected solid)",
crate::t!("Usage: 3DROTATE [X|Y|Z] <angle> (rotates the selected solid)").as_ref(),
),
}
}
@@ -1294,7 +1294,7 @@ impl OpenCADStudio {
match value {
Some(v) => return Some(self.solid_slice(axis, v, keep_low)),
None => self.command_line.push_info(
"Usage: SLICE [X|Y|Z] <value> [TOP|BOTTOM] (cuts the selected solid)",
crate::t!("Usage: SLICE [X|Y|Z] <value> [TOP|BOTTOM] (cuts the selected solid)").as_ref(),
),
}
}
+7 -7
View File
@@ -54,7 +54,7 @@ impl OpenCADStudio {
self.command_line.push_output(crate::tf!(
"SAVEALL: saved {saved} drawing(s){}.",
if skipped > 0 {
format!("; {skipped} need SAVEAS (no file path yet)")
crate::tf!("; {skipped} need SAVEAS (no file path yet)").into_owned()
} else {
String::new()
}
@@ -130,10 +130,10 @@ impl OpenCADStudio {
let style = cmd.split_whitespace().nth(1).unwrap_or("");
let Some(mode) = visual_style::mode_for_keyword(style) else {
self.command_line
.push_error(visual_style::keyword_prompt());
.push_error(crate::t!(visual_style::keyword_prompt()).as_ref());
return Some(Task::none());
};
let label = visual_style::label_for(mode);
let label = crate::t!(visual_style::label_for(mode));
self.command_line
.push_output(crate::tf!("Visual style: {label}.").as_ref());
return Some(Task::done(Message::SetRenderMode(mode)));
@@ -220,11 +220,11 @@ impl OpenCADStudio {
"PERF" => {
self.perf_hud = !self.perf_hud;
crate::perf::set_ui_enabled(self.perf_hud);
self.command_line.push_info(if self.perf_hud {
self.command_line.push_info(crate::t!(if self.perf_hud {
"PERF panel on — tracing render and interaction costs"
} else {
"PERF panel off"
});
}).as_ref());
return Some(Task::none());
}
@@ -299,7 +299,7 @@ impl OpenCADStudio {
rgb[2]
).as_ref());
} else {
self.command_line.push_info("Usage: BACKGROUND DESK <r> <g> <b> | DEFAULT");
self.command_line.push_info(crate::t!("Usage: BACKGROUND DESK <r> <g> <b> | DEFAULT").as_ref());
}
} else if let Some(rgba) = parse_background_color(&args) {
let [r, g, b, _] = rgba;
@@ -322,7 +322,7 @@ impl OpenCADStudio {
).as_ref());
} else {
self.command_line.push_info(
"Usage: BACKGROUND <r> <g> <b> (0–255) | THEME|CLASSIC|DEFAULT|DESK|BLACK|DARKGRAY|GRAY|LIGHTGRAY|WHITE",
crate::t!("Usage: BACKGROUND <r> <g> <b> (0–255) | THEME|CLASSIC|DEFAULT|DESK|BLACK|DARKGRAY|GRAY|LIGHTGRAY|WHITE").as_ref(),
);
}
}
+37 -37
View File
@@ -119,9 +119,9 @@ impl OpenCADStudio {
} else {
use std::collections::BTreeMap;
let space = if scene.current_layout == "Model" {
"Model space".to_string()
crate::t!("Model space").into_owned()
} else {
format!("Paper space '{}'", scene.current_layout)
crate::tf!("Paper space '{}'", scene.current_layout).into_owned()
};
let mut handles: Vec<u64> = Vec::with_capacity(selected.len());
let mut type_counts: BTreeMap<&'static str, usize> = BTreeMap::new();
@@ -139,18 +139,18 @@ impl OpenCADStudio {
let types: Vec<String> =
type_counts.iter().map(|(t, n)| format!("{t}×{n}")).collect();
let list: Vec<String> = handles.iter().map(|h| format!("{:X}", h)).collect();
let mut msg = format!(
let mut msg = crate::tf!(
"SELHANDLES: {} selected in {}\n Types: {}",
handles.len(),
space,
types.join(", ")
);
).into_owned();
if !block_counts.is_empty() {
let blocks: Vec<String> =
block_counts.iter().map(|(b, n)| format!("{b}×{n}")).collect();
msg.push_str(&format!("\n Blocks: {}", blocks.join(", ")));
msg.push_str(&crate::tf!("\n Blocks: {}", blocks.join(", ")).into_owned());
}
msg.push_str(&format!("\n Handles: {}", list.join(",")));
msg.push_str(&crate::tf!("\n Handles: {}", list.join(",")).into_owned());
self.command_line.push_output(&msg);
}
}
@@ -180,10 +180,10 @@ impl OpenCADStudio {
};
let details = entity_list_details(entity);
format!(
"{type_name} Handle:{:X} Layer:{} Color:{} LT:{}{}",
common.handle.value(),
common.layer,
color_str,
"{type_name} {}:{:X} {}:{} {}:{} LT:{}{}",
crate::t!("Handle"), common.handle.value(),
crate::t!("Layer"), common.layer,
crate::t!("Color"), color_str,
linetype,
if details.is_empty() {
String::new()
@@ -1360,7 +1360,7 @@ impl OpenCADStudio {
// Use the first selected object as the template.
let Some(handle) = self.tabs[i].scene.selected.iter().next().copied() else {
self.command_line.push_info(
"ADDSELECTED: select an object first, then run ADDSELECTED to draw a new one like it.",
crate::t!("ADDSELECTED: select an object first, then run ADDSELECTED to draw a new one like it.").as_ref(),
);
return Task::none();
};
@@ -1558,7 +1558,7 @@ fn add_selected_verb(entity: &acadrust::EntityType) -> Option<&'static str> {
fn entity_list_details(entity: &acadrust::EntityType) -> String {
use std::f64::consts::PI;
match entity {
acadrust::EntityType::Line(l) => format!(
acadrust::EntityType::Line(l) => crate::tf!(
"from ({:.4},{:.4},{:.4}) to ({:.4},{:.4},{:.4}) len={:.4}",
l.start.x,
l.start.y,
@@ -1570,16 +1570,16 @@ fn entity_list_details(entity: &acadrust::EntityType) -> String {
+ (l.end.y - l.start.y).powi(2)
+ (l.end.z - l.start.z).powi(2))
.sqrt()
),
acadrust::EntityType::Circle(c) => format!(
).into_owned(),
acadrust::EntityType::Circle(c) => crate::tf!(
"center ({:.4},{:.4},{:.4}) r={:.4} area={:.4}",
c.center.x,
c.center.y,
c.center.z,
c.radius,
PI * c.radius * c.radius
),
acadrust::EntityType::Arc(a) => format!(
).into_owned(),
acadrust::EntityType::Arc(a) => crate::tf!(
"center ({:.4},{:.4},{:.4}) r={:.4} start={:.2}° end={:.2}°",
a.center.x,
a.center.y,
@@ -1587,25 +1587,25 @@ fn entity_list_details(entity: &acadrust::EntityType) -> String {
a.radius,
a.start_angle.to_degrees(),
a.end_angle.to_degrees()
),
acadrust::EntityType::LwPolyline(p) => format!(
).into_owned(),
acadrust::EntityType::LwPolyline(p) => crate::tf!(
"{} vertices closed={} elevation={:.4}",
p.vertices.len(),
p.is_closed,
p.elevation
),
acadrust::EntityType::Text(t) => format!(
).into_owned(),
acadrust::EntityType::Text(t) => crate::tf!(
"\"{}\" h={:.4} at ({:.4},{:.4})",
t.value, t.height, t.insertion_point.x, t.insertion_point.y
),
acadrust::EntityType::MText(t) => format!(
).into_owned(),
acadrust::EntityType::MText(t) => crate::tf!(
"\"{}\" h={:.4} at ({:.4},{:.4})",
t.value.chars().take(40).collect::<String>(),
t.height,
t.insertion_point.x,
t.insertion_point.y
),
acadrust::EntityType::Insert(ins) => format!(
).into_owned(),
acadrust::EntityType::Insert(ins) => crate::tf!(
"block=\"{}\" at ({:.4},{:.4},{:.4}) scale=({:.4},{:.4},{:.4}) rot={:.2}°",
ins.block_name,
ins.insert_point.x,
@@ -1615,20 +1615,20 @@ fn entity_list_details(entity: &acadrust::EntityType) -> String {
ins.y_scale(),
ins.z_scale(),
ins.rotation.to_degrees()
),
acadrust::EntityType::Spline(s) => format!(
).into_owned(),
acadrust::EntityType::Spline(s) => crate::tf!(
"{} ctrl pts degree={} closed={}",
s.control_points.len(),
s.degree,
s.flags.closed
),
acadrust::EntityType::Ellipse(e) => format!(
).into_owned(),
acadrust::EntityType::Ellipse(e) => crate::tf!(
"center ({:.4},{:.4}) major_len={:.4} ratio={:.4}",
e.center.x,
e.center.y,
e.major_axis_length(),
e.minor_axis_ratio
),
).into_owned(),
_ => String::new(),
}
}
@@ -1967,13 +1967,13 @@ fn entity_extra_info(entity: &acadrust::EntityType) -> String {
"BLK={} @({:.3},{:.3})",
e.block_name, e.insert_point.x, e.insert_point.y
),
EntityType::LwPolyline(e) => format!("{} vertices", e.vertices.len()),
EntityType::Polyline(e) => format!("{} vertices", e.vertices.len()),
EntityType::Polyline2D(e) => format!("{} vertices", e.vertices.len()),
EntityType::Polyline3D(e) => format!("{} vertices", e.vertices.len()),
EntityType::LwPolyline(e) => crate::tf!("{} vertices", e.vertices.len()).into_owned(),
EntityType::Polyline(e) => crate::tf!("{} vertices", e.vertices.len()).into_owned(),
EntityType::Polyline2D(e) => crate::tf!("{} vertices", e.vertices.len()).into_owned(),
EntityType::Polyline3D(e) => crate::tf!("{} vertices", e.vertices.len()).into_owned(),
EntityType::Hatch(e) => format!("PAT={}", e.pattern.name),
EntityType::Dimension(e) => format!("{:.3}", e.base().actual_measurement),
EntityType::Spline(e) => format!("{} ctrl pts", e.control_points.len()),
EntityType::Spline(e) => crate::tf!("{} ctrl pts", e.control_points.len()).into_owned(),
_ => String::new(),
}
}
@@ -1997,7 +1997,7 @@ fn arith_eval(expr: &str) -> Result<f64, String> {
};
let v = p.expr()?;
if p.pos != p.chars.len() {
return Err(format!("unexpected '{}'", p.chars[p.pos]));
return Err(crate::tf!("unexpected '{}'", p.chars[p.pos]).into_owned());
}
Ok(v)
}
@@ -2101,7 +2101,7 @@ impl ArithParser {
Ok(v)
}
Some(c) if c.is_ascii_digit() || c == '.' => self.number(),
Some(c) => Err(format!("unexpected '{c}'")),
Some(c) => Err(crate::tf!("unexpected '{c}'").into_owned()),
None => Err("unexpected end of expression".into()),
}
}
@@ -2116,7 +2116,7 @@ impl ArithParser {
}
}
let s: String = self.chars[start..self.pos].iter().collect();
s.parse::<f64>().map_err(|_| format!("bad number '{s}'"))
s.parse::<f64>().map_err(|_| crate::tf!("bad number '{s}'").into_owned())
}
}
+8 -8
View File
@@ -706,10 +706,10 @@ impl OpenCADStudio {
}
})
.map(|s| {
format!(
crate::tf!(
"{} (h_margin:{:.2} v_margin:{:.2})",
s.name, s.horizontal_margin, s.vertical_margin
)
).into_owned()
})
.collect();
if styles.is_empty() {
@@ -909,7 +909,7 @@ impl OpenCADStudio {
.document
.dim_styles
.iter()
.map(|s| format!("{}(txt:{:.2} asz:{:.2})", s.name, s.dimtxt, s.dimasz))
.map(|s| crate::tf!("{}(txt:{:.2} asz:{:.2})", s.name, s.dimtxt, s.dimasz).into_owned())
.collect();
if styles.is_empty() {
self.command_line.push_output(crate::t!("No dim styles defined.").as_ref());
@@ -1019,7 +1019,7 @@ impl OpenCADStudio {
}
_ => {
self.command_line.push_info(
"Usage: DIMSTYLE LIST | NEW <name> | SET <name> <prop> <val>",
crate::t!("Usage: DIMSTYLE LIST | NEW <name> | SET <name> <prop> <val>").as_ref(),
);
}
}
@@ -1043,10 +1043,10 @@ impl OpenCADStudio {
.values()
.filter_map(|o| {
if let ObjectType::MultiLeaderStyle(s) = o {
Some(format!(
Some(crate::tf!(
"{}(txt:{:.2} asz:{:.2})",
s.name, s.text_height, s.arrowhead_size
))
).into_owned())
} else {
None
}
@@ -1206,13 +1206,13 @@ impl OpenCADStudio {
.text_styles
.iter()
.map(|s| {
format!(
crate::tf!(
"{} (font: {}, w: {:.2}, oblique: {:.1}°)",
s.name,
s.font_file,
s.width_factor,
s.oblique_angle.to_degrees()
)
).into_owned()
})
.collect();
if styles.is_empty() {
+5 -16
View File
@@ -91,21 +91,10 @@ impl OpenCADStudio {
.filter(|&(code, _)| code != 0)
.map(|(code, label)| (label, units::short(code), None))
.collect();
// Built once: the table it comes from never changes, and
// `KeywordCommand` wants a `&'static str`.
static PROMPT: std::sync::OnceLock<String> = std::sync::OnceLock::new();
let prompt = PROMPT.get_or_init(|| {
let listed = units::all()
.filter(|&(code, _)| code != 0)
.map(|(code, label)| format!("{label}({})", units::short(code)))
.collect::<Vec<_>>()
.join(" / ");
format!("DWGUNITS convert to [{listed}]:")
});
let current = units::label(self.tabs[i].scene.document.header.insertion_units);
let current = crate::t!(units::label(self.tabs[i].scene.document.header.insertion_units));
self.command_line
.push_info(crate::tf!("DWGUNITS current unit: {current}").as_ref());
let c = KeywordCommand::new("DWGUNITS", prompt.as_str(), choices);
let c = KeywordCommand::new("DWGUNITS", "DWGUNITS Convert drawing to:", choices);
self.command_line.push_info(&c.prompt());
self.tabs[i].active_cmd = Some(Box::new(c));
}
@@ -157,7 +146,7 @@ impl OpenCADStudio {
}
if layer.eq_ignore_ascii_case(&self.tabs[i].active_layer) {
self.command_line.push_error(
"LAYDEL: cannot delete the current layer. Make another layer current first.",
crate::t!("LAYDEL: cannot delete the current layer. Make another layer current first.").as_ref(),
);
return Some(Task::none());
}
@@ -234,7 +223,7 @@ impl OpenCADStudio {
}
if src.eq_ignore_ascii_case(&self.tabs[i].active_layer) {
self.command_line.push_error(
"LAYMRG: cannot merge the current layer. Make another layer current first.",
crate::t!("LAYMRG: cannot merge the current layer. Make another layer current first.").as_ref(),
);
return Some(Task::none());
}
@@ -280,7 +269,7 @@ impl OpenCADStudio {
let states = self.tabs[i].scene.document.layer_states();
if states.is_empty() {
self.command_line.push_info(
"LAYERSTATE: no saved states. Use LAYERSTATE SAVE <name>.",
crate::t!("LAYERSTATE: no saved states. Use LAYERSTATE SAVE <name>.").as_ref(),
);
} else {
let mut names: Vec<&str> =
+23 -23
View File
@@ -29,7 +29,7 @@ impl OpenCADStudio {
let describe = |c: &Color| match c {
Color::ByLayer => "ByLayer".to_string(),
Color::ByBlock => "ByBlock".to_string(),
Color::Index(n) => format!("index {n}"),
Color::Index(n) => crate::tf!("index {n}").into_owned(),
_ => "(custom)".to_string(),
};
let arg = if cmd == "BYLAYER" {
@@ -65,7 +65,7 @@ impl OpenCADStudio {
}
None => {
self.command_line.push_error(
"Usage: COLOR <ByLayer|ByBlock|1-255|red|yellow|green|cyan|blue|magenta|white>",
crate::t!("Usage: COLOR <ByLayer|ByBlock|1-255|red|yellow|green|cyan|blue|magenta|white>").as_ref(),
);
}
}
@@ -486,19 +486,19 @@ impl OpenCADStudio {
// Per-type breakdown so the user sees exactly what went.
let mut parts: Vec<String> = Vec::new();
if n_layers > 0 {
parts.push(format!("{n_layers} layer(s)"));
parts.push(crate::tf!("{n_layers} layer(s)").into_owned());
}
if n_styles > 0 {
parts.push(format!("{n_styles} text style(s)"));
parts.push(crate::tf!("{n_styles} text style(s)").into_owned());
}
if n_lts > 0 {
parts.push(format!("{n_lts} linetype(s)"));
parts.push(crate::tf!("{n_lts} linetype(s)").into_owned());
}
if n_blocks > 0 {
parts.push(format!("{n_blocks} block(s)"));
parts.push(crate::tf!("{n_blocks} block(s)").into_owned());
}
if n_sortents > 0 {
parts.push(format!("{n_sortents} stale draw-order table(s)"));
parts.push(crate::tf!("{n_sortents} stale draw-order table(s)").into_owned());
}
self.command_line.push_output(crate::tf!(
"PURGE: {} item(s) removed — {}.",
@@ -539,7 +539,7 @@ impl OpenCADStudio {
if prop.is_empty() {
self.command_line.push_info(
"Usage: CHPROP <prop> <val> (props: LAYER COLOR LINETYPE LTSCALE)",
crate::t!("Usage: CHPROP <prop> <val> (props: LAYER COLOR LINETYPE LTSCALE)").as_ref(),
);
} else {
let handles: Vec<_> = self.tabs[i]
@@ -940,7 +940,7 @@ impl OpenCADStudio {
let value = it.next().map(|s| s.trim().to_string());
if name.is_empty() || name == "?" {
self.command_line.push_info(
"SETVAR: LTSCALE CELTSCALE PDMODE PDSIZE TEXTSIZE ORTHOMODE FILLMODE MIRRTEXT FRAME IMAGEFRAME PDFFRAME WIPEOUTFRAME XCLIPFRAME POINTCLOUDCLIPFRAME ZOOMWHEEL ZOOMFACTOR CURSORSIZE PICKBOX CURSORTYPE SNAPANG TEXTFILL CLIPROMPTLINES COMMANDLINEFADETIME ATTREQ ATTDIA DIMASSOC DIMCONTINUEMODE ANGBASE ANGDIR SKETCHINC SKPOLY SKTOLERANCE DONUTID DONUTOD CENTEREXE CENTERLAYER CENTERLTYPE CENTERLTSCALE CENTERLTYPEFILE CENTERCROSSSIZE CENTERCROSSGAP CENTERMARKEXE COLORTHEME SELECTIONAREA SELECTIONAREAOPACITY SELECTIONEFFECT SELECTIONEFFECTCOLOR WINDOWSAREACOLOR CROSSINGAREACOLOR SELECTIONPREVIEW GRIPSIZE GRIPCOLOR GRIPHOT GRIPHOVER | CLAYER CELTYPE TEXTSTYLE (read-only)",
crate::t!("SETVAR: LTSCALE CELTSCALE PDMODE PDSIZE TEXTSIZE ORTHOMODE FILLMODE MIRRTEXT FRAME IMAGEFRAME PDFFRAME WIPEOUTFRAME XCLIPFRAME POINTCLOUDCLIPFRAME ZOOMWHEEL ZOOMFACTOR CURSORSIZE PICKBOX CURSORTYPE SNAPANG TEXTFILL CLIPROMPTLINES COMMANDLINEFADETIME ATTREQ ATTDIA DIMASSOC DIMCONTINUEMODE ANGBASE ANGDIR SKETCHINC SKPOLY SKTOLERANCE DONUTID DONUTOD CENTEREXE CENTERLAYER CENTERLTYPE CENTERLTSCALE CENTERLTYPEFILE CENTERCROSSSIZE CENTERCROSSGAP CENTERMARKEXE COLORTHEME SELECTIONAREA SELECTIONAREAOPACITY SELECTIONEFFECT SELECTIONEFFECTCOLOR WINDOWSAREACOLOR CROSSINGAREACOLOR SELECTIONPREVIEW GRIPSIZE GRIPCOLOR GRIPHOT GRIPHOVER | CLAYER CELTYPE TEXTSTYLE (read-only)").as_ref(),
);
} else {
if matches!(name.as_str(), "SHOWHIST" | "SOLIDHIST") {
@@ -964,12 +964,12 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
self.refresh_properties();
}
self.command_line.push_output(&format!("{name} = {mode}"));
self.command_line.push_output(&crate::tf!("{name} = {mode}"));
}
None => self.command_line.push_error(&format!("{name}: expected an integer from 0 to {maximum}.")),
None => self.command_line.push_error(&crate::tf!("{name}: expected an integer from 0 to {maximum}.")),
}
} else {
self.command_line.push_output(&format!("Enter new value for {name} <{current}>:"));
self.command_line.push_output(&crate::tf!("Enter new value for {name} <{current}>:"));
self.pending_setvar = Some(name.clone());
}
return Some(self.finish_dispatch(cmd));
@@ -1033,7 +1033,7 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
}
self.command_line
.push_output(&format!("{name} = {mode}"));
.push_output(&crate::tf!("{name} = {mode}"));
}
_ => self.command_line.push_error(
crate::tf!("SETVAR: {name} requires 0, 1, or 2.").as_ref(),
@@ -1095,10 +1095,10 @@ impl OpenCADStudio {
self.dimension_continue_mode = mode;
self.persist_settings_if_changed();
self.command_line
.push_output(&format!("DIMCONTINUEMODE = {mode}"));
.push_output(&crate::tf!("DIMCONTINUEMODE = {mode}"));
}
_ => self.command_line.push_error(
"SETVAR: DIMCONTINUEMODE requires 0 or 1.",
crate::t!("SETVAR: DIMCONTINUEMODE requires 0 or 1.").as_ref(),
),
}
} else {
@@ -1136,13 +1136,13 @@ impl OpenCADStudio {
crate::modules::draw::defaults::set_donut_outer_diameter(number);
}
self.command_line
.push_output(&format!("{name} = {number}"));
.push_output(&crate::tf!("{name} = {number}"));
} else {
self.command_line.push_error(if name == "DONUTID" {
self.command_line.push_error(crate::t!(if name == "DONUTID" {
"SETVAR: DONUTID requires a finite value greater than or equal to zero."
} else {
"SETVAR: DONUTOD requires a finite value greater than zero."
});
}).as_ref());
}
} else {
self.command_line.push_output(crate::tf!(
@@ -2097,7 +2097,7 @@ impl OpenCADStudio {
false,
)),
},
_ => Err(format!("SETVAR: unknown variable \"{name}\".")),
_ => Err(crate::tf!("SETVAR: unknown variable \"{name}\".").into_owned()),
}
};
match outcome {
@@ -2501,7 +2501,7 @@ impl OpenCADStudio {
self.command_line.push_output(crate::tf!("PDMODE set to {v}").as_ref());
} else {
self.command_line.push_error(
"Usage: PDMODE [value] (0=dot 1=none 2=+ 3=x 4=tick; +32 circle, +64 square)",
crate::t!("Usage: PDMODE [value] (0=dot 1=none 2=+ 3=x 4=tick; +32 circle, +64 square)").as_ref(),
);
}
}
@@ -2569,7 +2569,7 @@ impl OpenCADStudio {
self.persist_settings_if_changed();
match crate::io::file_association::register_as_handler() {
Ok(()) => self.command_line.push_output(
"FILEASSOC set to 1 — registered as a .dwg/.dxf/.bak handler",
crate::t!("FILEASSOC set to 1 — registered as a .dwg/.dxf/.bak handler").as_ref(),
),
Err(e) => self
.command_line
@@ -2614,7 +2614,7 @@ impl OpenCADStudio {
let msg = if v == 0 {
"SAVETIME set to 0 (autosave off)".to_string()
} else {
format!("SAVETIME set to {v} minute(s)")
crate::tf!("SAVETIME set to {v} minute(s)").into_owned()
};
self.command_line.push_output(&msg);
}
@@ -2646,7 +2646,7 @@ impl OpenCADStudio {
.push_output(crate::tf!("PDSIZE set to {v:.4}").as_ref());
} else {
self.command_line.push_error(
"Usage: PDSIZE [value] (>0 absolute size, <0 percent of viewport, 0 default)",
crate::t!("Usage: PDSIZE [value] (>0 absolute size, <0 percent of viewport, 0 default)").as_ref(),
);
}
}
+14 -14
View File
@@ -257,7 +257,7 @@ impl OpenCADStudio {
let path = cmd.trim_start_matches("CUIEXPORT").trim();
if path.is_empty() {
self.command_line.push_info(
"Usage: CUIEXPORT <path> — save the keyboard shortcuts to a file.",
crate::t!("Usage: CUIEXPORT <path> — save the keyboard shortcuts to a file.").as_ref(),
);
return Some(Task::none());
}
@@ -290,7 +290,7 @@ impl OpenCADStudio {
.trim();
if path.is_empty() {
self.command_line.push_info(
"Usage: CUIIMPORT <path> — load keyboard shortcuts from a file.",
crate::t!("Usage: CUIIMPORT <path> — load keyboard shortcuts from a file.").as_ref(),
);
return Some(Task::none());
}
@@ -381,12 +381,12 @@ impl OpenCADStudio {
"COLORSCHEME",
"COLORSCHEME Enter theme name (or ? to list):",
);
self.command_line.push_output(
"Available themes: DARK LIGHT DRACULA NORD SOLARIZED_LIGHT SOLARIZED_DARK \
self.command_line.push_output(&crate::tf!("Available themes: {}",
"DARK LIGHT DRACULA NORD SOLARIZED_LIGHT SOLARIZED_DARK \
GRUVBOX_LIGHT GRUVBOX_DARK TOKYONIGHT TOKYONIGHTSTORM TOKYONIGHTLIGHT \
KANAGAWAWAVE KANAGAWADRAGON KANAGAWALOTUS MOONFLY NIGHTFLY OXOCARBON FERRA",
);
self.command_line.push_info(&format!(
));
self.command_line.push_info(&crate::tf!(
"Current color scheme: <{}>",
self.ui_theme.name
));
@@ -398,23 +398,23 @@ impl OpenCADStudio {
let sub = cmd.split_once(' ').map(|(_, r)| r.trim()).unwrap_or("");
let upper_sub = sub.to_ascii_uppercase();
if upper_sub.is_empty() {
self.command_line.push_output(&format!(
self.command_line.push_output(&crate::tf!(
"Current color scheme: <{}>",
self.ui_theme.name
));
return Some(Task::none());
}
if upper_sub == "LIST" || upper_sub == "?" {
self.command_line.push_output(
"Available themes: DARK LIGHT DRACULA NORD SOLARIZED_LIGHT SOLARIZED_DARK \
self.command_line.push_output(&crate::tf!("Available themes: {}",
"DARK LIGHT DRACULA NORD SOLARIZED_LIGHT SOLARIZED_DARK \
GRUVBOX_LIGHT GRUVBOX_DARK TOKYONIGHT TOKYONIGHTSTORM TOKYONIGHTLIGHT \
KANAGAWAWAVE KANAGAWADRAGON KANAGAWALOTUS MOONFLY NIGHTFLY OXOCARBON FERRA",
);
));
return Some(Task::none());
}
if sub == "0" || sub == "1" {
self.command_line.push_error(
"COLORSCHEME: 0 and 1 are COLORTHEME options. Enter a theme name (e.g. DARK, LIGHT, DRACULA) or use COLORTHEME.",
crate::t!("COLORSCHEME: 0 and 1 are COLORTHEME options. Enter a theme name (e.g. DARK, LIGHT, DRACULA) or use COLORTHEME.").as_ref(),
);
return Some(Task::none());
}
@@ -630,7 +630,7 @@ impl OpenCADStudio {
}
_ => {
self.command_line.push_error(
"VPORTS: unknown option. Use VPORTS 2H | 2V | 4 | SINGLE",
crate::t!("VPORTS: unknown option. Use VPORTS 2H | 2V | 4 | SINGLE").as_ref(),
);
vec![]
}
@@ -1161,7 +1161,7 @@ impl OpenCADStudio {
.collect();
if vps.len() < 2 {
self.command_line.push_error(
"SYNCPVIEWPORTS: select two or more viewports (the first is the master).",
crate::t!("SYNCPVIEWPORTS: select two or more viewports (the first is the master).").as_ref(),
);
return Some(Task::none());
}
@@ -1215,7 +1215,7 @@ impl OpenCADStudio {
// that work.
None => self
.command_line
.push_info(visual_style::keyword_prompt()),
.push_info(crate::t!(visual_style::keyword_prompt()).as_ref()),
}
}
+1 -1
View File
@@ -836,7 +836,7 @@ impl OpenCADStudio {
if let Some(doc) = target {
let Some(i) = self.tabs.iter().position(|t| t.id == doc) else {
self.command_line
.push_error("Automation target document closed");
.push_error(crate::t!("Automation target document closed").as_ref());
return Task::none();
};
self.active_tab = i;
+13 -13
View File
@@ -60,12 +60,12 @@ impl OpenCADStudio {
}
self.find_replace.current_match = Some(target);
self.find_replace.status = format!(
self.find_replace.status = crate::tf!(
"{} of {} — {}",
index + 1,
matches.len(),
match_label(target)
);
).into_owned();
self.tabs[i].scene.deselect_all();
self.tabs[i]
.scene
@@ -99,7 +99,7 @@ impl OpenCADStudio {
let search = self.find_replace.search.clone();
let replacement = self.find_replace.replacement.clone();
if match_is_locked(&self.tabs[i].scene, target) {
self.find_replace.status = "The matching object is on a locked layer.".to_string();
self.find_replace.status = crate::t!("The matching object is on a locked layer.").into_owned();
return;
}
self.push_undo_snapshot(i, "FIND/REPLACE");
@@ -131,10 +131,10 @@ impl OpenCADStudio {
self.tabs[i].dirty = true;
self.find_replace.current_match = None;
let remaining = self.find_text_matches(i).len();
self.find_replace.status = format!(
self.find_replace.status = crate::tf!(
"Replaced 1 occurrence in {}; {remaining} matching object(s) remain.",
match_label(target)
);
).into_owned();
self.command_line.push_output(crate::tf!(
"FIND/REPLACE: replaced 1 occurrence of \"{search}\"."
).as_ref());
@@ -192,10 +192,10 @@ impl OpenCADStudio {
}
self.tabs[i].dirty = true;
self.find_replace.current_match = None;
self.find_replace.status = format!(
self.find_replace.status = crate::tf!(
"Replaced {replaced} occurrence(s) in {} object(s).",
changed.len()
);
).into_owned();
self.command_line.push_output(crate::tf!(
"FIND/REPLACE: replaced {replaced} occurrence(s) of \"{search}\"."
).as_ref());
@@ -286,9 +286,9 @@ impl OpenCADStudio {
fn no_match_status(search: &str) -> String {
if search.trim().is_empty() {
"Enter text to find.".to_string()
crate::t!("Enter text to find.").into_owned()
} else {
format!("\"{search}\" was not found.")
crate::tf!("\"{search}\" was not found.").into_owned()
}
}
@@ -372,16 +372,16 @@ fn match_is_locked(scene: &crate::scene::Scene, target: FindMatchKey) -> bool {
fn match_label(target: FindMatchKey) -> String {
match target {
FindMatchKey::Entity(handle) => format!("handle {:X}", handle.value()),
FindMatchKey::Entity(handle) => crate::tf!("handle {:X}", handle.value()).into_owned(),
FindMatchKey::BlockEntityInInsert { entity, insert } => {
format!(
crate::tf!(
"block {:X}, text {:X}",
insert.value(),
entity.value()
)
).into_owned()
}
FindMatchKey::InsertAttribute { insert, index } => {
format!("block {:X}, attribute {}", insert.value(), index + 1)
crate::tf!("block {:X}, attribute {}", insert.value(), index + 1).into_owned()
}
}
}
+1 -1
View File
@@ -160,7 +160,7 @@ impl std::fmt::Display for QSelectOp {
QSelectOp::Gt => "> Greater than",
QSelectOp::Lt => "< Less than",
};
f.write_str(s)
f.write_str(crate::t!(s).as_ref())
}
}
+6 -6
View File
@@ -161,7 +161,7 @@ pub(super) fn on_ribbon_tool_click(&mut self, tool_id: String, event: ModuleEven
crate::tf!("Unknown visual style \"{name}\".").as_ref(),
);
self.command_line
.push_info(visual_style::keyword_prompt());
.push_info(crate::t!(visual_style::keyword_prompt()).as_ref());
}
}
}
@@ -181,7 +181,7 @@ pub(super) fn on_ribbon_tool_click(&mut self, tool_id: String, event: ModuleEven
let path = crate::sys::file_dialog()
.set_title(title)
.add_filter(filter_name, &exts)
.add_filter("All Files", &["*"])
.add_filter(crate::t!("All Files").as_ref(), &["*"])
.pick_file()
.await
.map(|h| crate::sys::handle_path(&h));
@@ -520,8 +520,8 @@ pub(super) fn on_ribbon_tool_click(&mut self, tool_id: String, event: ModuleEven
BlockPaletteMsg::PickFile => iced::Task::perform(
async {
let handle = rfd::AsyncFileDialog::new()
.set_title("Select Drawing to Insert as Block")
.add_filter("DWG/DXF Files", &["dwg", "dxf", "DWG", "DXF"])
.set_title(crate::t!("Select Drawing to Insert as Block").as_ref())
.add_filter(crate::t!("DWG/DXF Files").as_ref(), &["dwg", "dxf", "DWG", "DXF"])
.pick_file()
.await;
match handle {
@@ -535,12 +535,12 @@ pub(super) fn on_ribbon_tool_click(&mut self, tool_id: String, event: ModuleEven
match self.import_file_as_block(path) {
Ok(name) => {
self.command_line
.push_output(&format!("Inserting \"{name}\" from file."));
.push_output(&crate::tf!("Inserting \"{name}\" from file."));
self.refresh_block_palette();
self.start_block_placement(&name);
}
Err(e) if e != "Cancelled" => {
self.command_line.push_error(&format!("INSERT FILE: {e}"));
self.command_line.push_error(&crate::tf!("INSERT FILE: {e}"));
}
Err(_) => {}
}
+23 -23
View File
@@ -2576,7 +2576,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
let pick = Task::perform(
async move {
let mut dlg = crate::sys::file_dialog()
.set_title("Save Drawing As")
.set_title(crate::t!("Save Drawing As").as_ref())
.set_file_name(default_name)
.add_filter(filter_label, &[filter_ext]);
if let Some(dir) = seed_dir {
@@ -2934,8 +2934,8 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
plot_style.as_ref(),
render_options,
)
.map(|_| format!("Exported: {}", worker_path.display()))
.map_err(|e| format!("Export failed: {e}"))
.map(|_| crate::tf!("Exported: {}", worker_path.display()).into_owned())
.map_err(|e| crate::tf!("Export failed: {e}").into_owned())
};
self.run_plot_work(self.plot_dialog.background, false, work)
}
@@ -2978,12 +2978,12 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
plot_style.as_ref(),
render_options,
)
.map(|_| {format!(
.map(|_| {crate::tf!(
"Plotted window to {}",
worker_path
.file_name().unwrap_or_default().to_string_lossy()
)
}).map_err(|e| format!("Plot failed: {e}"))
).into_owned()
}).map_err(|e| crate::tf!("Plot failed: {e}").into_owned())
};
self.run_plot_work(self.plot_dialog.background, false, work)
}
@@ -3071,7 +3071,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
let page_setup = self.tabs[i]
.scene
.plot_settings_for(&name)
.ok_or_else(|| format!("Layout '{name}' has no page setup."))?;
.ok_or_else(|| crate::tf!("Layout '{name}' has no page setup.").into_owned())?;
{
let scene = &mut self.tabs[i].scene;
scene.current_layout = name.clone();
@@ -3092,10 +3092,10 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
self.tabs[i].scene.restore_saved_camera();
}
if dialog.style_missing && dialog.apply_plot_styles {
return Err(format!(
return Err(crate::tf!(
"Layout '{name}' plot style table '{}' is not loaded.",
dialog.style_name
));
).into_owned());
}
let plot_style = self.dialog_plot_style(&dialog);
let params = match dialog.area.as_str() {
@@ -3135,7 +3135,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
rotation_deg,
scale,
clip,
) = params.ok_or_else(|| format!("Layout '{name}' plot area is empty."))?;
) = params.ok_or_else(|| crate::tf!("Layout '{name}' plot area is empty.").into_owned())?;
(
std::sync::Arc::new(wires),
hatches,
@@ -3219,8 +3219,8 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
&worker_path,
None,
)
.map(|_| format!("Exported {} layouts to {}", pages.len(), worker_path.display()))
.map_err(|error| format!("Export failed: {error}"))
.map(|_| crate::tf!("Exported {} layouts to {}", pages.len(), worker_path.display()).into_owned())
.map_err(|error| crate::tf!("Export failed: {error}").into_owned())
};
self.run_print_all_work(dialog.background, work)
}
@@ -3269,8 +3269,8 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
.and_then(|_| {
crate::io::print_to_printer::print_existing_pdf(&temp_path, &options)
})
.map(|printer| format!("Sent {} layouts to printer: {printer}", pages.len()))
.map_err(|error| format!("Print failed: {error}"))
.map(|printer| crate::tf!("Sent {} layouts to printer: {printer}", pages.len()).into_owned())
.map_err(|error| crate::tf!("Print failed: {error}").into_owned())
};
self.run_print_all_work(true, work)
}
@@ -4480,7 +4480,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
plot_style.as_ref(),
render_options,
).and_then(|_| crate::io::print_to_printer::open_in_viewer(&tmp))
.map(|_| "Opened plot preview.".to_string()).map_err(|e| format!("Preview failed: {e}"))
.map(|_| crate::t!("Opened plot preview.").into_owned()).map_err(|e| crate::tf!("Preview failed: {e}").into_owned())
};
return self.run_plot_work(d.background, true, work);
}
@@ -4497,8 +4497,8 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
plot_style.as_ref(),
render_options,
).and_then(|_| crate::io::print_to_printer::print_existing_pdf(&tmp, &opts))
.map(|printer| format!("Sent to printer: {printer}"))
.map_err(|e| format!("Print failed: {e}"))
.map(|printer| crate::tf!("Sent to printer: {printer}").into_owned())
.map_err(|e| crate::tf!("Print failed: {e}").into_owned())
};
return self.run_plot_work(true, false, work);
}
@@ -4525,7 +4525,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
plot_style.as_ref(),
render_options,
).and_then(|_| crate::io::print_to_printer::open_in_viewer(&tmp))
.map(|_| "Opened plot preview.".to_string()).map_err(|e| format!("Preview failed: {e}"))
.map(|_| crate::t!("Opened plot preview.").into_owned()).map_err(|e| crate::tf!("Preview failed: {e}").into_owned())
};
return self.run_plot_work(d.background, true, work);
}
@@ -4543,8 +4543,8 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
wires, hatches, wipeouts, page_w, page_h, ox, oy, rotation, scale, clip,
plot_style, opts,
))
.map(|printer| format!("Sent to printer: {printer}"))
.map_err(|error| format!("Print failed: {error}"))
.map(|printer| crate::tf!("Sent to printer: {printer}").into_owned())
.map_err(|error| crate::tf!("Print failed: {error}").into_owned())
};
self.run_plot_work(true, false, work)
}
@@ -4860,10 +4860,10 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
Task::perform(
async move {
let dialog = crate::sys::file_dialog()
.set_title("Save Plot Style Table")
.set_title(crate::t!("Save Plot Style Table").as_ref())
.set_file_name(&default_name)
.add_filter("Plot Style Files", &["ctb", "CTB"])
.add_filter("All Files", &["*"]);
.add_filter(crate::t!("Plot Style Files").as_ref(), &["ctb", "CTB"])
.add_filter(crate::t!("All Files").as_ref(), &["*"]);
#[cfg(not(target_arch = "wasm32"))]
let dialog = match crate::io::plot_style::ensure_plot_styles_dir() {
Ok(dir) => dialog.set_directory(dir),
+38 -38
View File
@@ -907,8 +907,8 @@ impl OpenCADStudio {
Message::PdfAttachPick => Task::perform(
async {
let handle = crate::sys::file_dialog()
.set_title("Select PDF Underlay")
.add_filter("PDF Files", &["pdf", "PDF"])
.set_title(crate::t!("Select PDF Underlay").as_ref())
.add_filter(crate::t!("PDF Files").as_ref(), &["pdf", "PDF"])
.pick_file()
.await;
@@ -961,11 +961,11 @@ impl OpenCADStudio {
Message::XAttachPick => Task::perform(
async {
let handle = crate::sys::file_dialog()
.set_title("Select External Reference File")
.add_filter("CAD Files", &["dwg", "dxf", "bak", "DWG", "DXF", "BAK"])
.add_filter("DWG Files", &["dwg", "DWG"])
.add_filter("DXF Files", &["dxf", "DXF"])
.add_filter("Backup Files", &["bak", "BAK"])
.set_title(crate::t!("Select External Reference File").as_ref())
.add_filter(crate::t!("CAD Files").as_ref(), &["dwg", "dxf", "bak", "DWG", "DXF", "BAK"])
.add_filter(crate::t!("DWG Files").as_ref(), &["dwg", "DWG"])
.add_filter(crate::t!("DXF Files").as_ref(), &["dxf", "DXF"])
.add_filter(crate::t!("Backup Files").as_ref(), &["bak", "BAK"])
.pick_file()
.await;
match handle {
@@ -999,9 +999,9 @@ impl OpenCADStudio {
Task::perform(
async move {
let path = crate::sys::file_dialog()
.set_title("Save Block As")
.set_title(crate::t!("Save Block As").as_ref())
.set_file_name("block.dwg")
.add_filter("DWG Files", &["dwg"])
.add_filter(crate::t!("DWG Files").as_ref(), &["dwg"])
.save_file()
.await
.map(|h| crate::sys::handle_path(&h));
@@ -1035,10 +1035,10 @@ impl OpenCADStudio {
Task::perform(
async move {
let path = crate::sys::file_dialog()
.set_title("Save Data Extraction")
.set_title(crate::t!("Save Data Extraction").as_ref())
.set_file_name("extraction.csv")
.add_filter("CSV", &["csv"])
.add_filter("All Files", &["*"])
.add_filter(crate::t!("CSV").as_ref(), &["csv"])
.add_filter(crate::t!("All Files").as_ref(), &["*"])
.save_file()
.await
.map(|h| crate::sys::handle_path(&h));
@@ -1078,10 +1078,10 @@ impl OpenCADStudio {
Task::perform(
async {
crate::sys::file_dialog()
.set_title("Export STL")
.set_title(crate::t!("Export STL").as_ref())
.set_file_name("export.stl")
.add_filter("STL Files", &["stl"])
.add_filter("All Files", &["*"])
.add_filter(crate::t!("STL Files").as_ref(), &["stl"])
.add_filter(crate::t!("All Files").as_ref(), &["*"])
.save_file()
.await
.map(|h| crate::sys::handle_path(&h))
@@ -1115,10 +1115,10 @@ impl OpenCADStudio {
Task::perform(
async {
crate::sys::file_dialog()
.set_title("Export STEP AP203")
.set_title(crate::t!("Export STEP AP203").as_ref())
.set_file_name("export.step")
.add_filter("STEP Files", &["step", "stp"])
.add_filter("All Files", &["*"])
.add_filter(crate::t!("STEP Files").as_ref(), &["step", "stp"])
.add_filter(crate::t!("All Files").as_ref(), &["*"])
.save_file()
.await
.map(|h| crate::sys::handle_path(&h))
@@ -1145,9 +1145,9 @@ impl OpenCADStudio {
Message::ObjImport => Task::perform(
async {
crate::sys::file_dialog()
.set_title("Import OBJ Mesh")
.add_filter("Wavefront OBJ", &["obj", "OBJ"])
.add_filter("All Files", &["*"])
.set_title(crate::t!("Import OBJ Mesh").as_ref())
.add_filter(crate::t!("Wavefront OBJ").as_ref(), &["obj", "OBJ"])
.add_filter(crate::t!("All Files").as_ref(), &["*"])
.pick_file()
.await
.map(|h| crate::sys::handle_path(&h))
@@ -1286,11 +1286,11 @@ impl OpenCADStudio {
.scene
.set_projection_preserving_frame(proj);
self.ribbon.set_ortho(ortho);
self.command_line.push_output(if ortho {
self.command_line.push_output(crate::t!(if ortho {
"Projection: Orthographic"
} else {
"Projection: Perspective"
});
}).as_ref());
Task::none()
}
@@ -6613,13 +6613,13 @@ impl OpenCADStudio {
crate::plugin::external::normalize_repository(&self.plugin_repo_input)
else {
self.marketplace_status =
"Enter a GitHub URL or repository in owner/repo format.".to_string();
crate::t!("Enter a GitHub URL or repository in owner/repo format.").into_owned();
return Task::none();
};
if self.plugin_repos.contains(&repo)
|| self.plugin_registry.iter().any(|entry| entry.repo == repo)
{
self.marketplace_status = format!("{repo} is already in the catalog.");
self.marketplace_status = crate::tf!("{repo} is already in the catalog.").into_owned();
self.selected_plugin_repo = Some(repo.clone());
if !self.plugin_readmes.contains_key(&repo)
&& self.plugin_readme_loading.insert(repo.clone())
@@ -6633,7 +6633,7 @@ impl OpenCADStudio {
.iter()
.any(|plugin| plugin.repository.as_deref() == Some(repo.as_str()))
{
self.marketplace_status = format!("{repo} is already installed.");
self.marketplace_status = crate::tf!("{repo} is already installed.").into_owned();
self.selected_plugin_repo = Some(repo.clone());
if !self.plugin_readmes.contains_key(&repo)
&& self.plugin_readme_loading.insert(repo.clone())
@@ -6645,7 +6645,7 @@ impl OpenCADStudio {
self.plugin_repos.push(repo.clone());
self.plugin_repo_input.clear();
self.persist_settings_if_changed();
self.marketplace_status = format!("Fetching releases for {repo}…");
self.marketplace_status = crate::tf!("Fetching releases for {repo}…").into_owned();
self.selected_plugin_repo = Some(repo.clone());
self.plugin_readmes.remove(&repo);
self.plugin_readme_loading.insert(repo.clone());
@@ -6791,12 +6791,12 @@ impl OpenCADStudio {
.entry(repo.clone())
.or_insert_with(|| first.tag.clone());
}
if self.marketplace_status == format!("Fetching releases for {repo}…") {
if self.marketplace_status == crate::tf!("Fetching releases for {repo}…").into_owned() {
self.marketplace_status =
format!(
crate::tf!(
"Repository added. {} installable release(s) found.",
releases.len()
);
).into_owned();
}
self.repo_release_tags.insert(repo, releases);
Task::none()
@@ -6834,15 +6834,15 @@ impl OpenCADStudio {
let Some(tag) = self.repo_selected_tag.get(&repo).cloned() else {
return Task::none();
};
self.marketplace_status = format!("Installing {repo} {tag}…");
self.marketplace_status = crate::tf!("Installing {repo} {tag}…").into_owned();
self.install_task(repo, tag)
}
Message::PluginUpdate(repo, tag) => {
self.marketplace_status = format!("Updating {repo} to {tag}…");
self.marketplace_status = crate::tf!("Updating {repo} to {tag}…").into_owned();
self.install_task(repo, tag)
}
Message::PluginInstalled(Ok(id)) => {
self.marketplace_status = format!("Installed '{id}'. Restart to load it.");
self.marketplace_status = crate::tf!("Installed '{id}'. Restart to load it.").into_owned();
self.plugin_load_errors.remove(&id);
#[cfg(not(target_arch = "wasm32"))]
{
@@ -6851,7 +6851,7 @@ impl OpenCADStudio {
Task::none()
}
Message::PluginInstalled(Err(e)) => {
self.marketplace_status = format!("Install failed: {e}");
self.marketplace_status = crate::tf!("Install failed: {e}").into_owned();
Task::none()
}
Message::PluginUninstall(id) => {
@@ -6861,20 +6861,20 @@ impl OpenCADStudio {
// and allows the package directory to be deleted.
if !crate::plugin::external::remove_plugin(&id) {
self.marketplace_status =
format!("Uninstall failed: plugin '{id}' did not stop in time");
crate::tf!("Uninstall failed: plugin '{id}' did not stop in time").into_owned();
return Task::none();
}
match crate::plugin::external::uninstall(&id) {
Ok(()) => {
self.marketplace_status =
format!("Uninstalled '{id}'.");
crate::tf!("Uninstalled '{id}'.").into_owned();
self.plugin_load_errors.remove(&id);
self.loaded_plugin_ids.remove(&id);
self.rebuild_ribbon_modules();
self.external_plugins = crate::plugin::external::discover();
}
Err(e) => {
self.marketplace_status = format!("Uninstall failed: {e}");
self.marketplace_status = crate::tf!("Uninstall failed: {e}").into_owned();
}
}
}
@@ -7344,7 +7344,7 @@ impl OpenCADStudio {
Message::PlotStyleLoaded(Some(table)) => {
if table.is_stb {
self.command_line.push_error(
"Named plot style tables are not supported by the vector plotter.",
crate::t!("Named plot style tables are not supported by the vector plotter.").as_ref(),
);
return Task::none();
}
+1 -1
View File
@@ -5122,7 +5122,7 @@ impl OpenCADStudio {
}
self.tabs[i].scene.camera_generation += 1;
self.command_line
.push_output(crate::tf!("View: {}", region.label()).as_ref());
.push_output(crate::tf!("View: {}", crate::t!(region.label())).as_ref());
Task::none()
}
+5 -5
View File
@@ -1485,7 +1485,7 @@ bg={bg_ms:.1}ms n={view_count}"
);
let trace = crate::perf::snapshot_tail_text(80);
let trace = if trace.is_empty() {
"No samples yet".to_string()
t!("No samples yet").into_owned()
} else {
trace
};
@@ -2204,7 +2204,7 @@ bg={bg_ms:.1}ms n={view_count}"
crate::ui::modal::modal(
base,
"Select Color",
t!("Select Color"),
content,
Message::CloseColorPicker,
self.modal_offset,
@@ -2713,7 +2713,7 @@ fn doc_tab_context_menu(
let item = |label: &'static str, msg: Option<Message>| -> Element<'static, Message> {
let enabled = msg.is_some();
let content = container(text(label).size(12))
let content = container(text(t!(label)).size(12))
.padding([4, 12])
.width(Fill)
.style(move |theme: &Theme| {
@@ -3233,7 +3233,7 @@ fn start_page_content<'a>(
{
// Filled with the active theme's primary colour.
secondary_items.push(
button(text("OCS Web").size(14))
button(text(crate::t!("OCS Web")).size(14))
.on_press(Message::RibbonToolClick {
tool_id: "WEBVERSION".to_string(),
event: crate::modules::ModuleEvent::Command("WEBVERSION".to_string()),
@@ -3245,7 +3245,7 @@ fn start_page_content<'a>(
}
#[cfg(target_arch = "wasm32")]
secondary_items.push(
button(text("OCS Desktop").size(14))
button(text(crate::t!("OCS Desktop")).size(14))
.on_press(Message::OpenUrl(
"https://github.com/HakanSeven12/OpenCADStudio/releases/latest".to_string(),
))
+9 -9
View File
@@ -69,7 +69,7 @@ pub(super) fn text_inline_overlay(
position_canvas_overlay(anchor, panel.into())
}
// Stroke-font families the renderer ships (LibreCAD LFF; see scene/lff.rs).
// Stroke-font families bundled with the renderer; see scene/lff.rs.
const MTEXT_FONTS: [&str; 10] = [
"[Style default]",
"Standard",
@@ -465,7 +465,7 @@ fn mtext_editor_content<'a>(
.iter()
.map(|s| s.to_string())
.collect::<Vec<_>>(),
|value| value.to_string(),
|value| t!(value).into_owned(),
)
.on_select(Message::MTextFont)
.text_size(11)
@@ -626,7 +626,7 @@ fn mtext_editor_content<'a>(
.into_iter()
.map(str::to_string)
.collect::<Vec<_>>(),
|value| value.to_string(),
|value| t!(value).into_owned(),
)
.on_select(Message::MTextColumnMode)
.text_size(11)
@@ -703,7 +703,7 @@ fn mtext_editor_content<'a>(
.width(width);
let row4 = row![
lbl("Find"),
text_input("Find", &ed.find_text)
text_input(&t!("Find"), &ed.find_text)
.on_input(Message::MTextFindText)
.width(iced::Length::Fixed(140.0))
.padding(3)
@@ -713,7 +713,7 @@ fn mtext_editor_content<'a>(
.padding(3)
.style(btn_style),
lbl("Replace"),
text_input("Replace", &ed.replace_text)
text_input(&t!("Replace"), &ed.replace_text)
.on_input(Message::MTextReplaceText)
.width(iced::Length::Fixed(140.0))
.padding(3)
@@ -1409,7 +1409,7 @@ fn qselect_content<'a>(
let mut prop_options: Vec<crate::app::QSelectPropertyChoice> =
vec![crate::app::QSelectPropertyChoice {
field: String::new(),
label: QSELECT_ANY_PROP.to_string(),
label: t!(QSELECT_ANY_PROP).into_owned(),
editor: crate::app::QSelectValueEditor::Text,
}];
prop_options.extend(properties.iter().cloned());
@@ -1436,7 +1436,7 @@ fn qselect_content<'a>(
.clone()
.unwrap_or(crate::app::QSelectPropertyChoice {
field: String::new(),
label: QSELECT_ANY_PROP.to_string(),
label: t!(QSELECT_ANY_PROP).into_owned(),
editor: crate::app::QSelectValueEditor::Text,
});
@@ -1552,7 +1552,7 @@ fn qselect_content<'a>(
.spacing(8)
.width(sizing.width),
Space::new().height(4),
text(format!("{} candidate object(s)", candidate_count))
text(crate::tf!("{} candidate object(s)", candidate_count))
.size(11)
.style(|theme: &Theme| iced::widget::text::Style {
color: Some(theme.palette().background.base.text.scale_alpha(0.65)),
@@ -1567,7 +1567,7 @@ fn qselect_content<'a>(
iced::widget::pick_list(
Some(type_sel),
type_options,
|value| value.to_string(),
|value| t!(value).into_owned(),
)
.on_select(|s: String| {
if s == QSELECT_ANY_TYPE {