From 0e87c22e5529f81e3956e3817a3de0415858db87 Mon Sep 17 00:00:00 2001 From: Terry Yiu <963907+tyiu@users.noreply.github.com> Date: Thu, 5 Dec 2024 11:47:54 -0500 Subject: [PATCH] WIP proof of concept to add localization using fluent-rs --- Cargo.lock | 189 +++++++++++++++++++++++++ Cargo.toml | 4 + assets/translations/en-US/notedeck.ftl | 1 + src/app.rs | 10 ++ src/ui/add_column.rs | 28 +++- 5 files changed, 227 insertions(+), 5 deletions(-) create mode 100644 assets/translations/en-US/notedeck.ftl diff --git a/Cargo.lock b/Cargo.lock index fc3e46c1..5f8770fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -313,6 +313,17 @@ dependencies = [ "syn 2.0.89", ] +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -757,6 +768,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "chunky-vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb7bdea464ae038f09197b82430b921c53619fc8d2bcaf7b151013b3ca008017" + [[package]] name = "cipher" version = "0.4.4" @@ -1038,6 +1055,17 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "dlib" version = "0.5.2" @@ -1250,6 +1278,15 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "elsa" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98e71ae4df57d214182a2e5cb90230c0192c6ddfcaa05c36453d46a54713e10" +dependencies = [ + "stable_deref_trait", +] + [[package]] name = "emath" version = "0.27.2" @@ -1458,6 +1495,81 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +[[package]] +name = "fluent" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb74634707bebd0ce645a981148e8fb8c7bccd4c33c652aeffd28bf2f96d555a" +dependencies = [ + "fluent-bundle", + "unic-langid", +] + +[[package]] +name = "fluent-bundle" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe0a21ee80050c678013f82edf4b705fe2f26f1f9877593d13198612503f493" +dependencies = [ + "fluent-langneg", + "fluent-syntax", + "intl-memoizer", + "intl_pluralrules", + "rustc-hash 1.1.0", + "self_cell 0.10.3", + "smallvec", + "unic-langid", +] + +[[package]] +name = "fluent-fallback" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1010c29cde3a7eeb231c59d95411dcea1c1d91ad00dd733b076dbd885815024a" +dependencies = [ + "async-trait", + "chunky-vec", + "fluent-bundle", + "futures", + "once_cell", + "pin-cell", + "rustc-hash 1.1.0", + "unic-langid", +] + +[[package]] +name = "fluent-langneg" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94" +dependencies = [ + "unic-langid", +] + +[[package]] +name = "fluent-resmgr" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2a2360469fd304ea6560a6dfb8f843328d3a6498f1c867f187e57993609af7e" +dependencies = [ + "elsa", + "fluent-bundle", + "fluent-fallback", + "futures", + "rustc-hash 1.1.0", + "thiserror 1.0.63", + "unic-langid", +] + +[[package]] +name = "fluent-syntax" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d" +dependencies = [ + "thiserror 1.0.63", +] + [[package]] name = "flume" version = "0.11.0" @@ -2063,6 +2175,25 @@ dependencies = [ "syn 2.0.89", ] +[[package]] +name = "intl-memoizer" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe22e020fce238ae18a6d5d8c502ee76a52a6e880d99477657e6acc30ec57bda" +dependencies = [ + "type-map", + "unic-langid", +] + +[[package]] +name = "intl_pluralrules" +version = "7.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972" +dependencies = [ + "unic-langid", +] + [[package]] name = "ipnet" version = "2.10.0" @@ -2617,6 +2748,9 @@ dependencies = [ "ehttp 0.2.0", "enostr", "env_logger 0.10.2", + "fluent", + "fluent-fallback", + "fluent-resmgr", "hex", "image", "indexmap", @@ -2639,6 +2773,7 @@ dependencies = [ "tracing-appender", "tracing-subscriber", "tracing-wasm", + "unic-langid", "url", "urlencoding", "uuid", @@ -3035,6 +3170,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" +[[package]] +name = "pin-cell" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1f4c4ebd3c5f82080164b7d9cc8e505cd9536fda8c750b779daceb4b7180a7b" + [[package]] name = "pin-project" version = "1.1.5" @@ -3871,6 +4012,21 @@ dependencies = [ "libc", ] +[[package]] +name = "self_cell" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d" +dependencies = [ + "self_cell 1.0.4", +] + +[[package]] +name = "self_cell" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" + [[package]] name = "semver" version = "1.0.23" @@ -4126,6 +4282,12 @@ dependencies = [ "bitflags 2.6.0", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" @@ -4366,6 +4528,15 @@ dependencies = [ "strict-num", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", +] + [[package]] name = "tinyvec" version = "1.8.0" @@ -4662,6 +4833,24 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unic-langid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dd9d1e72a73b25e07123a80776aae3e7b0ec461ef94f9151eed6ec88005a44" +dependencies = [ + "unic-langid-impl", +] + +[[package]] +name = "unic-langid-impl" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a5422c1f65949306c99240b81de9f3f15929f5a8bfe05bb44b034cc8bf593e5" +dependencies = [ + "tinystr", +] + [[package]] name = "unicase" version = "2.7.0" diff --git a/Cargo.toml b/Cargo.toml index 33c20cb3..0090d3c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,10 @@ tracing-appender = "0.2.3" urlencoding = "2.1.3" open = "5.3.0" url = "2.5" +fluent-resmgr = "0.0.7" +fluent-fallback = "0.7.1" +fluent = "0.16.1" +unic-langid = "0.9.5" [dev-dependencies] tempfile = "3.13.0" diff --git a/assets/translations/en-US/notedeck.ftl b/assets/translations/en-US/notedeck.ftl new file mode 100644 index 00000000..4159cf9c --- /dev/null +++ b/assets/translations/en-US/notedeck.ftl @@ -0,0 +1 @@ +universe-title = Universe with Fluent Translation \ No newline at end of file diff --git a/src/app.rs b/src/app.rs index b7ea27db..c28cbcaf 100644 --- a/src/app.rs +++ b/src/app.rs @@ -37,6 +37,8 @@ use std::path::Path; use std::time::Duration; use tracing::{error, info, trace, warn}; +use fluent_resmgr::resource_manager::ResourceManager; + #[derive(Debug, Eq, PartialEq, Clone)] pub enum DamusState { Initializing, @@ -69,6 +71,8 @@ pub struct Damus { pub debug: bool, pub since_optimize: bool, pub textmode: bool, + + pub res_mgr: ResourceManager, } fn handle_key_events(input: &egui::InputState, _pixels_per_point: f32, columns: &mut Columns) { @@ -471,6 +475,8 @@ impl Damus { let app_rect_handler = AppSizeHandler::new(&path); let support = Support::new(&path); + let res_mgr = ResourceManager::new("./assets/translations/{locale}/{res_id}".into()); + Self { pool, debug, @@ -492,6 +498,7 @@ impl Damus { path, app_rect_handler, support, + res_mgr, } } @@ -557,6 +564,8 @@ impl Damus { let config = Config::new().set_ingester_threads(2); + let res_mgr = ResourceManager::new("../assets/translations/{locale}/{res_id}".into()); + Self { debug, unknown_ids: UnknownIds::default(), @@ -585,6 +594,7 @@ impl Damus { path, app_rect_handler, support, + res_mgr, } } diff --git a/src/ui/add_column.rs b/src/ui/add_column.rs index b0acf580..e11126ea 100644 --- a/src/ui/add_column.rs +++ b/src/ui/add_column.rs @@ -2,10 +2,7 @@ use core::f32; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use egui::{ - pos2, vec2, Align, Button, Color32, FontId, Id, ImageSource, Margin, Pos2, Rect, RichText, - Separator, Ui, Vec2, -}; +use egui::{pos2, vec2, Align, Button, Color32, FontId, Id, ImageSource, Margin, Pos2, Rect, RichText, Separator, TextBuffer, Ui, Vec2}; use nostrdb::Ndb; use tracing::error; @@ -18,6 +15,9 @@ use crate::{ Damus, }; +use fluent_resmgr::resource_manager::ResourceManager; +use unic_langid::LanguageIdentifier; + use super::{anim::AnimationHelper, padding}; pub enum AddColumnResponse { @@ -85,6 +85,7 @@ pub struct AddColumnView<'a> { key_state_map: &'a mut HashMap, ndb: &'a Ndb, cur_account: Option<&'a UserAccount>, + res_mgr: &'a ResourceManager, } impl<'a> AddColumnView<'a> { @@ -92,11 +93,13 @@ impl<'a> AddColumnView<'a> { key_state_map: &'a mut HashMap, ndb: &'a Ndb, cur_account: Option<&'a UserAccount>, + res_mgr: &'a ResourceManager, ) -> Self { Self { key_state_map, ndb, cur_account, + res_mgr, } } @@ -276,9 +279,22 @@ impl<'a> AddColumnView<'a> { } fn get_base_options(&self) -> Vec { + let default_locale: LanguageIdentifier = "en-US".parse().expect("Parsing failed."); + let resources = vec!["notedeck.ftl".into()]; + let bundle = self.res_mgr + .get_bundle( + vec![default_locale], + resources, + ) + .expect("Could not get bundle"); + let mut errors = vec![]; + let msg = bundle.get_message("universe-title").expect("Message exists"); + let pattern = msg.value().expect("Message has a value"); + let value: &'static mut str = bundle.format_pattern(pattern, None, &mut errors).to_string().leak(); + let mut vec = Vec::new(); vec.push(ColumnOptionData { - title: "Universe", + title: value, description: "See the whole nostr universe", icon: egui::include_image!("../../assets/icons/universe_icon_dark_4x.png"), option: AddColumnOption::Universe, @@ -356,6 +372,7 @@ pub fn render_add_column_routes( &mut app.view_state.id_state_map, &app.ndb, app.accounts.get_selected_account(), + &app.res_mgr, ); let resp = match route { AddColumnRoute::Base => add_column_view.ui(ui), @@ -463,6 +480,7 @@ mod preview { &mut self.app.view_state.id_state_map, &self.app.ndb, self.app.accounts.get_selected_account(), + &self.app.res_mgr, ) .ui(ui); }