feat(locale): localize full interface
This commit is contained in:
parent
b90b3e3ecf
commit
3e6693b93f
205 changed files with 32367 additions and 3808 deletions
|
|
@ -19,6 +19,7 @@ use iced::widget::{
|
|||
use iced::{
|
||||
mouse, Background, Border, Color, Element, Length, Padding, Point, Rectangle, Size, Theme,
|
||||
};
|
||||
use crate::t;
|
||||
|
||||
// ── Row-height-derived constants ─────────────────────────────────────────
|
||||
const FONT_SZ: f32 = ROW_H * 0.42; // ≈11 px
|
||||
|
|
@ -60,9 +61,9 @@ pub struct LwItem(pub LineWeight);
|
|||
impl fmt::Display for LwItem {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.0 {
|
||||
LineWeight::ByLayer => write!(f, "ByLayer"),
|
||||
LineWeight::ByBlock => write!(f, "ByBlock"),
|
||||
LineWeight::Default => write!(f, "Default"),
|
||||
LineWeight::ByLayer => write!(f, "{}", crate::t!("ByLayer")),
|
||||
LineWeight::ByBlock => write!(f, "{}", crate::t!("ByBlock")),
|
||||
LineWeight::Default => write!(f, "{}", crate::t!("Default")),
|
||||
LineWeight::Value(v) => write!(f, "{:.2} mm", v as f64 / 100.0),
|
||||
}
|
||||
}
|
||||
|
|
@ -244,6 +245,27 @@ pub fn attr_edit_key(tag: &str) -> String {
|
|||
format!("\x01attr\x01{tag}")
|
||||
}
|
||||
|
||||
/// A translated choice label paired with the unchanged value stored in the
|
||||
/// drawing and emitted by the properties panel.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct LocalizedChoice {
|
||||
pub raw: String,
|
||||
label: String,
|
||||
}
|
||||
|
||||
impl LocalizedChoice {
|
||||
pub fn new(raw: String) -> Self {
|
||||
let label = crate::i18n::translate(&raw).into_owned();
|
||||
Self { raw, label }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for LocalizedChoice {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(&self.label)
|
||||
}
|
||||
}
|
||||
|
||||
// ── PropertiesPanel ───────────────────────────────────────────────────────
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -255,7 +277,7 @@ pub struct PropertiesPanel {
|
|||
/// Linetype items (name + ASCII art) from the document — used for combo_box options.
|
||||
pub linetype_items: Vec<LinetypeItem>,
|
||||
pub selection_group_combo: combo_box::State<SelectionGroup>,
|
||||
pub choice_combos: HashMap<String, combo_box::State<String>>,
|
||||
pub choice_combos: HashMap<String, combo_box::State<LocalizedChoice>>,
|
||||
pub layer_combo: combo_box::State<String>,
|
||||
pub lineweight_combo: combo_box::State<LwItem>,
|
||||
pub linetype_combo: combo_box::State<LinetypeItem>,
|
||||
|
|
@ -333,7 +355,7 @@ impl Default for PropertiesPanel {
|
|||
impl PropertiesPanel {
|
||||
pub fn empty() -> Self {
|
||||
Self {
|
||||
title: "No Selection".into(),
|
||||
title: t!("No selection").into_owned(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
|
@ -347,7 +369,7 @@ impl PropertiesPanel {
|
|||
|
||||
pub fn view(&self) -> Element<'_, Message> {
|
||||
// ── Header ──────────────────────────────────────────────────────────
|
||||
let header = container(text("Properties").size(12))
|
||||
let header = container(text(t!("Properties")).size(12))
|
||||
.style(|theme: &Theme| container::Style {
|
||||
background: Some(Background::Color(
|
||||
theme.palette().background.weak.color,
|
||||
|
|
@ -397,7 +419,7 @@ impl PropertiesPanel {
|
|||
// ── Content ─────────────────────────────────────────────────────────
|
||||
let content: Element<'_, Message> = if self.sections.is_empty() {
|
||||
container(
|
||||
text("Select an object to view properties")
|
||||
text(t!("Select an object to view properties"))
|
||||
.size(10)
|
||||
.style(hint_text_style),
|
||||
)
|
||||
|
|
@ -823,10 +845,13 @@ impl PropertiesPanel {
|
|||
let selected = if current == VARIES_LABEL {
|
||||
None
|
||||
} else {
|
||||
Some(current.to_string())
|
||||
Some(LocalizedChoice::new(current.to_string()))
|
||||
};
|
||||
let combo = combo_box(state, VARIES_LABEL, selected.as_ref(), move |value| {
|
||||
Message::PropGeomChoiceChanged { field, value }
|
||||
let combo = combo_box(state, VARIES_LABEL, selected.as_ref(), move |choice| {
|
||||
Message::PropGeomChoiceChanged {
|
||||
field,
|
||||
value: choice.raw,
|
||||
}
|
||||
})
|
||||
.size(FONT_SZ)
|
||||
.padding(Padding {
|
||||
|
|
@ -1058,7 +1083,7 @@ impl PropertiesPanel {
|
|||
return prop_row_widget(label, head.into());
|
||||
}
|
||||
|
||||
let search = text_input("Search patterns…", &self.hatch_pattern_search)
|
||||
let search = text_input(t!("Search patterns…").as_ref(), &self.hatch_pattern_search)
|
||||
.id(iced::widget::Id::new("hatch-pattern-search"))
|
||||
.on_input(Message::PropHatchPatternSearchChanged)
|
||||
.on_submit(Message::PropHatchPatternConfirm)
|
||||
|
|
@ -1127,7 +1152,7 @@ impl PropertiesPanel {
|
|||
|
||||
let results: Element<'_, Message> = if visible.is_empty() {
|
||||
container(
|
||||
text("No matching patterns")
|
||||
text(t!("No matching patterns"))
|
||||
.size(FONT_SZ)
|
||||
.style(hint_text_style),
|
||||
)
|
||||
|
|
@ -1227,9 +1252,13 @@ pub fn color_picker_dropdown<'a>(
|
|||
} else {
|
||||
crate::ui::icons::themed_arrow_down(9.0)
|
||||
},
|
||||
text(if palette_open { "Less" } else { "More Colors…" })
|
||||
.size(10)
|
||||
.style(hint_text_style),
|
||||
text(if palette_open {
|
||||
t!("Less").into_owned()
|
||||
} else {
|
||||
t!("More Colors…").into_owned()
|
||||
})
|
||||
.size(10)
|
||||
.style(hint_text_style),
|
||||
]
|
||||
.spacing(4)
|
||||
.align_y(iced::Center),
|
||||
|
|
@ -1365,7 +1394,11 @@ fn render_stepper_row<'a>(label: &'a str, display: &'a str) -> Element<'a, Messa
|
|||
}
|
||||
|
||||
fn render_bool_row<'a>(label: &'a str, field: &'static str, value: bool) -> Element<'a, Message> {
|
||||
let btn_label = if value { "Yes" } else { "No" };
|
||||
let btn_label = if value {
|
||||
t!("Yes").into_owned()
|
||||
} else {
|
||||
t!("No").into_owned()
|
||||
};
|
||||
let btn =
|
||||
button(
|
||||
text(btn_label)
|
||||
|
|
@ -1617,7 +1650,7 @@ fn prop_row_widget<'a>(label: &'a str, widget: Element<'a, Message>) -> Element<
|
|||
|
||||
/// A plain text button used inside the color picker for ByLayer / ByBlock.
|
||||
fn picker_text_btn(label: &str, msg: Message) -> Element<'_, Message> {
|
||||
button(text(label).size(FONT_SZ))
|
||||
button(text(t!(label)).size(FONT_SZ))
|
||||
.on_press(msg)
|
||||
.style(button::secondary)
|
||||
.padding([2, 8])
|
||||
|
|
|
|||
Loading…
Reference in a new issue