-
-
Notifications
You must be signed in to change notification settings - Fork 83
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(tui): replace rust-i18n with phf maps and simple replaces
- Loading branch information
Showing
11 changed files
with
162 additions
and
354 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} |
2 changes: 0 additions & 2 deletions
2
crates/trippy-tui/locales/app.toml → crates/trippy-tui/locales.toml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,3 @@ | ||
_version = 2 | ||
|
||
[trippy] | ||
en = "trippy" | ||
fr = "trippy" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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")); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters