egui: source GUI strings from Fluent files

This commit is contained in:
Mikolaj Wielgus 2024-08-11 00:13:30 +02:00
parent 0257568410
commit 4e37f5715b
8 changed files with 106 additions and 38 deletions

View File

@ -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 OriginDestination
specctra-session-file = Specctra session file

View File

@ -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),
}
}

View File

@ -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<Overlay>,
@ -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);

View File

@ -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<ExecuteWithStatus>,

View File

@ -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<()> {

View File

@ -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<String>,
history_sender: Sender<String>,
arc_mutex_maybe_invoker: Arc<Mutex<Option<Invoker<SpecctraMesadata>>>>,
@ -47,51 +49,66 @@ impl Top {
maybe_overlay: &mut Option<Overlay>,
maybe_design: &Option<SpecctraDesign>,
) -> 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 OriginDestination");
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 {

View File

@ -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)
}
}

View File

@ -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;