diff --git a/Cargo.lock b/Cargo.lock index f5243dd9..2631d024 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,12 +102,6 @@ version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" -[[package]] -name = "arc-swap" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" - [[package]] name = "arrayvec" version = "0.7.6" @@ -170,18 +164,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "base62" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48fa474cf7492f9a299ba6019fb99ec673e1739556d48e8a90eabaea282ef0e4" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.6.0" @@ -201,16 +183,6 @@ dependencies = [ "piper", ] -[[package]] -name = "bstr" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" -dependencies = [ - "memchr", - "serde", -] - [[package]] name = "bumpalo" version = "3.16.0" @@ -487,7 +459,7 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags 2.6.0", + "bitflags", "crossterm_winapi", "mio", "parking_lot", @@ -868,36 +840,6 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "globset" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" -dependencies = [ - "aho-corasick", - "bstr", - "log", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", -] - -[[package]] -name = "globwalk" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" -dependencies = [ - "bitflags 1.3.2", - "ignore", - "walkdir", -] - [[package]] name = "hashbrown" version = "0.15.2" @@ -1168,22 +1110,6 @@ dependencies = [ "icu_properties", ] -[[package]] -name = "ignore" -version = "0.4.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" -dependencies = [ - "crossbeam-deque", - "globset", - "log", - "memchr", - "regex-automata 0.4.9", - "same-file", - "walkdir", - "winapi-util", -] - [[package]] name = "indexmap" version = "2.7.0" @@ -1260,15 +1186,6 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -1316,12 +1233,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "libyml" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64804cc6a5042d4f05379909ba25b503ec04e2c082151d62122d5dcaa274b961" - [[package]] name = "linked-hash-map" version = "0.5.6" @@ -1469,22 +1380,13 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.6.0", + "bitflags", "cfg-if", "cfg_aliases", "libc", "memoffset", ] -[[package]] -name = "normpath" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8911957c4b1549ac0dc74e30db9c8b0e66ddcd6d7acc33098f4c63a64a6d7ed" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1576,6 +1478,44 @@ dependencies = [ "indexmap", ] +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.15" @@ -1704,13 +1644,13 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" dependencies = [ - "bitflags 2.6.0", + "bitflags", "cassowary", "compact_str", "crossterm", "indoc", "instability", - "itertools 0.13.0", + "itertools", "lru", "paste", "strum", @@ -1725,7 +1665,7 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags 2.6.0", + "bitflags", ] [[package]] @@ -1788,60 +1728,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3" -[[package]] -name = "rust-i18n" -version = "3.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "039f57d22229db401af3458ca939300178e99e88b938573cea12b7c2b0f09724" -dependencies = [ - "globwalk", - "once_cell", - "regex", - "rust-i18n-macro", - "rust-i18n-support", - "smallvec", -] - -[[package]] -name = "rust-i18n-macro" -version = "3.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde5c022360a2e54477882843d56b6f9bcb4bc62f504b651a2f497f0028d174f" -dependencies = [ - "glob", - "once_cell", - "proc-macro2", - "quote", - "rust-i18n-support", - "serde", - "serde_json", - "serde_yml", - "syn 2.0.90", -] - -[[package]] -name = "rust-i18n-support" -version = "3.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75d2844d36f62b5d6b66f9cf8f8cbdbbbdcdb5fd37a473a9cc2fb45fdcf485d2" -dependencies = [ - "arc-swap", - "base62", - "globwalk", - "itertools 0.11.0", - "lazy_static", - "normpath", - "once_cell", - "proc-macro2", - "regex", - "serde", - "serde_json", - "serde_yml", - "siphasher", - "toml 0.7.8", - "triomphe", -] - [[package]] name = "rustc-demangle" version = "0.1.24" @@ -1854,7 +1740,7 @@ version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ - "bitflags 2.6.0", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -1873,15 +1759,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - [[package]] name = "scopeguard" version = "1.2.0" @@ -1952,23 +1829,6 @@ dependencies = [ "syn 2.0.90", ] -[[package]] -name = "serde_yml" -version = "0.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e76bab63c3fd98d27c17f9cbce177f64a91f5e69ac04cafe04e1bb25d1dc3c" -dependencies = [ - "indexmap", - "itoa", - "libyml", - "log", - "memchr", - "ryu", - "serde", - "serde_json", - "tempfile", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -2022,9 +1882,9 @@ checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" [[package]] name = "siphasher" -version = "1.0.1" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "slab" @@ -2133,19 +1993,6 @@ dependencies = [ "libc", ] -[[package]] -name = "tempfile" -version = "3.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" -dependencies = [ - "cfg-if", - "fastrand", - "once_cell", - "rustix", - "windows-sys 0.59.0", -] - [[package]] name = "terminal_size" version = "0.4.1" @@ -2312,18 +2159,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "toml" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.19.15", -] - [[package]] name = "toml" version = "0.8.19" @@ -2333,7 +2168,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.22", + "toml_edit", ] [[package]] @@ -2345,19 +2180,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow 0.5.40", -] - [[package]] name = "toml_edit" version = "0.22.22" @@ -2368,7 +2190,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.20", + "winnow", ] [[package]] @@ -2377,7 +2199,7 @@ version = "0.1.0" dependencies = [ "anyhow", "clap", - "itertools 0.13.0", + "itertools", "trippy", ] @@ -2466,17 +2288,6 @@ dependencies = [ "tracing-serde", ] -[[package]] -name = "triomphe" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8f7726da4807b58ea5c96fdc122f80702030edc33b35aff9190a51148ccc85" -dependencies = [ - "arc-swap", - "serde", - "stable_deref_trait", -] - [[package]] name = "trippy" version = "0.13.0-dev" @@ -2495,12 +2306,12 @@ version = "0.13.0-dev" dependencies = [ "anyhow", "arrayvec", - "bitflags 2.6.0", + "bitflags", "derive_more", "hex-literal", "indexmap", "ipnetwork", - "itertools 0.13.0", + "itertools", "mockall", "nix", "parking_lot", @@ -2512,7 +2323,7 @@ dependencies = [ "thiserror 2.0.6", "tokio", "tokio-util", - "toml 0.8.19", + "toml", "tracing", "tracing-subscriber", "trippy-packet", @@ -2530,7 +2341,7 @@ dependencies = [ "crossbeam", "dns-lookup", "hickory-resolver", - "itertools 0.13.0", + "itertools", "parking_lot", "thiserror 2.0.6", ] @@ -2541,7 +2352,7 @@ version = "0.13.0-dev" dependencies = [ "anyhow", "hex-literal", - "itertools 0.13.0", + "itertools", "thiserror 2.0.6", ] @@ -2573,19 +2384,20 @@ dependencies = [ "etcetera", "humantime", "insta", - "itertools 0.13.0", + "itertools", "maxminddb", "petgraph", + "phf", + "phf_codegen", "pretty_assertions", "ratatui", - "rust-i18n", "serde", "serde_json", "serde_with", "strum", "sys-locale", "test-case", - "toml 0.8.19", + "toml", "tracing", "tracing-chrome", "tracing-subscriber", @@ -2634,7 +2446,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" dependencies = [ - "itertools 0.13.0", + "itertools", "unicode-segmentation", "unicode-width 0.1.14", ] @@ -2686,16 +2498,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -2778,15 +2580,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -2950,15 +2743,6 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - [[package]] name = "winnow" version = "0.6.20" diff --git a/Cargo.toml b/Cargo.toml index 220350b6..71aa2e2c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,10 +58,11 @@ nix = { version = "0.29.0", default-features = false } parking_lot = "0.12.3" paste = "1.0.15" petgraph = "0.6.5" +phf = "0.11" +phf_codegen = "0.11" pretty_assertions = "1.4.1" rand = "0.8.5" ratatui = "0.29.0" -rust-i18n = "3.1.2" serde = { version = "1.0.201", default-features = false } serde_json = { version = "1.0.117", default-features = false } serde_with = { version = "3.11.0", default-features = false, features = ["macros"] } diff --git a/crates/trippy-tui/Cargo.toml b/crates/trippy-tui/Cargo.toml index 2134f2bd..e269c4b3 100644 --- a/crates/trippy-tui/Cargo.toml +++ b/crates/trippy-tui/Cargo.toml @@ -40,8 +40,8 @@ humantime.workspace = true itertools.workspace = true maxminddb.workspace = true petgraph.workspace = true +phf.workspace = true ratatui.workspace = true -rust-i18n.workspace = true serde = { workspace = true, default-features = false, features = [ "derive" ] } serde_json.workspace = true serde_with.workspace = true @@ -58,5 +58,9 @@ insta = { workspace = true, features = ["serde"] } pretty_assertions.workspace = true test-case.workspace = true +[build-dependencies] +phf_codegen.workspace = true +toml = { workspace = true, default-features = false, features = [ "parse" ] } + [lints] -workspace = true \ No newline at end of file +workspace = true diff --git a/crates/trippy-tui/build.rs b/crates/trippy-tui/build.rs new file mode 100644 index 00000000..13641e31 --- /dev/null +++ b/crates/trippy-tui/build.rs @@ -0,0 +1,29 @@ +fn main() { + generate_locales(); +} + +fn generate_locales() { + let path = std::path::Path::new(&std::env::var("OUT_DIR").unwrap()).join("locale_strings.rs"); + let mut map = phf_codegen::Map::new(); + let data: toml::Value = + toml::from_str(&std::fs::read_to_string("locales.toml").unwrap()).unwrap(); + data.as_table().unwrap().iter().for_each(|(key, t)| { + let mut key_map = phf_codegen::Map::new(); + t.as_table().unwrap().iter().for_each(|(lang, value)| { + key_map.entry(lang, &format!("{:?}", value.as_str().unwrap())); + }); + map.entry(key, &format!("{}", key_map.build())); + }); + + std::fs::write( + path, + format!( + " +#[allow(clippy::unreadable_literal)] +static STRINGS: phf::Map<&'static str, phf::Map<&'static str, &'static str>> = {}; +", + map.build() + ), + ) + .unwrap(); +} diff --git a/crates/trippy-tui/locales/app.toml b/crates/trippy-tui/locales.toml similarity index 99% rename from crates/trippy-tui/locales/app.toml rename to crates/trippy-tui/locales.toml index c68b0c45..d64ea45b 100644 --- a/crates/trippy-tui/locales/app.toml +++ b/crates/trippy-tui/locales.toml @@ -1,5 +1,3 @@ -_version = 2 - [trippy] en = "trippy" fr = "trippy" diff --git a/crates/trippy-tui/src/app.rs b/crates/trippy-tui/src/app.rs index 77a09ecd..fb6b9450 100644 --- a/crates/trippy-tui/src/app.rs +++ b/crates/trippy-tui/src/app.rs @@ -19,7 +19,7 @@ pub fn run_trippy(cfg: &TrippyConfig, pid: u16) -> anyhow::Result<()> { let locale = locale(); let _guard = configure_logging(cfg); let resolver = start_dns_resolver(cfg)?; - let geoip_lookup = create_geoip_lookup(cfg, &locale)?; + let geoip_lookup = create_geoip_lookup(cfg, locale)?; let addrs = resolve_targets(cfg, &resolver)?; if addrs.is_empty() { return Err(anyhow!( @@ -88,7 +88,7 @@ fn start_tracer( /// Run the TUI, stream or report. fn run_frontend( args: &TrippyConfig, - locale: String, + locale: &str, resolver: DnsResolver, geoip_lookup: GeoIpLookup, traces: Vec, @@ -96,7 +96,7 @@ fn run_frontend( match args.mode { Mode::Tui => frontend::run_frontend( traces, - make_tui_config(args, locale), + make_tui_config(args, locale.to_string()), resolver, geoip_lookup, )?, diff --git a/crates/trippy-tui/src/frontend/render/bar.rs b/crates/trippy-tui/src/frontend/render/bar.rs index a0899d4f..7ebcc413 100644 --- a/crates/trippy-tui/src/frontend/render/bar.rs +++ b/crates/trippy-tui/src/frontend/render/bar.rs @@ -13,20 +13,17 @@ use trippy_dns::ResolveMethod; pub fn render(f: &mut Frame<'_>, rect: Rect, app: &TuiApp) { let protocol = Span::raw(match app.tracer_config().data.protocol() { Protocol::Icmp => format!( - "{}/{}", + "{}/ICMP", fmt_target_family(app.tracer_config().data.target_addr()), - t!("ICMP"), ), Protocol::Udp => format!( - "{}/{}/{}", + "{}/UDP/{}", fmt_target_family(app.tracer_config().data.target_addr()), - t!("UDP"), app.tracer_config().data.multipath_strategy(), ), Protocol::Tcp => format!( - "{}/{}", + "{}/TCP", fmt_target_family(app.tracer_config().data.target_addr()), - t!("TCP"), ), }); diff --git a/crates/trippy-tui/src/frontend/render/settings.rs b/crates/trippy-tui/src/frontend/render/settings.rs index 49fa5e7c..739c002c 100644 --- a/crates/trippy-tui/src/frontend/render/settings.rs +++ b/crates/trippy-tui/src/frontend/render/settings.rs @@ -170,8 +170,7 @@ fn format_all_settings(app: &TuiApp) -> Vec<(String, String, Vec)> c = toggle_column, d = move_down, u = move_up - ) - .to_string(), + ), columns_settings, ), ] diff --git a/crates/trippy-tui/src/lib.rs b/crates/trippy-tui/src/lib.rs index 32835ab9..ff0955f2 100644 --- a/crates/trippy-tui/src/lib.rs +++ b/crates/trippy-tui/src/lib.rs @@ -20,9 +20,6 @@ mod print; mod report; mod util; -// initialize the i18n system. -rust_i18n::i18n!("locales", fallback = "en"); - /// Run the Trippy application. pub fn trippy() -> anyhow::Result<()> { let args = Args::parse(); diff --git a/crates/trippy-tui/src/locale.rs b/crates/trippy-tui/src/locale.rs index 5739fd0f..f0f42664 100644 --- a/crates/trippy-tui/src/locale.rs +++ b/crates/trippy-tui/src/locale.rs @@ -1,5 +1,16 @@ +use std::sync::{OnceLock, RwLock}; + const FALLBACK_LOCALE: &str = "en"; +static CURRENT_LOCALE: OnceLock> = OnceLock::new(); + +pub fn locale() -> &'static str { + &CURRENT_LOCALE + .get_or_init(|| RwLock::new(FALLBACK_LOCALE)) + .read() + .unwrap() +} + /// Set the locale for the application. /// /// If the given locale is `None` or unsupported, the system locale is tried. If the system locale @@ -7,74 +18,63 @@ const FALLBACK_LOCALE: &str = "en"; /// /// In both cases, the language part of the locale is used if the full locale is not supported. pub fn set_locale(locale: Option<&str>) { - if let Some(locale) = locale { - set_locale_inner(locale); - } else if let Some(locale) = sys_locale::get_locale().as_ref() { - set_locale_inner(locale); + // SAFETY: locale should be a very short string (`"zh"`, `"en-GB"`), that even if leaked does not matter in memory + // usage, and this function should only be called once per run. + let new_locale = if let Some(locale) = locale { + locale.to_string().leak() + } else if let Some(locale) = sys_locale::get_locale() { + locale.leak() } else { - set_locale_inner(FALLBACK_LOCALE); - } + FALLBACK_LOCALE + }; + *CURRENT_LOCALE + .get_or_init(|| RwLock::new(FALLBACK_LOCALE)) + .write() + .unwrap() = new_locale; } -/// Get the current locale. -pub fn locale() -> String { - rust_i18n::locale().to_string() -} - -/// Get all available locales. pub fn available_locales() -> Vec<&'static str> { - rust_i18n::available_locales!() + let mut locales: Vec<_> = STRINGS.get("trippy").unwrap().keys().copied().collect(); + locales.sort_unstable(); + locales } -fn set_locale_inner(locale: &str) { - let all_locales = rust_i18n::available_locales!(); - if all_locales.contains(&locale) { - rust_i18n::set_locale(locale); - } else { - let language = split_locale(locale); - if all_locales.contains(&language.as_str()) { - rust_i18n::set_locale(&language); - } else { - rust_i18n::set_locale(FALLBACK_LOCALE); - } +/// Like [`set_locale`], the language part of current locale is used if the full locale is not supported. +pub fn get_string(key: &str) -> &str { + let kt = STRINGS.get(key).unwrap(); + let locale = locale(); + if let Some(v) = kt.get(locale) { + v + } else if let Some(v) = kt.get(&locale[..2]) { + v + } else { + kt.get(FALLBACK_LOCALE).unwrap() } } -fn split_locale(locale: &str) -> String { - let mut parts = locale.split(['-', '_']); - parts - .next() - .map_or_else(|| FALLBACK_LOCALE, |lang| lang) - .to_string() -} - -// A macro for translating a text string. #[macro_export] macro_rules! t { - ($($all:tt)*) => { - rust_i18n::t!($($all)*) - } + ($key:expr) => { + std::borrow::Cow::Borrowed($crate::locale::get_string($key)) + }; + ($key:expr, $($kt:ident = $kv:expr),+) => { + { + let string = t!($key); + $( + let string = string.replace(concat!("%{", stringify!($kt), "}"), &$kv.to_string()); + )+ + string + } + }; + ($key:expr, $($kt:literal => $kv:expr),+) => { + { + let string = t!($key); + $( + let string = string.replace(concat!("%{", $kt, "}"), &$kv.to_string()); + )+ + string + } + }; } -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_split_locale_dash() { - let language = split_locale("en-US"); - assert_eq!(language, "en"); - } - - #[test] - fn test_split_locale_underscore() { - let language = split_locale("en_US"); - assert_eq!(language, "en"); - } - - #[test] - fn test_split_locale_no_region() { - let language = split_locale("en"); - assert_eq!(language, "en"); - } -} +include!(concat!(env!("OUT_DIR"), "/locale_strings.rs")); diff --git a/crates/trippy-tui/src/print.rs b/crates/trippy-tui/src/print.rs index ce14aa2c..d6bfed2d 100644 --- a/crates/trippy-tui/src/print.rs +++ b/crates/trippy-tui/src/print.rs @@ -2,7 +2,6 @@ use crate::config::{Args, TuiCommandItem, TuiThemeItem}; use crate::locale::available_locales; use clap::CommandFactory; use clap_complete::Shell; -use itertools::Itertools; use std::process; use strum::VariantNames; @@ -32,7 +31,7 @@ pub fn print_man_page() -> anyhow::Result<()> { } pub fn print_locales() { - println!("TUI locales: {}", available_locales().iter().join(", ")); + println!("TUI locales: {}", available_locales().join(", ")); process::exit(0); }