aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuben Beltran del Rio <jj@r.bdr.sh>2026-03-23 20:52:55 +0100
committerRubén Beltrán del Río <jj@r.bdr.sh>2026-04-05 00:31:21 +0200
commit1d28fb5599337bf1891ac8cc43b7656975d239d7 (patch)
treee75bcfaed71d668c87afa65ca524d1a0338a0ce1 /src
parentef32d65ac1852da581ac75d20f903dbcb2d0b5cd (diff)
Use english as the base language
Diffstat (limited to 'src')
-rw-r--r--src/components/footer.rs4
-rw-r--r--src/components/header.rs42
-rw-r--r--src/components/preference_pages/editor.rs12
-rw-r--r--src/components/preference_pages/general.rs11
-rw-r--r--src/components/preference_pages/map.rs18
-rw-r--r--src/components/preference_pages/stages.rs16
-rw-r--r--src/components/preference_pages/templates.rs12
-rw-r--r--src/components/preferences_window.rs20
-rw-r--r--src/components/stage_form.rs2
-rw-r--r--src/components/template_row.rs4
-rw-r--r--src/dialogs.rs24
-rw-r--r--src/handlers/export.rs6
-rw-r--r--src/handlers/file.rs12
-rw-r--r--src/main.rs72
-rw-r--r--src/preferences/models.rs79
-rw-r--r--src/stages.rs220
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 = &gtk::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 -&gt; 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: _,