From 8eacf42fbeaf17dfba7e78338dc6ba14c1fa0b94 Mon Sep 17 00:00:00 2001 From: ShootingStarDragons Date: Wed, 13 Nov 2024 21:54:21 +0900 Subject: [PATCH] feat: i18n --- Cargo.lock | 333 +++++++++++++++++++++++++++++++++- i18n.toml | 10 + lala_bar/Cargo.toml | 8 +- lala_bar/i18n.toml | 10 + lala_bar/i18n/en/lala_bar.ftl | 3 + lala_bar/src/localize.rs | 45 +++++ lala_bar/src/main.rs | 2 + lala_bar/src/music_bar.rs | 8 +- 8 files changed, 412 insertions(+), 7 deletions(-) create mode 100644 i18n.toml create mode 100644 lala_bar/i18n.toml create mode 100644 lala_bar/i18n/en/lala_bar.ftl create mode 100644 lala_bar/src/localize.rs diff --git a/Cargo.lock b/Cargo.lock index 4f56c06..186f19e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -200,6 +200,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "arrayref" version = "0.3.9" @@ -403,6 +409,15 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "basic-toml" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" +dependencies = [ + "serde", +] + [[package]] name = "bit-set" version = "0.5.3" @@ -825,7 +840,7 @@ dependencies = [ "rayon", "rustc-hash 1.1.0", "rustybuzz", - "self_cell", + "self_cell 1.0.4", "swash", "sys-locale", "ttf-parser 0.21.1", @@ -953,7 +968,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.11.1", "syn 2.0.87", ] @@ -968,6 +983,19 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core 0.9.10", +] + [[package]] name = "data-url" version = "0.3.1" @@ -1253,6 +1281,15 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "find-crate" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a98bbaacea1c0eb6a0876280051b892eb73594fd90cf3b20e9c817029c57d2" +dependencies = [ + "toml 0.5.11", +] + [[package]] name = "flate2" version = "1.0.34" @@ -1275,6 +1312,50 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8" +[[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-langneg" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94" +dependencies = [ + "unic-langid", +] + +[[package]] +name = "fluent-syntax" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d" +dependencies = [ + "thiserror", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1799,6 +1880,76 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "i18n-config" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e88074831c0be5b89181b05e6748c4915f77769ecc9a4c372f88b169a8509c9" +dependencies = [ + "basic-toml", + "log", + "serde", + "serde_derive", + "thiserror", + "unic-langid", +] + +[[package]] +name = "i18n-embed" +version = "0.13.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92a86226a7a16632de6723449ee5fe70bac5af718bc642ee9ca2f0f6e14fa1fa" +dependencies = [ + "arc-swap", + "fluent", + "fluent-langneg", + "fluent-syntax", + "i18n-embed-impl", + "intl-memoizer", + "lazy_static", + "locale_config", + "log", + "parking_lot 0.12.3", + "rust-embed", + "thiserror", + "unic-langid", + "walkdir", +] + +[[package]] +name = "i18n-embed-fl" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26a3d3569737dfaac7fc1c4078e6af07471c3060b8e570bcd83cdd5f4685395" +dependencies = [ + "dashmap", + "find-crate", + "fluent", + "fluent-syntax", + "i18n-config", + "i18n-embed", + "lazy_static", + "proc-macro-error", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 2.0.87", + "unic-langid", +] + +[[package]] +name = "i18n-embed-impl" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f2cc0e0523d1fe6fc2c6f66e5038624ea8091b3e7748b5e8e0c84b1698db6c2" +dependencies = [ + "find-crate", + "i18n-config", + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "iana-time-zone" version = "0.1.61" @@ -2269,6 +2420,25 @@ dependencies = [ "cfg-if", ] +[[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 = "is_terminal_polyfill" version = "1.70.1" @@ -2397,6 +2567,8 @@ dependencies = [ "futures", "futures-util", "gio", + "i18n-embed", + "i18n-embed-fl", "iced", "iced_aw", "iced_fonts", @@ -2405,6 +2577,7 @@ dependencies = [ "iced_runtime", "iced_zbus_notification", "regex", + "rust-embed", "serde", "tokio", "tracing", @@ -2510,6 +2683,19 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" +[[package]] +name = "locale_config" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d2c35b16f4483f6c26f0e4e9550717a2f6575bcd6f12a53ff0c490a94a6934" +dependencies = [ + "lazy_static", + "objc", + "objc-foundation", + "regex", + "winapi", +] + [[package]] name = "lock_api" version = "0.4.12" @@ -2836,6 +3022,17 @@ dependencies = [ "objc_exception", ] +[[package]] +name = "objc-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" +dependencies = [ + "block", + "objc", + "objc_id", +] + [[package]] name = "objc-sys" version = "0.3.5" @@ -3048,6 +3245,15 @@ dependencies = [ "cc", ] +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", +] + [[package]] name = "object" version = "0.36.5" @@ -3346,6 +3552,30 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro-utils" version = "0.10.0" @@ -3615,6 +3845,40 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" +[[package]] +name = "rust-embed" +version = "6.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a36224c3276f8c4ebc8c20f158eca7ca4359c8db89991c4925132aaaf6702661" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "6.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b94b81e5b2c284684141a2fb9e2a31be90638caf040bf9afbc5a0416afe1ac" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn 2.0.87", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "7.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d38ff6bf570dc3bb7100fce9f7b60c33fa71d80e88da3f2580df4ff2bdded74" +dependencies = [ + "sha2", + "walkdir", +] + [[package]] name = "rust-ini" version = "0.18.0" @@ -3707,6 +3971,15 @@ dependencies = [ "tiny-skia", ] +[[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" @@ -3764,6 +4037,17 @@ dependencies = [ "digest", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -3966,6 +4250,12 @@ dependencies = [ "float-cmp", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "strsim" version = "0.11.1" @@ -4050,7 +4340,7 @@ dependencies = [ "cfg-expr", "heck", "pkg-config", - "toml", + "toml 0.8.19", "version-compare", ] @@ -4217,6 +4507,15 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.8.19" @@ -4342,6 +4641,15 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5902c5d130972a0000f60860bfbf46f7ca3db5391eddfedd1b8728bd9dc96c0e" +[[package]] +name = "type-map" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f" +dependencies = [ + "rustc-hash 1.1.0", +] + [[package]] name = "typenum" version = "1.17.0" @@ -4359,6 +4667,25 @@ dependencies = [ "winapi", ] +[[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 = [ + "serde", + "tinystr", +] + [[package]] name = "unicase" version = "2.8.0" diff --git a/i18n.toml b/i18n.toml new file mode 100644 index 0000000..2aaedd4 --- /dev/null +++ b/i18n.toml @@ -0,0 +1,10 @@ +# (for which all strings must be present) when using the fluent +# system. +fallback_language = "en" + +# (Optional) Use the fluent localization system. +[fluent] +# (Required) The path to the assets directory. +# The paths inside the assets directory should be structured like so: +# `assets_dir/{language}/{domain}.ftl` +assets_dir = "i18n" diff --git a/lala_bar/Cargo.toml b/lala_bar/Cargo.toml index f5382c4..0a58bee 100644 --- a/lala_bar/Cargo.toml +++ b/lala_bar/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lala-bar" -version.workspace = true +version = "0.4.1" edition.workspace = true description = "a bar on layershell with iced-rs" authors.workspace = true @@ -46,3 +46,9 @@ async-trait.workspace = true tracing-journald = "0.3.0" iced_aw = "0.11.0" iced_fonts = "0.1.1" +i18n-embed = { version = "0.13.4", features = [ + "fluent-system", + "desktop-requester", +] } +i18n-embed-fl = "0.6.4" +rust-embed = "6.3.0" diff --git a/lala_bar/i18n.toml b/lala_bar/i18n.toml new file mode 100644 index 0000000..2aaedd4 --- /dev/null +++ b/lala_bar/i18n.toml @@ -0,0 +1,10 @@ +# (for which all strings must be present) when using the fluent +# system. +fallback_language = "en" + +# (Optional) Use the fluent localization system. +[fluent] +# (Required) The path to the assets directory. +# The paths inside the assets directory should be structured like so: +# `assets_dir/{language}/{domain}.ftl` +assets_dir = "i18n" diff --git a/lala_bar/i18n/en/lala_bar.ftl b/lala_bar/i18n/en/lala_bar.ftl new file mode 100644 index 0000000..238074a --- /dev/null +++ b/lala_bar/i18n/en/lala_bar.ftl @@ -0,0 +1,3 @@ +balance = balance +right = right +left = left diff --git a/lala_bar/src/localize.rs b/lala_bar/src/localize.rs new file mode 100644 index 0000000..018125a --- /dev/null +++ b/lala_bar/src/localize.rs @@ -0,0 +1,45 @@ +use i18n_embed::{ + fluent::{fluent_language_loader, FluentLanguageLoader}, + DefaultLocalizer, LanguageLoader, Localizer, +}; +use rust_embed::RustEmbed; +use std::sync::LazyLock; + +#[derive(RustEmbed)] +#[folder = "i18n/"] +struct Localizations; + +pub static LANGUAGE_LOADER: LazyLock = LazyLock::new(|| { + let loader: FluentLanguageLoader = fluent_language_loader!(); + + loader + .load_fallback_language(&Localizations) + .expect("Error while loading fallback language"); + + loader +}); + +#[macro_export] +macro_rules! fl { + ($message_id:literal) => {{ + i18n_embed_fl::fl!($crate::localize::LANGUAGE_LOADER, $message_id) + }}; + + ($message_id:literal, $($args:expr),*) => {{ + i18n_embed_fl::fl!($crate::localize::LANGUAGE_LOADER, $message_id, $($args), *) + }}; +} + +// Get the `Localizer` to be used for localizing this library. +pub fn localizer() -> Box { + Box::from(DefaultLocalizer::new(&*LANGUAGE_LOADER, &Localizations)) +} + +pub fn localize() { + let localizer = localizer(); + let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages(); + + if let Err(error) = localizer.select(&requested_languages) { + eprintln!("Error while loading language for App List {}", error); + } +} diff --git a/lala_bar/src/main.rs b/lala_bar/src/main.rs index 1f7b3ec..8b90db4 100644 --- a/lala_bar/src/main.rs +++ b/lala_bar/src/main.rs @@ -19,6 +19,7 @@ mod music_bar; mod notify; mod slider; mod zbus_mpirs; +mod localize; use crate::music_bar::LalaMusicBar; use crate::notify::NotifyCommand; @@ -35,6 +36,7 @@ pub fn main() -> Result<(), iced_layershell::Error> { //.unwrap(), ) .init(); + localize::localize(); LalaMusicBar::run(Settings { layer_settings: LayerShellSettings { size: Some((0, 35)), diff --git a/lala_bar/src/music_bar.rs b/lala_bar/src/music_bar.rs index a1d74f7..6843a2d 100644 --- a/lala_bar/src/music_bar.rs +++ b/lala_bar/src/music_bar.rs @@ -1,5 +1,6 @@ use crate::config::*; use crate::dbusbackend; +use crate::fl; use crate::get_metadata; use crate::launcher::LaunchMessage; use crate::notify::{NotifyCommand, NotifyUnitWidgetInfo}; @@ -109,9 +110,10 @@ impl LalaMusicBar { fn update_balance(&mut self) { self.left = aximer::get_left().unwrap_or(0); self.right = aximer::get_right().unwrap_or(0); - self.left_text = format!("left {}%", self.left); - self.right_text = format!("right {}%", self.right); - self.balance_text = format!("balance {}%", self.balance_percent()); + + self.left_text = format!("{} {}%", fl!("left"), self.left); + self.right_text = format!("{} {}%", fl!("right"), self.right); + self.balance_text = format!("{} {}%", fl!("balance"), self.balance_percent()); } fn set_balance(&mut self, balance: u8) {