Skip to content

Commit

Permalink
refactor(tui): replace rust-i18n with phf maps and simple replaces
Browse files Browse the repository at this point in the history
  • Loading branch information
nc7s committed Dec 13, 2024
1 parent 98f3f8e commit 5270cc8
Show file tree
Hide file tree
Showing 11 changed files with 162 additions and 354 deletions.
334 changes: 59 additions & 275 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
Expand Down
8 changes: 6 additions & 2 deletions crates/trippy-tui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
workspace = true
29 changes: 29 additions & 0 deletions crates/trippy-tui/build.rs
Original file line number Diff line number Diff line change
@@ -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();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
_version = 2

[trippy]
en = "trippy"
fr = "trippy"
Expand Down
6 changes: 3 additions & 3 deletions crates/trippy-tui/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(
Expand Down Expand Up @@ -88,15 +88,15 @@ 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<TraceInfo>,
) -> anyhow::Result<()> {
match args.mode {
Mode::Tui => frontend::run_frontend(
traces,
make_tui_config(args, locale),
make_tui_config(args, locale.to_string()),
resolver,
geoip_lookup,
)?,
Expand Down
9 changes: 3 additions & 6 deletions crates/trippy-tui/src/frontend/render/bar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
),
});

Expand Down
3 changes: 1 addition & 2 deletions crates/trippy-tui/src/frontend/render/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,7 @@ fn format_all_settings(app: &TuiApp) -> Vec<(String, String, Vec<SettingsItem>)>
c = toggle_column,
d = move_down,
u = move_up
)
.to_string(),
),
columns_settings,
),
]
Expand Down
3 changes: 0 additions & 3 deletions crates/trippy-tui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
116 changes: 58 additions & 58 deletions crates/trippy-tui/src/locale.rs
Original file line number Diff line number Diff line change
@@ -1,80 +1,80 @@
use std::sync::{OnceLock, RwLock};

const FALLBACK_LOCALE: &str = "en";

static CURRENT_LOCALE: OnceLock<RwLock<&str>> = 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
/// is not supported, the fallback locale is used.
///
/// 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"));
3 changes: 1 addition & 2 deletions crates/trippy-tui/src/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
}

Expand Down

0 comments on commit 5270cc8

Please sign in to comment.