feat: optimize backend i18n resource usage and improve language loading

This commit is contained in:
Tunglies
2025-09-30 15:22:08 +08:00
parent 1cd013fb94
commit 14288568bf
2 changed files with 38 additions and 28 deletions

View File

@@ -16,6 +16,7 @@
- 改进 macos 下系统代理设置的方法 - 改进 macos 下系统代理设置的方法
- 优化 TUN 模式可用性的判断 - 优化 TUN 模式可用性的判断
- 移除流媒体检测的系统级提示(使用软件内通知) - 移除流媒体检测的系统级提示(使用软件内通知)
- 优化后端 i18n 资源占用
### 🐞 修复问题 ### 🐞 修复问题

View File

@@ -1,7 +1,7 @@
use crate::{config::Config, utils::dirs}; use crate::{config::Config, utils::dirs};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use serde_json::Value; use serde_json::Value;
use std::{collections::HashMap, fs, path::PathBuf}; use std::{fs, path::PathBuf, sync::RwLock};
use sys_locale; use sys_locale;
const DEFAULT_LANGUAGE: &str = "zh"; const DEFAULT_LANGUAGE: &str = "zh";
@@ -33,22 +33,20 @@ pub fn get_supported_languages() -> Vec<String> {
languages languages
} }
static TRANSLATIONS: Lazy<HashMap<String, Value>> = Lazy::new(|| { static TRANSLATIONS: Lazy<RwLock<(String, Value)>> = Lazy::new(|| {
let mut translations = HashMap::new(); let lang = get_system_language();
let json = load_lang_file(&lang).unwrap_or_else(|| Value::Object(Default::default()));
if let Some(locales_dir) = get_locales_dir() { RwLock::new((lang, json))
for lang in get_supported_languages() {
let file_path = locales_dir.join(format!("{lang}.json"));
if let Ok(content) = fs::read_to_string(file_path)
&& let Ok(json) = serde_json::from_str(&content)
{
translations.insert(lang.to_string(), json);
}
}
}
translations
}); });
fn load_lang_file(lang: &str) -> Option<Value> {
let locales_dir = get_locales_dir()?;
let file_path = locales_dir.join(format!("{lang}.json"));
fs::read_to_string(file_path)
.ok()
.and_then(|content| serde_json::from_str(&content).ok())
}
fn get_system_language() -> String { fn get_system_language() -> String {
sys_locale::get_locale() sys_locale::get_locale()
.map(|locale| locale.to_lowercase()) .map(|locale| locale.to_lowercase())
@@ -58,8 +56,6 @@ fn get_system_language() -> String {
} }
pub async fn t(key: &str) -> String { pub async fn t(key: &str) -> String {
let key = key.to_string(); // own the string
let current_lang = Config::verge() let current_lang = Config::verge()
.await .await
.latest_ref() .latest_ref()
@@ -68,22 +64,35 @@ pub async fn t(key: &str) -> String {
.map(String::from) .map(String::from)
.unwrap_or_else(get_system_language); .unwrap_or_else(get_system_language);
if let Some(text) = TRANSLATIONS
.get(&current_lang)
.and_then(|trans| trans.get(&key))
.and_then(|val| val.as_str())
{ {
return text.to_string(); if let Ok(cache) = TRANSLATIONS.read()
&& cache.0 == current_lang
&& let Some(text) = cache.1.get(key).and_then(|val| val.as_str())
{
return text.to_string();
}
}
if let Some(new_json) = load_lang_file(&current_lang)
&& let Ok(mut cache) = TRANSLATIONS.write()
{
*cache = (current_lang.clone(), new_json);
if let Some(text) = cache.1.get(key).and_then(|val| val.as_str()) {
return text.to_string();
}
} }
if current_lang != DEFAULT_LANGUAGE if current_lang != DEFAULT_LANGUAGE
&& let Some(text) = TRANSLATIONS && let Some(default_json) = load_lang_file(DEFAULT_LANGUAGE)
.get(DEFAULT_LANGUAGE) && let Ok(mut cache) = TRANSLATIONS.write()
.and_then(|trans| trans.get(&key))
.and_then(|val| val.as_str())
{ {
return text.to_string(); *cache = (DEFAULT_LANGUAGE.to_string(), default_json);
if let Some(text) = cache.1.get(key).and_then(|val| val.as_str()) {
return text.to_string();
}
} }
key key.to_string()
} }