i18n: interface translations are looked up by hash, not by scanning the catalog (#398)
tr() scanned the whole catalog (about 380 rows) for every string a panel draws, every frame, in Chinese. Each catalog is now indexed once, on first use, in a HashMap keyed by the English source; English and languages without rows still skip the lookup. The catalogs already have no duplicate sources (catalogs_are_unique_and_keep_the_english_shape), so the index finds the same rows. Test: the i18n tests (pass-through, tr_args, catalog shape). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
4fad3e7af4
commit
ea5dfae95f
|
|
@ -14,7 +14,9 @@
|
|||
//! drop a value, and `tr_args` itself cannot panic.
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
thread_local! {
|
||||
/// The resolved interface language ("en", "ja", "zh-hans", "zh-hant"); "en" until the first
|
||||
|
|
@ -33,18 +35,24 @@ pub(crate) fn current() -> &'static str {
|
|||
CURRENT.with(Cell::get)
|
||||
}
|
||||
|
||||
/// The catalog for `language`: empty for English and for any language that has no rows yet.
|
||||
fn catalog(language: &str) -> &'static [(&'static str, &'static str)] {
|
||||
match language {
|
||||
"zh-hans" => SIMPLIFIED_CHINESE,
|
||||
"zh-hant" => TRADITIONAL_CHINESE,
|
||||
_ => &[],
|
||||
}
|
||||
type Index = HashMap<&'static str, &'static str>;
|
||||
|
||||
/// The catalog for `language`, indexed by English source (built on first use: panels translate
|
||||
/// hundreds of strings a frame); `None` for English and any language that has no rows yet.
|
||||
fn catalog(language: &str) -> Option<&'static Index> {
|
||||
static HANS: OnceLock<Index> = OnceLock::new();
|
||||
static HANT: OnceLock<Index> = OnceLock::new();
|
||||
let (index, rows) = match language {
|
||||
"zh-hans" => (&HANS, SIMPLIFIED_CHINESE),
|
||||
"zh-hant" => (&HANT, TRADITIONAL_CHINESE),
|
||||
_ => return None,
|
||||
};
|
||||
Some(index.get_or_init(|| rows.iter().copied().collect()))
|
||||
}
|
||||
|
||||
/// Translate one interface string: the current language's row for `text`, or `text` itself.
|
||||
pub(crate) fn tr(text: &str) -> &str {
|
||||
catalog(current()).iter().find(|(en, _)| *en == text).map_or(text, |(_, translated)| *translated)
|
||||
catalog(current()).and_then(|c| c.get(text)).copied().unwrap_or(text)
|
||||
}
|
||||
|
||||
/// Translate an interface string that carries values: each `{}` takes the next argument. A missing
|
||||
|
|
|
|||
Loading…
Reference in New Issue