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

View File

@@ -33,11 +33,14 @@
"diff": "^8.0.2", "diff": "^8.0.2",
"framer-motion": "^12.0.0-alpha.1", "framer-motion": "^12.0.0-alpha.1",
"html2canvas": "^1.4.1", "html2canvas": "^1.4.1",
"i18next": "^25.3.2",
"i18next-browser-languagedetector": "^8.2.0",
"lucide-react": "^0.468.0", "lucide-react": "^0.468.0",
"posthog-js": "^1.258.3", "posthog-js": "^1.258.3",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-hook-form": "^7.54.2", "react-hook-form": "^7.54.2",
"react-i18next": "^15.6.1",
"react-markdown": "^9.0.3", "react-markdown": "^9.0.3",
"react-syntax-highlighter": "^15.6.1", "react-syntax-highlighter": "^15.6.1",
"recharts": "^2.14.1", "recharts": "^2.14.1",
@@ -677,12 +680,18 @@
"highlightjs-vue": ["highlightjs-vue@1.0.0", "", {}, "sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA=="], "highlightjs-vue": ["highlightjs-vue@1.0.0", "", {}, "sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA=="],
"html-parse-stringify": ["html-parse-stringify@3.0.1", "https://registry.npmmirror.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", { "dependencies": { "void-elements": "3.1.0" } }, "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg=="],
"html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="], "html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="],
"html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="], "html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="],
"html2canvas": ["html2canvas@1.4.1", "", { "dependencies": { "css-line-break": "^2.1.0", "text-segmentation": "^1.0.3" } }, "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA=="], "html2canvas": ["html2canvas@1.4.1", "", { "dependencies": { "css-line-break": "^2.1.0", "text-segmentation": "^1.0.3" } }, "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA=="],
"i18next": ["i18next@25.3.2", "https://registry.npmmirror.com/i18next/-/i18next-25.3.2.tgz", { "dependencies": { "@babel/runtime": "^7.27.6" }, "peerDependencies": { "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-JSnbZDxRVbphc5jiptxr3o2zocy5dEqpVm9qCGdJwRNO+9saUJS0/u4LnM/13C23fUEWxAylPqKU/NpMV/IjqA=="],
"i18next-browser-languagedetector": ["i18next-browser-languagedetector@8.2.0", "https://registry.npmmirror.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.2.0.tgz", { "dependencies": { "@babel/runtime": "^7.23.2" } }, "sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g=="],
"inline-style-parser": ["inline-style-parser@0.2.4", "", {}, "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q=="], "inline-style-parser": ["inline-style-parser@0.2.4", "", {}, "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q=="],
"internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="], "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="],
@@ -891,6 +900,8 @@
"react-hook-form": ["react-hook-form@7.58.1", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-Lml/KZYEEFfPhUVgE0RdCVpnC4yhW+PndRhbiTtdvSlQTL8IfVR+iQkBjLIvmmc6+GGoVeM11z37ktKFPAb0FA=="], "react-hook-form": ["react-hook-form@7.58.1", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-Lml/KZYEEFfPhUVgE0RdCVpnC4yhW+PndRhbiTtdvSlQTL8IfVR+iQkBjLIvmmc6+GGoVeM11z37ktKFPAb0FA=="],
"react-i18next": ["react-i18next@15.6.1", "https://registry.npmmirror.com/react-i18next/-/react-i18next-15.6.1.tgz", { "dependencies": { "@babel/runtime": "^7.27.6", "html-parse-stringify": "^3.0.1" }, "peerDependencies": { "i18next": ">= 23.2.3", "react": ">= 16.8.0", "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-uGrzSsOUUe2sDBG/+FJq2J1MM+Y4368/QW8OLEKSFvnDflHBbZhSd1u3UkW0Z06rMhZmnB/AQrhCpYfE5/5XNg=="],
"react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], "react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
"react-markdown": ["react-markdown@9.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "html-url-attributes": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" }, "peerDependencies": { "@types/react": ">=18", "react": ">=18" } }, "sha512-xaijuJB0kzGiUdG7nc2MOMDUDBWPyGAjZtUrow9XxUeua8IqeP+VlIfAZ3bphpcLTnSZXz6z9jcVC/TCwbfgdw=="], "react-markdown": ["react-markdown@9.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "html-url-attributes": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" }, "peerDependencies": { "@types/react": ">=18", "react": ">=18" } }, "sha512-xaijuJB0kzGiUdG7nc2MOMDUDBWPyGAjZtUrow9XxUeua8IqeP+VlIfAZ3bphpcLTnSZXz6z9jcVC/TCwbfgdw=="],
@@ -1023,6 +1034,8 @@
"vite": ["vite@6.3.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ=="], "vite": ["vite@6.3.5", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ=="],
"void-elements": ["void-elements@3.1.0", "https://registry.npmmirror.com/void-elements/-/void-elements-3.1.0.tgz", {}, "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w=="],
"web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="], "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="],
"web-vitals": ["web-vitals@4.2.4", "", {}, "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw=="], "web-vitals": ["web-vitals@4.2.4", "", {}, "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw=="],

View File

@@ -41,11 +41,14 @@
"diff": "^8.0.2", "diff": "^8.0.2",
"framer-motion": "^12.0.0-alpha.1", "framer-motion": "^12.0.0-alpha.1",
"html2canvas": "^1.4.1", "html2canvas": "^1.4.1",
"i18next": "^25.3.2",
"i18next-browser-languagedetector": "^8.2.0",
"lucide-react": "^0.468.0", "lucide-react": "^0.468.0",
"posthog-js": "^1.258.3", "posthog-js": "^1.258.3",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-hook-form": "^7.54.2", "react-hook-form": "^7.54.2",
"react-i18next": "^15.6.1",
"react-markdown": "^9.0.3", "react-markdown": "^9.0.3",
"react-syntax-highlighter": "^15.6.1", "react-syntax-highlighter": "^15.6.1",
"recharts": "^2.14.1", "recharts": "^2.14.1",

119
src-tauri/Cargo.lock generated
View File

@@ -625,11 +625,14 @@ dependencies = [
"cocoa", "cocoa",
"dirs 5.0.1", "dirs 5.0.1",
"env_logger", "env_logger",
"fluent",
"fluent-bundle",
"futures", "futures",
"glob", "glob",
"libc", "libc",
"log", "log",
"objc", "objc",
"once_cell",
"regex", "regex",
"reqwest", "reqwest",
"rusqlite", "rusqlite",
@@ -650,6 +653,7 @@ dependencies = [
"tauri-plugin-updater", "tauri-plugin-updater",
"tempfile", "tempfile",
"tokio", "tokio",
"unic-langid",
"uuid", "uuid",
"walkdir", "walkdir",
"which", "which",
@@ -1333,6 +1337,50 @@ dependencies = [
"miniz_oxide", "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]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
@@ -2243,6 +2291,25 @@ dependencies = [
"cfb", "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]] [[package]]
name = "ipnet" name = "ipnet"
version = "2.11.0" version = "2.11.0"
@@ -3604,7 +3671,7 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
"quinn-proto", "quinn-proto",
"quinn-udp", "quinn-udp",
"rustc-hash", "rustc-hash 2.1.1",
"rustls", "rustls",
"socket2", "socket2",
"thiserror 2.0.12", "thiserror 2.0.12",
@@ -3624,7 +3691,7 @@ dependencies = [
"lru-slab", "lru-slab",
"rand 0.9.1", "rand 0.9.1",
"ring", "ring",
"rustc-hash", "rustc-hash 2.1.1",
"rustls", "rustls",
"rustls-pki-types", "rustls-pki-types",
"slab", "slab",
@@ -3947,6 +4014,12 @@ version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]] [[package]]
name = "rustc-hash" name = "rustc-hash"
version = "2.1.1" version = "2.1.1"
@@ -4129,6 +4202,21 @@ dependencies = [
"thin-slice", "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]] [[package]]
name = "semver" name = "semver"
version = "1.0.26" version = "1.0.26"
@@ -5428,6 +5516,15 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 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]] [[package]]
name = "typeid" name = "typeid"
version = "1.0.3" version = "1.0.3"
@@ -5472,6 +5569,24 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" 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]] [[package]]
name = "unic-ucd-ident" name = "unic-ucd-ident"
version = "0.9.0" version = "0.9.0"

View File

@@ -53,6 +53,10 @@ zstd = "0.13"
uuid = { version = "1.6", features = ["v4", "serde"] } uuid = { version = "1.6", features = ["v4", "serde"] }
walkdir = "2" walkdir = "2"
serde_yaml = "0.9" 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] [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 storage;
pub mod slash_commands; pub mod slash_commands;
pub mod proxy; 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 claude_binary;
pub mod commands; pub mod commands;
pub mod process; pub mod process;
pub mod i18n;
#[cfg_attr(mobile, tauri::mobile_entry_point)] #[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() { pub fn run() {

View File

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

View File

@@ -5,6 +5,7 @@ import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { Toast, ToastContainer } from "@/components/ui/toast"; import { Toast, ToastContainer } from "@/components/ui/toast";
import { useTranslation } from "@/hooks/useTranslation";
import { api, type Agent } from "@/lib/api"; import { api, type Agent } from "@/lib/api";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import MDEditor from "@uiw/react-md-editor"; import MDEditor from "@uiw/react-md-editor";
@@ -43,6 +44,7 @@ export const CreateAgent: React.FC<CreateAgentProps> = ({
onAgentCreated, onAgentCreated,
className, className,
}) => { }) => {
const { t } = useTranslation();
const [name, setName] = useState(agent?.name || ""); const [name, setName] = useState(agent?.name || "");
const [selectedIcon, setSelectedIcon] = useState<AgentIconName>((agent?.icon as AgentIconName) || "bot"); const [selectedIcon, setSelectedIcon] = useState<AgentIconName>((agent?.icon as AgentIconName) || "bot");
const [systemPrompt, setSystemPrompt] = useState(agent?.system_prompt || ""); const [systemPrompt, setSystemPrompt] = useState(agent?.system_prompt || "");
@@ -92,9 +94,9 @@ export const CreateAgent: React.FC<CreateAgentProps> = ({
onAgentCreated(); onAgentCreated();
} catch (err) { } catch (err) {
console.error("Failed to save agent:", err); console.error("Failed to save agent:", err);
setError(isEditMode ? "Failed to update agent" : "Failed to create agent"); setError(isEditMode ? t('agents.updateFailed') : t('agents.createFailed'));
setToast({ setToast({
message: isEditMode ? "Failed to update agent" : "Failed to create agent", message: isEditMode ? t('agents.updateFailed') : t('agents.createFailed'),
type: "error" type: "error"
}); });
} finally { } finally {
@@ -108,7 +110,7 @@ export const CreateAgent: React.FC<CreateAgentProps> = ({
systemPrompt !== (agent?.system_prompt || "") || systemPrompt !== (agent?.system_prompt || "") ||
defaultTask !== (agent?.default_task || "") || defaultTask !== (agent?.default_task || "") ||
model !== (agent?.model || "sonnet")) && model !== (agent?.model || "sonnet")) &&
!confirm("You have unsaved changes. Are you sure you want to leave?")) { !confirm(t('messages.unsavedChanges'))) {
return; return;
} }
onBack(); onBack();
@@ -135,10 +137,10 @@ export const CreateAgent: React.FC<CreateAgentProps> = ({
</Button> </Button>
<div> <div>
<h2 className="text-lg font-semibold"> <h2 className="text-lg font-semibold">
{isEditMode ? "Edit CC Agent" : "Create CC Agent"} {isEditMode ? t('agents.editAgent') : t('agents.createAgent')}
</h2> </h2>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
{isEditMode ? "Update your Claude Code agent" : "Create a new Claude Code agent"} {isEditMode ? t('agents.updateAgentDescription') : t('agents.createAgentDescription')}
</p> </p>
</div> </div>
</div> </div>
@@ -153,7 +155,7 @@ export const CreateAgent: React.FC<CreateAgentProps> = ({
) : ( ) : (
<Save className="mr-2 h-4 w-4" /> <Save className="mr-2 h-4 w-4" />
)} )}
{saving ? "Saving..." : "Save"} {saving ? t('app.loading') : t('app.save')}
</Button> </Button>
</motion.div> </motion.div>

View File

@@ -0,0 +1,85 @@
import React from 'react';
import { Globe, Check } from 'lucide-react';
import { Button } from '@/components/ui/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { useTranslation } from '@/hooks/useTranslation';
import { api } from '@/lib/api';
import { cn } from '@/lib/utils';
interface LanguageSwitcherProps {
className?: string;
showText?: boolean;
}
/**
* 语言切换组件
*
* @example
* <LanguageSwitcher />
* <LanguageSwitcher showText={true} className="ml-2" />
*/
export const LanguageSwitcher: React.FC<LanguageSwitcherProps> = ({
className,
showText = false
}) => {
const { changeLanguage, currentLanguage, supportedLanguages } = useTranslation();
const handleLanguageChange = async (languageCode: string) => {
try {
// 映射前端语言代码到后端格式
const backendLocale = languageCode === 'zh' ? 'zh-CN' : 'en-US';
// 同步到后端
await api.setLanguage(backendLocale);
// 更新前端
changeLanguage(languageCode);
} catch (error) {
console.error('Failed to change language:', error);
// 即使后端同步失败,也要尝试更新前端
changeLanguage(languageCode);
}
};
const getCurrentLanguageDisplay = () => {
const currentLang = supportedLanguages.find(lang => lang.code === currentLanguage);
return currentLang?.nativeName || currentLanguage.toUpperCase();
};
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="sm"
className={cn("gap-2", className)}
>
<Globe className="h-4 w-4" />
{showText && <span className="hidden sm:inline">{getCurrentLanguageDisplay()}</span>}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-48">
{supportedLanguages.map((language) => (
<DropdownMenuItem
key={language.code}
onClick={() => handleLanguageChange(language.code)}
className="flex items-center justify-between cursor-pointer"
>
<div className="flex flex-col">
<span className="font-medium">{language.nativeName}</span>
<span className="text-xs text-muted-foreground">{language.name}</span>
</div>
{currentLanguage === language.code && (
<Check className="h-4 w-4 text-primary" />
)}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
);
};

View File

@@ -3,6 +3,8 @@ import { motion } from "framer-motion";
import { Circle, FileText, Settings, ExternalLink, BarChart3, Network, Info, Bot } from "lucide-react"; import { Circle, FileText, Settings, ExternalLink, BarChart3, Network, Info, Bot } from "lucide-react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Popover } from "@/components/ui/popover"; import { Popover } from "@/components/ui/popover";
import { LanguageSwitcher } from "@/components/LanguageSwitcher";
import { useTranslation } from "@/hooks/useTranslation";
import { api, type ClaudeVersionStatus } from "@/lib/api"; import { api, type ClaudeVersionStatus } from "@/lib/api";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
@@ -57,6 +59,7 @@ export const Topbar: React.FC<TopbarProps> = ({
onAgentsClick, onAgentsClick,
className, className,
}) => { }) => {
const { t } = useTranslation();
const [versionStatus, setVersionStatus] = useState<ClaudeVersionStatus | null>(null); const [versionStatus, setVersionStatus] = useState<ClaudeVersionStatus | null>(null);
const [checking, setChecking] = useState(true); const [checking, setChecking] = useState(true);
@@ -130,7 +133,7 @@ export const Topbar: React.FC<TopbarProps> = ({
trigger={statusContent} trigger={statusContent}
content={ content={
<div className="space-y-3 max-w-xs"> <div className="space-y-3 max-w-xs">
<p className="text-sm font-medium">Claude Code not found</p> <p className="text-sm font-medium">{t('messages.claudeCodeNotFound')}</p>
<div className="rounded-md bg-muted p-3"> <div className="rounded-md bg-muted p-3">
<pre className="text-xs font-mono whitespace-pre-wrap"> <pre className="text-xs font-mono whitespace-pre-wrap">
{versionStatus.output} {versionStatus.output}
@@ -142,7 +145,7 @@ export const Topbar: React.FC<TopbarProps> = ({
className="w-full" className="w-full"
onClick={onSettingsClick} onClick={onSettingsClick}
> >
Select Claude Installation {t('messages.selectClaudeInstallation')}
</Button> </Button>
<a <a
href="https://www.anthropic.com/claude-code" href="https://www.anthropic.com/claude-code"
@@ -150,7 +153,7 @@ export const Topbar: React.FC<TopbarProps> = ({
rel="noopener noreferrer" rel="noopener noreferrer"
className="flex items-center space-x-1 text-xs text-primary hover:underline" className="flex items-center space-x-1 text-xs text-primary hover:underline"
> >
<span>Install Claude Code</span> <span>{t('messages.installClaudeCode')}</span>
<ExternalLink className="h-3 w-3" /> <ExternalLink className="h-3 w-3" />
</a> </a>
</div> </div>
@@ -186,7 +189,7 @@ export const Topbar: React.FC<TopbarProps> = ({
className="text-xs" className="text-xs"
> >
<Bot className="mr-2 h-3 w-3" /> <Bot className="mr-2 h-3 w-3" />
Agents {t('navigation.agents')}
</Button> </Button>
)} )}
@@ -197,7 +200,7 @@ export const Topbar: React.FC<TopbarProps> = ({
className="text-xs" className="text-xs"
> >
<BarChart3 className="mr-2 h-3 w-3" /> <BarChart3 className="mr-2 h-3 w-3" />
Usage Dashboard {t('navigation.usage')}
</Button> </Button>
<Button <Button
@@ -217,7 +220,7 @@ export const Topbar: React.FC<TopbarProps> = ({
className="text-xs" className="text-xs"
> >
<Network className="mr-2 h-3 w-3" /> <Network className="mr-2 h-3 w-3" />
MCP {t('navigation.mcp')}
</Button> </Button>
<Button <Button
@@ -227,15 +230,18 @@ export const Topbar: React.FC<TopbarProps> = ({
className="text-xs" className="text-xs"
> >
<Settings className="mr-2 h-3 w-3" /> <Settings className="mr-2 h-3 w-3" />
Settings {t('navigation.settings')}
</Button> </Button>
{/* Language Switcher */}
<LanguageSwitcher />
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
onClick={onInfoClick} onClick={onInfoClick}
className="h-8 w-8" className="h-8 w-8"
title="About" title={t('navigation.about')}
> >
<Info className="h-4 w-4" /> <Info className="h-4 w-4" />
</Button> </Button>

View File

@@ -24,3 +24,4 @@ export {
useAsyncPerformanceTracker useAsyncPerformanceTracker
} from './usePerformanceMonitor'; } from './usePerformanceMonitor';
export { TAB_SCREEN_NAMES } from './useAnalytics'; export { TAB_SCREEN_NAMES } from './useAnalytics';
export { useTranslation, getLanguageDisplayName } from './useTranslation';

View File

@@ -0,0 +1,55 @@
import { useTranslation as useI18nTranslation } from 'react-i18next';
/**
* 自定义 i18n Hook提供类型安全的翻译功能
*/
export const useTranslation = (namespace?: string) => {
const { t, i18n } = useI18nTranslation(namespace || 'common');
/**
* 切换语言
* @param language 语言代码 ('en' | 'zh')
*/
const changeLanguage = (language: string) => {
i18n.changeLanguage(language);
};
/**
* 获取当前语言
*/
const currentLanguage = i18n.language;
/**
* 检查是否是中文
*/
const isChineseLang = currentLanguage.startsWith('zh');
/**
* 获取支持的语言列表
*/
const supportedLanguages = [
{ code: 'en', name: 'English', nativeName: 'English' },
{ code: 'zh', name: 'Chinese', nativeName: '中文' },
];
return {
t,
changeLanguage,
currentLanguage,
isChineseLang,
supportedLanguages,
i18n,
};
};
/**
* 语言选择器组件的辅助函数
*/
export const getLanguageDisplayName = (code: string, displayInNative = false) => {
const languages = {
en: displayInNative ? 'English' : 'English',
zh: displayInNative ? '中文' : 'Chinese',
};
return languages[code as keyof typeof languages] || code;
};

View File

@@ -1879,5 +1879,49 @@ export const api = {
console.error("Failed to delete slash command:", error); console.error("Failed to delete slash command:", error);
throw error; throw error;
} }
},
// ================================
// Language Settings
// ================================
/**
* Gets the current language setting
* @returns Promise resolving to the current language locale
*/
async getCurrentLanguage(): Promise<string> {
try {
return await invoke<string>("get_current_language");
} catch (error) {
console.error("Failed to get current language:", error);
throw error;
}
},
/**
* Sets the language setting
* @param locale - Language locale to set (e.g., 'en-US', 'zh-CN')
* @returns Promise resolving when language is set
*/
async setLanguage(locale: string): Promise<void> {
try {
await invoke<void>("set_language", { locale });
} catch (error) {
console.error("Failed to set language:", error);
throw error;
}
},
/**
* Gets the list of supported languages
* @returns Promise resolving to array of supported language locales
*/
async getSupportedLanguages(): Promise<string[]> {
try {
return await invoke<string[]>("get_supported_languages");
} catch (error) {
console.error("Failed to get supported languages:", error);
throw error;
}
} }
}; };

57
src/lib/i18n.ts Normal file
View File

@@ -0,0 +1,57 @@
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
// 引入语言资源文件
import en from '@/locales/en/common.json';
import zh from '@/locales/zh/common.json';
// 配置语言检测器
const languageDetectorOptions = {
// 检测顺序
order: ['localStorage', 'navigator', 'htmlTag'],
// 缓存语言到localStorage
caches: ['localStorage'],
// 检查所有可用语言
checkWhitelist: true,
};
i18n
.use(LanguageDetector)
.use(initReactI18next)
.init({
// 回退语言
fallbackLng: 'en',
// 调试模式(开发环境)
debug: process.env.NODE_ENV === 'development',
// 语言资源
resources: {
en: {
common: en,
},
zh: {
common: zh,
},
},
// 命名空间配置
defaultNS: 'common',
ns: ['common'],
// 语言检测选项
detection: languageDetectorOptions,
// 插值配置
interpolation: {
escapeValue: false, // React 已经默认防止XSS
},
// 白名单支持的语言
supportedLngs: ['en', 'zh'],
// 非显式支持的语言回退到en
nonExplicitSupportedLngs: true,
});
export default i18n;

156
src/locales/en/common.json Normal file
View File

@@ -0,0 +1,156 @@
{
"app": {
"name": "Claudia",
"welcome": "Welcome to Claudia",
"loading": "Loading...",
"error": "Error",
"success": "Success",
"cancel": "Cancel",
"save": "Save",
"delete": "Delete",
"edit": "Edit",
"create": "Create",
"update": "Update",
"remove": "Remove",
"add": "Add",
"confirm": "Confirm",
"back": "Back",
"next": "Next",
"previous": "Previous",
"refresh": "Refresh",
"close": "Close",
"open": "Open"
},
"navigation": {
"projects": "CC Projects",
"agents": "CC Agents",
"settings": "Settings",
"usage": "Usage Dashboard",
"mcp": "MCP Manager",
"about": "About"
},
"projects": {
"title": "Projects",
"noProjects": "No projects found",
"selectProject": "Select a project",
"openSession": "Open Session",
"newSession": "New Session",
"sessions": "Sessions",
"noSessions": "No sessions found",
"lastModified": "Last Modified",
"sessionHistory": "Session History"
},
"agents": {
"title": "CC Agents",
"newAgent": "New Agent",
"createAgent": "Create Agent",
"editAgent": "Edit Agent",
"deleteAgent": "Delete Agent",
"executeAgent": "Execute Agent",
"agentName": "Agent Name",
"agentIcon": "Agent Icon",
"systemPrompt": "System Prompt",
"defaultTask": "Default Task",
"model": "Model",
"permissions": "Permissions",
"fileAccess": "File Access",
"networkAccess": "Network Access",
"noAgents": "No agents found",
"agentCreated": "Agent created successfully",
"agentUpdated": "Agent updated successfully",
"agentDeleted": "Agent deleted successfully",
"confirmDelete": "Are you sure you want to delete this agent?",
"executionHistory": "Execution History",
"runAgent": "Run Agent",
"agentRuns": "Agent Runs",
"createAgentDescription": "Create a new Claude Code agent",
"updateAgentDescription": "Update your Claude Code agent",
"createFailed": "Failed to create agent",
"updateFailed": "Failed to update agent"
},
"settings": {
"title": "Settings",
"general": "General",
"appearance": "Appearance",
"language": "Language",
"theme": "Theme",
"checkpointSettings": "Checkpoint Settings",
"autoCheckpoint": "Auto Checkpoint",
"checkpointInterval": "Checkpoint Interval",
"maxCheckpoints": "Max Checkpoints",
"proxySettings": "Proxy Settings",
"enableProxy": "Enable Proxy",
"httpProxy": "HTTP Proxy",
"httpsProxy": "HTTPS Proxy",
"noProxy": "No Proxy",
"analyticsConsent": "Analytics Consent",
"enableAnalytics": "Enable Analytics",
"disableAnalytics": "Disable Analytics"
},
"mcp": {
"title": "MCP Server Management",
"addServer": "Add Server",
"serverName": "Server Name",
"serverCommand": "Server Command",
"serverArgs": "Server Arguments",
"testConnection": "Test Connection",
"connectionSuccess": "Connection successful",
"connectionFailed": "Connection failed",
"importFromClaude": "Import from Claude Desktop",
"exportConfig": "Export Configuration",
"noServers": "No MCP servers configured"
},
"usage": {
"title": "Usage Dashboard",
"totalTokens": "Total Tokens",
"totalCost": "Total Cost",
"byModel": "By Model",
"byProject": "By Project",
"byDate": "By Date",
"last7Days": "Last 7 Days",
"last30Days": "Last 30 Days",
"allTime": "All Time",
"exportData": "Export Data"
},
"checkpoint": {
"title": "Checkpoints",
"createCheckpoint": "Create Checkpoint",
"restoreCheckpoint": "Restore Checkpoint",
"deleteCheckpoint": "Delete Checkpoint",
"checkpointName": "Checkpoint Name",
"checkpointMessage": "Checkpoint Message",
"timeline": "Timeline",
"diff": "Diff",
"noCheckpoints": "No checkpoints found"
},
"placeholders": {
"searchProjects": "Search projects...",
"searchAgents": "Search agents...",
"enterAgentName": "Enter agent name...",
"enterSystemPrompt": "Enter system prompt...",
"enterDefaultTask": "Enter default task...",
"enterURL": "Enter URL...",
"searchCommands": "Search commands...",
"enterCommand": "Enter command...",
"enterDescription": "Enter description..."
},
"validation": {
"required": "This field is required",
"invalidEmail": "Invalid email address",
"invalidUrl": "Invalid URL",
"minLength": "Minimum {{count}} characters required",
"maxLength": "Maximum {{count}} characters allowed"
},
"messages": {
"saveSuccess": "Saved successfully",
"deleteSuccess": "Deleted successfully",
"operationFailed": "Operation failed",
"confirmAction": "Are you sure you want to perform this action?",
"unsavedChanges": "You have unsaved changes",
"networkError": "Network error occurred",
"unknownError": "Unknown error occurred",
"claudeCodeNotFound": "Claude Code not found",
"selectClaudeInstallation": "Select Claude Installation",
"installClaudeCode": "Install Claude Code"
}
}

156
src/locales/zh/common.json Normal file
View File

@@ -0,0 +1,156 @@
{
"app": {
"name": "Claudia",
"welcome": "欢迎使用 Claudia",
"loading": "加载中...",
"error": "错误",
"success": "成功",
"cancel": "取消",
"save": "保存",
"delete": "删除",
"edit": "编辑",
"create": "创建",
"update": "更新",
"remove": "移除",
"add": "添加",
"confirm": "确认",
"back": "返回",
"next": "下一步",
"previous": "上一步",
"refresh": "刷新",
"close": "关闭",
"open": "打开"
},
"navigation": {
"projects": "CC 项目",
"agents": "CC 智能体",
"settings": "设置",
"usage": "用量仪表板",
"mcp": "MCP 管理器",
"about": "关于"
},
"projects": {
"title": "项目",
"noProjects": "未找到项目",
"selectProject": "选择项目",
"openSession": "打开会话",
"newSession": "新建会话",
"sessions": "会话",
"noSessions": "未找到会话",
"lastModified": "最近修改",
"sessionHistory": "会话历史"
},
"agents": {
"title": "CC 智能体",
"newAgent": "新建智能体",
"createAgent": "创建智能体",
"editAgent": "编辑智能体",
"deleteAgent": "删除智能体",
"executeAgent": "执行智能体",
"agentName": "智能体名称",
"agentIcon": "智能体图标",
"systemPrompt": "系统提示",
"defaultTask": "默认任务",
"model": "模型",
"permissions": "权限",
"fileAccess": "文件访问",
"networkAccess": "网络访问",
"noAgents": "未找到智能体",
"agentCreated": "智能体创建成功",
"agentUpdated": "智能体更新成功",
"agentDeleted": "智能体删除成功",
"confirmDelete": "确认要删除此智能体吗?",
"executionHistory": "执行历史",
"runAgent": "运行智能体",
"agentRuns": "智能体运行记录",
"createAgentDescription": "创建新的 Claude Code 智能体",
"updateAgentDescription": "更新您的 Claude Code 智能体",
"createFailed": "创建智能体失败",
"updateFailed": "更新智能体失败"
},
"settings": {
"title": "设置",
"general": "常规",
"appearance": "外观",
"language": "语言",
"theme": "主题",
"checkpointSettings": "检查点设置",
"autoCheckpoint": "自动检查点",
"checkpointInterval": "检查点间隔",
"maxCheckpoints": "最大检查点数",
"proxySettings": "代理设置",
"enableProxy": "启用代理",
"httpProxy": "HTTP 代理",
"httpsProxy": "HTTPS 代理",
"noProxy": "无代理",
"analyticsConsent": "分析同意",
"enableAnalytics": "启用分析",
"disableAnalytics": "禁用分析"
},
"mcp": {
"title": "MCP 服务器管理",
"addServer": "添加服务器",
"serverName": "服务器名称",
"serverCommand": "服务器命令",
"serverArgs": "服务器参数",
"testConnection": "测试连接",
"connectionSuccess": "连接成功",
"connectionFailed": "连接失败",
"importFromClaude": "从 Claude Desktop 导入",
"exportConfig": "导出配置",
"noServers": "未配置 MCP 服务器"
},
"usage": {
"title": "用量仪表板",
"totalTokens": "总令牌数",
"totalCost": "总成本",
"byModel": "按模型",
"byProject": "按项目",
"byDate": "按日期",
"last7Days": "最近 7 天",
"last30Days": "最近 30 天",
"allTime": "全部时间",
"exportData": "导出数据"
},
"checkpoint": {
"title": "检查点",
"createCheckpoint": "创建检查点",
"restoreCheckpoint": "恢复检查点",
"deleteCheckpoint": "删除检查点",
"checkpointName": "检查点名称",
"checkpointMessage": "检查点消息",
"timeline": "时间线",
"diff": "差异",
"noCheckpoints": "未找到检查点"
},
"placeholders": {
"searchProjects": "搜索项目...",
"searchAgents": "搜索智能体...",
"enterAgentName": "输入智能体名称...",
"enterSystemPrompt": "输入系统提示...",
"enterDefaultTask": "输入默认任务...",
"enterURL": "输入 URL...",
"searchCommands": "搜索命令...",
"enterCommand": "输入命令...",
"enterDescription": "输入描述..."
},
"validation": {
"required": "此字段为必填项",
"invalidEmail": "无效的邮箱地址",
"invalidUrl": "无效的 URL",
"minLength": "至少需要 {{count}} 个字符",
"maxLength": "最多允许 {{count}} 个字符"
},
"messages": {
"saveSuccess": "保存成功",
"deleteSuccess": "删除成功",
"operationFailed": "操作失败",
"confirmAction": "确认要执行此操作吗?",
"unsavedChanges": "您有未保存的更改",
"networkError": "网络错误",
"unknownError": "未知错误",
"claudeCodeNotFound": "未找到 Claude Code",
"selectClaudeInstallation": "选择 Claude 安装",
"installClaudeCode": "安装 Claude Code"
}
}

View File

@@ -5,6 +5,7 @@ import { ErrorBoundary } from "./components/ErrorBoundary";
import { AnalyticsErrorBoundary } from "./components/AnalyticsErrorBoundary"; import { AnalyticsErrorBoundary } from "./components/AnalyticsErrorBoundary";
import { analytics, resourceMonitor } from "./lib/analytics"; import { analytics, resourceMonitor } from "./lib/analytics";
import { PostHogProvider } from "posthog-js/react"; import { PostHogProvider } from "posthog-js/react";
import "./lib/i18n"; // 初始化国际化
import "./assets/shimmer.css"; import "./assets/shimmer.css";
import "./styles.css"; import "./styles.css";