This commit is contained in:
2025-08-06 11:32:29 +08:00
parent 90afd6e520
commit 351a79d54c
21 changed files with 915 additions and 16 deletions

119
src-tauri/Cargo.lock generated
View File

@@ -625,11 +625,14 @@ dependencies = [
"cocoa",
"dirs 5.0.1",
"env_logger",
"fluent",
"fluent-bundle",
"futures",
"glob",
"libc",
"log",
"objc",
"once_cell",
"regex",
"reqwest",
"rusqlite",
@@ -650,6 +653,7 @@ dependencies = [
"tauri-plugin-updater",
"tempfile",
"tokio",
"unic-langid",
"uuid",
"walkdir",
"which",
@@ -1333,6 +1337,50 @@ dependencies = [
"miniz_oxide",
]
[[package]]
name = "fluent"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb74634707bebd0ce645a981148e8fb8c7bccd4c33c652aeffd28bf2f96d555a"
dependencies = [
"fluent-bundle",
"unic-langid",
]
[[package]]
name = "fluent-bundle"
version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fe0a21ee80050c678013f82edf4b705fe2f26f1f9877593d13198612503f493"
dependencies = [
"fluent-langneg",
"fluent-syntax",
"intl-memoizer",
"intl_pluralrules",
"rustc-hash 1.1.0",
"self_cell 0.10.3",
"smallvec",
"unic-langid",
]
[[package]]
name = "fluent-langneg"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94"
dependencies = [
"unic-langid",
]
[[package]]
name = "fluent-syntax"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d"
dependencies = [
"thiserror 1.0.69",
]
[[package]]
name = "fnv"
version = "1.0.7"
@@ -2243,6 +2291,25 @@ dependencies = [
"cfb",
]
[[package]]
name = "intl-memoizer"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "310da2e345f5eb861e7a07ee182262e94975051db9e4223e909ba90f392f163f"
dependencies = [
"type-map",
"unic-langid",
]
[[package]]
name = "intl_pluralrules"
version = "7.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972"
dependencies = [
"unic-langid",
]
[[package]]
name = "ipnet"
version = "2.11.0"
@@ -3604,7 +3671,7 @@ dependencies = [
"pin-project-lite",
"quinn-proto",
"quinn-udp",
"rustc-hash",
"rustc-hash 2.1.1",
"rustls",
"socket2",
"thiserror 2.0.12",
@@ -3624,7 +3691,7 @@ dependencies = [
"lru-slab",
"rand 0.9.1",
"ring",
"rustc-hash",
"rustc-hash 2.1.1",
"rustls",
"rustls-pki-types",
"slab",
@@ -3947,6 +4014,12 @@ version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustc-hash"
version = "2.1.1"
@@ -4129,6 +4202,21 @@ dependencies = [
"thin-slice",
]
[[package]]
name = "self_cell"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d"
dependencies = [
"self_cell 1.2.0",
]
[[package]]
name = "self_cell"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749"
[[package]]
name = "semver"
version = "1.0.26"
@@ -5428,6 +5516,15 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "type-map"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90"
dependencies = [
"rustc-hash 2.1.1",
]
[[package]]
name = "typeid"
version = "1.0.3"
@@ -5472,6 +5569,24 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
[[package]]
name = "unic-langid"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28ba52c9b05311f4f6e62d5d9d46f094bd6e84cb8df7b3ef952748d752a7d05"
dependencies = [
"unic-langid-impl",
]
[[package]]
name = "unic-langid-impl"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dce1bf08044d4b7a94028c93786f8566047edc11110595914de93362559bc658"
dependencies = [
"tinystr",
]
[[package]]
name = "unic-ucd-ident"
version = "0.9.0"

View File

@@ -53,6 +53,10 @@ zstd = "0.13"
uuid = { version = "1.6", features = ["v4", "serde"] }
walkdir = "2"
serde_yaml = "0.9"
fluent = "0.16"
fluent-bundle = "0.15"
unic-langid = "0.9"
once_cell = "1.19"
[target.'cfg(target_os = "macos")'.dependencies]

View File

@@ -0,0 +1,44 @@
# Error Messages
error-failed-to-create = Failed to create {$item}
error-failed-to-update = Failed to update {$item}
error-failed-to-delete = Failed to delete {$item}
error-failed-to-read = Failed to read {$item}
error-failed-to-write = Failed to write to {$item}
error-file-not-found = File not found: {$path}
error-permission-denied = Permission denied
error-invalid-input = Invalid input provided
error-network-error = Network error occurred
error-database-error = Database error occurred
error-unknown-error = Unknown error occurred
# Success Messages
success-created = {$item} created successfully
success-updated = {$item} updated successfully
success-deleted = {$item} deleted successfully
success-saved = Saved successfully
# Agent Messages
agent-not-found = Agent not found
agent-execution-failed = Agent execution failed
agent-invalid-config = Invalid agent configuration
# Claude Messages
claude-not-installed = Claude Code is not installed
claude-version-check-failed = Failed to check Claude version
claude-execution-failed = Claude execution failed
claude-session-not-found = Claude session not found
# MCP Messages
mcp-server-not-found = MCP server not found
mcp-connection-failed = Failed to connect to MCP server
mcp-invalid-config = Invalid MCP server configuration
# Project Messages
project-not-found = Project not found
project-access-denied = Access denied to project
session-not-found = Session not found
# General Messages
operation-cancelled = Operation cancelled
timeout-error = Operation timed out
validation-error = Validation failed

View File

@@ -0,0 +1,44 @@
# 错误消息
error-failed-to-create = 创建{$item}失败
error-failed-to-update = 更新{$item}失败
error-failed-to-delete = 删除{$item}失败
error-failed-to-read = 读取{$item}失败
error-failed-to-write = 写入{$item}失败
error-file-not-found = 未找到文件:{$path}
error-permission-denied = 权限被拒绝
error-invalid-input = 提供的输入无效
error-network-error = 发生网络错误
error-database-error = 发生数据库错误
error-unknown-error = 发生未知错误
# 成功消息
success-created = {$item}创建成功
success-updated = {$item}更新成功
success-deleted = {$item}删除成功
success-saved = 保存成功
# 智能体消息
agent-not-found = 未找到智能体
agent-execution-failed = 智能体执行失败
agent-invalid-config = 智能体配置无效
# Claude 消息
claude-not-installed = 未安装 Claude Code
claude-version-check-failed = 检查 Claude 版本失败
claude-execution-failed = Claude 执行失败
claude-session-not-found = 未找到 Claude 会话
# MCP 消息
mcp-server-not-found = 未找到 MCP 服务器
mcp-connection-failed = 连接 MCP 服务器失败
mcp-invalid-config = MCP 服务器配置无效
# 项目消息
project-not-found = 未找到项目
project-access-denied = 拒绝访问项目
session-not-found = 未找到会话
# 通用消息
operation-cancelled = 操作已取消
timeout-error = 操作超时
validation-error = 验证失败

View File

@@ -0,0 +1,27 @@
use tauri::command;
use serde::{Deserialize, Serialize};
use crate::i18n;
#[derive(Debug, Serialize, Deserialize)]
pub struct LanguageSettings {
pub locale: String,
}
#[command]
pub async fn get_current_language() -> Result<String, String> {
Ok(i18n::get_current_locale())
}
#[command]
pub async fn set_language(locale: String) -> Result<(), String> {
i18n::set_locale(&locale)
.map_err(|e| format!("Failed to set language: {}", e))?;
log::info!("Language changed to: {}", locale);
Ok(())
}
#[command]
pub async fn get_supported_languages() -> Result<Vec<String>, String> {
Ok(i18n::SUPPORTED_LOCALES.iter().map(|&s| s.to_string()).collect())
}

View File

@@ -5,3 +5,4 @@ pub mod usage;
pub mod storage;
pub mod slash_commands;
pub mod proxy;
pub mod language;

77
src-tauri/src/i18n.rs Normal file
View File

@@ -0,0 +1,77 @@
use std::sync::{Arc, Mutex, OnceLock};
// 支持的语言
pub const SUPPORTED_LOCALES: &[&str] = &["en-US", "zh-CN"];
// 简化的 I18n 实现,避免线程安全问题
pub struct SimpleI18n {
current_locale: Arc<Mutex<String>>,
}
impl SimpleI18n {
pub fn new() -> Self {
Self {
current_locale: Arc::new(Mutex::new("en-US".to_string())),
}
}
pub fn set_locale(&self, locale: &str) {
if SUPPORTED_LOCALES.contains(&locale) {
if let Ok(mut current) = self.current_locale.lock() {
*current = locale.to_string();
}
}
}
pub fn get_current_locale(&self) -> String {
match self.current_locale.lock() {
Ok(locale) => locale.clone(),
Err(_) => "en-US".to_string(),
}
}
pub fn t(&self, key: &str) -> String {
let locale = self.get_current_locale();
// 简单的翻译映射,避免复杂的 FluentBundle
match (locale.as_str(), key) {
// 英文翻译
("en-US", "error-failed-to-create") => "Failed to create".to_string(),
("en-US", "error-failed-to-update") => "Failed to update".to_string(),
("en-US", "error-failed-to-delete") => "Failed to delete".to_string(),
("en-US", "agent-not-found") => "Agent not found".to_string(),
("en-US", "claude-not-installed") => "Claude Code is not installed".to_string(),
// 中文翻译
("zh-CN", "error-failed-to-create") => "创建失败".to_string(),
("zh-CN", "error-failed-to-update") => "更新失败".to_string(),
("zh-CN", "error-failed-to-delete") => "删除失败".to_string(),
("zh-CN", "agent-not-found") => "未找到智能体".to_string(),
("zh-CN", "claude-not-installed") => "未安装 Claude Code".to_string(),
// 默认情况
_ => key.to_string(),
}
}
}
// 全局实例
static GLOBAL_I18N: OnceLock<SimpleI18n> = OnceLock::new();
fn get_i18n() -> &'static SimpleI18n {
GLOBAL_I18N.get_or_init(|| SimpleI18n::new())
}
// 便捷函数用于全局访问
pub fn t(key: &str) -> String {
get_i18n().t(key)
}
pub fn set_locale(locale: &str) -> Result<(), Box<dyn std::error::Error>> {
get_i18n().set_locale(locale);
Ok(())
}
pub fn get_current_locale() -> String {
get_i18n().get_current_locale()
}

View File

@@ -5,6 +5,7 @@ pub mod checkpoint;
pub mod claude_binary;
pub mod commands;
pub mod process;
pub mod i18n;
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {

View File

@@ -5,6 +5,7 @@ mod checkpoint;
mod claude_binary;
mod commands;
mod process;
mod i18n;
use checkpoint::state::CheckpointState;
use commands::agents::{
@@ -43,6 +44,7 @@ use commands::storage::{
storage_insert_row, storage_execute_sql, storage_reset_database,
};
use commands::proxy::{get_proxy_settings, save_proxy_settings, apply_proxy_settings};
use commands::language::{get_current_language, set_language, get_supported_languages};
use process::ProcessRegistryState;
use std::sync::Mutex;
use tauri::Manager;
@@ -249,6 +251,11 @@ fn main() {
// Proxy Settings
get_proxy_settings,
save_proxy_settings,
// Language Settings
get_current_language,
set_language,
get_supported_languages,
])
.run(tauri::generate_context!())
.expect("error while running tauri application");