diff options
| author | Rubén Beltrán del Río <jj@r.bdr.sh> | 2026-01-17 00:36:49 +0100 |
|---|---|---|
| committer | Rubén Beltrán del Río <jj@r.bdr.sh> | 2026-01-17 02:43:21 +0100 |
| commit | 17898fbabde35ab346c133114e78614e707c0eca (patch) | |
| tree | 90f0fd36211c036a507a0af092aac3c5fb8e7ac8 /src/preferences | |
| parent | 90b12c34debaa4aa816d4e6862cdb4e39c7181e4 (diff) | |
Add localization
Diffstat (limited to 'src/preferences')
| -rw-r--r-- | src/preferences/pages/editor.rs | 13 | ||||
| -rw-r--r-- | src/preferences/pages/general.rs | 30 | ||||
| -rw-r--r-- | src/preferences/pages/map.rs | 17 | ||||
| -rw-r--r-- | src/preferences/pages/stages.rs | 22 | ||||
| -rw-r--r-- | src/preferences/pages/templates.rs | 77 | ||||
| -rw-r--r-- | src/preferences/window.rs | 15 |
6 files changed, 73 insertions, 101 deletions
diff --git a/src/preferences/pages/editor.rs b/src/preferences/pages/editor.rs index 9f10d43..d4acb94 100644 --- a/src/preferences/pages/editor.rs +++ b/src/preferences/pages/editor.rs @@ -18,6 +18,7 @@ use gtk::prelude::*; use relm4::Sender; use relm4::gtk; +use crate::tr; use crate::ui_helpers::create_switch_row; use super::super::models::UserPreferences; @@ -41,7 +42,7 @@ impl EditorPage { container.set_valign(gtk::Align::Start); // Font Size section - let font_size_label = gtk::Label::new(Some("Font Size")); + let font_size_label = gtk::Label::new(Some(&tr!("preferences.editor.font_size.title"))); font_size_label.add_css_class("heading"); font_size_label.set_halign(gtk::Align::Start); container.append(&font_size_label); @@ -56,18 +57,18 @@ impl EditorPage { }); } font_size_box.append(&font_size_spin); - font_size_box.append(>k::Label::new(Some("pt"))); + font_size_box.append(>k::Label::new(Some(&tr!("preferences.editor.font_size.unit")))); container.append(&font_size_box); // Editor Style section - let style_label = gtk::Label::new(Some("Editor Style")); + let style_label = gtk::Label::new(Some(&tr!("preferences.editor.editor_style.title"))); style_label.add_css_class("heading"); style_label.set_halign(gtk::Align::Start); style_label.set_margin_top(10); container.append(&style_label); // Soft Wrap Lines - let soft_wrap_row = create_switch_row("Soft Wrap Lines", preferences.soft_wrap_lines); + let soft_wrap_row = create_switch_row(&tr!("preferences.editor.editor_style.soft_wrap_lines"), preferences.soft_wrap_lines); let soft_wrap_switch = soft_wrap_row.1.clone(); { let sender = sender.clone(); @@ -80,13 +81,13 @@ impl EditorPage { // Use Custom Font let custom_font_row = - create_switch_row("Use Custom Editor Font", preferences.use_custom_editor_font); + create_switch_row(&tr!("preferences.editor.editor_style.use_custom_font"), preferences.use_custom_editor_font); let custom_font_switch = custom_font_row.1.clone(); container.append(&custom_font_row.0); // Font selection let font_row = gtk::Box::new(gtk::Orientation::Horizontal, 10); - font_row.append(>k::Label::new(Some("Font"))); + font_row.append(>k::Label::new(Some(&tr!("preferences.editor.font")))); let font_button = gtk::FontButton::new(); font_button.set_font(&format!( diff --git a/src/preferences/pages/general.rs b/src/preferences/pages/general.rs index 43cd784..d70e9e6 100644 --- a/src/preferences/pages/general.rs +++ b/src/preferences/pages/general.rs @@ -19,6 +19,8 @@ use gtk::prelude::*; use relm4::Sender; use relm4::gtk; +use crate::tr; + use super::super::window::PreferencesInput; pub struct GeneralPage { @@ -35,7 +37,7 @@ impl GeneralPage { container.set_valign(gtk::Align::Start); // Preferences section - let prefs_label = gtk::Label::new(Some("Preferences")); + let prefs_label = gtk::Label::new(Some(&tr!("preferences.general.preferences.title"))); prefs_label.add_css_class("heading"); prefs_label.set_halign(gtk::Align::Start); container.append(&prefs_label); @@ -43,7 +45,7 @@ impl GeneralPage { let button_box = gtk::Box::new(gtk::Orientation::Horizontal, 10); // Export button - let export_button = gtk::Button::with_label("Export..."); + let export_button = gtk::Button::with_label(&tr!("preferences.general.preferences.export")); { let sender = sender.clone(); export_button.connect_clicked(move |_| { @@ -53,7 +55,7 @@ impl GeneralPage { button_box.append(&export_button); // Import button - let import_button = gtk::Button::with_label("Import..."); + let import_button = gtk::Button::with_label(&tr!("preferences.general.preferences.import")); { let sender = sender.clone(); import_button.connect_clicked(move |_| { @@ -63,7 +65,7 @@ impl GeneralPage { button_box.append(&import_button); // Reset button - let reset_button = gtk::Button::with_label("Reset to Defaults"); + let reset_button = gtk::Button::with_label(&tr!("preferences.general.preferences.reset")); reset_button.add_css_class("destructive-action"); { let sender = sender.clone(); @@ -76,9 +78,7 @@ impl GeneralPage { container.append(&button_box); // Help text - let help_label = gtk::Label::new(Some( - "Export your preferences to share with others or back up your settings.\nImport preferences from a file to restore settings.", - )); + let help_label = gtk::Label::new(Some(&tr!("preferences.general.explanation"))); help_label.add_css_class("dim-label"); help_label.set_halign(gtk::Align::Start); help_label.set_wrap(true); @@ -95,15 +95,15 @@ impl GeneralPage { pub fn show_export_dialog(sender: &Sender<PreferencesInput>, window: >k::Window) { let filter = FileFilter::new(); filter.add_pattern("*.json"); - filter.set_name(Some("JSON files")); + filter.set_name(Some(&tr!("dialog.file_type.json"))); let dialog = gtk::FileChooserDialog::new( - Some("Export Preferences"), + Some(&tr!("dialog.export_preferences.title")), Some(window), gtk::FileChooserAction::Save, &[ - ("Cancel", gtk::ResponseType::Cancel), - ("Save", gtk::ResponseType::Accept), + (&tr!("dialog.action.cancel"), gtk::ResponseType::Cancel), + (&tr!("dialog.action.save"), gtk::ResponseType::Accept), ], ); dialog.set_current_name("preferences.json"); @@ -127,15 +127,15 @@ pub fn show_export_dialog(sender: &Sender<PreferencesInput>, window: >k::Windo pub fn show_import_dialog(sender: &Sender<PreferencesInput>, window: >k::Window) { let filter = FileFilter::new(); filter.add_pattern("*.json"); - filter.set_name(Some("JSON files")); + filter.set_name(Some(&tr!("dialog.file_type.json"))); let dialog = gtk::FileChooserDialog::new( - Some("Import Preferences"), + Some(&tr!("dialog.import_preferences.title")), Some(window), gtk::FileChooserAction::Open, &[ - ("Cancel", gtk::ResponseType::Cancel), - ("Open", gtk::ResponseType::Accept), + (&tr!("dialog.action.cancel"), gtk::ResponseType::Cancel), + (&tr!("dialog.action.open"), gtk::ResponseType::Accept), ], ); dialog.add_filter(&filter); diff --git a/src/preferences/pages/map.rs b/src/preferences/pages/map.rs index 8deae20..5ffd04a 100644 --- a/src/preferences/pages/map.rs +++ b/src/preferences/pages/map.rs @@ -18,6 +18,7 @@ use gtk::prelude::*; use relm4::Sender; use relm4::gtk; +use crate::tr; use crate::ui_helpers::create_switch_row; use super::super::models::UserPreferences; @@ -42,14 +43,14 @@ impl MapPage { container.set_valign(gtk::Align::Start); // Map Style section - let style_label = gtk::Label::new(Some("Map Style")); + let style_label = gtk::Label::new(Some(&tr!("preferences.map.map_style.title"))); style_label.add_css_class("heading"); style_label.set_halign(gtk::Align::Start); container.append(&style_label); // Show Background let background_row = - create_switch_row("Show Map Background", preferences.show_map_background); + create_switch_row(&tr!("preferences.map.map_style.show_background"), preferences.show_map_background); let show_background_switch = background_row.1.clone(); { let sender = sender.clone(); @@ -62,7 +63,7 @@ impl MapPage { // Smart Label Positioning let smart_row = create_switch_row( - "Use Smart Label Positioning", + &tr!("preferences.map.map_style.use_smart_label_positioning"), preferences.use_smart_label_positioning, ); let smart_positioning_switch = smart_row.1.clone(); @@ -76,13 +77,13 @@ impl MapPage { container.append(&smart_row.0); // Use Custom Font - let custom_font_row = create_switch_row("Use Custom Font", preferences.use_custom_font); + let custom_font_row = create_switch_row(&tr!("preferences.map.map_style.use_custom_font"), preferences.use_custom_font); let custom_font_switch = custom_font_row.1.clone(); container.append(&custom_font_row.0); // Font selection let font_row = gtk::Box::new(gtk::Orientation::Horizontal, 10); - font_row.append(>k::Label::new(Some("Font"))); + font_row.append(>k::Label::new(Some(&tr!("preferences.map.font")))); let font_button = gtk::FontButton::new(); font_button.set_font(&preferences.custom_font_name); @@ -115,16 +116,16 @@ impl MapPage { } // Export section - let export_label = gtk::Label::new(Some("Export")); + let export_label = gtk::Label::new(Some(&tr!("preferences.map.export.title"))); export_label.add_css_class("heading"); export_label.set_halign(gtk::Align::Start); export_label.set_margin_top(10); container.append(&export_label); let export_row = gtk::Box::new(gtk::Orientation::Horizontal, 10); - export_row.append(>k::Label::new(Some("Default Export Format"))); + export_row.append(>k::Label::new(Some(&tr!("preferences.map.export.default_format")))); - let formats = gtk::StringList::new(&["PNG", "SVG"]); + let formats = gtk::StringList::new(&[&tr!("export_formats.png"), &tr!("export_formats.svg")]); let export_format_dropdown = gtk::DropDown::new(Some(formats), None::<gtk::Expression>); let selected = match preferences.default_export_format.as_str() { "svg" => 1, diff --git a/src/preferences/pages/stages.rs b/src/preferences/pages/stages.rs index 6f4121e..9f0685d 100644 --- a/src/preferences/pages/stages.rs +++ b/src/preferences/pages/stages.rs @@ -19,6 +19,8 @@ use relm4::Sender; use relm4::gtk; use uuid::Uuid; +use crate::tr; + use super::super::models::UserPreferences; use super::super::window::{PreferencesInput, StageLabel}; @@ -37,14 +39,12 @@ impl StagesPage { container.set_margin_end(20); // Header - let header_label = gtk::Label::new(Some("Custom Stages")); + let header_label = gtk::Label::new(Some(&tr!("preferences.stages.title"))); header_label.add_css_class("heading"); header_label.set_halign(gtk::Align::Start); container.append(&header_label); - let help_label = gtk::Label::new(Some( - "Custom stages allow you to define your own evolution axis labels. These will be available for rendering when the renderer supports custom stages.", - )); + let help_label = gtk::Label::new(Some(&tr!("preferences.stages.explanation"))); help_label.add_css_class("dim-label"); help_label.set_halign(gtk::Align::Start); help_label.set_wrap(true); @@ -55,27 +55,27 @@ impl StagesPage { let header_row = gtk::Box::new(gtk::Orientation::Horizontal, 5); header_row.add_css_class("dim-label"); - let name_header = gtk::Label::new(Some("Name")); + let name_header = gtk::Label::new(Some(&tr!("preferences.stages.column.name"))); name_header.set_width_chars(15); name_header.set_xalign(0.0); header_row.append(&name_header); - let i_header = gtk::Label::new(Some("Stage I")); + let i_header = gtk::Label::new(Some(&tr!("preferences.stages.column.stage_i"))); i_header.set_width_chars(12); i_header.set_xalign(0.0); header_row.append(&i_header); - let ii_header = gtk::Label::new(Some("Stage II")); + let ii_header = gtk::Label::new(Some(&tr!("preferences.stages.column.stage_ii"))); ii_header.set_width_chars(12); ii_header.set_xalign(0.0); header_row.append(&ii_header); - let iii_header = gtk::Label::new(Some("Stage III")); + let iii_header = gtk::Label::new(Some(&tr!("preferences.stages.column.stage_iii"))); iii_header.set_width_chars(12); iii_header.set_xalign(0.0); header_row.append(&iii_header); - let iv_header = gtk::Label::new(Some("Stage IV")); + let iv_header = gtk::Label::new(Some(&tr!("preferences.stages.column.stage_iv"))); iv_header.set_width_chars(12); iv_header.set_xalign(0.0); header_row.append(&iv_header); @@ -104,7 +104,7 @@ impl StagesPage { button_box.set_halign(gtk::Align::End); let add_button = gtk::Button::from_icon_name("list-add-symbolic"); - add_button.set_tooltip_text(Some("Add custom stage")); + add_button.set_tooltip_text(Some(&tr!("preferences.stages.help.add"))); { let sender = sender.clone(); add_button.connect_clicked(move |_| { @@ -238,7 +238,7 @@ impl StagesPage { // Delete button let delete_button = gtk::Button::from_icon_name("list-remove-symbolic"); delete_button.add_css_class("flat"); - delete_button.set_tooltip_text(Some("Remove stage")); + delete_button.set_tooltip_text(Some(&tr!("preferences.stages.help.remove"))); { let sender = self.sender.clone(); delete_button.connect_clicked(move |_| { diff --git a/src/preferences/pages/templates.rs b/src/preferences/pages/templates.rs index da3cafc..acc679f 100644 --- a/src/preferences/pages/templates.rs +++ b/src/preferences/pages/templates.rs @@ -22,6 +22,8 @@ use relm4::gtk; use sourceview5::prelude::*; use uuid::Uuid; +use crate::tr; + use super::super::models::{Template, UserPreferences}; use super::super::window::PreferencesInput; @@ -49,7 +51,7 @@ impl TemplatesPage { let sidebar = gtk::Box::new(gtk::Orientation::Vertical, 5); sidebar.set_width_request(200); - let sidebar_label = gtk::Label::new(Some("Templates")); + let sidebar_label = gtk::Label::new(Some(&tr!("preferences.templates.title"))); sidebar_label.add_css_class("heading"); sidebar_label.set_halign(gtk::Align::Start); sidebar_label.set_margin_start(5); @@ -72,18 +74,19 @@ impl TemplatesPage { button_box.set_margin_top(5); let add_button = gtk::Button::from_icon_name("list-add-symbolic"); - add_button.set_tooltip_text(Some("Add template")); + add_button.set_tooltip_text(Some(&tr!("preferences.templates.help.add"))); { let sender = sender.clone(); add_button.connect_clicked(move |_| { - // Show a simple dialog to get the template name - show_add_template_dialog(sender.clone()); + sender.emit(PreferencesInput::AddTemplate( + tr!("dialog.template.default_label"), + )); }); } button_box.append(&add_button); let remove_button = gtk::Button::from_icon_name("list-remove-symbolic"); - remove_button.set_tooltip_text(Some("Remove template")); + remove_button.set_tooltip_text(Some(&tr!("preferences.templates.help.remove"))); { let sender = sender.clone(); let selected_id = selected_id.clone(); @@ -108,7 +111,7 @@ impl TemplatesPage { let editor_box = gtk::Box::new(gtk::Orientation::Vertical, 5); editor_box.set_hexpand(true); - let editor_label = gtk::Label::new(Some("Template Content")); + let editor_label = gtk::Label::new(Some(&tr!("preferences.templates.content"))); editor_label.add_css_class("heading"); editor_label.set_halign(gtk::Align::Start); editor_box.append(&editor_label); @@ -245,10 +248,10 @@ impl TemplatesPage { let default_button = gtk::Button::new(); if template.is_default { default_button.set_icon_name("emblem-default-symbolic"); - default_button.set_tooltip_text(Some("Default template")); + default_button.set_tooltip_text(Some(&tr!("preferences.templates.help.default"))); } else { default_button.set_icon_name("radio-symbolic"); - default_button.set_tooltip_text(Some("Set as default")); + default_button.set_tooltip_text(Some(&tr!("preferences.templates.help.set_as_default"))); } default_button.add_css_class("flat"); { @@ -260,54 +263,20 @@ impl TemplatesPage { } hbox.append(&default_button); - // Template name - let name_label = gtk::Label::new(Some(&template.name)); - name_label.set_hexpand(true); - name_label.set_xalign(0.0); - hbox.append(&name_label); + // Template name (editable) + let name_entry = gtk::Entry::new(); + name_entry.set_text(&template.name); + name_entry.set_hexpand(true); + { + let sender = self.sender.clone(); + let id = template.id; + name_entry.connect_changed(move |entry| { + sender.emit(PreferencesInput::SetTemplateName(id, entry.text().to_string())); + }); + } + hbox.append(&name_entry); row.set_child(Some(&hbox)); row } } - -fn show_add_template_dialog(sender: Sender<PreferencesInput>) { - let dialog = gtk::Dialog::with_buttons( - Some("New Template"), - None::<>k::Window>, - gtk::DialogFlags::MODAL | gtk::DialogFlags::DESTROY_WITH_PARENT, - &[ - ("Cancel", gtk::ResponseType::Cancel), - ("Add", gtk::ResponseType::Accept), - ], - ); - dialog.set_default_response(gtk::ResponseType::Accept); - - let content = dialog.content_area(); - content.set_margin_top(10); - content.set_margin_bottom(10); - content.set_margin_start(10); - content.set_margin_end(10); - content.set_spacing(10); - - let label = gtk::Label::new(Some("Template name:")); - label.set_halign(gtk::Align::Start); - content.append(&label); - - let entry = gtk::Entry::new(); - entry.set_placeholder_text(Some("My Template")); - entry.set_activates_default(true); - content.append(&entry); - - dialog.connect_response(move |dialog, response| { - if response == gtk::ResponseType::Accept { - let name = entry.text().to_string(); - if !name.is_empty() { - sender.emit(PreferencesInput::AddTemplate(name)); - } - } - dialog.close(); - }); - - dialog.present(); -} diff --git a/src/preferences/window.rs b/src/preferences/window.rs index 8b38c29..2118056 100644 --- a/src/preferences/window.rs +++ b/src/preferences/window.rs @@ -22,6 +22,8 @@ use std::path::PathBuf; use gtk::prelude::*; use relm4::{ComponentParts, ComponentSender, SimpleComponent, gtk}; +use crate::tr; + use super::models::UserPreferences; use super::pages::{editor, general, map, stages, templates}; use super::storage; @@ -52,7 +54,6 @@ pub enum PreferencesInput { AddTemplate(String), RemoveTemplate(uuid::Uuid), SetTemplateContent(uuid::Uuid, String), - #[allow(dead_code)] SetTemplateName(uuid::Uuid, String), SetDefaultTemplate(uuid::Uuid), @@ -101,7 +102,7 @@ impl SimpleComponent for PreferencesWindow { view! { gtk::Window { - set_title: Some("Preferences"), + set_title: Some(&tr!("preferences.title")), set_default_width: 700, set_default_height: 500, set_modal: true, @@ -127,11 +128,11 @@ impl SimpleComponent for PreferencesWindow { set_transition_type: gtk::StackTransitionType::SlideLeftRight, set_vexpand: true, - add_titled[Some("general"), "General"] = &model.general_page.widget() -> gtk::Box {}, - add_titled[Some("editor"), "Editor"] = &model.editor_page.widget() -> gtk::Box {}, - add_titled[Some("map"), "Map"] = &model.map_page.widget() -> gtk::Box {}, - add_titled[Some("stages"), "Stages"] = &model.stages_page.widget() -> gtk::Box {}, - add_titled[Some("templates"), "Templates"] = &model.templates_page.widget() -> gtk::Box {}, + add_titled[Some("general"), &tr!("preferences.menu.general")] = &model.general_page.widget() -> gtk::Box {}, + add_titled[Some("editor"), &tr!("preferences.menu.editor")] = &model.editor_page.widget() -> gtk::Box {}, + add_titled[Some("map"), &tr!("preferences.menu.map")] = &model.map_page.widget() -> gtk::Box {}, + add_titled[Some("stages"), &tr!("preferences.menu.stages")] = &model.stages_page.widget() -> gtk::Box {}, + add_titled[Some("templates"), &tr!("preferences.menu.templates")] = &model.templates_page.widget() -> gtk::Box {}, }, }, } |