diff --git a/scripts/check.mjs b/scripts/check.mjs index 54ec19c2..b1d4da30 100644 --- a/scripts/check.mjs +++ b/scripts/check.mjs @@ -398,6 +398,34 @@ const resolveServicePermission = async () => { } }; +// 在 resolveResource 函数后添加新函数 +async function resolveLocales() { + const srcLocalesDir = path.join(cwd, "src/locales"); + const targetLocalesDir = path.join(cwd, "src-tauri/resources/locales"); + + try { + // 确保目标目录存在 + await fsp.mkdir(targetLocalesDir, { recursive: true }); + + // 读取所有语言文件 + const files = await fsp.readdir(srcLocalesDir); + + // 复制每个文件 + for (const file of files) { + const srcPath = path.join(srcLocalesDir, file); + const targetPath = path.join(targetLocalesDir, file); + + await fsp.copyFile(srcPath, targetPath); + log_success(`Copied locale file: ${file}`); + } + + log_success("All locale files copied successfully"); + } catch (err) { + log_error("Error copying locale files:", err.message); + throw err; + } +} + /** * main */ @@ -509,6 +537,11 @@ const tasks = [ retry: 5, macosOnly: true, }, + { + name: "locales", + func: resolveLocales, + retry: 2, + }, ]; async function runTask() { diff --git a/src-tauri/src/utils/i18n.rs b/src-tauri/src/utils/i18n.rs index 0e0999a0..088c0ac4 100644 --- a/src-tauri/src/utils/i18n.rs +++ b/src-tauri/src/utils/i18n.rs @@ -1,81 +1,88 @@ use crate::config::Config; +use crate::utils::dirs; use once_cell::sync::Lazy; use serde_json::Value; -use std::{collections::HashMap, fs, path::Path}; +use std::{collections::HashMap, fs, path::PathBuf}; use sys_locale; +const DEFAULT_LANGUAGE: &str = "zh"; + +fn get_locales_dir() -> Option { + dirs::app_resources_dir() + .map(|resource_path| resource_path.join("locales")) + .ok() +} + pub fn get_supported_languages() -> Vec { - let project_dir = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap(); - let locales_dir = project_dir.join("src/locales"); let mut languages = Vec::new(); - if let Ok(entries) = fs::read_dir(locales_dir) { - for entry in entries.flatten() { - if let Some(file_name) = entry.file_name().to_str() { - if let Some(lang) = file_name.strip_suffix(".json") { - languages.push(lang.to_string()); + if let Some(locales_dir) = get_locales_dir() { + if let Ok(entries) = fs::read_dir(locales_dir) { + for entry in entries.flatten() { + if let Some(file_name) = entry.file_name().to_str() { + if let Some(lang) = file_name.strip_suffix(".json") { + languages.push(lang.to_string()); + } } } } } + + if languages.is_empty() { + languages.push(DEFAULT_LANGUAGE.to_string()); + } languages } static TRANSLATIONS: Lazy> = Lazy::new(|| { - let project_dir = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap(); - let locales_dir = project_dir.join("src/locales"); let mut translations = HashMap::new(); - for lang in get_supported_languages() { - let file_path = locales_dir.join(format!("{}.json", lang)); - if let Ok(content) = fs::read_to_string(file_path) { - if let Ok(json) = serde_json::from_str(&content) { - translations.insert(lang.to_string(), json); + if let Some(locales_dir) = get_locales_dir() { + for lang in get_supported_languages() { + let file_path = locales_dir.join(format!("{}.json", lang)); + if let Ok(content) = fs::read_to_string(file_path) { + if let Ok(json) = serde_json::from_str(&content) { + translations.insert(lang.to_string(), json); + } } } } translations }); -pub fn t(key: &str) -> String { - let config = Config::verge(); - let verge = config.latest(); - let current_lang = verge - .language - .as_ref() - .map_or_else(|| get_system_language(), |lang| lang.to_string()); +fn get_system_language() -> String { + sys_locale::get_locale() + .map(|locale| locale.to_lowercase()) + .and_then(|locale| locale.split(['_', '-']).next().map(String::from)) + .filter(|lang| get_supported_languages().contains(lang)) + .unwrap_or_else(|| DEFAULT_LANGUAGE.to_string()) +} - if let Some(translations) = TRANSLATIONS.get(¤t_lang) { - if let Some(text) = translations.get(key) { - if let Some(text) = text.as_str() { - return text.to_string(); - } - } +pub fn t(key: &str) -> String { + let current_lang = Config::verge() + .latest() + .language + .as_deref() + .map(String::from) + .unwrap_or_else(get_system_language); + + if let Some(text) = TRANSLATIONS + .get(¤t_lang) + .and_then(|trans| trans.get(key)) + .and_then(|val| val.as_str()) + { + return text.to_string(); } - // Fallback to Chinese - if let Some(translations) = TRANSLATIONS.get("zh") { - if let Some(text) = translations.get(key) { - if let Some(text) = text.as_str() { - return text.to_string(); - } + if current_lang != DEFAULT_LANGUAGE { + if let Some(text) = TRANSLATIONS + .get(DEFAULT_LANGUAGE) + .and_then(|trans| trans.get(key)) + .and_then(|val| val.as_str()) + { + return text.to_string(); } } key.to_string() } - -fn get_system_language() -> String { - let sys_lang = sys_locale::get_locale() - .unwrap_or_else(|| String::from("zh")) - .to_lowercase(); - - let lang_code = sys_lang.split(['_', '-']).next().unwrap_or("zh"); - let supported_languages = get_supported_languages(); - - if supported_languages.contains(&lang_code.to_string()) { - lang_code.to_string() - } else { - String::from("zh") - } -} diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 865809f6..11bd1819 100755 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -10,7 +10,7 @@ "icons/icon.icns", "icons/icon.ico" ], - "resources": ["resources"], + "resources": ["resources", "resources/locales/*"], "publisher": "Clash Verge Rev", "externalBin": ["sidecar/verge-mihomo", "sidecar/verge-mihomo-alpha"], "copyright": "GNU General Public License v3.0", diff --git a/src-tauri/tauri.macos.conf.json b/src-tauri/tauri.macos.conf.json index cbe488e1..809e86c0 100644 --- a/src-tauri/tauri.macos.conf.json +++ b/src-tauri/tauri.macos.conf.json @@ -3,7 +3,6 @@ "identifier": "io.github.clash-verge-rev.clash-verge-rev", "bundle": { "targets": ["app", "dmg"], - "resources": ["resources"], "macOS": { "frameworks": [], "minimumSystemVersion": "10.15",