diff --git a/locales/en-US/main.ftl b/locales/en-US/main.ftl index 6ade4f7..78ad085 100644 --- a/locales/en-US/main.ftl +++ b/locales/en-US/main.ftl @@ -1 +1,23 @@ -reference = simple text with a reference: { -something } +menu-file = File +menu-debug = Debug + +action-open-dsn = Open +action-export-ses = Export session file +action-import-cmd = Import history +action-export-cmd = Export history + +action-quit = Quit +action-autoroute = Autoroute +action-place-via = Place Via +action-remove-bands = Remove Bands +action-compare-detours = Compare Detours + +action-undo = Undo +action-redo = Redo + +show-ratsnest = Show Ratsnest +show-navmesh = Show Navmesh +show-bboxes = Show BBoxes +show-origin-destination = Show Origin–Destination + +specctra-session-file = Specctra session file diff --git a/src/bin/topola-egui/action.rs b/src/bin/topola-egui/action.rs index 35a9680..60fcbdb 100644 --- a/src/bin/topola-egui/action.rs +++ b/src/bin/topola-egui/action.rs @@ -4,9 +4,9 @@ pub struct Action { } impl Action { - pub fn new(name: &str, modifiers: egui::Modifiers, key: egui::Key) -> Self { + pub fn new(name: String, modifiers: egui::Modifiers, key: egui::Key) -> Self { Self { - name: String::from(name), + name, shortcut: egui::KeyboardShortcut::new(modifiers, key), } } diff --git a/src/bin/topola-egui/app.rs b/src/bin/topola-egui/app.rs index 1b08b89..6756b99 100644 --- a/src/bin/topola-egui/app.rs +++ b/src/bin/topola-egui/app.rs @@ -43,14 +43,14 @@ use topola::{ use crate::{ bottom::Bottom, file_receiver::FileReceiver, layers::Layers, overlay::Overlay, - painter::Painter, top::Top, viewport::Viewport, + painter::Painter, top::Top, translator::Translator, viewport::Viewport, }; /// Deserialize/Serialize is needed to persist app state between restarts. #[derive(Serialize, Deserialize)] #[serde(default)] pub struct App { - langid: LanguageIdentifier, + translator: Translator, #[serde(skip)] maybe_overlay: Option, @@ -89,7 +89,7 @@ pub struct App { impl Default for App { fn default() -> Self { Self { - langid: langid!("en-US"), + translator: Translator::new(langid!("en-US")), maybe_overlay: None, arc_mutex_maybe_invoker: Arc::new(Mutex::new(None)), maybe_execute: None, @@ -111,14 +111,14 @@ impl App { // Load previous app state if one exists. if let Some(storage) = cc.storage { let this = Self { - langid, + translator: Translator::new(langid), ..eframe::get_value(storage, eframe::APP_KEY).unwrap_or_default() }; return this; } Self { - langid, + translator: Translator::new(langid), ..Default::default() } } @@ -176,6 +176,7 @@ impl eframe::App for App { self.top.update( ctx, + &self.translator, self.content_channel.0.clone(), self.history_channel.0.clone(), self.arc_mutex_maybe_invoker.clone(), @@ -199,8 +200,13 @@ impl eframe::App for App { &self.maybe_layers, ); - self.bottom - .update(ctx, &self.viewport, viewport_rect, &self.maybe_execute); + self.bottom.update( + ctx, + &self.translator, + &self.viewport, + viewport_rect, + &self.maybe_execute, + ); if ctx.input(|i| i.key_pressed(egui::Key::Escape)) { ctx.send_viewport_cmd(egui::ViewportCommand::Close); diff --git a/src/bin/topola-egui/bottom.rs b/src/bin/topola-egui/bottom.rs index dca3096..9a1e705 100644 --- a/src/bin/topola-egui/bottom.rs +++ b/src/bin/topola-egui/bottom.rs @@ -1,6 +1,6 @@ use topola::autorouter::invoker::{Execute, ExecuteWithStatus, InvokerStatus}; -use crate::viewport::Viewport; +use crate::{translator::Translator, viewport::Viewport}; pub struct Bottom {} @@ -12,6 +12,7 @@ impl Bottom { pub fn update( &mut self, ctx: &egui::Context, + tr: &Translator, viewport: &Viewport, viewport_rect: egui::Rect, maybe_execute: &Option, diff --git a/src/bin/topola-egui/main.rs b/src/bin/topola-egui/main.rs index a5d6cf7..7d51971 100644 --- a/src/bin/topola-egui/main.rs +++ b/src/bin/topola-egui/main.rs @@ -9,19 +9,14 @@ mod layers; mod overlay; mod painter; mod top; +mod translator; mod viewport; + use app::App; use fluent_templates::static_loader; use sys_locale::get_locale; use unic_langid::{langid, LanguageIdentifier}; -static_loader! { - static LOCALES = { - locales: "./locales", - fallback_language: "en-US", - }; -} - // Build to native. #[cfg(not(target_arch = "wasm32"))] fn main() -> eframe::Result<()> { diff --git a/src/bin/topola-egui/top.rs b/src/bin/topola-egui/top.rs index 5d85b7d..1e73663 100644 --- a/src/bin/topola-egui/top.rs +++ b/src/bin/topola-egui/top.rs @@ -16,6 +16,7 @@ use crate::{ app::{channel_text, execute}, file_sender::FileSender, overlay::Overlay, + translator::Translator, }; pub struct Top { @@ -40,6 +41,7 @@ impl Top { pub fn update( &mut self, ctx: &egui::Context, + tr: &Translator, content_sender: Sender, history_sender: Sender, arc_mutex_maybe_invoker: Arc>>>, @@ -47,51 +49,66 @@ impl Top { maybe_overlay: &mut Option, maybe_design: &Option, ) -> Result<(), InvokerError> { - let mut open_design = - Trigger::new(Action::new("Open", egui::Modifiers::CTRL, egui::Key::O)); + let mut open_design = Trigger::new(Action::new( + tr.text("action-open-dsn"), + egui::Modifiers::CTRL, + egui::Key::O, + )); let mut export_session = Trigger::new(Action::new( - "Export session file", + tr.text("action-export-ses"), egui::Modifiers::CTRL, egui::Key::S, )); let mut import_history = Trigger::new(Action::new( - "Import history", + tr.text("action-import-cmd"), egui::Modifiers::CTRL, egui::Key::I, )); let mut export_history = Trigger::new(Action::new( - "Export history", + tr.text("action-export-cmd"), egui::Modifiers::CTRL, egui::Key::E, )); - let mut quit = Trigger::new(Action::new("Quit", egui::Modifiers::CTRL, egui::Key::V)); + let mut quit = Trigger::new(Action::new( + tr.text("action-quit"), + egui::Modifiers::CTRL, + egui::Key::V, + )); let mut autoroute = Trigger::new(Action::new( - "Autoroute", + tr.text("action-autoroute"), egui::Modifiers::CTRL, egui::Key::A, )); let mut place_via = Switch::new(Action::new( - "Place Via", + tr.text("action-place-via"), egui::Modifiers::CTRL, egui::Key::P, )); let mut remove_bands = Trigger::new(Action::new( - "Remove Selected Bands", + tr.text("action-remove-bands"), egui::Modifiers::NONE, egui::Key::Delete, )); let mut compare_detours = Trigger::new(Action::new( - "Compare Detours", + tr.text("action-compare-detours"), egui::Modifiers::NONE, egui::Key::Minus, )); - let mut undo = Trigger::new(Action::new("Undo", egui::Modifiers::CTRL, egui::Key::Z)); - let mut redo = Trigger::new(Action::new("Redo", egui::Modifiers::CTRL, egui::Key::Y)); + let mut undo = Trigger::new(Action::new( + tr.text("action-undo"), + egui::Modifiers::CTRL, + egui::Key::Z, + )); + let mut redo = Trigger::new(Action::new( + tr.text("action-redo"), + egui::Modifiers::CTRL, + egui::Key::Y, + )); egui::TopBottomPanel::top("top_panel") .show(ctx, |ui| { egui::menu::bar(ui, |ui| { - ui.menu_button("File", |ui| { + ui.menu_button(tr.text("menu-file"), |ui| { open_design.button(ctx, ui); export_session.button(ctx, ui); @@ -123,11 +140,14 @@ impl Top { ui.separator(); - ui.menu_button("Debug", |ui| { - ui.checkbox(&mut self.show_ratsnest, "Show Ratsnest"); - ui.checkbox(&mut self.show_navmesh, "Show Navmesh"); - ui.checkbox(&mut self.show_bboxes, "Show BBoxes"); - ui.checkbox(&mut self.show_origin_destination, "Show Origin–Destination"); + ui.menu_button(tr.text("menu-debug"), |ui| { + ui.checkbox(&mut self.show_ratsnest, tr.text("show-ratsnest")); + ui.checkbox(&mut self.show_navmesh, tr.text("show-navmesh")); + ui.checkbox(&mut self.show_bboxes, tr.text("show-bboxes")); + ui.checkbox( + &mut self.show_origin_destination, + tr.text("show-origin-destination"), + ); ui.separator(); compare_detours.button(ctx, ui); @@ -170,7 +190,7 @@ impl Top { } } let task = dialog - .add_filter("Specctra session file", &["ses"]) + .add_filter(tr.text("specctra-session-file"), &["ses"]) .save_file(); execute(async move { diff --git a/src/bin/topola-egui/translator.rs b/src/bin/topola-egui/translator.rs new file mode 100644 index 0000000..244b985 --- /dev/null +++ b/src/bin/topola-egui/translator.rs @@ -0,0 +1,25 @@ +use fluent_templates::{static_loader, Loader}; +use serde::{Deserialize, Serialize}; +use unic_langid::LanguageIdentifier; + +static_loader! { + static LOCALES = { + locales: "./locales", + fallback_language: "en-US", + }; +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Translator { + langid: LanguageIdentifier, +} + +impl Translator { + pub fn new(langid: LanguageIdentifier) -> Self { + Self { langid } + } + + pub fn text(&self, fluent_id: &str) -> String { + LOCALES.lookup(&self.langid, fluent_id) + } +} diff --git a/src/bin/topola/main.rs b/src/bin/topola/main.rs index 3a273f3..3d1016c 100644 --- a/src/bin/topola/main.rs +++ b/src/bin/topola/main.rs @@ -1,5 +1,4 @@ use clap::{Error, Parser}; -use fluent_templates::static_loader; use std::fs::File; use std::io::prelude::*; use std::io::BufReader;