refactor(i18n): group Fluent attributes

This commit is contained in:
Hakan Seven committed 2026-08-09 11:12:47 +03:00
1 parent f3c2e061e0
commit 2f60dd0f59
26 files changed
+45139 -44415

No files matched your search

File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -1384,7 +1384,7 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
&& destination_is_current && destination_is_current
{ {
self.command_line.push_error_once( self.command_line.push_error_once(
crate::tr!("recovery-save-new-file-required").as_ref(), crate::tr!("recovery", "save-new-file-required").as_ref(),
); );
self.restore_failed_save_continuation(continuation, i); self.restore_failed_save_continuation(continuation, i);
self.active_tab = i; self.active_tab = i;
+4 -4
View File
@@ -3995,23 +3995,23 @@ impl OpenCADStudio {
} }
Text::EmptyOrUnsupported => { Text::EmptyOrUnsupported => {
self.command_line.push_error( self.command_line.push_error(
crate::tr!("clipboard-no-supported-content").as_ref(), crate::tr!("clipboard", "no-supported-content").as_ref(),
); );
Task::none() Task::none()
} }
Text::Unavailable => { Text::Unavailable => {
self.command_line self.command_line
.push_error(crate::tr!("clipboard-unavailable").as_ref()); .push_error(crate::tr!("clipboard", "unavailable").as_ref());
Task::none() Task::none()
} }
Text::Occupied => { Text::Occupied => {
self.command_line self.command_line
.push_error(crate::tr!("clipboard-occupied").as_ref()); .push_error(crate::tr!("clipboard", "occupied").as_ref());
Task::none() Task::none()
} }
Text::ConversionFailed => { Text::ConversionFailed => {
self.command_line self.command_line
.push_error(crate::tr!("clipboard-conversion-failed").as_ref()); .push_error(crate::tr!("clipboard", "conversion-failed").as_ref());
Task::none() Task::none()
} }
} }
+4 -4
View File
@@ -449,7 +449,7 @@ pub(super) fn viewport_controls<'a>(
crate::ui::icons::SPLIT_V, crate::ui::icons::SPLIT_V,
false, false,
Message::SplitModelViewport(false), Message::SplitModelViewport(false),
crate::tr!("viewport-split-vertical"), crate::tr!("viewport", "split-vertical"),
"VPORTS 2V", "VPORTS 2V",
)) ))
.push(sep()) .push(sep())
@@ -457,7 +457,7 @@ pub(super) fn viewport_controls<'a>(
crate::ui::icons::SPLIT_H, crate::ui::icons::SPLIT_H,
false, false,
Message::SplitModelViewport(true), Message::SplitModelViewport(true),
crate::tr!("viewport-split-horizontal"), crate::tr!("viewport", "split-horizontal"),
"VPORTS 2H", "VPORTS 2H",
)); ));
// Drag handle + close: only meaningful with more than one model tile. // Drag handle + close: only meaningful with more than one model tile.
@@ -478,7 +478,7 @@ pub(super) fn viewport_controls<'a>(
) )
.interaction(iced::mouse::Interaction::Grab) .interaction(iced::mouse::Interaction::Grab)
.on_press(Message::PaneMoveStart); .on_press(Message::PaneMoveStart);
let drag = viewport_tooltip(drag, crate::tr!("viewport-move"), "VPORTS"); let drag = viewport_tooltip(drag, crate::tr!("viewport", "move"), "VPORTS");
bar = bar bar = bar
.push(sep()) .push(sep())
.push(drag) .push(drag)
@@ -486,7 +486,7 @@ pub(super) fn viewport_controls<'a>(
.push(danger_btn( .push(danger_btn(
crate::ui::icons::CLOSE, crate::ui::icons::CLOSE,
Message::CloseModelViewport, Message::CloseModelViewport,
crate::tr!("viewport-close"), crate::tr!("viewport", "close"),
"VPORTS SINGLE", "VPORTS SINGLE",
)); ));
} }
+27 -27
View File
@@ -2624,7 +2624,7 @@ fn start_page_content<'a>(
button( button(
row![ row![
crate::ui::icons::themed_danger_text(crate::ui::icons::HEART, 14.0), crate::ui::icons::themed_danger_text(crate::ui::icons::HEART, 14.0),
text(crate::tr!("start-donate")).size(14), text(crate::tr!("start", "donate")).size(14),
] ]
.spacing(5) .spacing(5)
.align_y(iced::Center), .align_y(iced::Center),
@@ -2638,8 +2638,8 @@ fn start_page_content<'a>(
}; };
let primary_row = WrapFlow::new(vec![ let primary_row = WrapFlow::new(vec![
outline_btn(crate::tr!("start-new-drawing"), Message::TabNew).into(), outline_btn(crate::tr!("start", "new-drawing"), Message::TabNew).into(),
outline_btn(crate::tr!("start-open-file"), Message::OpenFile).into(), outline_btn(crate::tr!("start", "open-file"), Message::OpenFile).into(),
donate_btn.into(), donate_btn.into(),
]) ])
.spacing_x(12.0) .spacing_x(12.0)
@@ -2649,16 +2649,16 @@ fn start_page_content<'a>(
#[cfg_attr(target_arch = "wasm32", allow(unused_mut))] #[cfg_attr(target_arch = "wasm32", allow(unused_mut))]
let mut secondary_items: Vec<Element<'a, Message>> = vec![ let mut secondary_items: Vec<Element<'a, Message>> = vec![
outline_btn( outline_btn(
crate::tr!("start-send-feedback"), crate::tr!("start", "send-feedback"),
Message::RibbonToolClick { Message::RibbonToolClick {
tool_id: "REPORT".to_string(), tool_id: "REPORT".to_string(),
event: crate::modules::ModuleEvent::Command("REPORT".to_string()), event: crate::modules::ModuleEvent::Command("REPORT".to_string()),
}, },
) )
.into(), .into(),
outline_btn(crate::tr!("action-options"), Message::OptionsOpen).into(), outline_btn(crate::tr!("action", "options"), Message::OptionsOpen).into(),
]; ];
secondary_items.push(outline_btn(crate::tr!("action-plugins"), Message::PluginManagerOpen).into()); secondary_items.push(outline_btn(crate::tr!("action", "plugins"), Message::PluginManagerOpen).into());
// The web build is already in the browser, so only the desktop offers a // The web build is already in the browser, so only the desktop offers a
// link to the web version. // link to the web version.
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
@@ -2681,7 +2681,7 @@ fn start_page_content<'a>(
.report_natural_width(action_width_out.clone()); .report_natural_width(action_width_out.clone());
let sponsors = column![ let sponsors = column![
text(crate::tr!("start-sponsors")).size(15), text(crate::tr!("start", "sponsors")).size(15),
mouse_area( mouse_area(
container( container(
iced::widget::svg(iced::widget::svg::Handle::from_memory(include_bytes!( iced::widget::svg(iced::widget::svg::Handle::from_memory(include_bytes!(
@@ -2783,7 +2783,7 @@ fn start_page_content<'a>(
// whole thumbnail remains visible when that width changes. // whole thumbnail remains visible when that width changes.
let thumb_h = let thumb_h =
(panel_w - VIDEO_PANEL_PADDING * 2.0 - VIDEO_SCROLL_GUTTER) * 9.0 / 16.0; (panel_w - VIDEO_PANEL_PADDING * 2.0 - VIDEO_SCROLL_GUTTER) * 9.0 / 16.0;
let mut list = column![text(crate::tr!("start-tutorials")).size(15)] let mut list = column![text(crate::tr!("start", "tutorials")).size(15)]
.spacing(10) .spacing(10)
.width(Fill) .width(Fill)
// Keep the scrollbar off the thumbnails. // Keep the scrollbar off the thumbnails.
@@ -2823,14 +2823,14 @@ fn start_page_content<'a>(
} }
if videos.is_empty() { if videos.is_empty() {
let note = if videos_loading { let note = if videos_loading {
crate::tr!("start-loading-videos") crate::tr!("start", "loading-videos")
} else { } else {
crate::tr!("start-videos-online") crate::tr!("start", "videos-online")
}; };
list = list.push(text(note).size(12).style(start_muted_style)); list = list.push(text(note).size(12).style(start_muted_style));
} }
let playlist_btn = mouse_area( let playlist_btn = mouse_area(
container(text(crate::tr!("start-open-playlist")).size(12)) container(text(crate::tr!("start", "open-playlist")).size(12))
.padding([6, 10]) .padding([6, 10])
.width(Fill) .width(Fill)
.center_x(Fill) .center_x(Fill)
@@ -2883,7 +2883,7 @@ fn start_page_content<'a>(
// web builds read the CI-generated snapshot. Both sources mark pinned // web builds read the CI-generated snapshot. Both sources mark pinned
// discussions and sort them before the rest of the list. // discussions and sort them before the rest of the list.
let discussions_panel: Element<'a, Message> = { let discussions_panel: Element<'a, Message> = {
let mut list = column![text(crate::tr!("start-discussions")).size(15)] let mut list = column![text(crate::tr!("start", "discussions")).size(15)]
.spacing(8) .spacing(8)
.width(Fill); .width(Fill);
for discussion in discussions { for discussion in discussions {
@@ -2896,7 +2896,7 @@ fn start_page_content<'a>(
.align_y(iced::Center); .align_y(iced::Center);
if discussion.pinned { if discussion.pinned {
meta = meta.push( meta = meta.push(
text(crate::tr!("start-pinned")) text(crate::tr!("start", "pinned"))
.size(10) .size(10)
.style(start_primary_style), .style(start_primary_style),
); );
@@ -2939,14 +2939,14 @@ fn start_page_content<'a>(
} }
if discussions.is_empty() { if discussions.is_empty() {
let note = if discussions_loading { let note = if discussions_loading {
crate::tr!("start-loading-discussions") crate::tr!("start", "loading-discussions")
} else { } else {
crate::tr!("start-discussions-online") crate::tr!("start", "discussions-online")
}; };
list = list.push(text(note).size(12).style(start_muted_style)); list = list.push(text(note).size(12).style(start_muted_style));
} }
let open_btn = mouse_area( let open_btn = mouse_area(
container(text(crate::tr!("start-open-discussions")).size(12)) container(text(crate::tr!("start", "open-discussions")).size(12))
.padding([6, 10]) .padding([6, 10])
.width(Fill) .width(Fill)
.center_x(Fill) .center_x(Fill)
@@ -3003,7 +3003,7 @@ fn start_page_content<'a>(
// shows, so the rail always invites support. // shows, so the rail always invites support.
let supporters: Element<'a, Message> = { let supporters: Element<'a, Message> = {
let mut list = column![ let mut list = column![
text(crate::tr!("start-supporters")).size(15), text(crate::tr!("start", "supporters")).size(15),
Space::new().height(iced::Length::Fixed(12.0)), Space::new().height(iced::Length::Fixed(12.0)),
] ]
.spacing(6) .spacing(6)
@@ -3028,7 +3028,7 @@ fn start_page_content<'a>(
container( container(
iced::widget::row![ iced::widget::row![
crate::ui::icons::themed_danger_text(crate::ui::icons::HEART, 13.0), crate::ui::icons::themed_danger_text(crate::ui::icons::HEART, 13.0),
text(crate::tr!("start-support-on-patreon")).size(12), text(crate::tr!("start", "support-on-patreon")).size(12),
] ]
.spacing(6) .spacing(6)
.align_y(iced::Center), .align_y(iced::Center),
@@ -3146,11 +3146,11 @@ fn start_page_content<'a>(
}) })
}; };
let tab_bar = Row::with_children(vec![ let tab_bar = Row::with_children(vec![
tab_btn(crate::tr!("start-recent-files"), super::StartSection::Recent).into(), tab_btn(crate::tr!("start", "recent-files"), super::StartSection::Recent).into(),
tab_btn(crate::tr!("start-videos"), super::StartSection::Videos).into(), tab_btn(crate::tr!("start", "videos"), super::StartSection::Videos).into(),
tab_btn(crate::tr!("start-welcome"), super::StartSection::Welcome).into(), tab_btn(crate::tr!("start", "welcome"), super::StartSection::Welcome).into(),
tab_btn(crate::tr!("start-discussions"), super::StartSection::Discussions).into(), tab_btn(crate::tr!("start", "discussions"), super::StartSection::Discussions).into(),
tab_btn(crate::tr!("start-supporters"), super::StartSection::Supporters).into(), tab_btn(crate::tr!("start", "supporters"), super::StartSection::Supporters).into(),
]) ])
.spacing(6.0) .spacing(6.0)
.align_y(iced::Center) .align_y(iced::Center)
@@ -3226,11 +3226,11 @@ pub(super) fn recent_files_panel<'a>(
) -> Element<'a, Message> { ) -> Element<'a, Message> {
// Title mirrors the Supporters rail: size 15 in the bright text colour, // Title mirrors the Supporters rail: size 15 in the bright text colour,
// followed by a 12px gap before the content. // followed by a 12px gap before the content.
let title = text(crate::tr!("start-recent-documents")).size(15); let title = text(crate::tr!("start", "recent-documents")).size(15);
let body: Element<'a, Message> = if recents.is_empty() { let body: Element<'a, Message> = if recents.is_empty() {
container( container(
text(crate::tr!("start-no-recent-files")) text(crate::tr!("start", "no-recent-files"))
.size(12) .size(12)
.style(start_muted_style) .style(start_muted_style)
) )
@@ -3258,7 +3258,7 @@ pub(super) fn recent_files_panel<'a>(
// directory line. // directory line.
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
let dir = if dir.is_empty() { let dir = if dir.is_empty() {
crate::tr!("start-browser-storage") crate::tr!("start", "browser-storage")
} else { } else {
dir dir
}; };
@@ -3369,7 +3369,7 @@ pub(super) fn recent_files_panel<'a>(
.padding([2, 6]) .padding([2, 6])
.width(iced::Length::Fixed(46.0)); .width(iced::Length::Fixed(46.0));
let limit_row = row![ let limit_row = row![
text(crate::tr!("start-keep-recent-files")).size(11).style(start_muted_style).width(Fill), text(crate::tr!("start", "keep-recent-files")).size(11).style(start_muted_style).width(Fill),
button(crate::ui::icons::themed(crate::ui::icons::MINUS, 11.0)) button(crate::ui::icons::themed(crate::ui::icons::MINUS, 11.0))
.on_press(Message::SetRecentLimit(shown.saturating_sub(STEP))) .on_press(Message::SetRecentLimit(shown.saturating_sub(STEP)))
.padding([3, 6]) .padding([3, 6])
+32 -32
View File
@@ -10,43 +10,43 @@ impl OpenCADStudio {
pub(super) fn modal_title(&self) -> String { pub(super) fn modal_title(&self) -> String {
use super::super::ModalKind as K; use super::super::ModalKind as K;
match self.active_modal { match self.active_modal {
Some(K::About) => crate::tr!("modal-about"), Some(K::About) => crate::tr!("modal", "about"),
Some(K::Shortcuts) => crate::tr!("modal-keyboard-shortcuts"), Some(K::Shortcuts) => crate::tr!("modal", "keyboard-shortcuts"),
Some(K::Aliases) => crate::tr!("modal-command-aliases"), Some(K::Aliases) => crate::tr!("modal", "command-aliases"),
Some(K::Options) => crate::tr!("action-options"), Some(K::Options) => crate::tr!("action", "options"),
Some(K::FindReplace) => crate::tr!("modal-find-replace"), Some(K::FindReplace) => crate::tr!("modal", "find-replace"),
Some(K::PluginManager) => crate::tr!("modal-plugin-manager"), Some(K::PluginManager) => crate::tr!("modal", "plugin-manager"),
Some(K::UpdateNotice) => crate::tr!("modal-update-available"), Some(K::UpdateNotice) => crate::tr!("modal", "update-available"),
Some(K::Layers) => crate::tr!("modal-layer-manager"), Some(K::Layers) => crate::tr!("modal", "layer-manager"),
Some(K::LayerStateManager) => crate::tr!("modal-layer-state-manager"), Some(K::LayerStateManager) => crate::tr!("modal", "layer-state-manager"),
Some(K::LayerTranslator) => crate::t!("Layer Translator").into_owned(), Some(K::LayerTranslator) => crate::t!("Layer Translator").into_owned(),
Some(K::DrawingUnits) => crate::t!("Drawing Units").into_owned(), Some(K::DrawingUnits) => crate::t!("Drawing Units").into_owned(),
Some(K::DraftingSettings) => crate::t!("Drafting Settings").into_owned(), Some(K::DraftingSettings) => crate::t!("Drafting Settings").into_owned(),
Some(K::LayerStateEditor) => crate::tr!("modal-edit-layer-state"), Some(K::LayerStateEditor) => crate::tr!("modal", "edit-layer-state"),
Some(K::Plot) => crate::tr!("modal-plot"), Some(K::Plot) => crate::tr!("modal", "plot"),
Some(K::PrintAll) => t!("Print All").into_owned(), Some(K::PrintAll) => t!("Print All").into_owned(),
Some(K::LayoutManager) => crate::tr!("modal-layout-manager"), Some(K::LayoutManager) => crate::tr!("modal", "layout-manager"),
Some(K::ScaleManager) => crate::tr!("modal-scale-manager"), Some(K::ScaleManager) => crate::tr!("modal", "scale-manager"),
Some(K::AnnoObjectScale) => crate::tr!("modal-annotation-object-scale"), Some(K::AnnoObjectScale) => crate::tr!("modal", "annotation-object-scale"),
Some(K::Plotstyle) => crate::tr!("modal-plot-style-editor"), Some(K::Plotstyle) => crate::tr!("modal", "plot-style-editor"),
Some(K::TextStyle) => crate::tr!("modal-text-style-manager"), Some(K::TextStyle) => crate::tr!("modal", "text-style-manager"),
Some(K::MlStyle) => crate::tr!("modal-multiline-style-manager"), Some(K::MlStyle) => crate::tr!("modal", "multiline-style-manager"),
Some(K::TableStyle) => crate::tr!("modal-table-style-manager"), Some(K::TableStyle) => crate::tr!("modal", "table-style-manager"),
Some(K::MLeaderStyle) => crate::tr!("modal-multileader-style-manager"), Some(K::MLeaderStyle) => crate::tr!("modal", "multileader-style-manager"),
Some(K::DimStyle) => crate::tr!("modal-dimension-style-manager"), Some(K::DimStyle) => crate::tr!("modal", "dimension-style-manager"),
Some(K::AssocPrompt) => crate::tr!("modal-default-application"), Some(K::AssocPrompt) => crate::tr!("modal", "default-application"),
Some(K::AecDropWarning) => crate::tr!("modal-save-warning"), Some(K::AecDropWarning) => crate::tr!("modal", "save-warning"),
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
Some(K::FileInUse) => crate::tr!("modal-unable-save"), Some(K::FileInUse) => crate::tr!("modal", "unable-save"),
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
Some(K::ExternalChange) => crate::tr!("modal-drawing-changed"), Some(K::ExternalChange) => crate::tr!("modal", "drawing-changed"),
Some(K::LayerDeleteWarning) => crate::tr!("modal-delete-layer"), Some(K::LayerDeleteWarning) => crate::tr!("modal", "delete-layer"),
Some(K::Unsaved) => crate::tr!("modal-unsaved-changes"), Some(K::Unsaved) => crate::tr!("modal", "unsaved-changes"),
Some(K::PointStyle) => crate::tr!("modal-point-style"), Some(K::PointStyle) => crate::tr!("modal", "point-style"),
Some(K::AttributeEditor) => crate::tr!("modal-attribute-editor"), Some(K::AttributeEditor) => crate::tr!("modal", "attribute-editor"),
Some(K::SaveDialog) => crate::tr!("modal-save-drawing-as"), Some(K::SaveDialog) => crate::tr!("modal", "save-drawing-as"),
Some(K::Recovery) => crate::tr!("modal-recovery-report"), Some(K::Recovery) => crate::tr!("modal", "recovery-report"),
Some(K::RecoveryPrompt) => crate::tr!("modal-recovery-prompt"), Some(K::RecoveryPrompt) => crate::tr!("modal", "recovery-prompt"),
None => String::new(), None => String::new(),
} }
} }
@@ -1528,7 +1528,7 @@ fn unsaved_changes_dialog_window(
column![ column![
text(name.to_owned()).size(14), text(name.to_owned()).size(14),
iced::widget::Space::new().height(4), iced::widget::Space::new().height(4),
text(crate::tr!("modal-unsaved-save-prompt")) text(crate::tr!("modal", "unsaved-save-prompt"))
.size(12) .size(12)
.style(dialog_muted_text_style), .style(dialog_muted_text_style),
iced::widget::Space::new().height(20), iced::widget::Space::new().height(20),
+37 -26
View File
@@ -88,19 +88,19 @@ impl Language {
pub fn label(self) -> String { pub fn label(self) -> String {
match self { match self {
Language::System => crate::tr!("language-system"), Language::System => crate::tr!("language", "system"),
Language::EnUs => crate::tr!("language-english"), Language::EnUs => crate::tr!("language", "english"),
Language::TrTr => crate::tr!("language-turkish"), Language::TrTr => crate::tr!("language", "turkish"),
Language::NlNl => crate::tr!("language-dutch"), Language::NlNl => crate::tr!("language", "dutch"),
Language::FrFr => crate::tr!("language-french"), Language::FrFr => crate::tr!("language", "french"),
Language::DeDe => crate::tr!("language-german"), Language::DeDe => crate::tr!("language", "german"),
Language::HiIn => crate::tr!("language-hindi"), Language::HiIn => crate::tr!("language", "hindi"),
Language::RuRu => crate::tr!("language-russian"), Language::RuRu => crate::tr!("language", "russian"),
Language::ZhCn => crate::tr!("language-chinese-simplified"), Language::ZhCn => crate::tr!("language", "chinese-simplified"),
Language::EsEs => crate::tr!("language-spanish"), Language::EsEs => crate::tr!("language", "spanish"),
Language::PtBr => crate::tr!("language-portuguese"), Language::PtBr => crate::tr!("language", "portuguese"),
Language::ArSa => crate::tr!("language-arabic"), Language::ArSa => crate::tr!("language", "arabic"),
Language::JaJp => crate::tr!("language-japanese"), Language::JaJp => crate::tr!("language", "japanese"),
} }
} }
} }
@@ -200,8 +200,8 @@ pub fn active_language_tag() -> String {
/// translatable data. /// translatable data.
pub fn translate(source: impl AsRef<str>) -> Cow<'static, str> { pub fn translate(source: impl AsRef<str>) -> Cow<'static, str> {
let source = source.as_ref(); let source = source.as_ref();
locale_catalog::message_id(source) locale_catalog::message_attribute(source)
.map(|message_id| Cow::Owned(loader().get(message_id))) .map(|(message_id, attribute_id)| Cow::Owned(loader().get_attr(message_id, attribute_id)))
.unwrap_or_else(|| Cow::Owned(source.to_string())) .unwrap_or_else(|| Cow::Owned(source.to_string()))
} }
@@ -213,8 +213,8 @@ pub fn translate_args(
args: &[(&str, String)], args: &[(&str, String)],
) -> Cow<'static, str> { ) -> Cow<'static, str> {
let source = source.as_ref(); let source = source.as_ref();
let mut translated = locale_catalog::message_id(source) let mut translated = locale_catalog::message_attribute(source)
.map(|message_id| loader().get(message_id)) .map(|(message_id, attribute_id)| loader().get_attr(message_id, attribute_id))
.unwrap_or_else(|| source.to_string()); .unwrap_or_else(|| source.to_string());
for (name, value) in args { for (name, value) in args {
translated = translated.replace(&format!("__ocs_arg_{name}__"), value); translated = translated.replace(&format!("__ocs_arg_{name}__"), value);
@@ -229,13 +229,13 @@ pub fn translate_args(
/// sentence. File names, handles, counts, and command values therefore remain /// sentence. File names, handles, counts, and command values therefore remain
/// data instead of being sent through translation. /// data instead of being sent through translation.
pub fn translate_format(template: &str, rendered: String) -> Cow<'static, str> { pub fn translate_format(template: &str, rendered: String) -> Cow<'static, str> {
let Some(message_id) = locale_catalog::message_id(template) else { let Some((message_id, attribute_id)) = locale_catalog::message_attribute(template) else {
return Cow::Owned(rendered); return Cow::Owned(rendered);
}; };
let Some(values) = format_values(template, &rendered) else { let Some(values) = format_values(template, &rendered) else {
return Cow::Owned(rendered); return Cow::Owned(rendered);
}; };
let mut translated = loader().get(message_id); let mut translated = loader().get_attr(message_id, attribute_id);
for (index, value) in values.iter().enumerate() { for (index, value) in values.iter().enumerate() {
translated = translated.replace(&format!("__ocs_fmt_{index}__"), value); translated = translated.replace(&format!("__ocs_fmt_{index}__"), value);
} }
@@ -297,19 +297,30 @@ fn format_values(template: &str, rendered: &str) -> Option<Vec<String>> {
/// until they provide their own localization bundle. /// until they provide their own localization bundle.
pub fn ribbon_module_title(id: &str, fallback: &str) -> String { pub fn ribbon_module_title(id: &str, fallback: &str) -> String {
match id { match id {
"draw" => crate::tr!("ribbon-tab-draw"), "draw" => crate::tr!("ribbon-tab", "draw"),
"annotate" => crate::tr!("ribbon-tab-annotate"), "annotate" => crate::tr!("ribbon-tab", "annotate"),
"insert" => crate::tr!("ribbon-tab-insert"), "insert" => crate::tr!("ribbon-tab", "insert"),
"model" => crate::tr!("ribbon-tab-model"), "model" => crate::tr!("ribbon-tab", "model"),
"layout" => crate::tr!("ribbon-tab-layout"), "layout" => crate::tr!("ribbon-tab", "layout"),
"manage" => crate::tr!("ribbon-tab-manage"), "manage" => crate::tr!("ribbon-tab", "manage"),
"view" => crate::tr!("ribbon-tab-view"), "view" => crate::tr!("ribbon-tab", "view"),
_ => fallback.to_string(), _ => fallback.to_string(),
} }
} }
#[macro_export] #[macro_export]
macro_rules! tr { macro_rules! tr {
($message_id:literal, $attribute_id:literal $(,)?) => {
i18n_embed_fl::fl!($crate::i18n::loader(), $message_id, $attribute_id)
};
($message_id:literal, $attribute_id:literal, $($name:ident = $value:expr),+ $(,)?) => {
i18n_embed_fl::fl!(
$crate::i18n::loader(),
$message_id,
$attribute_id,
$($name = $value),+
)
};
($message_id:literal $(,)?) => { ($message_id:literal $(,)?) => {
i18n_embed_fl::fl!($crate::i18n::loader(), $message_id) i18n_embed_fl::fl!($crate::i18n::loader(), $message_id)
}; };
+3172 -3172
View File
File diff suppressed because it is too large. Load diff
+14 -14
View File
@@ -165,25 +165,25 @@ impl AreaCommand {
fn result_message(measurement: AreaMeasurement) -> String { fn result_message(measurement: AreaMeasurement) -> String {
match measurement.perimeter { match measurement.perimeter {
Some(perimeter) => crate::tr!( Some(perimeter) => crate::tr!(
"area-result", "area", "result",
area = format!("{:.4}", measurement.area), area = format!("{:.4}", measurement.area),
perimeter = format!("{perimeter:.4}"), perimeter = format!("{perimeter:.4}"),
), ),
None => crate::tr!("area-result-area-only", area = format!("{:.4}", measurement.area)), None => crate::tr!("area", "result-area-only", area = format!("{:.4}", measurement.area)),
} }
} }
fn running_result_message(&self, measurement: AreaMeasurement) -> String { fn running_result_message(&self, measurement: AreaMeasurement) -> String {
match measurement.perimeter { match measurement.perimeter {
Some(perimeter) => crate::tr!( Some(perimeter) => crate::tr!(
"area-running-result", "area", "running-result",
area = format!("{:.4}", measurement.area), area = format!("{:.4}", measurement.area),
perimeter = format!("{perimeter:.4}"), perimeter = format!("{perimeter:.4}"),
total_area = format!("{:.4}", self.total_area), total_area = format!("{:.4}", self.total_area),
total_perimeter = format!("{:.4}", self.total_perimeter), total_perimeter = format!("{:.4}", self.total_perimeter),
), ),
None => crate::tr!( None => crate::tr!(
"area-running-result-area-only", "area", "running-result-area-only",
area = format!("{:.4}", measurement.area), area = format!("{:.4}", measurement.area),
total_area = format!("{:.4}", self.total_area), total_area = format!("{:.4}", self.total_area),
), ),
@@ -224,30 +224,30 @@ impl CadCommand for AreaCommand {
fn prompt(&self) -> String { fn prompt(&self) -> String {
if self.objects_gathering { if self.objects_gathering {
return crate::tr!( return crate::tr!(
"area-prompt-objects", "area", "prompt-objects",
count = self.selected_entities.len() count = self.selected_entities.len()
); );
} }
if !self.points.is_empty() { if !self.points.is_empty() {
return crate::tr!("area-prompt-next", count = self.points.len()); return crate::tr!("area", "prompt-next", count = self.points.len());
} }
match self.mode { match self.mode {
AreaMode::Single => crate::tr!("area-prompt-first"), AreaMode::Single => crate::tr!("area", "prompt-first"),
AreaMode::Add => crate::tr!("area-prompt-add"), AreaMode::Add => crate::tr!("area", "prompt-add"),
AreaMode::Subtract => crate::tr!("area-prompt-subtract"), AreaMode::Subtract => crate::tr!("area", "prompt-subtract"),
} }
} }
fn options(&self) -> Vec<CmdOption> { fn options(&self) -> Vec<CmdOption> {
if self.objects_gathering { if self.objects_gathering {
return vec![Self::option(crate::tr!("area-option-back"), "BACK")]; return vec![Self::option(crate::tr!("area", "option-back"), "BACK")];
} }
if !self.points.is_empty() { if !self.points.is_empty() {
return Vec::new(); return Vec::new();
} }
let objects = || Self::option(crate::tr!("area-option-objects"), "OBJECTS"); let objects = || Self::option(crate::tr!("area", "option-objects"), "OBJECTS");
let add = || Self::option(crate::tr!("area-option-add"), "ADD"); let add = || Self::option(crate::tr!("area", "option-add"), "ADD");
let subtract = || Self::option(crate::tr!("area-option-subtract"), "SUBTRACT"); let subtract = || Self::option(crate::tr!("area", "option-subtract"), "SUBTRACT");
match self.mode { match self.mode {
AreaMode::Single => vec![objects(), add(), subtract()], AreaMode::Single => vec![objects(), add(), subtract()],
AreaMode::Add => vec![objects(), subtract()], AreaMode::Add => vec![objects(), subtract()],
@@ -323,7 +323,7 @@ impl CadCommand for AreaCommand {
let Some((measurement, handles)) = self.selection_measurement() else { let Some((measurement, handles)) = self.selection_measurement() else {
self.selected_entities.clear(); self.selected_entities.clear();
return CmdResult::ReportMeasurementAndDeselect(crate::tr!( return CmdResult::ReportMeasurementAndDeselect(crate::tr!(
"area-objects-not-measurable" "area", "objects-not-measurable"
)); ));
}; };
if self.mode != AreaMode::Single { if self.mode != AreaMode::Single {
+4 -4
View File
@@ -61,24 +61,24 @@ impl CadCommand for CopyCommand {
fn prompt(&self) -> String { fn prompt(&self) -> String {
if self.awaiting_count { if self.awaiting_count {
return crate::tr!("command-copy-array-count"); return crate::tr!("command-copy", "array-count");
} }
match &self.step { match &self.step {
Step::Base => crate::tr!( Step::Base => crate::tr!(
"command-copy-base", "command-copy", "base",
count = (self.handles.len() as i64), count = (self.handles.len() as i64),
), ),
Step::Placing(base) => { Step::Placing(base) => {
if let Some(n) = self.array_count { if let Some(n) = self.array_count {
crate::tr!( crate::tr!(
"command-copy-array-target", "command-copy", "array-target",
count = (n as i64), count = (n as i64),
x = format!("{:.3}", base.x), x = format!("{:.3}", base.x),
y = format!("{:.3}", base.y), y = format!("{:.3}", base.y),
) )
} else { } else {
crate::tr!( crate::tr!(
"command-copy-target", "command-copy", "target",
count = (self.count as i64), count = (self.count as i64),
x = format!("{:.3}", base.x), x = format!("{:.3}", base.x),
y = format!("{:.3}", base.y), y = format!("{:.3}", base.y),
+2 -2
View File
@@ -54,11 +54,11 @@ impl CadCommand for MoveCommand {
fn prompt(&self) -> String { fn prompt(&self) -> String {
match &self.step { match &self.step {
Step::Base => crate::tr!( Step::Base => crate::tr!(
"command-move-base", "command-move", "base",
count = (self.handles.len() as i64), count = (self.handles.len() as i64),
), ),
Step::Target(base) => crate::tr!( Step::Target(base) => crate::tr!(
"command-move-target", "command-move", "target",
x = format!("{:.3}", base.x), x = format!("{:.3}", base.x),
y = format!("{:.3}", base.y), y = format!("{:.3}", base.y),
), ),
+4 -4
View File
@@ -183,8 +183,8 @@ impl CommandLine {
pub fn new() -> Self { pub fn new() -> Self {
let mut cl = Self::default(); let mut cl = Self::default();
cl.history_height = HISTORY_HEIGHT_DEFAULT; cl.history_height = HISTORY_HEIGHT_DEFAULT;
cl.push_info(&crate::tr!("command-line-ready")); cl.push_info(&crate::tr!("command-line", "ready"));
cl.push_info(&crate::tr!("command-line-hint")); cl.push_info(&crate::tr!("command-line", "hint"));
cl cl
} }
@@ -522,7 +522,7 @@ impl CommandLine {
} }
}); });
let prompt = container( let prompt = container(
text(crate::tr!("command-line-label")).size(11).style(|theme: &Theme| iced::widget::text::Style { text(crate::tr!("command-line", "label")).size(11).style(|theme: &Theme| iced::widget::text::Style {
color: Some(theme.palette().success.base.color), color: Some(theme.palette().success.base.color),
}), }),
) )
@@ -559,7 +559,7 @@ impl CommandLine {
..Default::default() ..Default::default()
} }
}); });
let literal_tip = container(text(crate::tr!("command-line-literal-spaces")).size(11)) let literal_tip = container(text(crate::tr!("command-line", "literal-spaces")).size(11))
.padding([3, 6]) .padding([3, 6])
.style(container::bordered_box); .style(container::bordered_box);
let literal_btn = tooltip(literal_btn, literal_tip, tooltip::Position::Top).gap(4); let literal_btn = tooltip(literal_btn, literal_tip, tooltip::Position::Top).gap(4);
+1 -1
View File
@@ -106,7 +106,7 @@ pub fn view_window<'a>(
); );
} }
let close = button(text(crate::tr!("action-close")).size(12)) let close = button(text(crate::tr!("action", "close")).size(12))
.on_press(Message::CloseModal) .on_press(Message::CloseModal)
.padding([6, 18]) .padding([6, 18])
.style(button::secondary); .style(button::secondary);
+15 -15
View File
@@ -91,12 +91,12 @@ pub fn view_window<'a>(
let palette = ui_theme.palette.to_iced(); let palette = ui_theme.palette.to_iced();
let colors = [ let colors = [
(crate::tr!("options-color-background"), palette.background), (crate::tr!("options", "color-background"), palette.background),
(crate::tr!("options-color-text"), palette.text), (crate::tr!("options", "color-text"), palette.text),
(crate::tr!("options-color-primary"), palette.primary), (crate::tr!("options", "color-primary"), palette.primary),
(crate::tr!("options-color-success"), palette.success), (crate::tr!("options", "color-success"), palette.success),
(crate::tr!("options-color-warning"), palette.warning), (crate::tr!("options", "color-warning"), palette.warning),
(crate::tr!("options-color-danger"), palette.danger), (crate::tr!("options", "color-danger"), palette.danger),
]; ];
let mut color_controls = column![].spacing(8); let mut color_controls = column![].spacing(8);
@@ -126,16 +126,16 @@ pub fn view_window<'a>(
); );
} }
let close = button(text(crate::tr!("action-close")).size(12)) let close = button(text(crate::tr!("action", "close")).size(12))
.on_press(Message::CloseModal) .on_press(Message::CloseModal)
.padding([6, 18]) .padding([6, 18])
.style(button::secondary); .style(button::secondary);
let general = column![ let general = column![
text(crate::tr!("options-language-section")).size(15), text(crate::tr!("options", "language-section")).size(15),
Space::new().height(10), Space::new().height(10),
row![ row![
text(crate::tr!("options-language-label")).size(12).width(150), text(crate::tr!("options", "language-label")).size(12).width(150),
iced::widget::pick_list( iced::widget::pick_list(
selected_language, selected_language,
language_options, language_options,
@@ -147,10 +147,10 @@ pub fn view_window<'a>(
.spacing(12) .spacing(12)
.align_y(iced::Center), .align_y(iced::Center),
Space::new().height(22), Space::new().height(22),
text(crate::tr!("options-open-save-section")).size(15), text(crate::tr!("options", "open-save-section")).size(15),
Space::new().height(10), Space::new().height(10),
row![ row![
text(crate::tr!("options-default-save-format-label")).size(12).width(150), text(crate::tr!("options", "default-save-format-label")).size(12).width(150),
iced::widget::pick_list( iced::widget::pick_list(
selected_format, selected_format,
crate::io::SAVE_FORMAT_OPTIONS, crate::io::SAVE_FORMAT_OPTIONS,
@@ -162,7 +162,7 @@ pub fn view_window<'a>(
.spacing(12) .spacing(12)
.align_y(iced::Center), .align_y(iced::Center),
Space::new().height(8), Space::new().height(8),
text(crate::tr!("options-default-save-format-help")) text(crate::tr!("options", "default-save-format-help"))
.size(11) .size(11)
.width(sizing.width), .width(sizing.width),
Space::new().height(14), Space::new().height(14),
@@ -204,10 +204,10 @@ pub fn view_window<'a>(
}); });
let display = column![ let display = column![
text(crate::tr!("options-theme-section")).size(15), text(crate::tr!("options", "theme-section")).size(15),
Space::new().height(10), Space::new().height(10),
row![ row![
text(crate::tr!("options-theme-label")).size(12).width(150), text(crate::tr!("options", "theme-label")).size(12).width(150),
iced::widget::pick_list( iced::widget::pick_list(
selected_theme, selected_theme,
theme_options, theme_options,
@@ -219,7 +219,7 @@ pub fn view_window<'a>(
.spacing(12) .spacing(12)
.align_y(iced::Center), .align_y(iced::Center),
Space::new().height(8), Space::new().height(8),
text(crate::tr!("options-theme-help")) text(crate::tr!("options", "theme-help"))
.size(11) .size(11)
.width(sizing.width), .width(sizing.width),
Space::new().height(12), Space::new().height(12),
+20 -20
View File
@@ -49,32 +49,32 @@ pub fn view_window<'a>(
) -> Element<'a, Message> { ) -> Element<'a, Message> {
let recovered = report.status == RecoveryStatus::Recovered; let recovered = report.status == RecoveryStatus::Recovered;
let heading = if recovered { let heading = if recovered {
crate::tr!("recovery-opened-with-repairs") crate::tr!("recovery", "opened-with-repairs")
} else { } else {
crate::tr!("recovery-open-failed") crate::tr!("recovery", "open-failed")
}; };
let description = if recovered { let description = if recovered {
crate::tr!("recovery-repaired-description") crate::tr!("recovery", "repaired-description")
} else { } else {
crate::tr!("recovery-failed-description") crate::tr!("recovery", "failed-description")
}; };
let status = report.status; let status = report.status;
let metrics = row![ let metrics = row![
metric( metric(
crate::tr!("recovery-entities-checked"), crate::tr!("recovery", "entities-checked"),
report.entities_scanned.to_string(), report.entities_scanned.to_string(),
), ),
metric( metric(
crate::tr!("recovery-issues-found"), crate::tr!("recovery", "issues-found"),
report.issues_found().to_string(), report.issues_found().to_string(),
), ),
metric( metric(
crate::tr!("recovery-entities-removed"), crate::tr!("recovery", "entities-removed"),
report.removed_total().to_string(), report.removed_total().to_string(),
), ),
metric( metric(
crate::tr!("recovery-references-checked"), crate::tr!("recovery", "references-checked"),
report.references_checked.to_string(), report.references_checked.to_string(),
), ),
] ]
@@ -86,7 +86,7 @@ pub fn view_window<'a>(
details = details.push( details = details.push(
text(format!( text(format!(
"{}: {}", "{}: {}",
crate::tr!("recovery-referenced-entities-removed"), crate::tr!("recovery", "referenced-entities-removed"),
report.referenced_entities_removed report.referenced_entities_removed
)) ))
.size(11), .size(11),
@@ -96,7 +96,7 @@ pub fn view_window<'a>(
details = details.push( details = details.push(
text(format!( text(format!(
"{}: {}", "{}: {}",
crate::tr!("recovery-references-unavailable"), crate::tr!("recovery", "references-unavailable"),
report report
.references_missing .references_missing
.saturating_add(report.references_failed) .saturating_add(report.references_failed)
@@ -112,7 +112,7 @@ pub fn view_window<'a>(
} }
if let Some(path) = &report.log_path { if let Some(path) = &report.log_path {
details = details.push( details = details.push(
text(format!("{}: {}", crate::tr!("recovery-log-path"), path.display())) text(format!("{}: {}", crate::tr!("recovery", "log-path"), path.display()))
.size(10) .size(10)
.style(muted_style), .style(muted_style),
); );
@@ -120,14 +120,14 @@ pub fn view_window<'a>(
details = details.push( details = details.push(
text(format!( text(format!(
"{}: {error}", "{}: {error}",
crate::tr!("recovery-log-write-failed") crate::tr!("recovery", "log-write-failed")
)) ))
.size(10) .size(10)
.style(status_style(RecoveryStatus::Failed)), .style(status_style(RecoveryStatus::Failed)),
); );
} else if cfg!(target_arch = "wasm32") { } else if cfg!(target_arch = "wasm32") {
details = details.push( details = details.push(
text(crate::tr!("recovery-log-download-ready")) text(crate::tr!("recovery", "log-download-ready"))
.size(10) .size(10)
.style(muted_style), .style(muted_style),
); );
@@ -142,7 +142,7 @@ pub fn view_window<'a>(
let mut actions = row![Space::new().width(Fill)].spacing(8); let mut actions = row![Space::new().width(Fill)].spacing(8);
if recovered && report.save_as_required && allow_save_copy { if recovered && report.save_as_required && allow_save_copy {
actions = actions.push( actions = actions.push(
button(text(crate::tr!("recovery-save-copy")).size(12)) button(text(crate::tr!("recovery", "save-copy")).size(12))
.on_press(Message::RecoverySaveAs) .on_press(Message::RecoverySaveAs)
.style(button::primary) .style(button::primary)
.padding([6, 14]), .padding([6, 14]),
@@ -150,14 +150,14 @@ pub fn view_window<'a>(
} }
if report.log_path.is_some() || cfg!(target_arch = "wasm32") { if report.log_path.is_some() || cfg!(target_arch = "wasm32") {
actions = actions.push( actions = actions.push(
button(text(crate::tr!("recovery-show-log")).size(12)) button(text(crate::tr!("recovery", "show-log")).size(12))
.on_press(Message::RecoveryShowLog) .on_press(Message::RecoveryShowLog)
.style(button::secondary) .style(button::secondary)
.padding([6, 14]), .padding([6, 14]),
); );
} }
actions = actions.push( actions = actions.push(
button(text(crate::tr!("action-close")).size(12)) button(text(crate::tr!("action", "close")).size(12))
.on_press(Message::RecoveryClose) .on_press(Message::RecoveryClose)
.style(button::secondary) .style(button::secondary)
.padding([6, 14]), .padding([6, 14]),
@@ -200,11 +200,11 @@ pub fn view_prompt<'a>(
}; };
let actions = row![ let actions = row![
Space::new().width(content_width), Space::new().width(content_width),
button(text(crate::tr!("recovery-decline")).size(12)) button(text(crate::tr!("recovery", "decline")).size(12))
.on_press(Message::RecoveryDecline) .on_press(Message::RecoveryDecline)
.style(button::secondary) .style(button::secondary)
.padding([6, 14]), .padding([6, 14]),
button(text(crate::tr!("recovery-attempt")).size(12)) button(text(crate::tr!("recovery", "attempt")).size(12))
.on_press(Message::RecoveryAttempt) .on_press(Message::RecoveryAttempt)
.style(button::primary) .style(button::primary)
.padding([6, 14]), .padding([6, 14]),
@@ -213,9 +213,9 @@ pub fn view_prompt<'a>(
container( container(
column![ column![
text(crate::tr!("recovery-prompt-heading")).size(20), text(crate::tr!("recovery", "prompt-heading")).size(20),
text(file_name).size(13), text(file_name).size(13),
text(crate::tr!("recovery-prompt-description")) text(crate::tr!("recovery", "prompt-description"))
.size(11) .size(11)
.style(muted_style), .style(muted_style),
container(scrollable(text(error).size(10)).height(content_height)) container(scrollable(text(error).size(10)).height(content_height))