feat(locale): localize full interface

This commit is contained in:
Hakan Seven 2026-08-02 22:09:25 +03:00
commit 3e6693b93f
205 changed files with 32367 additions and 3808 deletions

View file

@ -4,6 +4,7 @@ use crate::io::linetypes;
use crate::scene::view::dispatch;
use crate::ui;
use acadrust::{EntityType, Handle};
use crate::t;
/// Above this many selected objects the Properties panel skips per-entity
/// property aggregation (which is O(n) per row, plus an O(n²) group filter) and
@ -259,30 +260,30 @@ impl OpenCADStudio {
};
let sections = vec![
PropSection {
title: "General".to_string(),
title: t!("General").into_owned(),
props: vec![
read_only("AC Version", doc.version.as_str().to_string()),
read_only(t!("AC Version").as_ref(), doc.version.as_str().to_string()),
Property {
label: "Color".to_string(),
label: t!("Color").into_owned(),
field: "color",
value: PropValue::ColorChoice(header.current_entity_color),
},
Property {
label: "Layer".to_string(),
label: t!("Layer").into_owned(),
field: "layer",
value: PropValue::LayerChoice(current_layer),
},
Property {
label: "Linetype".to_string(),
label: t!("Linetype").into_owned(),
field: "linetype",
value: PropValue::LinetypeChoice(current_linetype),
},
read_only(
"Linetype scale",
t!("Linetype scale").as_ref(),
format_length(header.current_entity_linetype_scale),
),
Property {
label: "Lineweight".to_string(),
label: t!("Lineweight").into_owned(),
field: "line_weight",
value: PropValue::LwChoice(
acadrust::types::LineWeight::from_value(
@ -290,21 +291,21 @@ impl OpenCADStudio {
),
),
},
read_only("Transparency", "ByLayer".to_string()),
read_only("Thickness", format_length(header.thickness)),
read_only(t!("Transparency").as_ref(), "ByLayer".to_string()),
read_only(t!("Thickness").as_ref(), format_length(header.thickness)),
],
},
PropSection {
title: "3D Visualization".to_string(),
props: vec![read_only("Material", material)],
title: t!("3D Visualization").into_owned(),
props: vec![read_only(t!("Material").as_ref(), material)],
},
PropSection {
title: "Plot style".to_string(),
title: t!("Plot style").into_owned(),
props: vec![
read_only("Plot style", plot_style.to_string()),
read_only("Plot style table", plot_table.clone()),
read_only(t!("Plot style").as_ref(), plot_style.to_string()),
read_only(t!("Plot style table").as_ref(), plot_table.clone()),
read_only(
"Plot table attached to",
t!("Plot table attached to").as_ref(),
if plot_table == "None" {
"None".to_string()
} else {
@ -312,7 +313,7 @@ impl OpenCADStudio {
},
),
read_only(
"Plot table type",
t!("Plot table type").as_ref(),
if header.plotstyle_mode {
"Named plot styles".to_string()
} else {
@ -322,39 +323,39 @@ impl OpenCADStudio {
],
},
PropSection {
title: "View".to_string(),
title: t!("View").into_owned(),
props: vec![
read_only("Center X", format_length(camera.target.x)),
read_only("Center Y", format_length(camera.target.y)),
read_only("Center Z", format_length(camera.target.z)),
read_only("Height", format_length(view_height)),
read_only("Width", format_length(view_width)),
read_only(t!("Center X").as_ref(), format_length(camera.target.x)),
read_only(t!("Center Y").as_ref(), format_length(camera.target.y)),
read_only(t!("Center Z").as_ref(), format_length(camera.target.z)),
read_only(t!("Height").as_ref(), format_length(view_height)),
read_only(t!("Width").as_ref(), format_length(view_width)),
],
},
PropSection {
title: "Misc".to_string(),
title: t!("Misc").into_owned(),
props: vec![
read_only("Annotation scale", annotation_scale),
read_only(t!("Annotation scale").as_ref(), annotation_scale),
read_only(
"UCS icon On",
t!("UCS icon On").as_ref(),
if self.show_ucs_icon { "Yes" } else { "No" }.to_string(),
),
read_only(
"UCS icon at origin",
t!("UCS icon at origin").as_ref(),
if self.ucs_icon_at_origin { "Yes" } else { "No" }
.to_string(),
),
read_only(
"UCS per viewport",
t!("UCS per viewport").as_ref(),
if ucs_per_viewport { "Yes" } else { "No" }.to_string(),
),
read_only("UCS Name", ucs_name),
read_only("Visual Style", tab.visual_style.clone()),
read_only(t!("UCS Name").as_ref(), ucs_name),
read_only(t!("Visual Style").as_ref(), tab.visual_style.clone()),
],
},
];
ui::PropertiesPanel {
title: "No selection".to_string(),
title: t!("No selection").into_owned(),
sections,
layer_combo: iced::widget::combo_box::State::new(layer_names.clone()),
linetype_combo: iced::widget::combo_box::State::new(
@ -435,61 +436,61 @@ impl OpenCADStudio {
{
use crate::entities::common::ro_prop;
sections.push(crate::scene::model::object::PropSection {
title: "Material Details".to_string(),
title: t!("Material Details").into_owned(),
props: vec![
ro_prop("Name", "mat_name", material.name.clone()),
ro_prop(t!("Name").as_ref(), "mat_name", material.name.clone()),
ro_prop(
"Description",
t!("Description").as_ref(),
"mat_description",
material.description.clone(),
),
ro_prop(
"Ambient",
t!("Ambient").as_ref(),
"mat_ambient",
material_color_text(&material.ambient_color),
),
ro_prop(
"Diffuse",
t!("Diffuse").as_ref(),
"mat_diffuse",
material_color_text(&material.diffuse_color),
),
ro_prop(
"Specular",
t!("Specular").as_ref(),
"mat_specular",
material_color_text(&material.specular_color),
),
ro_prop(
"Gloss",
t!("Gloss").as_ref(),
"mat_gloss",
format!("{:.3}", material.specular_gloss_factor),
),
ro_prop(
"Opacity",
t!("Opacity").as_ref(),
"mat_opacity",
format!("{:.3}", material.opacity_percent),
),
ro_prop(
"Reflectivity",
t!("Reflectivity").as_ref(),
"mat_reflectivity",
format!("{:.3}", material.reflectivity),
),
ro_prop(
"Translucence",
t!("Translucence").as_ref(),
"mat_translucence",
format!("{:.3}", material.translucence),
),
ro_prop(
"Refraction",
t!("Refraction").as_ref(),
"mat_refraction",
format!("{:.3}", material.refraction_index),
),
ro_prop(
"Self Illumination",
t!("Self Illumination").as_ref(),
"mat_self_illumination",
format!("{:.3}", material.self_illumination),
),
ro_prop(
"Luminance",
t!("Luminance").as_ref(),
"mat_luminance",
format!(
"{:.3} (mode {})",
@ -497,42 +498,42 @@ impl OpenCADStudio {
),
),
ro_prop(
"Diffuse Map",
t!("Diffuse Map").as_ref(),
"mat_diffuse_map",
material_map_text(&material.diffuse_map),
),
ro_prop(
"Specular Map",
t!("Specular Map").as_ref(),
"mat_specular_map",
material_map_text(&material.specular_map),
),
ro_prop(
"Reflection Map",
t!("Reflection Map").as_ref(),
"mat_reflection_map",
material_map_text(&material.reflection_map),
),
ro_prop(
"Opacity Map",
t!("Opacity Map").as_ref(),
"mat_opacity_map",
material_map_text(&material.opacity_map),
),
ro_prop(
"Bump Map",
t!("Bump Map").as_ref(),
"mat_bump_map",
material_map_text(&material.bump_map),
),
ro_prop(
"Refraction Map",
t!("Refraction Map").as_ref(),
"mat_refraction_map",
material_map_text(&material.refraction_map),
),
ro_prop(
"Normal Map",
t!("Normal Map").as_ref(),
"mat_normal_map",
material_map_text(&material.normal_map),
),
ro_prop(
"Render Flags",
t!("Render Flags").as_ref(),
"mat_render_flags",
format!(
"illumination {}; channels {}; mode {}; two-sided {}",
@ -543,7 +544,7 @@ impl OpenCADStudio {
),
),
ro_prop(
"Advanced",
t!("Advanced").as_ref(),
"mat_advanced",
format!(
"normal {:.3}; bump {:.3}; reflect {:.3}; transmit {:.3}",
@ -578,16 +579,16 @@ impl OpenCADStudio {
}
use crate::entities::common::ro_prop;
sections.push(crate::scene::model::object::PropSection {
title: "Color Book".to_string(),
title: t!("Color Book").into_owned(),
props: vec![
ro_prop("Book", "book_color_book", book.book_name.clone()),
ro_prop(t!("Book").as_ref(), "book_color_book", book.book_name.clone()),
ro_prop(
"Color Name",
t!("Color Name").as_ref(),
"book_color_name",
book.color_name.clone(),
),
ro_prop(
"Color",
t!("Color").as_ref(),
"book_color_value",
format!("{:?}", book.color),
),
@ -616,25 +617,25 @@ impl OpenCADStudio {
};
use crate::entities::common::ro_prop;
sections.push(crate::scene::model::object::PropSection {
title: format!("{scope} Visual Style"),
title: t!("%{scope} Visual Style", scope = scope).into_owned(),
props: vec![
ro_prop(
"Handle",
t!("Handle").as_ref(),
"vs_handle",
format!("{:X}", handle.value()),
),
ro_prop(
"Description",
t!("Description").as_ref(),
"vs_description",
style.description.clone(),
),
ro_prop(
"Type",
t!("Type").as_ref(),
"vs_type",
style.style_type.to_string(),
),
ro_prop(
"Face",
t!("Face").as_ref(),
"vs_face",
format!(
"lighting {}; quality {}; color {}; modifiers {}",
@ -645,7 +646,7 @@ impl OpenCADStudio {
),
),
ro_prop(
"Edges",
t!("Edges").as_ref(),
"vs_edges",
format!(
"model {}; style {}",
@ -653,17 +654,17 @@ impl OpenCADStudio {
),
),
ro_prop(
"Extended Lighting",
t!("Extended Lighting").as_ref(),
"vs_extended_lighting",
style.extended_lighting_model.to_string(),
),
ro_prop(
"Internal",
t!("Internal").as_ref(),
"vs_internal",
style.internal_use_only.to_string(),
),
ro_prop(
"Property Bag",
t!("Property Bag").as_ref(),
"vs_properties",
visual_style_properties_text(style),
),
@ -692,22 +693,22 @@ impl OpenCADStudio {
let metrics = mesh.metrics;
let mut props = vec![
ro_prop(
"Vertices",
t!("Vertices").as_ref(),
"mesh_vertices",
metrics.vertices.to_string(),
),
ro_prop(
"Triangles",
t!("Triangles").as_ref(),
"mesh_triangles",
metrics.triangles.to_string(),
),
ro_prop(
"Surface Area",
t!("Surface Area").as_ref(),
"mesh_surface_area",
format!("{:.6}", metrics.surface_area),
),
ro_prop(
"Centroid",
t!("Centroid").as_ref(),
"mesh_centroid",
format!(
"{:.6}, {:.6}, {:.6}",
@ -717,7 +718,7 @@ impl OpenCADStudio {
),
),
ro_prop(
"Tessellation",
t!("Tessellation").as_ref(),
"mesh_complete",
if mesh.complete { "Complete" } else { "Partial" },
),
@ -733,14 +734,14 @@ impl OpenCADStudio {
props.insert(
3,
ro_prop(
"Volume",
t!("Volume").as_ref(),
"mesh_volume",
format!("{:.6}", metrics.volume),
),
);
}
sections.push(crate::scene::model::object::PropSection {
title: "Mass Properties".to_string(),
title: t!("Mass Properties").into_owned(),
props,
});
}
@ -770,7 +771,7 @@ impl OpenCADStudio {
continue;
};
let toggle = crate::scene::model::object::Property {
label: "Uniform scale".into(),
label: t!("Uniform scale").into_owned(),
field: "ins_uniform",
value: crate::scene::model::object::PropValue::BoolToggle {
field: "ins_uniform",
@ -787,7 +788,7 @@ impl OpenCADStudio {
.position(|p| p.field == "x_scale")
.unwrap_or(xi.min(section.props.len()));
section.props[xi] = crate::entities::common::edit_prop(
"Scale",
t!("Scale").as_ref(),
"u_scale",
ins.x_scale(),
);
@ -975,7 +976,7 @@ impl OpenCADStudio {
if let Some(geom) = sections.last_mut() {
geom.props.push(crate::scene::model::object::Property {
label: "Frozen Layers".to_string(),
label: t!("Frozen Layers").into_owned(),
field: "frozen_layers",
value: crate::scene::model::object::PropValue::EditText(
frozen_names.join(", "),
@ -983,7 +984,7 @@ impl OpenCADStudio {
});
if !ucs_names.is_empty() {
geom.props.push(crate::scene::model::object::Property {
label: "UCS Name".to_string(),
label: t!("UCS Name").into_owned(),
field: "vp_ucs_name",
value: crate::scene::model::object::PropValue::Choice {
selected: current_ucs,
@ -993,7 +994,7 @@ impl OpenCADStudio {
}
if !view_names.is_empty() {
geom.props.push(crate::scene::model::object::Property {
label: "Named View".to_string(),
label: t!("Named View").into_owned(),
field: "vp_named_view",
value: crate::scene::model::object::PropValue::Choice {
selected: String::new(),
@ -1385,7 +1386,7 @@ impl OpenCADStudio {
&mut sections,
anchor,
crate::entities::common::ro_prop(
"Annotative",
t!("Annotative").as_ref(),
"annotative",
"No",
),
@ -1430,7 +1431,7 @@ impl OpenCADStudio {
&mut sections,
anno_field,
crate::entities::common::ro_prop(
"Annotative scale",
t!("Annotative scale").as_ref(),
"annotative_scale",
doc.header.current_annotation_scale.clone(),
),
@ -1443,7 +1444,7 @@ impl OpenCADStudio {
let label = group_names.join(", ");
if let Some(general) = sections.first_mut() {
general.props.push(crate::scene::model::object::Property {
label: "Group".to_string(),
label: t!("Group").into_owned(),
field: "group",
value: crate::scene::model::object::PropValue::ReadOnly(label),
});
@ -1460,7 +1461,7 @@ impl OpenCADStudio {
.map(|br| br.flags.is_xref || br.flags.is_xref_overlay)
.unwrap_or(false);
if is_xref {
"External Reference".to_string()
t!("External Reference").into_owned()
} else {
entity_type_label(entity)
}
@ -1474,7 +1475,13 @@ impl OpenCADStudio {
.filter_map(|prop| match &prop.value {
crate::scene::model::object::PropValue::Choice { options, .. } => Some((
prop.field.to_string(),
iced::widget::combo_box::State::new(options.clone()),
iced::widget::combo_box::State::new(
options
.iter()
.cloned()
.map(ui::properties::LocalizedChoice::new)
.collect(),
),
)),
_ => None,
})
@ -1495,7 +1502,7 @@ impl OpenCADStudio {
// for seconds at tens of thousands of objects. Above the cap show a
// count-only panel; bulk edits still go through the ribbon.
n if n > MAX_PROP_AGGREGATE => ui::PropertiesPanel {
title: format!("{} objects selected", n),
title: t!("%{count} objects selected", count = n).into_owned(),
layer_combo: iced::widget::combo_box::State::new(layer_names.clone()),
linetype_combo: iced::widget::combo_box::State::new(linetype_items.clone()),
lineweight_combo: iced::widget::combo_box::State::new(
@ -1529,13 +1536,19 @@ impl OpenCADStudio {
.filter_map(|prop| match &prop.value {
crate::scene::model::object::PropValue::Choice { options, .. } => Some((
prop.field.to_string(),
iced::widget::combo_box::State::new(options.clone()),
iced::widget::combo_box::State::new(
options
.iter()
.cloned()
.map(ui::properties::LocalizedChoice::new)
.collect(),
),
)),
_ => None,
})
.collect(),
sections,
title: format!("{} objects selected", selected.len()),
title: t!("%{count} objects selected", count = selected.len()).into_owned(),
selection_group_combo: iced::widget::combo_box::State::new(groups.clone()),
selection_groups: groups,
selected_group: active_group,
@ -1998,7 +2011,7 @@ impl OpenCADStudio {
}
Err(e) => {
self.command_line
.push_error(&format!("Viewport could not be added: {e}"));
.push_error(crate::tf!("Viewport could not be added: {e}").as_ref());
None
}
}
@ -2037,7 +2050,7 @@ pub(super) fn build_selection_groups(
selected: &[(Handle, &EntityType)],
) -> Vec<ui::properties::SelectionGroup> {
let mut groups = vec![ui::properties::SelectionGroup {
label: format!("All({})", selected.len()),
label: format!("{} ({})", t!("All").into_owned(), selected.len()),
handles: selected.iter().map(|(handle, _)| *handle).collect(),
}];
@ -2052,7 +2065,7 @@ pub(super) fn build_selection_groups(
for (kind, handles) in by_type {
groups.push(ui::properties::SelectionGroup {
label: format!("{}({})", title_case_word(&kind), handles.len()),
label: format!("{}({})", t!(title_case_word(&kind)), handles.len()),
handles,
});
}