diff options
| author | Ruben Beltran del Rio <jj@r.bdr.sh> | 2026-03-23 20:52:55 +0100 |
|---|---|---|
| committer | Rubén Beltrán del Río <jj@r.bdr.sh> | 2026-04-05 00:31:21 +0200 |
| commit | 1d28fb5599337bf1891ac8cc43b7656975d239d7 (patch) | |
| tree | e75bcfaed71d668c87afa65ca524d1a0338a0ce1 /src | |
| parent | ef32d65ac1852da581ac75d20f903dbcb2d0b5cd (diff) | |
Use english as the base language
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/footer.rs | 4 | ||||
| -rw-r--r-- | src/components/header.rs | 42 | ||||
| -rw-r--r-- | src/components/preference_pages/editor.rs | 12 | ||||
| -rw-r--r-- | src/components/preference_pages/general.rs | 11 | ||||
| -rw-r--r-- | src/components/preference_pages/map.rs | 18 | ||||
| -rw-r--r-- | src/components/preference_pages/stages.rs | 16 | ||||
| -rw-r--r-- | src/components/preference_pages/templates.rs | 12 | ||||
| -rw-r--r-- | src/components/preferences_window.rs | 20 | ||||
| -rw-r--r-- | src/components/stage_form.rs | 2 | ||||
| -rw-r--r-- | src/components/template_row.rs | 4 | ||||
| -rw-r--r-- | src/dialogs.rs | 24 | ||||
| -rw-r--r-- | src/handlers/export.rs | 6 | ||||
| -rw-r--r-- | src/handlers/file.rs | 12 | ||||
| -rw-r--r-- | src/main.rs | 72 | ||||
| -rw-r--r-- | src/preferences/models.rs | 79 | ||||
| -rw-r--r-- | src/stages.rs | 220 |
16 files changed, 334 insertions, 220 deletions
diff --git a/src/components/footer.rs b/src/components/footer.rs index a7999be..27c666c 100644 --- a/src/components/footer.rs +++ b/src/components/footer.rs @@ -56,7 +56,7 @@ impl SimpleComponent for Footer { set_margin_end: 5 }, - gtk::Button::with_label(&tr!("command.view.zoom_out")) { + gtk::Button::with_label(&tr!("Zoom Out")) { set_icon_name: ZOOM_OUT_REGULAR, set_margin_end: 5, add_css_class: "flat", @@ -79,7 +79,7 @@ impl SimpleComponent for Footer { } }, - gtk::Button::with_label(&tr!("command.view.zoom_in")) { + gtk::Button::with_label(&tr!("Zoom In")) { set_icon_name: ZOOM_IN_REGULAR, add_css_class: "flat", add_css_class: "zoom", diff --git a/src/components/header.rs b/src/components/header.rs index f41d6a1..8e20850 100644 --- a/src/components/header.rs +++ b/src/components/header.rs @@ -54,8 +54,8 @@ impl SimpleComponent for Header { adw::HeaderBar { pack_start = &adw::ToolbarView { gtk::Button::with_label(&match model.orientation { - gtk::Orientation::Horizontal => tr!("command.view.use_vertical_layout"), - _ => tr!("command.view.use_horizontal_layout") + gtk::Orientation::Horizontal => tr!("Use Vertical Layout"), + _ => tr!("Use Horizontal Layout") }) { #[watch] set_icon_name: match model.orientation { @@ -69,7 +69,7 @@ impl SimpleComponent for Header { }, pack_end = >k::Box { - gtk::Button::with_label(&tr!("command.file.export")) { + gtk::Button::with_label(&tr!("Export as Image")) { set_icon_name: IMAGE_REGULAR, ActionablePlus::set_stateless_action::<ExportImageAction>: &(), }, @@ -160,44 +160,32 @@ impl Header { } let main_menu = gio::Menu::new(); - main_menu.append(Some(&tr!("command.file.new")), Some("window.new")); - main_menu.append_submenu( - Some(&tr!("command.file.new_from_template")), - &templates_menu, - ); - main_menu.append(Some(&tr!("command.file.open")), Some("window.open")); - main_menu.append(Some(&tr!("command.file.save")), Some("window.save")); - main_menu.append(Some(&tr!("command.file.save_as")), Some("window.save-as")); - main_menu.append(Some(&tr!("command.file.close")), Some("window.close")); - main_menu.append( - Some(&tr!("command.file.export")), - Some("window.export-image"), - ); + main_menu.append(Some(&tr!("New Map")), Some("window.new")); + main_menu.append_submenu(Some(&tr!("New from Template")), &templates_menu); + main_menu.append(Some(&tr!("Open…")), Some("window.open")); + main_menu.append(Some(&tr!("Save")), Some("window.save")); + main_menu.append(Some(&tr!("Save As…")), Some("window.save-as")); + main_menu.append(Some(&tr!("Close")), Some("window.close")); + main_menu.append(Some(&tr!("Export as Image")), Some("window.export-image")); let layout_section = gio::Menu::new(); layout_section.append( - Some(&tr!("command.view.use_vertical_layout")), + Some(&tr!("Use Vertical Layout")), Some("window.change-orientation"), ); main_menu.append_section(None, &layout_section); let zoom_section = gio::Menu::new(); - zoom_section.append(Some(&tr!("command.view.zoom_in")), Some("window.zoom-in")); - zoom_section.append(Some(&tr!("command.view.zoom_out")), Some("window.zoom-out")); + zoom_section.append(Some(&tr!("Zoom In")), Some("window.zoom-in")); + zoom_section.append(Some(&tr!("Zoom Out")), Some("window.zoom-out")); main_menu.append_section(None, &zoom_section); let help_section = gio::Menu::new(); - help_section.append( - Some(&tr!("command.application.about")), - Some("window.about"), - ); + help_section.append(Some(&tr!("About")), Some("window.about")); main_menu.append_section(None, &help_section); let prefs_section = gio::Menu::new(); - prefs_section.append( - Some(&tr!("command.application.preferences")), - Some("window.preferences"), - ); + prefs_section.append(Some(&tr!("Preferences…")), Some("window.preferences")); main_menu.append_section(None, &prefs_section); (templates_menu, main_menu) diff --git a/src/components/preference_pages/editor.rs b/src/components/preference_pages/editor.rs index 0c6bda6..b064077 100644 --- a/src/components/preference_pages/editor.rs +++ b/src/components/preference_pages/editor.rs @@ -70,7 +70,7 @@ impl SimpleComponent for Editor { set_spacing: 10, gtk::Label { - set_label: &tr!("preferences.editor.font_size.title"), + set_label: &tr!("Font Size"), add_css_class: "heading", set_halign: gtk::Align::Start, }, @@ -90,7 +90,7 @@ impl SimpleComponent for Editor { format!( "{} ({})", value as i32, - tr!("preferences.editor.default_font_size") + tr!("Default") ) } else { format!("{}", value as i32) @@ -104,7 +104,7 @@ impl SimpleComponent for Editor { }, gtk::Label { - set_label: &tr!("preferences.editor.editor_style.title"), + set_label: &tr!("Editor Style"), add_css_class: "heading", set_halign: gtk::Align::Start, set_margin_top: 10, @@ -118,7 +118,7 @@ impl SimpleComponent for Editor { set_spacing: 10, gtk::Label { - set_label: &tr!("preferences.editor.font"), + set_label: &tr!("Font"), }, gtk::FontDialogButton::new(Some(gtk::FontDialog::new())) { @@ -149,7 +149,7 @@ impl SimpleComponent for Editor { ) -> ComponentParts<Self> { let soft_wrap_switch = switch::Switch::builder() .launch(switch::SwitchInit { - label: tr!("preferences.editor.editor_style.soft_wrap_lines"), + label: tr!("Soft wrap lines"), state: init.soft_wrap, }) .forward(sender.input_sender(), move |output| match output { @@ -158,7 +158,7 @@ impl SimpleComponent for Editor { let custom_font_switch = switch::Switch::builder() .launch(switch::SwitchInit { - label: tr!("preferences.editor.editor_style.use_custom_font"), + label: tr!("Use custom font"), state: init.use_custom_font, }) .forward(sender.input_sender(), move |output| match output { diff --git a/src/components/preference_pages/general.rs b/src/components/preference_pages/general.rs index 351c4a5..532e654 100644 --- a/src/components/preference_pages/general.rs +++ b/src/components/preference_pages/general.rs @@ -37,7 +37,7 @@ impl SimpleComponent for General { set_valign: gtk::Align::Start, gtk::Label { - set_label: &tr!("preferences.general.preferences.title"), + set_label: &tr!("Preferences"), add_css_class: "heading", set_halign: gtk::Align::Start, }, @@ -45,17 +45,17 @@ impl SimpleComponent for General { set_orientation: gtk::Orientation::Horizontal, set_spacing: 10, - gtk::Button::with_label(&tr!("preferences.general.preferences.export")) { + gtk::Button::with_label(&tr!("Export")) { connect_clicked => { sender.output(PreferencesAction::Export).ok(); } }, - gtk::Button::with_label(&tr!("preferences.general.preferences.import")) { + gtk::Button::with_label(&tr!("Import")) { connect_clicked => { sender.output(PreferencesAction::Import).ok(); } }, - gtk::Button::with_label(&tr!("preferences.general.preferences.reset")) { + gtk::Button::with_label(&tr!("Reset to defaults")) { add_css_class: "destructive-action", connect_clicked => { sender.output(PreferencesAction::ResetToDefaults).ok(); @@ -64,7 +64,8 @@ impl SimpleComponent for General { }, gtk::Label { - set_label: &tr!("preferences.general.explanation"), + set_label: &tr!(r"Export your preferences to share with others or back up your settings. + Import preferences from a file to restore settings."), add_css_class: "dim-label", set_halign: gtk::Align::Start, set_wrap: true diff --git a/src/components/preference_pages/map.rs b/src/components/preference_pages/map.rs index 5ec59e1..fb5178c 100644 --- a/src/components/preference_pages/map.rs +++ b/src/components/preference_pages/map.rs @@ -68,7 +68,7 @@ impl SimpleComponent for Map { set_valign: gtk::Align::Start, gtk::Label { - set_label: &tr!("preferences.map.map_style.title"), + set_label: &tr!("Map Style"), add_css_class: "heading", set_halign: gtk::Align::Start, }, @@ -81,7 +81,7 @@ impl SimpleComponent for Map { set_spacing: 10, gtk::Label { - set_label: &tr!("preferences.map.font"), + set_label: &tr!("Font"), }, gtk::FontDialogButton::new(Some(gtk::FontDialog::new())) { @@ -101,7 +101,7 @@ impl SimpleComponent for Map { }, gtk::Label { - set_label: &tr!("preferences.map.export.title"), + set_label: &tr!("Export"), add_css_class: "heading", set_halign: gtk::Align::Start, set_margin_top: 10, @@ -112,11 +112,11 @@ impl SimpleComponent for Map { set_spacing: 10, gtk::Label { - set_label: &tr!("preferences.map.export.default_format"), + set_label: &tr!("Default export format"), }, gtk::DropDown::new(Some(gtk::StringList::new(&[ - &tr!("export_formats.png"), - &tr!("export_formats.svg"), + &tr!("PNG (Raster)"), + &tr!("SVG (Vector)"), ])), None::<gtk::Expression>) { #[watch] #[block_signal(export_handler)] @@ -143,7 +143,7 @@ impl SimpleComponent for Map { ) -> ComponentParts<Self> { let show_background_switch = switch::Switch::builder() .launch(switch::SwitchInit { - label: tr!("preferences.map.map_style.show_background"), + label: tr!("Show map background"), state: init.show_background, }) .forward(sender.input_sender(), move |output| match output { @@ -152,7 +152,7 @@ impl SimpleComponent for Map { let custom_font_switch = switch::Switch::builder() .launch(switch::SwitchInit { - label: tr!("preferences.map.map_style.use_custom_font"), + label: tr!("Use custom font"), state: init.use_custom_font, }) .forward(sender.input_sender(), move |output| match output { @@ -161,7 +161,7 @@ impl SimpleComponent for Map { let smart_label_positioning_switch = switch::Switch::builder() .launch(switch::SwitchInit { - label: tr!("preferences.map.map_style.use_smart_label_positioning"), + label: tr!("Use smart label positioning"), state: init.use_smart_label_positioning, }) .forward(sender.input_sender(), move |output| match output { diff --git a/src/components/preference_pages/stages.rs b/src/components/preference_pages/stages.rs index 12ee0e6..0534f37 100644 --- a/src/components/preference_pages/stages.rs +++ b/src/components/preference_pages/stages.rs @@ -53,12 +53,12 @@ impl SimpleComponent for Stages { set_valign: gtk::Align::Start, gtk::Label { - set_label: &tr!("preferences.stages.title"), + set_label: &tr!("Custom Stages"), add_css_class: "heading", set_halign: gtk::Align::Start, }, gtk::Label { - set_label: &tr!("preferences.stages.explanation"), + set_label: &tr!("Custom stages allow you to define your own evolution axis label."), add_css_class: "dim-label", set_halign: gtk::Align::Start, set_wrap: true, @@ -82,31 +82,31 @@ impl SimpleComponent for Stages { add_css_class: "dim-label", gtk::Label { - set_label: &tr!("preferences.stages.column.name"), + set_label: &tr!("Name"), set_xalign: 0.0, set_hexpand: true, set_width_chars: 15, }, gtk::Label { - set_label: &tr!("preferences.stages.column.stage_i"), + set_label: &tr!("Stage I"), set_xalign: 0.0, set_hexpand: true, set_width_chars: 12, }, gtk::Label { - set_label: &tr!("preferences.stages.column.stage_ii"), + set_label: &tr!("Stage II"), set_xalign: 0.0, set_hexpand: true, set_width_chars: 12, }, gtk::Label { - set_label: &tr!("preferences.stages.column.stage_iii"), + set_label: &tr!("Stage III"), set_xalign: 0.0, set_hexpand: true, set_width_chars: 12, }, gtk::Label { - set_label: &tr!("preferences.stages.column.stage_iv"), + set_label: &tr!("Stage IV"), set_xalign: 0.0, set_hexpand: true, set_width_chars: 12, @@ -129,7 +129,7 @@ impl SimpleComponent for Stages { set_spacing: 10, set_halign: gtk::Align::End, gtk::Button::from_icon_name("list-add-symbolic") { - set_tooltip_text: Some(&tr!("preferences.stages.help.add")), + set_tooltip_text: Some(&tr!("Add custom stage")), connect_clicked => StagesAction::AddCustomStage, } }, diff --git a/src/components/preference_pages/templates.rs b/src/components/preference_pages/templates.rs index 4682ab9..4e95dab 100644 --- a/src/components/preference_pages/templates.rs +++ b/src/components/preference_pages/templates.rs @@ -83,14 +83,14 @@ impl SimpleComponent for Templates { #[wrap(Some)] set_sidebar = &adw::NavigationPage { - set_title: &tr!("preferences.templates.title"), + set_title: &tr!("Templates"), gtk::Box { set_orientation: gtk::Orientation::Vertical, set_margin_all: 20, set_spacing: 10, gtk::Label { - set_label: &tr!("preferences.templates.title"), + set_label: &tr!("Templates"), add_css_class: "heading", set_halign: gtk::Align::Start, set_margin_start: 5, @@ -113,7 +113,7 @@ impl SimpleComponent for Templates { set_halign: gtk::Align::End, gtk::Button::from_icon_name("list-remove-symbolic") { - set_tooltip_text: Some(&tr!("preferences.templates.help.remove")), + set_tooltip_text: Some(&tr!("Remove template")), connect_clicked[sender] => move |_| { sender.input(TemplatesAction::RemoveTemplate); @@ -121,11 +121,11 @@ impl SimpleComponent for Templates { }, gtk::Button::from_icon_name("list-add-symbolic") { - set_tooltip_text: Some(&tr!("preferences.templates.help.add")), + set_tooltip_text: Some(&tr!("Add template")), connect_clicked[sender] => move |_| { sender.output(PreferencesAction::AddTemplate(tr!( - "dialog.template.default_label" + "My Template" ))).ok(); }, }, @@ -184,7 +184,7 @@ impl SimpleComponent for Templates { } } else { gtk::Label { - set_label: &tr!("preferences.templates.empty"), + set_label: &tr!("There are no templates. Click on the + button to create one."), add_css_class: "dim-label", set_hexpand: true, set_vexpand: true, diff --git a/src/components/preferences_window.rs b/src/components/preferences_window.rs index 29e42fe..0df49e9 100644 --- a/src/components/preferences_window.rs +++ b/src/components/preferences_window.rs @@ -46,7 +46,7 @@ impl SimpleComponent for PreferencesWindow { view! { adw::Window { - set_title: Some(&tr!("preferences.title")), + set_title: Some(&tr!("Preferences")), set_default_width: 700, set_default_height: 500, set_modal: true, @@ -70,11 +70,11 @@ impl SimpleComponent for PreferencesWindow { adw::ViewStack { set_vexpand: true, - add_titled_with_icon[Some("general"), &tr!("preferences.menu.general"), SETTINGS] = model.general_page.widget(), - add_titled_with_icon[Some("editor"), &tr!("preferences.menu.editor"), BUILD] = model.editor_page.widget(), - add_titled_with_icon[Some("map"), &tr!("preferences.menu.map"), MAP] = model.map_page.widget(), - add_titled_with_icon[Some("stages"), &tr!("preferences.menu.stages"), AGENDA] = model.stages_page.widget(), - add_titled_with_icon[Some("templates"), &tr!("preferences.menu.templates"), PAPYRUS] = model.templates_page.widget(), + add_titled_with_icon[Some("general"), &tr!("General"), SETTINGS] = model.general_page.widget(), + add_titled_with_icon[Some("editor"), &tr!("Editor"), BUILD] = model.editor_page.widget(), + add_titled_with_icon[Some("map"), &tr!("Map"), MAP] = model.map_page.widget(), + add_titled_with_icon[Some("stages"), &tr!("Stages"), AGENDA] = model.stages_page.widget(), + add_titled_with_icon[Some("templates"), &tr!("Templates"), PAPYRUS] = model.templates_page.widget(), }, #[name = "switcher_bar"] @@ -433,13 +433,13 @@ impl PreferencesWindow { fn show_export_dialog(sender: &ComponentSender<Self>, window: &adw::Window) { let filter = FileFilter::new(); filter.add_pattern("*.json"); - filter.set_name(Some(&tr!("dialog.file_type.json"))); + filter.set_name(Some(&tr!("JSON File"))); let filters = gtk::gio::ListStore::new::<gtk::FileFilter>(); filters.append(&filter); let dialog = gtk::FileDialog::builder() - .title(tr!("dialog.export_preferences.title")) + .title(tr!("Export Preferences")) .modal(true) .filters(&filters) .initial_name("preferences.json") @@ -459,13 +459,13 @@ impl PreferencesWindow { fn show_import_dialog(sender: &ComponentSender<Self>, window: &adw::Window) { let filter = FileFilter::new(); filter.add_pattern("*.json"); - filter.set_name(Some(&tr!("dialog.file_type.json"))); + filter.set_name(Some(&tr!("JSON File"))); let filters = gtk::gio::ListStore::new::<gtk::FileFilter>(); filters.append(&filter); let dialog = gtk::FileDialog::builder() - .title(tr!("dialog.import_preferences.title")) + .title(tr!("Import Preferences")) .modal(true) .filters(&filters) .build(); diff --git a/src/components/stage_form.rs b/src/components/stage_form.rs index cb4c40f..44e3c88 100644 --- a/src/components/stage_form.rs +++ b/src/components/stage_form.rs @@ -108,7 +108,7 @@ impl FactoryComponent for StageForm { gtk::Button::from_icon_name("list-remove-symbolic") { add_css_class: "flat", - set_tooltip_text: Some(&tr!("preferences.stages.help.remove")), + set_tooltip_text: Some(&tr!("Remove stage")), connect_clicked[sender] => move |_| { sender.input(StageFormAction::Remove); } diff --git a/src/components/template_row.rs b/src/components/template_row.rs index 959c392..68696f6 100644 --- a/src/components/template_row.rs +++ b/src/components/template_row.rs @@ -64,7 +64,7 @@ impl FactoryComponent for TemplateRow { #[watch] set_icon_name: if self.template.is_default { "radio-checked-symbolic" } else { "radio-symbolic" }, #[watch] - set_tooltip_text: Some(&if self.template.is_default { tr!("preferences.templates.help.default") } else { tr!("preferences.templates.help.set_as_default") }), + set_tooltip_text: Some(&if self.template.is_default { tr!("This is the default template.") } else { tr!("Set as default template.") }), connect_clicked[sender, index] => move |_| { sender.output(TemplateRowOutput::SetDefault(index.clone())).ok(); } @@ -84,7 +84,7 @@ impl FactoryComponent for TemplateRow { }, gtk::Button::from_icon_name(RIGHT) { - set_tooltip_text: Some(&tr!("preferences.templates.help.activate")), + set_tooltip_text: Some(&tr!("Edit Template")), #[watch] set_visible: self.is_arrow_shown, diff --git a/src/dialogs.rs b/src/dialogs.rs index 22b12df..45956ab 100644 --- a/src/dialogs.rs +++ b/src/dialogs.rs @@ -33,7 +33,7 @@ pub fn create_file_filter() -> gtk::FileFilter { let filter = gtk::FileFilter::new(); filter.add_pattern(&format!("*.{}", constants::FILE_EXTENSION)); filter.add_mime_type(constants::MIME_TYPE); - filter.set_name(Some(&tr!("dialog.file_type.wmap"))); + filter.set_name(Some(&tr!("Wardley Map Files"))); filter } @@ -41,7 +41,7 @@ pub fn create_file_filter() -> gtk::FileFilter { pub fn show_error(window: &adw::Window, title: &str, message: &str) { let dialog = gtk::AlertDialog::builder() .modal(true) - .buttons([&tr!("dialog.action.cancel"), "Ok"]) + .buttons([&tr!("Cancel"), "Ok"]) .message(title) .detail(message) .build(); @@ -55,7 +55,7 @@ pub fn show_open_dialog( sender: ComponentSender<AppModel>, ) { let dialog = gtk::FileDialog::builder() - .title(tr!("dialog.open.title")) + .title(tr!("Open Map")) .modal(true) .build(); @@ -92,7 +92,7 @@ pub fn show_save_dialog( sender: ComponentSender<AppModel>, ) { let mut dialog_builder = gtk::FileDialog::builder() - .title(tr!("dialog.save.title")) + .title(tr!("Save Map As")) .modal(true); let filter = create_file_filter(); @@ -133,13 +133,9 @@ pub fn show_unsaved_changes_dialog( ) { let dialog = gtk::AlertDialog::builder() .modal(true) - .message(tr!("dialog.unsaved_changes.title")) - .detail(tr!("dialog.unsaved_changes.message")) - .buttons([ - tr!("dialog.action.dont_save"), - tr!("dialog.action.cancel"), - tr!("dialog.action.save"), - ]) + .message(tr!("Unsaved Changes")) + .detail(tr!("Save changes before closing?")) + .buttons([tr!("Don't save"), tr!("Cancel"), tr!("Save")]) .cancel_button(1) .default_button(2) .build(); @@ -175,8 +171,8 @@ fn create_image_filter(format: ImageFormat) -> gtk::FileFilter { filter.add_pattern(&format!("*.{}", format.extension())); filter.add_mime_type(format.mime_type()); let name = match format { - ImageFormat::Png => tr!("dialog.file_type.png"), - ImageFormat::Svg => tr!("dialog.file_type.svg"), + ImageFormat::Png => tr!("PNG Image"), + ImageFormat::Svg => tr!("SVG Image"), }; filter.set_name(Some(&name)); filter @@ -196,7 +192,7 @@ pub fn show_export_dialog( filters.append(&svg_filter); let mut dialog_builder = gtk::FileDialog::builder() - .title(tr!("dialog.export.title")) + .title(tr!("Export Map as Image")) .modal(true) .filters(&filters) .default_filter(&png_filter); diff --git a/src/handlers/export.rs b/src/handlers/export.rs index bf9dfc5..6fb1713 100644 --- a/src/handlers/export.rs +++ b/src/handlers/export.rs @@ -42,6 +42,10 @@ pub fn export_to_file(model: &AppModel, path: &PathBuf, format: ImageFormat) { }; if let Err(error) = result { - dialogs::show_error(&model.window, &tr!("error.file.export"), &error); + dialogs::show_error( + &model.window, + &tr!("Could not export image. Please make sure the destination is writable."), + &error, + ); } } diff --git a/src/handlers/file.rs b/src/handlers/file.rs index bd501e8..f816e62 100644 --- a/src/handlers/file.rs +++ b/src/handlers/file.rs @@ -36,7 +36,11 @@ pub fn load_file(model: &mut AppModel, path: PathBuf) { model.modified = false; } Err(error) => { - dialogs::show_error(&model.window, &tr!("errors.file.open"), &error.to_string()); + dialogs::show_error( + &model.window, + &tr!("Could not open file. Please make sure the file is readable."), + &error.to_string(), + ); } } } @@ -59,7 +63,11 @@ pub fn save_to_file(model: &mut AppModel, path: PathBuf, close_after: bool) { } } Err(error) => { - dialogs::show_error(&model.window, &tr!("errors.file.save"), &error.to_string()); + dialogs::show_error( + &model.window, + &tr!("Could not save file. Please make sure the destination is writable."), + &error.to_string(), + ); } } } diff --git a/src/main.rs b/src/main.rs index e40681f..1d45a42 100644 --- a/src/main.rs +++ b/src/main.rs @@ -168,7 +168,7 @@ impl AppModel { } fn window_title(&self) -> String { - let default_name = tr!("document.untitled"); + let default_name = tr!("Untitled"); let filename = self .current_file .as_ref() @@ -177,9 +177,9 @@ impl AppModel { .unwrap_or(&default_name); if self.modified { - format!("{}* - {}", filename, tr!("application.name")) + format!("{}* - {}", filename, tr!("Map")) } else { - format!("{} - {}", filename, tr!("application.name")) + format!("{} - {}", filename, tr!("Map")) } } @@ -602,7 +602,7 @@ impl SimpleComponent for AppModel { .map(String::from) .collect::<Vec<_>>(), ) - .comments(tr!("about.comment")) + .comments(about_comment()) .copyright("© 2026 Rubén Beltrán del Río") .license_type(gtk::License::Agpl30) .application_icon("systems.tranquil.Map") @@ -648,3 +648,67 @@ fn main() { initial_content, }); } + +fn about_comment() -> String { + tr!( + r#"Map is a <a href="https://medium.com/wardleymaps">wardley map</a> editor for linux that uses a simple language to easily create and edit maps. Draw components, link dependencies, create groups, write notes, or add inertia and evolution markers, and see your map change in an instant. + +<big><b>Language Reference</b></big> + +The wmap language is a simple notation to create and edit wardley maps and is easy to pick up: + +<b>Components</b> + +Components are written as <tt>Name (x,y)</tt>. The name can contain spaces, and the x and y coordinates are a whole or decimal number from 0 to 100 and represent how far from the top left corner the component will be drawn. + +By default, components will be drawn as a circle, but you can specify the shape by appending <tt>[Square]</tt>, <tt>[Triangle]</tt>, or <tt>[x]</tt>. Here's some examples: + +<tt>Component (1,2)</tt> +<tt>My Cool Component (10.0,21.0)</tt> +<tt>A (1, 2.0) [Square]</tt> +<tt>Rose Wall (44.3, 50.0) [x]</tt> + +<b>Dependencies</b> + +Dependencies connect two components, and they are written as <tt>Component A -- Component B</tt>. This will draw a simple line between them. If you want an arrow, you can use <tt>Component -> Component</tt> instead. + +<tt>Component -- My Cool Component</tt> +<tt>A -> Component</tt> + +<b>Inertia</b> + +You can place an inertia marker in front of a component by writing <tt>[Inertia] Component</tt>. + +<tt>[Inertia] My Cool Component</tt> +<tt>[Inertia] A</tt> + +<b>Evolution</b> + +Evolution arrows are notated by using <tt>[Evolution] Component +x</tt> or <tt>[Evolution] Component -x</tt>, where x is a whole or decimal number between 0 and 100. + +<tt>[Evolution] My Cool Component -10</tt> +<tt>[Evolution] A +15</tt> + +<b>Notes</b> + +Sometimes it's helpful to add some text clarifying the map. Writing <tt>[Note] (x, y) Text</tt> will create a note block right at those coordinates. Just like components, x and y are numbers between 0 and 100. You can write \n to force a line break. + +<tt>[Note] (30, 45) Here we want to call out an explanation or context.</tt> +<tt>[Note] (90, 25) We're close to the edge \n so we can multiline it.</tt> + +<b>Groups</b> + +You can group components together by using <tt>[Group] ComponentA, ComponentB...</tt> + +<tt>[Group] Tinker, Tailor, Soldier</tt> +<tt>[Group] Two Words, Three Words Here</tt> + +<b>Resizing Evolution Stages</b> + +If you need more space for one of the four stages, you can use <b>[I] x</b>, <b>[II] x</b>, or <b>[III] x</b>. As with other lines, x is a number between 0-100. + +<tt>[I] 15</tt> +<tt>[II] 35.5</tt> +<tt>[III] 80</tt>"# + ) +} diff --git a/src/preferences/models.rs b/src/preferences/models.rs index 93f3fa0..97fa85a 100644 --- a/src/preferences/models.rs +++ b/src/preferences/models.rs @@ -50,12 +50,12 @@ impl CustomStage { pub fn cynefin_default() -> Self { Self { id: Uuid::new_v4(), - name: tr!("stages.cynefin.name"), + name: tr!("Cynefin"), stage: Stage { - i: tr!("stages.cynefin.i"), - ii: tr!("stages.cynefin.ii"), - iii: tr!("stages.cynefin.iii"), - iv: tr!("stages.cynefin.iv"), + i: tr!("Chaotic"), + ii: tr!("Complex"), + iii: tr!("Complicated"), + iv: tr!("Clear"), }, } } @@ -63,12 +63,12 @@ impl CustomStage { pub fn placeholder_default() -> Self { Self { id: Uuid::new_v4(), - name: tr!("stages.new.name"), + name: tr!("New Stage"), stage: Stage { - i: tr!("stages.evolution_stage.i"), - ii: tr!("stages.evolution_stage.ii"), - iii: tr!("stages.evolution_stage.iii"), - iv: tr!("stages.evolution_stage.iv"), + i: tr!("Stage I"), + ii: tr!("Stage II"), + iii: tr!("Stage III"), + iv: tr!("Stage IV"), }, } } @@ -177,11 +177,64 @@ impl Default for UserPreferences { map_templates: vec![ Template::new( - tr!("templates.defaults.example.title"), - tr!("templates.defaults.example.source"), + tr!("Example Map"), + tr!(r"Client (39, 0) [x] +Consumer (55, 10) [x] + +Client -- Consumer + +Find out about (65, 15) +Test printer (42, 20) + +Consumer -- Test printer +Consumer -- Find out about + +Microsite (60, 30) + +Find out about -- Microsite + +[Group] Consumer, Test printer, Find out about, Microsite +[Note] (63, 10) Team, Settlers + +Testing Application (34, 35) +Microsite -- Testing Application +Test Printer -- Testing Application + +FinDev (30, 50) +Testing Application -- FinDev +Microsite -- Findev +[Group] Testing Application, FinDev +[Note] (24, 41.5) Team, Pioneers +[Evolution] Testing Application +15 +[Evolution] FinDev +30 + +Platform [now] (50, 60) [triangle] +Platform [then] (71, 60) +Platform [now] -> Platform [then] +[Inertia] Platform [now] +FinDev -- Platform [then] +[Group] Platform +[Note] (74, 60) Team, Town Planners + +Distribution (65, 70) +Brochure (60, 75) +Distribution -- Brochure +[Evolution] Distribution +20 +Testing Application -- Distribution +Distribution -- Brochure +[Group] Distribution, Brochure +[Note] (65, 75) Team, Town Planners + +Large Format Printer (45, 75) +Testing Application -- Large Format Printer +[Group] Large Format Printer +[Note] (42, 78.5) Team, Settlers +[i] 20 +[ii] 40 +[iii] 70"), true, ), - Template::new(tr!("templates.defaults.empty.title"), String::new(), false), + Template::new(tr!("Empty"), String::new(), false), ], custom_stages: vec![CustomStage::cynefin_default()], diff --git a/src/stages.rs b/src/stages.rs index 3ab1f5a..1231e55 100644 --- a/src/stages.rs +++ b/src/stages.rs @@ -55,28 +55,28 @@ pub trait LocalizedStageType { impl LocalizedStageType for StageType { fn localized_name(&self) -> String { match self { - StageType::Activities => tr!("stage.activities.name"), - StageType::Practice => tr!("stage.practice.name"), - StageType::Data => tr!("stage.data.name"), - StageType::Knowledge => tr!("stages.knowledge.name"), - StageType::Ubiquity => tr!("stages.ubiquity.name"), - StageType::Certainty => tr!("stages.certainty.name"), - StageType::PublicationTypes => tr!("stages.publication_types.name"), - StageType::Market => tr!("stages.market.name"), - StageType::KnowledgeManagement => tr!("stages.knowledge_management.name"), - StageType::MarketPerception => tr!("stages.market_perception.name"), - StageType::UserPerception => tr!("stages.user_perception.name"), - StageType::PerceptionInIndustry => tr!("stages.perception_in_industry.name"), - StageType::FocusOfValue => tr!("stages.focus_of_value.name"), - StageType::Understanding => tr!("stages.understanding.name"), - StageType::Comparison => tr!("stages.comparison.name"), - StageType::Failure => tr!("stages.failure.name"), - StageType::MarketAction => tr!("stages.market_action.name"), - StageType::Efficiency => tr!("stages.efficiency.name"), - StageType::DecisionDrivers => tr!("stages.decision_drivers.name"), - StageType::Behavior => tr!("stages.behavior.name"), - StageType::Cynefin => tr!("stages.cynefin.name"), - StageType::EvolutionStage => tr!("stages.evolution_stage.name"), + StageType::Activities => tr!("Activities"), + StageType::Practice => tr!("Practice"), + StageType::Data => tr!("Data"), + StageType::Knowledge => tr!("Knowledge"), + StageType::Ubiquity => tr!("Ubiquity"), + StageType::Certainty => tr!("Certainty"), + StageType::PublicationTypes => tr!("Publication Types"), + StageType::Market => tr!("Market"), + StageType::KnowledgeManagement => tr!("Knowledge Management"), + StageType::MarketPerception => tr!("Market Perception"), + StageType::UserPerception => tr!("User Perception"), + StageType::PerceptionInIndustry => tr!("Perception in Industry"), + StageType::FocusOfValue => tr!("Focus of Value"), + StageType::Understanding => tr!("Understanding"), + StageType::Comparison => tr!("Comparison"), + StageType::Failure => tr!("Failure"), + StageType::MarketAction => tr!("Market Action"), + StageType::Efficiency => tr!("Efficiency"), + StageType::DecisionDrivers => tr!("Decision Drivers"), + StageType::Behavior => tr!("Behavior"), + StageType::Cynefin => tr!("Cynefin"), + StageType::EvolutionStage => tr!("Evolution Stage"), StageType::Custom { name, i: _, @@ -88,28 +88,28 @@ impl LocalizedStageType for StageType { } fn localized_i(&self) -> String { match self { - StageType::Activities => tr!("stage.activities.i"), - StageType::Practice => tr!("stage.practice.i"), - StageType::Data => tr!("stage.data.i"), - StageType::Knowledge => tr!("stages.knowledge.i"), - StageType::Ubiquity => tr!("stages.ubiquity.i"), - StageType::Certainty => tr!("stages.certainty.i"), - StageType::PublicationTypes => tr!("stages.publication_types.i"), - StageType::Market => tr!("stages.market.i"), - StageType::KnowledgeManagement => tr!("stages.knowledge_management.i"), - StageType::MarketPerception => tr!("stages.market_perception.i"), - StageType::UserPerception => tr!("stages.user_perception.i"), - StageType::PerceptionInIndustry => tr!("stages.perception_in_industry.i"), - StageType::FocusOfValue => tr!("stages.focus_of_value.i"), - StageType::Understanding => tr!("stages.understanding.i"), - StageType::Comparison => tr!("stages.comparison.i"), - StageType::Failure => tr!("stages.failure.i"), - StageType::MarketAction => tr!("stages.market_action.i"), - StageType::Efficiency => tr!("stages.efficiency.i"), - StageType::DecisionDrivers => tr!("stages.decision_drivers.i"), - StageType::Behavior => tr!("stages.behavior.i"), - StageType::Cynefin => tr!("stages.cynefin.i"), - StageType::EvolutionStage => tr!("stages.evolution_stage.i"), + StageType::Activities => tr!("Genesis"), + StageType::Practice => tr!("Novel"), + StageType::Data => tr!("Unmodelled"), + StageType::Knowledge => tr!("Concept"), + StageType::Ubiquity => tr!("Rare"), + StageType::Certainty => tr!("Poorly Understood / exploring the unknown"), + StageType::PublicationTypes => tr!("Describe the wonder of the thing / the discovery of some marvel / a new land / an unknown frontier"), + StageType::Market => tr!("Undefined Market"), + StageType::KnowledgeManagement => tr!("Uncertain"), + StageType::MarketPerception => tr!(r#"Chaotic (non-linear) / domain of the "crazy""#), + StageType::UserPerception => tr!("Different / confusing / exciting / surprising / dangerous"), + StageType::PerceptionInIndustry => tr!("Future source of competitive advantage / unpredictable / unknown"), + StageType::FocusOfValue => tr!("High future worth but immediate investment"), + StageType::Understanding => tr!("Poorly Understood / unpredictable"), + StageType::Comparison => tr!("Constantly changing / a differential / unstable"), + StageType::Failure => tr!("High / tolerated / assumed to be wrong"), + StageType::MarketAction => tr!("Gambling / driven by gut"), + StageType::Efficiency => tr!("Reducing the cost of change (experimentation)"), + StageType::DecisionDrivers => tr!("Heritage / culture"), + StageType::Behavior => tr!("Uncertain when to use"), + StageType::Cynefin => tr!("Chaotic"), + StageType::EvolutionStage => tr!("Stage I"), StageType::Custom { name: _, i, @@ -121,28 +121,28 @@ impl LocalizedStageType for StageType { } fn localized_ii(&self) -> String { match self { - StageType::Activities => tr!("stage.activities.ii"), - StageType::Practice => tr!("stage.practice.ii"), - StageType::Data => tr!("stage.data.ii"), - StageType::Knowledge => tr!("stages.knowledge.ii"), - StageType::Ubiquity => tr!("stages.ubiquity.ii"), - StageType::Certainty => tr!("stages.certainty.ii"), - StageType::PublicationTypes => tr!("stages.publication_types.ii"), - StageType::Market => tr!("stages.market.ii"), - StageType::KnowledgeManagement => tr!("stages.knowledge_management.ii"), - StageType::MarketPerception => tr!("stages.market_perception.ii"), - StageType::UserPerception => tr!("stages.user_perception.ii"), - StageType::PerceptionInIndustry => tr!("stages.perception_in_industry.ii"), - StageType::FocusOfValue => tr!("stages.focus_of_value.ii"), - StageType::Understanding => tr!("stages.understanding.ii"), - StageType::Comparison => tr!("stages.comparison.ii"), - StageType::Failure => tr!("stages.failure.ii"), - StageType::MarketAction => tr!("stages.market_action.ii"), - StageType::Efficiency => tr!("stages.efficiency.ii"), - StageType::DecisionDrivers => tr!("stages.decision_drivers.ii"), - StageType::Behavior => tr!("stages.behavior.ii"), - StageType::Cynefin => tr!("stages.cynefin.ii"), - StageType::EvolutionStage => tr!("stages.evolution_stage.ii"), + StageType::Activities => tr!("Custom"), + StageType::Practice => tr!("Emerging"), + StageType::Data => tr!("Divergent"), + StageType::Knowledge => tr!("Hypothesis"), + StageType::Ubiquity => tr!("Slowly Increasing"), + StageType::Certainty => tr!("Rapid Increase In Learning / discovery becomes refining"), + StageType::PublicationTypes => tr!("Focused on build / construct / awareness and learning / many models of explanation / no accepted forms / a wild west"), + StageType::Market => tr!("Forming Market / an array of competing forms and models of understanding"), + StageType::KnowledgeManagement => tr!("Learning on use / focused on testing prediction"), + StageType::MarketPerception => tr!(r#"Domain of "experts""#), + StageType::UserPerception => tr!("Leading edge / emerging / uncertainty over results"), + StageType::PerceptionInIndustry => tr!("Seen as a scompetitive advantage / a differential / ROI / case examples"), + StageType::FocusOfValue => tr!("Seeking ways to profit and a ROI / seeking confirmation of value"), + StageType::Understanding => tr!("Increasing understanding / development of measures"), + StageType::Comparison => tr!("Learning from others / testing the water / some evidential support"), + StageType::Failure => tr!("Moderate / unsurprising if wrong but disappointed"), + StageType::MarketAction => tr!(r#"Exploring a "found" value"#), + StageType::Efficiency => tr!("Reducing cost of waste (Learning)"), + StageType::DecisionDrivers => tr!("Analyses & synthesis"), + StageType::Behavior => tr!("Learning when to use"), + StageType::Cynefin => tr!("Complex"), + StageType::EvolutionStage => tr!("Stage II"), StageType::Custom { name: _, i: _, @@ -154,28 +154,28 @@ impl LocalizedStageType for StageType { } fn localized_iii(&self) -> String { match self { - StageType::Activities => tr!("stage.activities.iii"), - StageType::Practice => tr!("stage.practice.iii"), - StageType::Data => tr!("stage.data.iii"), - StageType::Knowledge => tr!("stages.knowledge.iii"), - StageType::Ubiquity => tr!("stages.ubiquity.iii"), - StageType::Certainty => tr!("stages.certainty.iii"), - StageType::PublicationTypes => tr!("stages.publication_types.iii"), - StageType::Market => tr!("stages.market.iii"), - StageType::KnowledgeManagement => tr!("stages.knowledge_management.iii"), - StageType::MarketPerception => tr!("stages.market_perception.iii"), - StageType::UserPerception => tr!("stages.user_perception.iii"), - StageType::PerceptionInIndustry => tr!("stages.perception_in_industry.iii"), - StageType::FocusOfValue => tr!("stages.focus_of_value.iii"), - StageType::Understanding => tr!("stages.understanding.iii"), - StageType::Comparison => tr!("stages.comparison.iii"), - StageType::Failure => tr!("stages.failure.iii"), - StageType::MarketAction => tr!("stages.market_action.iii"), - StageType::Efficiency => tr!("stages.efficiency.iii"), - StageType::DecisionDrivers => tr!("stages.decision_drivers.iii"), - StageType::Behavior => tr!("stages.behavior.iii"), - StageType::Cynefin => tr!("stages.cynefin.iii"), - StageType::EvolutionStage => tr!("stages.evolution_stage.iii"), + StageType::Activities => tr!("Product (+rental)"), + StageType::Practice => tr!("Good"), + StageType::Data => tr!("Convergent"), + StageType::Knowledge => tr!("Theory"), + StageType::Ubiquity => tr!("Rapidly Increasing"), + StageType::Certainty => tr!("Rapid increase in use / increasing fit for purpose"), + StageType::PublicationTypes => tr!("Maintenance / operations / installation / comparison between competing forms / feature analysis"), + StageType::Market => tr!("Growing Market / consolidation to a few competing but more accepted forms"), + StageType::KnowledgeManagement => tr!("Learning on operation / using prediction / verification"), + StageType::MarketPerception => tr!(r#"Increasing expectation of use / domain of "professionals""#), + StageType::UserPerception => tr!("Increasingly common / disappointed if not used or available / feeling left behind"), + StageType::PerceptionInIndustry => tr!("Advantage through implementation / features / this model is better than that"), + StageType::FocusOfValue => tr!("High profitability per unit / a valuable model / a feeling of understanding / focus on exploitation"), + StageType::Understanding => tr!("Increasing education / constant refinement of needs / measures"), + StageType::Comparison => tr!("Competing models / feature difference / evidential support"), + StageType::Failure => tr!("Not tolerated / focus on constant improvement / assumed to be in the right direction / resistance to changing the model"), + StageType::MarketAction => tr!("Market analysis / listening to customers"), + StageType::Efficiency => tr!("Reducing cost of waste (Learning)"), + StageType::DecisionDrivers => tr!("Analyses & synthesis"), + StageType::Behavior => tr!("Learning through use"), + StageType::Cynefin => tr!("Complicated"), + StageType::EvolutionStage => tr!("Stage III"), StageType::Custom { name: _, i: _, @@ -187,28 +187,28 @@ impl LocalizedStageType for StageType { } fn localized_iv(&self) -> String { match self { - StageType::Activities => tr!("stage.activities.iv"), - StageType::Practice => tr!("stage.practice.iv"), - StageType::Data => tr!("stage.data.iv"), - StageType::Knowledge => tr!("stages.knowledge.iv"), - StageType::Ubiquity => tr!("stages.ubiquity.iv"), - StageType::Certainty => tr!("stages.certainty.iv"), - StageType::PublicationTypes => tr!("stages.publication_types.iv"), - StageType::Market => tr!("stages.market.iv"), - StageType::KnowledgeManagement => tr!("stages.knowledge_management.iv"), - StageType::MarketPerception => tr!("stages.market_perception.iv"), - StageType::UserPerception => tr!("stages.user_perception.iv"), - StageType::PerceptionInIndustry => tr!("stages.perception_in_industry.iv"), - StageType::FocusOfValue => tr!("stages.focus_of_value.iv"), - StageType::Understanding => tr!("stages.understanding.iv"), - StageType::Comparison => tr!("stages.comparison.iv"), - StageType::Failure => tr!("stages.failure.iv"), - StageType::MarketAction => tr!("stages.market_action.iv"), - StageType::Efficiency => tr!("stages.efficiency.iv"), - StageType::DecisionDrivers => tr!("stages.decision_drivers.iv"), - StageType::Behavior => tr!("stages.behavior.iv"), - StageType::Cynefin => tr!("stages.cynefin.iv"), - StageType::EvolutionStage => tr!("stages.evolution_stage.iv"), + StageType::Activities => tr!("Commodity (+utility)"), + StageType::Practice => tr!("Best"), + StageType::Data => tr!("Modelled"), + StageType::Knowledge => tr!("Accepted"), + StageType::Ubiquity => tr!("Widespread in the applicable market / ecosystem"), + StageType::Certainty => tr!("Commonly understood (in terms of use)"), + StageType::PublicationTypes => tr!("Focused on use / increasingly an accepted, almost invisible component"), + StageType::Market => tr!("Mature Market / stabilised to an accepted form"), + StageType::KnowledgeManagement => tr!("Known / accepted"), + StageType::MarketPerception => tr!("Ordered (appearance of being linear) / trivial / formula to be applied"), + StageType::UserPerception => tr!("Standard / expected / feeling of shock if not used"), + StageType::PerceptionInIndustry => tr!("Cost of doing business / accepted / specific defined models"), + StageType::FocusOfValue => tr!("High volume / reducing margin / important but invisible / an essential component of something more complex"), + StageType::Understanding => tr!("Believed to be well defined / stable / measurable"), + StageType::Comparison => tr!("Essential / any advantage is operational / accepted norm"), + StageType::Failure => tr!("Surprised by failure / focus on operational efficiency"), + StageType::MarketAction => tr!("Metric driven / build what is needed"), + StageType::Efficiency => tr!("Reducing cost of deviation (Volume)"), + StageType::DecisionDrivers => tr!("Previous Experience"), + StageType::Behavior => tr!("Known / common usage"), + StageType::Cynefin => tr!("Clear"), + StageType::EvolutionStage => tr!("Stage IV"), StageType::Custom { name: _, i: _, |