mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-11-07 18:42:11 +08:00
chore: i18n (#5276)
* chore: notice i18n * feat: add script to clean up unused i18n keys * chore: cleanup i18n keys * refactor(i18n/proxies): migrate proxies UI to structured locale keys * chore: i18n for rule module * chore: i18n for profile module * chore: i18n for connections module * chore: i18n for settings module * chore: i18n for verge settings * chore: i18n for theme settings * chore: i18n for theme * chore(i18n): components.home.* * chore(i18n): remove unused i18n keys * chore(i18n): components.profile.* * chore(i18n): components.connection * chore(i18n): pages.logs.* * chore(i18n): pages.*.provider * chore(i18n): components.settings.externalCors.* * chore(i18n): components.settings.clash.* * chore(i18n): components.settings.liteMode.* * chore(i18n): components.settings.backup.* * chore(i18n): components.settings.clash.port.* * chore(i18n): components.settings.misc.* * chore(i18n): components.settings.update.* * chore(i18n): components.settings.sysproxy.* * chore(i18n): components.settings.sysproxy.* * chore(i18n): pages.profiles.notices/components.providers.notices * refactor(notice): unify showNotice usage * refactor(notice): add typed showNotice shortcuts, centralize defaults, and simplify subscriptions * refactor: unify showNotice usage * refactor(notice): unify showNotice API * refactor(notice): unify showNotice usage * chore(i18n): components.test.* * chore(i18n): components.settings.dns.* * chore(i18n): components.home.clashInfo.* * chore(i18n): components.home.systemInfo.* * chore(i18n): components.home.ipInfo/traffic.* * chore(i18n): navigation.* * refactor(i18n): remove pages.* namespace and migrate route texts under module-level page keys * chore(i18n): common.* * chore(i18n): common.* * fix: change error handling in patch_profiles_config to return false when a switch is in progress * fix: improve error handling in patch_profiles_config to prevent requests during profile switching * fix: change error handling in patch_profiles_config to return false when a switch is in progress fix: ensure CURRENT_SWITCHING_PROFILE is reset after config updates in perform_config_update and patch_profiles_config * chore(i18n): restructure root-level locale keys into namespaces * chore(i18n): add missing i18n keys * docs: i18n guide * chore: adjust i18n * refactor(i18n): align UI actions and status labels with common keys * refactor(i18n): unify two-name locale namespaces * refactor(i18n/components): unify locale keys and update component references * chore(i18n): add shared and entities namespaces to all locale files * refactor(i18n): consolidate shared and entity namespaces across features * chore(deps): update npm dependencies to ^7.3.5 (#5310) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * refactor(i18n): migrate shared editor modes and consolidate entities namespaces * tmp * refactor(i18n): flatten locales and move theme/validation strings * docs: CONTRIBUTING_i18n.md * refactor(i18n): restructure feedback and profile namespaces for better organization * refactor(i18n): unify settings locale structure and update references * refactor(i18n): reorganize locale keys for home, proxies, rules, connections, logs, unlock, and tests * refactor(i18n/feedback/layout): unify shared toasts & normalize layout namespace * refactor(i18n): centralize common UI strings in shared * refactor(i18n): flatten headers and unify locale schema * refactor(i18n): consolidate duplicate per-feature translations into shared namespace * refactor(i18n): split locales into per-namespace files * style: lint * refactor(i18n): unify unlock UI translations under tests namespace * feat(i18n): add type-checked translation keys * style: eslint import order * feat(i18n): replace ad-hoc loader with rust-i18n backend bundles * chore(prebuild): remove locale-copy step * fix(i18n, notice): propagate runtime params and update cleanup script path * fix(i18n,notice): make locale formatting idempotent and guard early notice translations * fix(i18n): resolve locale aliases and match OS codes correctly * fix(unlock): use i18next-compatible double-brace interpolation in failure notice * fix(i18n): route unlock error notices through translation keys * fix(i18n): i18n types * feat(i18n): localize upgrade notice for Clash core viewer * fix(notice): ensure runtime overrides apply to prefix translations * chore(i18n): replace literal notices with translation keys * chore(i18n): types * chore(i18n): regen typings before formatting to keep keys in sync * chore(i18n): simply labels * chore(i18n): adjust translation * chore: remove eslint-plugin-i18next * chore(i18n): add/refine Korean translations across frontend scopes and Rust backend (#5341) * chore(i18n): translate settings.json (missed in previous pass) (#5343) * chore(i18n): add/refine Korean translations across frontend scopes and Rust backend * chore(i18n): add/refine Korean translations across frontend scopes and Rust backend * fix(i18n-tauri): quote placeholder-leading value in ko.yml to prevent rust_i18n parse panic * chore(i18n): translate settings.json (forgot to include previously) --------- Co-authored-by: rozan <34974262+thelojan@users.noreply.github.com>
This commit is contained in:
co-authored by
renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
rozan
parent
c1a2e99f63
commit
c8aa72186e
Generated
+184
-14
@@ -572,6 +572,12 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base62"
|
||||
version = "2.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1adf9755786e27479693dedd3271691a92b5e242ab139cacb9fb8e7fb5381111"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.1"
|
||||
@@ -822,6 +828,16 @@ dependencies = [
|
||||
"alloc-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "1.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.19.0"
|
||||
@@ -1131,6 +1147,7 @@ dependencies = [
|
||||
"reqwest",
|
||||
"reqwest_dav",
|
||||
"runas",
|
||||
"rust-i18n",
|
||||
"scopeguard",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -2847,7 +2864,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"proc-macro-crate 2.0.2",
|
||||
"proc-macro-crate 2.0.0",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2888,6 +2905,30 @@ dependencies = [
|
||||
"xkeysym",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "globset"
|
||||
version = "0.4.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"bstr",
|
||||
"log",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "globwalk"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"ignore",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gobject-sys"
|
||||
version = "0.18.0"
|
||||
@@ -3512,6 +3553,22 @@ dependencies = [
|
||||
"icu_properties",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ignore"
|
||||
version = "0.4.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"globset",
|
||||
"log",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"same-file",
|
||||
"walkdir",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.25.8"
|
||||
@@ -3701,6 +3758,15 @@ dependencies = [
|
||||
"waker-fn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
@@ -4432,6 +4498,15 @@ dependencies = [
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "normpath"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf23ab2b905654b4cb177e30b629937b3868311d4e1cba859f899c041046e69b"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify-rust"
|
||||
version = "4.11.7"
|
||||
@@ -5554,11 +5629,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "2.0.2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24"
|
||||
checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8"
|
||||
dependencies = [
|
||||
"toml_datetime 0.6.3",
|
||||
"toml_edit 0.20.2",
|
||||
]
|
||||
|
||||
@@ -6230,6 +6304,60 @@ dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-i18n"
|
||||
version = "3.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fda2551fdfaf6cc5ee283adc15e157047b92ae6535cf80f6d4962d05717dc332"
|
||||
dependencies = [
|
||||
"globwalk",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"rust-i18n-macro",
|
||||
"rust-i18n-support",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-i18n-macro"
|
||||
version = "3.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22baf7d7f56656d23ebe24f6bb57a5d40d2bce2a5f1c503e692b5b2fa450f965"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rust-i18n-support",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"syn 2.0.108",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-i18n-support"
|
||||
version = "3.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "940ed4f52bba4c0152056d771e563b7133ad9607d4384af016a134b58d758f19"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"base62",
|
||||
"globwalk",
|
||||
"itertools 0.11.0",
|
||||
"lazy_static",
|
||||
"normpath",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"siphasher 1.0.1",
|
||||
"toml 0.8.23",
|
||||
"triomphe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-ini"
|
||||
version = "0.21.3"
|
||||
@@ -6672,6 +6800,19 @@ dependencies = [
|
||||
"syn 2.0.108",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.9.34+deprecated"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
||||
dependencies = [
|
||||
"indexmap 2.12.0",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
"unsafe-libyaml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml_ng"
|
||||
version = "0.10.0"
|
||||
@@ -7185,7 +7326,7 @@ dependencies = [
|
||||
"cfg-expr",
|
||||
"heck 0.5.0",
|
||||
"pkg-config",
|
||||
"toml 0.8.2",
|
||||
"toml 0.8.23",
|
||||
"version-compare",
|
||||
]
|
||||
|
||||
@@ -8126,14 +8267,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.2"
|
||||
version = "0.8.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d"
|
||||
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned 0.6.9",
|
||||
"toml_datetime 0.6.3",
|
||||
"toml_edit 0.20.2",
|
||||
"toml_datetime 0.6.11",
|
||||
"toml_edit 0.22.27",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8153,9 +8294,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.3"
|
||||
version = "0.6.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
|
||||
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@@ -8176,7 +8317,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
||||
dependencies = [
|
||||
"indexmap 2.12.0",
|
||||
"toml_datetime 0.6.3",
|
||||
"toml_datetime 0.6.11",
|
||||
"winnow 0.5.40",
|
||||
]
|
||||
|
||||
@@ -8185,12 +8326,24 @@ name = "toml_edit"
|
||||
version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
|
||||
dependencies = [
|
||||
"indexmap 2.12.0",
|
||||
"toml_datetime 0.6.11",
|
||||
"winnow 0.5.40",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
|
||||
dependencies = [
|
||||
"indexmap 2.12.0",
|
||||
"serde",
|
||||
"serde_spanned 0.6.9",
|
||||
"toml_datetime 0.6.3",
|
||||
"winnow 0.5.40",
|
||||
"toml_datetime 0.6.11",
|
||||
"toml_write",
|
||||
"winnow 0.7.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8214,6 +8367,12 @@ dependencies = [
|
||||
"winnow 0.7.13",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_write"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
|
||||
|
||||
[[package]]
|
||||
name = "toml_writer"
|
||||
version = "1.0.4"
|
||||
@@ -8513,6 +8672,17 @@ dependencies = [
|
||||
"petgraph",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "triomphe"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"serde",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "try-lock"
|
||||
version = "0.2.5"
|
||||
|
||||
@@ -87,6 +87,7 @@ clash_verge_service_ipc = { version = "2.0.21", features = [
|
||||
"client",
|
||||
], git = "https://github.com/clash-verge-rev/clash-verge-service-ipc" }
|
||||
arc-swap = "1.7.1"
|
||||
rust-i18n = "3.1.5"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
runas = "=1.2.0"
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
_version: 1
|
||||
notifications:
|
||||
dashboardToggled:
|
||||
title: Dashboard
|
||||
body: Dashboard visibility has been updated.
|
||||
clashModeChanged:
|
||||
title: Mode Switch
|
||||
body: Switched to {mode}.
|
||||
systemProxyToggled:
|
||||
title: System Proxy
|
||||
body: System proxy status has been updated.
|
||||
tunModeToggled:
|
||||
title: TUN Mode
|
||||
body: TUN mode status has been updated.
|
||||
lightweightModeEntered:
|
||||
title: Lightweight Mode
|
||||
body: Entered lightweight mode.
|
||||
appQuit:
|
||||
title: About to Exit
|
||||
body: Clash Verge is about to exit.
|
||||
appHidden:
|
||||
title: Application Hidden
|
||||
body: Clash Verge is running in the background.
|
||||
service:
|
||||
adminPrompt: Installing the service requires administrator privileges.
|
||||
tray:
|
||||
dashboard: Dashboard
|
||||
ruleMode: Rule Mode
|
||||
globalMode: Global Mode
|
||||
directMode: Direct Mode
|
||||
profiles: Profiles
|
||||
proxies: Proxies
|
||||
systemProxy: System Proxy
|
||||
tunMode: TUN Mode
|
||||
closeAllConnections: Close All Connections
|
||||
lightweightMode: Lightweight Mode
|
||||
copyEnv: Copy Environment Variables
|
||||
confDir: Configuration Directory
|
||||
coreDir: Core Directory
|
||||
logsDir: Log Directory
|
||||
openDir: Open Directory
|
||||
appLog: Application Log
|
||||
coreLog: Core Log
|
||||
restartClash: Restart Clash Core
|
||||
restartApp: Restart Application
|
||||
vergeVersion: Verge Version
|
||||
more: More
|
||||
exit: Exit
|
||||
tooltip:
|
||||
systemProxy: System Proxy
|
||||
tun: TUN
|
||||
profile: Profile
|
||||
@@ -0,0 +1,52 @@
|
||||
_version: 1
|
||||
notifications:
|
||||
dashboardToggled:
|
||||
title: Dashboard
|
||||
body: Dashboard visibility has been updated.
|
||||
clashModeChanged:
|
||||
title: Mode Switch
|
||||
body: Switched to {mode}.
|
||||
systemProxyToggled:
|
||||
title: System Proxy
|
||||
body: System proxy status has been updated.
|
||||
tunModeToggled:
|
||||
title: TUN Mode
|
||||
body: TUN mode status has been updated.
|
||||
lightweightModeEntered:
|
||||
title: Lightweight Mode
|
||||
body: Entered lightweight mode.
|
||||
appQuit:
|
||||
title: About to Exit
|
||||
body: Clash Verge is about to exit.
|
||||
appHidden:
|
||||
title: Application Hidden
|
||||
body: Clash Verge is running in the background.
|
||||
service:
|
||||
adminPrompt: Installing the service requires administrator privileges.
|
||||
tray:
|
||||
dashboard: Dashboard
|
||||
ruleMode: Rule Mode
|
||||
globalMode: Global Mode
|
||||
directMode: Direct Mode
|
||||
profiles: Profiles
|
||||
proxies: Proxies
|
||||
systemProxy: System Proxy
|
||||
tunMode: TUN Mode
|
||||
closeAllConnections: Close All Connections
|
||||
lightweightMode: Lightweight Mode
|
||||
copyEnv: Copy Environment Variables
|
||||
confDir: Configuration Directory
|
||||
coreDir: Core Directory
|
||||
logsDir: Log Directory
|
||||
openDir: Open Directory
|
||||
appLog: Application Log
|
||||
coreLog: Core Log
|
||||
restartClash: Restart Clash Core
|
||||
restartApp: Restart Application
|
||||
vergeVersion: Verge Version
|
||||
more: More
|
||||
exit: Exit
|
||||
tooltip:
|
||||
systemProxy: System Proxy
|
||||
tun: TUN
|
||||
profile: Profile
|
||||
@@ -0,0 +1,52 @@
|
||||
_version: 1
|
||||
notifications:
|
||||
dashboardToggled:
|
||||
title: Dashboard
|
||||
body: Dashboard visibility has been updated.
|
||||
clashModeChanged:
|
||||
title: Mode Switch
|
||||
body: Switched to {mode}.
|
||||
systemProxyToggled:
|
||||
title: System Proxy
|
||||
body: System proxy status has been updated.
|
||||
tunModeToggled:
|
||||
title: TUN Mode
|
||||
body: TUN mode status has been updated.
|
||||
lightweightModeEntered:
|
||||
title: Lightweight Mode
|
||||
body: Entered lightweight mode.
|
||||
appQuit:
|
||||
title: About to Exit
|
||||
body: Clash Verge is about to exit.
|
||||
appHidden:
|
||||
title: Application Hidden
|
||||
body: Clash Verge is running in the background.
|
||||
service:
|
||||
adminPrompt: Installing the service requires administrator privileges.
|
||||
tray:
|
||||
dashboard: Dashboard
|
||||
ruleMode: Rule Mode
|
||||
globalMode: Global Mode
|
||||
directMode: Direct Mode
|
||||
profiles: Profiles
|
||||
proxies: Proxies
|
||||
systemProxy: System Proxy
|
||||
tunMode: TUN Mode
|
||||
closeAllConnections: Close All Connections
|
||||
lightweightMode: Lightweight Mode
|
||||
copyEnv: Copy Environment Variables
|
||||
confDir: Configuration Directory
|
||||
coreDir: Core Directory
|
||||
logsDir: Log Directory
|
||||
openDir: Open Directory
|
||||
appLog: Application Log
|
||||
coreLog: Core Log
|
||||
restartClash: Restart Clash Core
|
||||
restartApp: Restart Application
|
||||
vergeVersion: Verge Version
|
||||
more: More
|
||||
exit: Exit
|
||||
tooltip:
|
||||
systemProxy: System Proxy
|
||||
tun: TUN
|
||||
profile: Profile
|
||||
@@ -0,0 +1,52 @@
|
||||
_version: 1
|
||||
notifications:
|
||||
dashboardToggled:
|
||||
title: Dashboard
|
||||
body: Dashboard visibility has been updated.
|
||||
clashModeChanged:
|
||||
title: Mode Switch
|
||||
body: Switched to {mode}.
|
||||
systemProxyToggled:
|
||||
title: System Proxy
|
||||
body: System proxy status has been updated.
|
||||
tunModeToggled:
|
||||
title: TUN Mode
|
||||
body: TUN mode status has been updated.
|
||||
lightweightModeEntered:
|
||||
title: Lightweight Mode
|
||||
body: Entered lightweight mode.
|
||||
appQuit:
|
||||
title: About to Exit
|
||||
body: Clash Verge is about to exit.
|
||||
appHidden:
|
||||
title: Application Hidden
|
||||
body: Clash Verge is running in the background.
|
||||
service:
|
||||
adminPrompt: Installing the service requires administrator privileges.
|
||||
tray:
|
||||
dashboard: Dashboard
|
||||
ruleMode: Rule Mode
|
||||
globalMode: Global Mode
|
||||
directMode: Direct Mode
|
||||
profiles: Profiles
|
||||
proxies: Proxies
|
||||
systemProxy: System Proxy
|
||||
tunMode: TUN Mode
|
||||
closeAllConnections: Close All Connections
|
||||
lightweightMode: Lightweight Mode
|
||||
copyEnv: Copy Environment Variables
|
||||
confDir: Configuration Directory
|
||||
coreDir: Core Directory
|
||||
logsDir: Log Directory
|
||||
openDir: Open Directory
|
||||
appLog: Application Log
|
||||
coreLog: Core Log
|
||||
restartClash: Restart Clash Core
|
||||
restartApp: Restart Application
|
||||
vergeVersion: Verge Version
|
||||
more: More
|
||||
exit: Exit
|
||||
tooltip:
|
||||
systemProxy: System Proxy
|
||||
tun: TUN
|
||||
profile: Profile
|
||||
@@ -0,0 +1,52 @@
|
||||
_version: 1
|
||||
notifications:
|
||||
dashboardToggled:
|
||||
title: Dashboard
|
||||
body: Dashboard visibility has been updated.
|
||||
clashModeChanged:
|
||||
title: Mode Switch
|
||||
body: Switched to {mode}.
|
||||
systemProxyToggled:
|
||||
title: System Proxy
|
||||
body: System proxy status has been updated.
|
||||
tunModeToggled:
|
||||
title: TUN Mode
|
||||
body: TUN mode status has been updated.
|
||||
lightweightModeEntered:
|
||||
title: Lightweight Mode
|
||||
body: Entered lightweight mode.
|
||||
appQuit:
|
||||
title: About to Exit
|
||||
body: Clash Verge is about to exit.
|
||||
appHidden:
|
||||
title: Application Hidden
|
||||
body: Clash Verge is running in the background.
|
||||
service:
|
||||
adminPrompt: Installing the service requires administrator privileges.
|
||||
tray:
|
||||
dashboard: Dashboard
|
||||
ruleMode: Rule Mode
|
||||
globalMode: Global Mode
|
||||
directMode: Direct Mode
|
||||
profiles: Profiles
|
||||
proxies: Proxies
|
||||
systemProxy: System Proxy
|
||||
tunMode: TUN Mode
|
||||
closeAllConnections: Close All Connections
|
||||
lightweightMode: Lightweight Mode
|
||||
copyEnv: Copy Environment Variables
|
||||
confDir: Configuration Directory
|
||||
coreDir: Core Directory
|
||||
logsDir: Log Directory
|
||||
openDir: Open Directory
|
||||
appLog: Application Log
|
||||
coreLog: Core Log
|
||||
restartClash: Restart Clash Core
|
||||
restartApp: Restart Application
|
||||
vergeVersion: Verge Version
|
||||
more: More
|
||||
exit: Exit
|
||||
tooltip:
|
||||
systemProxy: System Proxy
|
||||
tun: TUN
|
||||
profile: Profile
|
||||
@@ -0,0 +1,52 @@
|
||||
_version: 1
|
||||
notifications:
|
||||
dashboardToggled:
|
||||
title: Dashboard
|
||||
body: Dashboard visibility has been updated.
|
||||
clashModeChanged:
|
||||
title: Mode Switch
|
||||
body: Switched to {mode}.
|
||||
systemProxyToggled:
|
||||
title: System Proxy
|
||||
body: System proxy status has been updated.
|
||||
tunModeToggled:
|
||||
title: TUN Mode
|
||||
body: TUN mode status has been updated.
|
||||
lightweightModeEntered:
|
||||
title: Lightweight Mode
|
||||
body: Entered lightweight mode.
|
||||
appQuit:
|
||||
title: About to Exit
|
||||
body: Clash Verge is about to exit.
|
||||
appHidden:
|
||||
title: Application Hidden
|
||||
body: Clash Verge is running in the background.
|
||||
service:
|
||||
adminPrompt: Installing the service requires administrator privileges.
|
||||
tray:
|
||||
dashboard: Dashboard
|
||||
ruleMode: Rule Mode
|
||||
globalMode: Global Mode
|
||||
directMode: Direct Mode
|
||||
profiles: Profiles
|
||||
proxies: Proxies
|
||||
systemProxy: System Proxy
|
||||
tunMode: TUN Mode
|
||||
closeAllConnections: Close All Connections
|
||||
lightweightMode: Lightweight Mode
|
||||
copyEnv: Copy Environment Variables
|
||||
confDir: Configuration Directory
|
||||
coreDir: Core Directory
|
||||
logsDir: Log Directory
|
||||
openDir: Open Directory
|
||||
appLog: Application Log
|
||||
coreLog: Core Log
|
||||
restartClash: Restart Clash Core
|
||||
restartApp: Restart Application
|
||||
vergeVersion: Verge Version
|
||||
more: More
|
||||
exit: Exit
|
||||
tooltip:
|
||||
systemProxy: System Proxy
|
||||
tun: TUN
|
||||
profile: Profile
|
||||
@@ -0,0 +1,52 @@
|
||||
_version: 1
|
||||
notifications:
|
||||
dashboardToggled:
|
||||
title: Dashboard
|
||||
body: Dashboard visibility has been updated.
|
||||
clashModeChanged:
|
||||
title: Mode Switch
|
||||
body: Switched to {mode}.
|
||||
systemProxyToggled:
|
||||
title: System Proxy
|
||||
body: System proxy status has been updated.
|
||||
tunModeToggled:
|
||||
title: TUN Mode
|
||||
body: TUN mode status has been updated.
|
||||
lightweightModeEntered:
|
||||
title: Lightweight Mode
|
||||
body: Entered lightweight mode.
|
||||
appQuit:
|
||||
title: About to Exit
|
||||
body: Clash Verge is about to exit.
|
||||
appHidden:
|
||||
title: Application Hidden
|
||||
body: Clash Verge is running in the background.
|
||||
service:
|
||||
adminPrompt: Installing the service requires administrator privileges.
|
||||
tray:
|
||||
dashboard: Dashboard
|
||||
ruleMode: Rule Mode
|
||||
globalMode: Global Mode
|
||||
directMode: Direct Mode
|
||||
profiles: Profiles
|
||||
proxies: Proxies
|
||||
systemProxy: System Proxy
|
||||
tunMode: TUN Mode
|
||||
closeAllConnections: Close All Connections
|
||||
lightweightMode: Lightweight Mode
|
||||
copyEnv: Copy Environment Variables
|
||||
confDir: Configuration Directory
|
||||
coreDir: Core Directory
|
||||
logsDir: Log Directory
|
||||
openDir: Open Directory
|
||||
appLog: Application Log
|
||||
coreLog: Core Log
|
||||
restartClash: Restart Clash Core
|
||||
restartApp: Restart Application
|
||||
vergeVersion: Verge Version
|
||||
more: More
|
||||
exit: Exit
|
||||
tooltip:
|
||||
systemProxy: System Proxy
|
||||
tun: TUN
|
||||
profile: Profile
|
||||
@@ -0,0 +1,52 @@
|
||||
_version: 1
|
||||
notifications:
|
||||
dashboardToggled:
|
||||
title: 대시보드
|
||||
body: 대시보드 표시 상태가 업데이트되었습니다.
|
||||
clashModeChanged:
|
||||
title: 모드 전환
|
||||
body: "{mode}(으)로 전환되었습니다."
|
||||
systemProxyToggled:
|
||||
title: 시스템 프록시
|
||||
body: 시스템 프록시 상태가 업데이트되었습니다.
|
||||
tunModeToggled:
|
||||
title: TUN 모드
|
||||
body: TUN 모드 상태가 업데이트되었습니다.
|
||||
lightweightModeEntered:
|
||||
title: 경량 모드
|
||||
body: 경량 모드에 진입했습니다.
|
||||
appQuit:
|
||||
title: 곧 종료
|
||||
body: Clash Verge가 곧 종료됩니다.
|
||||
appHidden:
|
||||
title: 앱이 숨겨짐
|
||||
body: Clash Verge가 백그라운드에서 실행 중입니다.
|
||||
service:
|
||||
adminPrompt: 서비스를 설치하려면 관리자 권한이 필요합니다.
|
||||
tray:
|
||||
dashboard: 대시보드
|
||||
ruleMode: 규칙 모드
|
||||
globalMode: 전역 모드
|
||||
directMode: 직접 모드
|
||||
profiles: 프로필
|
||||
proxies: 프록시
|
||||
systemProxy: 시스템 프록시
|
||||
tunMode: TUN 모드
|
||||
closeAllConnections: 모든 연결 닫기
|
||||
lightweightMode: 경량 모드
|
||||
copyEnv: 환경 변수 복사
|
||||
confDir: 구성 디렉터리
|
||||
coreDir: 코어 디렉터리
|
||||
logsDir: 로그 디렉터리
|
||||
openDir: 디렉터리 열기
|
||||
appLog: 애플리케이션 로그
|
||||
coreLog: 코어 로그
|
||||
restartClash: Clash 코어 재시작
|
||||
restartApp: 애플리케이션 재시작
|
||||
vergeVersion: Verge 버전
|
||||
more: 더 보기
|
||||
exit: 종료
|
||||
tooltip:
|
||||
systemProxy: 시스템 프록시
|
||||
tun: TUN
|
||||
profile: 프로필
|
||||
@@ -0,0 +1,52 @@
|
||||
_version: 1
|
||||
notifications:
|
||||
dashboardToggled:
|
||||
title: Dashboard
|
||||
body: Dashboard visibility has been updated.
|
||||
clashModeChanged:
|
||||
title: Mode Switch
|
||||
body: Switched to {mode}.
|
||||
systemProxyToggled:
|
||||
title: System Proxy
|
||||
body: System proxy status has been updated.
|
||||
tunModeToggled:
|
||||
title: TUN Mode
|
||||
body: TUN mode status has been updated.
|
||||
lightweightModeEntered:
|
||||
title: Lightweight Mode
|
||||
body: Entered lightweight mode.
|
||||
appQuit:
|
||||
title: About to Exit
|
||||
body: Clash Verge is about to exit.
|
||||
appHidden:
|
||||
title: Application Hidden
|
||||
body: Clash Verge is running in the background.
|
||||
service:
|
||||
adminPrompt: Installing the service requires administrator privileges.
|
||||
tray:
|
||||
dashboard: Dashboard
|
||||
ruleMode: Rule Mode
|
||||
globalMode: Global Mode
|
||||
directMode: Direct Mode
|
||||
profiles: Profiles
|
||||
proxies: Proxies
|
||||
systemProxy: System Proxy
|
||||
tunMode: TUN Mode
|
||||
closeAllConnections: Close All Connections
|
||||
lightweightMode: Lightweight Mode
|
||||
copyEnv: Copy Environment Variables
|
||||
confDir: Configuration Directory
|
||||
coreDir: Core Directory
|
||||
logsDir: Log Directory
|
||||
openDir: Open Directory
|
||||
appLog: Application Log
|
||||
coreLog: Core Log
|
||||
restartClash: Restart Clash Core
|
||||
restartApp: Restart Application
|
||||
vergeVersion: Verge Version
|
||||
more: More
|
||||
exit: Exit
|
||||
tooltip:
|
||||
systemProxy: System Proxy
|
||||
tun: TUN
|
||||
profile: Profile
|
||||
@@ -0,0 +1,52 @@
|
||||
_version: 1
|
||||
notifications:
|
||||
dashboardToggled:
|
||||
title: Dashboard
|
||||
body: Dashboard visibility has been updated.
|
||||
clashModeChanged:
|
||||
title: Mode Switch
|
||||
body: Switched to {mode}.
|
||||
systemProxyToggled:
|
||||
title: System Proxy
|
||||
body: System proxy status has been updated.
|
||||
tunModeToggled:
|
||||
title: TUN Mode
|
||||
body: TUN mode status has been updated.
|
||||
lightweightModeEntered:
|
||||
title: Lightweight Mode
|
||||
body: Entered lightweight mode.
|
||||
appQuit:
|
||||
title: About to Exit
|
||||
body: Clash Verge is about to exit.
|
||||
appHidden:
|
||||
title: Application Hidden
|
||||
body: Clash Verge is running in the background.
|
||||
service:
|
||||
adminPrompt: Installing the service requires administrator privileges.
|
||||
tray:
|
||||
dashboard: Dashboard
|
||||
ruleMode: Rule Mode
|
||||
globalMode: Global Mode
|
||||
directMode: Direct Mode
|
||||
profiles: Profiles
|
||||
proxies: Proxies
|
||||
systemProxy: System Proxy
|
||||
tunMode: TUN Mode
|
||||
closeAllConnections: Close All Connections
|
||||
lightweightMode: Lightweight Mode
|
||||
copyEnv: Copy Environment Variables
|
||||
confDir: Configuration Directory
|
||||
coreDir: Core Directory
|
||||
logsDir: Log Directory
|
||||
openDir: Open Directory
|
||||
appLog: Application Log
|
||||
coreLog: Core Log
|
||||
restartClash: Restart Clash Core
|
||||
restartApp: Restart Application
|
||||
vergeVersion: Verge Version
|
||||
more: More
|
||||
exit: Exit
|
||||
tooltip:
|
||||
systemProxy: System Proxy
|
||||
tun: TUN
|
||||
profile: Profile
|
||||
@@ -0,0 +1,52 @@
|
||||
_version: 1
|
||||
notifications:
|
||||
dashboardToggled:
|
||||
title: Dashboard
|
||||
body: Dashboard visibility has been updated.
|
||||
clashModeChanged:
|
||||
title: Mode Switch
|
||||
body: Switched to {mode}.
|
||||
systemProxyToggled:
|
||||
title: System Proxy
|
||||
body: System proxy status has been updated.
|
||||
tunModeToggled:
|
||||
title: TUN Mode
|
||||
body: TUN mode status has been updated.
|
||||
lightweightModeEntered:
|
||||
title: Lightweight Mode
|
||||
body: Entered lightweight mode.
|
||||
appQuit:
|
||||
title: About to Exit
|
||||
body: Clash Verge is about to exit.
|
||||
appHidden:
|
||||
title: Application Hidden
|
||||
body: Clash Verge is running in the background.
|
||||
service:
|
||||
adminPrompt: Installing the service requires administrator privileges.
|
||||
tray:
|
||||
dashboard: Dashboard
|
||||
ruleMode: Rule Mode
|
||||
globalMode: Global Mode
|
||||
directMode: Direct Mode
|
||||
profiles: Profiles
|
||||
proxies: Proxies
|
||||
systemProxy: System Proxy
|
||||
tunMode: TUN Mode
|
||||
closeAllConnections: Close All Connections
|
||||
lightweightMode: Lightweight Mode
|
||||
copyEnv: Copy Environment Variables
|
||||
confDir: Configuration Directory
|
||||
coreDir: Core Directory
|
||||
logsDir: Log Directory
|
||||
openDir: Open Directory
|
||||
appLog: Application Log
|
||||
coreLog: Core Log
|
||||
restartClash: Restart Clash Core
|
||||
restartApp: Restart Application
|
||||
vergeVersion: Verge Version
|
||||
more: More
|
||||
exit: Exit
|
||||
tooltip:
|
||||
systemProxy: System Proxy
|
||||
tun: TUN
|
||||
profile: Profile
|
||||
@@ -0,0 +1,52 @@
|
||||
_version: 1
|
||||
notifications:
|
||||
dashboardToggled:
|
||||
title: 仪表板
|
||||
body: 仪表板显示状态已更新。
|
||||
clashModeChanged:
|
||||
title: 模式切换
|
||||
body: 已切换至 {mode}。
|
||||
systemProxyToggled:
|
||||
title: 系统代理
|
||||
body: 系统代理状态已更新。
|
||||
tunModeToggled:
|
||||
title: TUN 模式
|
||||
body: TUN 模式状态已更新。
|
||||
lightweightModeEntered:
|
||||
title: 轻量模式
|
||||
body: 已进入轻量模式。
|
||||
appQuit:
|
||||
title: 即将退出
|
||||
body: Clash Verge 即将退出。
|
||||
appHidden:
|
||||
title: 应用已隐藏
|
||||
body: Clash Verge 正在后台运行。
|
||||
service:
|
||||
adminPrompt: 安装服务需要管理员权限
|
||||
tray:
|
||||
dashboard: 仪表板
|
||||
ruleMode: 规则模式
|
||||
globalMode: 全局模式
|
||||
directMode: 直连模式
|
||||
profiles: 订阅
|
||||
proxies: 代理
|
||||
systemProxy: 系统代理
|
||||
tunMode: TUN 模式
|
||||
closeAllConnections: 关闭所有连接
|
||||
lightweightMode: 轻量模式
|
||||
copyEnv: 复制环境变量
|
||||
confDir: 配置目录
|
||||
coreDir: 内核目录
|
||||
logsDir: 日志目录
|
||||
openDir: 打开目录
|
||||
appLog: 应用日志
|
||||
coreLog: 内核日志
|
||||
restartClash: 重启 Clash 内核
|
||||
restartApp: 重启应用
|
||||
vergeVersion: Verge 版本
|
||||
more: 更多
|
||||
exit: 退出
|
||||
tooltip:
|
||||
systemProxy: 系统代理
|
||||
tun: TUN
|
||||
profile: 订阅
|
||||
@@ -0,0 +1,52 @@
|
||||
_version: 1
|
||||
notifications:
|
||||
dashboardToggled:
|
||||
title: 儀表板
|
||||
body: 儀表板顯示狀態已更新。
|
||||
clashModeChanged:
|
||||
title: 模式切換
|
||||
body: 已切換至 {mode}。
|
||||
systemProxyToggled:
|
||||
title: 系統代理
|
||||
body: 系統代理狀態已更新。
|
||||
tunModeToggled:
|
||||
title: TUN 模式
|
||||
body: TUN 模式狀態已更新。
|
||||
lightweightModeEntered:
|
||||
title: 輕量模式
|
||||
body: 已進入輕量模式。
|
||||
appQuit:
|
||||
title: 即將退出
|
||||
body: Clash Verge 即將退出。
|
||||
appHidden:
|
||||
title: 應用已隱藏
|
||||
body: Clash Verge 正在背景執行。
|
||||
service:
|
||||
adminPrompt: 安裝服務需要管理員權限
|
||||
tray:
|
||||
dashboard: 儀表板
|
||||
ruleMode: 規則模式
|
||||
globalMode: 全域模式
|
||||
directMode: 直連模式
|
||||
profiles: 訂閱
|
||||
proxies: 代理
|
||||
systemProxy: 系統代理
|
||||
tunMode: TUN 模式
|
||||
closeAllConnections: 關閉所有連線
|
||||
lightweightMode: 輕量模式
|
||||
copyEnv: 複製環境變數
|
||||
confDir: 設定目錄
|
||||
coreDir: 核心目錄
|
||||
logsDir: 日誌目錄
|
||||
openDir: 開啟目錄
|
||||
appLog: 應用程式日誌
|
||||
coreLog: 核心日誌
|
||||
restartClash: 重新啟動 Clash 核心
|
||||
restartApp: 重新啟動應用程式
|
||||
vergeVersion: Verge 版本
|
||||
more: 更多
|
||||
exit: 離開
|
||||
tooltip:
|
||||
systemProxy: 系統代理
|
||||
tun: TUN
|
||||
profile: 訂閱
|
||||
@@ -1,8 +1,5 @@
|
||||
use super::{CmdResult, StringifyErr};
|
||||
use crate::{
|
||||
core::service::{self, SERVICE_MANAGER, ServiceStatus},
|
||||
utils::i18n::t,
|
||||
};
|
||||
use crate::core::service::{self, SERVICE_MANAGER, ServiceStatus};
|
||||
use smartstring::SmartString;
|
||||
|
||||
async fn execute_service_operation_sync(status: ServiceStatus, op_type: &str) -> CmdResult {
|
||||
@@ -13,7 +10,7 @@ async fn execute_service_operation_sync(status: ServiceStatus, op_type: &str) ->
|
||||
.await
|
||||
{
|
||||
let emsg = format!("{} Service failed: {}", op_type, e);
|
||||
return Err(SmartString::from(&*t(emsg.as_str()).await));
|
||||
return Err(SmartString::from(emsg));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -227,8 +227,6 @@ fn linux_running_as_root() -> bool {
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
async fn uninstall_service() -> Result<()> {
|
||||
use crate::utils::i18n::t;
|
||||
|
||||
logging!(info, Type::Service, "uninstall service");
|
||||
|
||||
let binary_path = dirs::service_path()?;
|
||||
@@ -240,7 +238,9 @@ async fn uninstall_service() -> Result<()> {
|
||||
|
||||
let uninstall_shell: String = uninstall_path.to_string_lossy().into_owned();
|
||||
|
||||
let prompt = t("Service Administrator Prompt").await;
|
||||
crate::utils::i18n::sync_locale().await;
|
||||
|
||||
let prompt = rust_i18n::t!("service.adminPrompt").to_string();
|
||||
let command = format!(
|
||||
r#"do shell script "sudo '{uninstall_shell}'" with administrator privileges with prompt "{prompt}""#
|
||||
);
|
||||
@@ -263,8 +263,6 @@ async fn uninstall_service() -> Result<()> {
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
async fn install_service() -> Result<()> {
|
||||
use crate::utils::i18n::t;
|
||||
|
||||
logging!(info, Type::Service, "install service");
|
||||
|
||||
let binary_path = dirs::service_path()?;
|
||||
@@ -276,7 +274,9 @@ async fn install_service() -> Result<()> {
|
||||
|
||||
let install_shell: String = install_path.to_string_lossy().into_owned();
|
||||
|
||||
let prompt = t("Service Administrator Prompt").await;
|
||||
crate::utils::i18n::sync_locale().await;
|
||||
|
||||
let prompt = rust_i18n::t!("service.adminPrompt").to_string();
|
||||
let command = format!(
|
||||
r#"do shell script "sudo '{install_shell}'" with administrator privileges with prompt "{prompt}""#
|
||||
);
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
use crate::utils::i18n::t;
|
||||
use std::sync::Arc;
|
||||
use rust_i18n::t;
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
|
||||
fn to_arc_str(value: Cow<'static, str>) -> Arc<str> {
|
||||
match value {
|
||||
Cow::Borrowed(s) => Arc::from(s),
|
||||
Cow::Owned(s) => Arc::from(s.into_boxed_str()),
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! define_menu {
|
||||
($($field:ident => $const_name:ident, $id:expr, $text:expr),+ $(,)?) => {
|
||||
@@ -11,9 +18,10 @@ macro_rules! define_menu {
|
||||
pub struct MenuIds;
|
||||
|
||||
impl MenuTexts {
|
||||
pub async fn new() -> Self {
|
||||
let ($($field,)+) = futures::join!($(t($text),)+);
|
||||
Self { $($field,)+ }
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
$($field: to_arc_str(t!($text)),)+
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,26 +32,26 @@ macro_rules! define_menu {
|
||||
}
|
||||
|
||||
define_menu! {
|
||||
dashboard => DASHBOARD, "tray_dashboard", "Dashboard",
|
||||
rule_mode => RULE_MODE, "tray_rule_mode", "Rule Mode",
|
||||
global_mode => GLOBAL_MODE, "tray_global_mode", "Global Mode",
|
||||
direct_mode => DIRECT_MODE, "tray_direct_mode", "Direct Mode",
|
||||
profiles => PROFILES, "tray_profiles", "Profiles",
|
||||
proxies => PROXIES, "tray_proxies", "Proxies",
|
||||
system_proxy => SYSTEM_PROXY, "tray_system_proxy", "System Proxy",
|
||||
tun_mode => TUN_MODE, "tray_tun_mode", "TUN Mode",
|
||||
close_all_connections => CLOSE_ALL_CONNECTIONS, "tray_close_all_connections", "Close All Connections",
|
||||
lightweight_mode => LIGHTWEIGHT_MODE, "tray_lightweight_mode", "LightWeight Mode",
|
||||
copy_env => COPY_ENV, "tray_copy_env", "Copy Env",
|
||||
conf_dir => CONF_DIR, "tray_conf_dir", "Conf Dir",
|
||||
core_dir => CORE_DIR, "tray_core_dir", "Core Dir",
|
||||
logs_dir => LOGS_DIR, "tray_logs_dir", "Logs Dir",
|
||||
open_dir => OPEN_DIR, "tray_open_dir", "Open Dir",
|
||||
app_log => APP_LOG, "tray_app_log", "Open App Log",
|
||||
core_log => CORE_LOG, "tray_core_log", "Open Core Log",
|
||||
restart_clash => RESTART_CLASH, "tray_restart_clash", "Restart Clash Core",
|
||||
restart_app => RESTART_APP, "tray_restart_app", "Restart App",
|
||||
verge_version => VERGE_VERSION, "tray_verge_version", "Verge Version",
|
||||
more => MORE, "tray_more", "More",
|
||||
exit => EXIT, "tray_exit", "Exit",
|
||||
dashboard => DASHBOARD, "tray_dashboard", "tray.dashboard",
|
||||
rule_mode => RULE_MODE, "tray_rule_mode", "tray.ruleMode",
|
||||
global_mode => GLOBAL_MODE, "tray_global_mode", "tray.globalMode",
|
||||
direct_mode => DIRECT_MODE, "tray_direct_mode", "tray.directMode",
|
||||
profiles => PROFILES, "tray_profiles", "tray.profiles",
|
||||
proxies => PROXIES, "tray_proxies", "tray.proxies",
|
||||
system_proxy => SYSTEM_PROXY, "tray_system_proxy", "tray.systemProxy",
|
||||
tun_mode => TUN_MODE, "tray_tun_mode", "tray.tunMode",
|
||||
close_all_connections => CLOSE_ALL_CONNECTIONS, "tray_close_all_connections", "tray.closeAllConnections",
|
||||
lightweight_mode => LIGHTWEIGHT_MODE, "tray_lightweight_mode", "tray.lightweightMode",
|
||||
copy_env => COPY_ENV, "tray_copy_env", "tray.copyEnv",
|
||||
conf_dir => CONF_DIR, "tray_conf_dir", "tray.confDir",
|
||||
core_dir => CORE_DIR, "tray_core_dir", "tray.coreDir",
|
||||
logs_dir => LOGS_DIR, "tray_logs_dir", "tray.logsDir",
|
||||
open_dir => OPEN_DIR, "tray_open_dir", "tray.openDir",
|
||||
app_log => APP_LOG, "tray_app_log", "tray.appLog",
|
||||
core_log => CORE_LOG, "tray_core_log", "tray.coreLog",
|
||||
restart_clash => RESTART_CLASH, "tray_restart_clash", "tray.restartClash",
|
||||
restart_app => RESTART_APP, "tray_restart_app", "tray.restartApp",
|
||||
verge_version => VERGE_VERSION, "tray_verge_version", "tray.vergeVersion",
|
||||
more => MORE, "tray_more", "tray.more",
|
||||
exit => EXIT, "tray_exit", "tray.exit",
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ use crate::{
|
||||
feat, logging,
|
||||
module::lightweight::is_in_lightweight_mode,
|
||||
singleton_lazy,
|
||||
utils::{dirs::find_target_icons, i18n::t},
|
||||
utils::{dirs::find_target_icons, i18n},
|
||||
};
|
||||
|
||||
use super::handle;
|
||||
@@ -438,6 +438,8 @@ impl Tray {
|
||||
|
||||
let app_handle = handle::Handle::app_handle();
|
||||
|
||||
i18n::sync_locale().await;
|
||||
|
||||
let verge = Config::verge().await.latest_arc();
|
||||
let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false);
|
||||
let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
|
||||
@@ -464,9 +466,9 @@ impl Tray {
|
||||
}
|
||||
|
||||
// Get localized strings before using them
|
||||
let sys_proxy_text = t("SysProxy").await;
|
||||
let tun_text = t("TUN").await;
|
||||
let profile_text = t("Profile").await;
|
||||
let sys_proxy_text = rust_i18n::t!("tray.tooltip.systemProxy");
|
||||
let tun_text = rust_i18n::t!("tray.tooltip.tun");
|
||||
let profile_text = rust_i18n::t!("tray.tooltip.profile");
|
||||
|
||||
let v = env!("CARGO_PKG_VERSION");
|
||||
let reassembled_version = v.split_once('+').map_or_else(
|
||||
@@ -622,7 +624,7 @@ async fn create_profile_menu_item(
|
||||
CheckMenuItem::with_id(
|
||||
&app_handle,
|
||||
format!("profiles_{profile_uid}"),
|
||||
t(profile_name).await,
|
||||
profile_name.as_str(),
|
||||
true,
|
||||
is_current_profile,
|
||||
None::<&str>,
|
||||
@@ -817,6 +819,8 @@ async fn create_tray_menu(
|
||||
) -> Result<tauri::menu::Menu<Wry>> {
|
||||
let current_proxy_mode = mode.unwrap_or("");
|
||||
|
||||
i18n::sync_locale().await;
|
||||
|
||||
// 获取当前配置文件的选中代理组信息
|
||||
let current_profile_selected = {
|
||||
let profiles_config = Config::profiles().await;
|
||||
@@ -877,7 +881,7 @@ async fn create_tray_menu(
|
||||
create_profile_menu_item(app_handle, profile_uid_and_name).await?;
|
||||
|
||||
// Pre-fetch all localized strings
|
||||
let texts = &MenuTexts::new().await;
|
||||
let texts = MenuTexts::new();
|
||||
// Convert to references only when needed
|
||||
let profile_menu_items_refs: Vec<&dyn IsMenuItem<Wry>> = profile_menu_items
|
||||
.iter()
|
||||
|
||||
@@ -25,12 +25,15 @@ use crate::{
|
||||
use anyhow::Result;
|
||||
use config::Config;
|
||||
use once_cell::sync::OnceCell;
|
||||
use rust_i18n::i18n;
|
||||
use tauri::{AppHandle, Manager};
|
||||
#[cfg(target_os = "macos")]
|
||||
use tauri_plugin_autostart::MacosLauncher;
|
||||
use tauri_plugin_deep_link::DeepLinkExt;
|
||||
use utils::logging::Type;
|
||||
|
||||
i18n!("locales", fallback = "zh");
|
||||
|
||||
pub static APP_HANDLE: OnceCell<AppHandle> = OnceCell::new();
|
||||
/// Application initialization helper functions
|
||||
mod app_init {
|
||||
|
||||
+78
-93
@@ -1,43 +1,80 @@
|
||||
use crate::{config::Config, utils::dirs};
|
||||
use once_cell::sync::Lazy;
|
||||
use smartstring::alias::String;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs,
|
||||
path::PathBuf,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
use crate::config::Config;
|
||||
use sys_locale;
|
||||
|
||||
const DEFAULT_LANGUAGE: &str = "zh";
|
||||
|
||||
type TranslationMap = (String, HashMap<String, Arc<str>>);
|
||||
fn supported_languages_internal() -> Vec<&'static str> {
|
||||
rust_i18n::available_locales!()
|
||||
}
|
||||
|
||||
fn get_locales_dir() -> Option<PathBuf> {
|
||||
dirs::app_resources_dir()
|
||||
.map(|resource_path| resource_path.join("locales"))
|
||||
.ok()
|
||||
const fn fallback_language() -> &'static str {
|
||||
DEFAULT_LANGUAGE
|
||||
}
|
||||
|
||||
fn locale_alias(locale: &str) -> Option<&'static str> {
|
||||
match locale {
|
||||
"ja" | "ja-jp" | "jp" => Some("jp"),
|
||||
"zh" | "zh-cn" | "zh-hans" | "zh-sg" | "zh-my" | "zh-chs" => Some("zh"),
|
||||
"zh-tw" | "zh-hk" | "zh-hant" | "zh-mo" | "zh-cht" => Some("zhtw"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_supported_language(language: &str) -> Option<String> {
|
||||
if language.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let normalized = language.to_lowercase().replace('_', "-");
|
||||
|
||||
let mut candidates: Vec<String> = Vec::new();
|
||||
let mut push_candidate = |candidate: String| {
|
||||
if !candidate.is_empty()
|
||||
&& !candidates
|
||||
.iter()
|
||||
.any(|existing| existing.eq_ignore_ascii_case(&candidate))
|
||||
{
|
||||
candidates.push(candidate);
|
||||
}
|
||||
};
|
||||
|
||||
let segments: Vec<&str> = normalized.split('-').collect();
|
||||
|
||||
for i in (1..=segments.len()).rev() {
|
||||
let prefix = segments[..i].join("-");
|
||||
if let Some(alias) = locale_alias(&prefix) {
|
||||
push_candidate(alias.to_string());
|
||||
}
|
||||
push_candidate(prefix);
|
||||
}
|
||||
|
||||
let supported = supported_languages_internal();
|
||||
|
||||
candidates.into_iter().find(|candidate| {
|
||||
supported
|
||||
.iter()
|
||||
.any(|&lang| lang.eq_ignore_ascii_case(candidate))
|
||||
})
|
||||
}
|
||||
|
||||
fn system_language() -> String {
|
||||
sys_locale::get_locale()
|
||||
.as_deref()
|
||||
.and_then(resolve_supported_language)
|
||||
.unwrap_or_else(|| fallback_language().to_string())
|
||||
}
|
||||
|
||||
pub fn get_supported_languages() -> Vec<String> {
|
||||
let mut languages = Vec::new();
|
||||
supported_languages_internal()
|
||||
.into_iter()
|
||||
.map(|lang| lang.to_string())
|
||||
.collect()
|
||||
}
|
||||
|
||||
if let Some(locales_dir) = get_locales_dir()
|
||||
&& let Ok(entries) = fs::read_dir(locales_dir)
|
||||
{
|
||||
for entry in entries.flatten() {
|
||||
if let Some(file_name) = entry.file_name().to_str()
|
||||
&& let Some(lang) = file_name.strip_suffix(".json")
|
||||
{
|
||||
languages.push(lang.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if languages.is_empty() {
|
||||
languages.push(DEFAULT_LANGUAGE.into());
|
||||
}
|
||||
languages
|
||||
pub fn set_locale(language: &str) {
|
||||
let lang =
|
||||
resolve_supported_language(language).unwrap_or_else(|| fallback_language().to_string());
|
||||
rust_i18n::set_locale(&lang);
|
||||
}
|
||||
|
||||
pub async fn current_language() -> String {
|
||||
@@ -45,70 +82,18 @@ pub async fn current_language() -> String {
|
||||
.await
|
||||
.latest_arc()
|
||||
.language
|
||||
.as_deref()
|
||||
.map(String::from)
|
||||
.unwrap_or_else(get_system_language)
|
||||
.clone()
|
||||
.filter(|lang| !lang.is_empty())
|
||||
.and_then(|lang| resolve_supported_language(&lang))
|
||||
.unwrap_or_else(system_language)
|
||||
}
|
||||
|
||||
static TRANSLATIONS: Lazy<RwLock<TranslationMap>> = Lazy::new(|| {
|
||||
let lang = get_system_language();
|
||||
let map = load_lang_file(&lang).unwrap_or_default();
|
||||
RwLock::new((lang, map))
|
||||
});
|
||||
|
||||
fn load_lang_file(lang: &str) -> Option<HashMap<String, Arc<str>>> {
|
||||
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::<HashMap<String, String>>(&content).ok())
|
||||
.map(|map| {
|
||||
map.into_iter()
|
||||
.map(|(k, v)| (k, Arc::from(v.as_str())))
|
||||
.collect()
|
||||
})
|
||||
pub async fn sync_locale() -> String {
|
||||
let language = current_language().await;
|
||||
set_locale(&language);
|
||||
language
|
||||
}
|
||||
|
||||
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.into())
|
||||
}
|
||||
|
||||
pub async fn t(key: &str) -> Arc<str> {
|
||||
let current_lang = current_language().await;
|
||||
|
||||
{
|
||||
if let Ok(cache) = TRANSLATIONS.read()
|
||||
&& cache.0 == current_lang
|
||||
&& let Some(text) = cache.1.get(key)
|
||||
{
|
||||
return Arc::clone(text);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(new_map) = load_lang_file(¤t_lang)
|
||||
&& let Ok(mut cache) = TRANSLATIONS.write()
|
||||
{
|
||||
*cache = (current_lang.clone(), new_map);
|
||||
|
||||
if let Some(text) = cache.1.get(key) {
|
||||
return Arc::clone(text);
|
||||
}
|
||||
}
|
||||
|
||||
if current_lang != DEFAULT_LANGUAGE
|
||||
&& let Some(default_map) = load_lang_file(DEFAULT_LANGUAGE)
|
||||
&& let Ok(mut cache) = TRANSLATIONS.write()
|
||||
{
|
||||
*cache = (DEFAULT_LANGUAGE.into(), default_map);
|
||||
|
||||
if let Some(text) = cache.1.get(key) {
|
||||
return Arc::clone(text);
|
||||
}
|
||||
}
|
||||
|
||||
Arc::from(key)
|
||||
pub const fn default_language() -> &'static str {
|
||||
fallback_language()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use crate::{core::handle, utils::i18n::t};
|
||||
|
||||
use crate::{core::handle, utils::i18n};
|
||||
use tauri_plugin_notification::NotificationExt;
|
||||
|
||||
pub enum NotificationEvent<'a> {
|
||||
@@ -27,48 +26,44 @@ fn notify(title: &str, body: &str) {
|
||||
}
|
||||
|
||||
pub async fn notify_event<'a>(event: NotificationEvent<'a>) {
|
||||
i18n::sync_locale().await;
|
||||
|
||||
match event {
|
||||
NotificationEvent::DashboardToggled => {
|
||||
notify(
|
||||
&t("DashboardToggledTitle").await,
|
||||
&t("DashboardToggledBody").await,
|
||||
);
|
||||
let title = rust_i18n::t!("notifications.dashboardToggled.title").to_string();
|
||||
let body = rust_i18n::t!("notifications.dashboardToggled.body").to_string();
|
||||
notify(&title, &body);
|
||||
}
|
||||
NotificationEvent::ClashModeChanged { mode } => {
|
||||
notify(
|
||||
&t("ClashModeChangedTitle").await,
|
||||
&t_with_args("ClashModeChangedBody", mode).await,
|
||||
);
|
||||
let title = rust_i18n::t!("notifications.clashModeChanged.title").to_string();
|
||||
let body = rust_i18n::t!("notifications.clashModeChanged.body").replace("{mode}", mode);
|
||||
notify(&title, &body);
|
||||
}
|
||||
NotificationEvent::SystemProxyToggled => {
|
||||
notify(
|
||||
&t("SystemProxyToggledTitle").await,
|
||||
&t("SystemProxyToggledBody").await,
|
||||
);
|
||||
let title = rust_i18n::t!("notifications.systemProxyToggled.title").to_string();
|
||||
let body = rust_i18n::t!("notifications.systemProxyToggled.body").to_string();
|
||||
notify(&title, &body);
|
||||
}
|
||||
NotificationEvent::TunModeToggled => {
|
||||
notify(
|
||||
&t("TunModeToggledTitle").await,
|
||||
&t("TunModeToggledBody").await,
|
||||
);
|
||||
let title = rust_i18n::t!("notifications.tunModeToggled.title").to_string();
|
||||
let body = rust_i18n::t!("notifications.tunModeToggled.body").to_string();
|
||||
notify(&title, &body);
|
||||
}
|
||||
NotificationEvent::LightweightModeEntered => {
|
||||
notify(
|
||||
&t("LightweightModeEnteredTitle").await,
|
||||
&t("LightweightModeEnteredBody").await,
|
||||
);
|
||||
let title = rust_i18n::t!("notifications.lightweightModeEntered.title").to_string();
|
||||
let body = rust_i18n::t!("notifications.lightweightModeEntered.body").to_string();
|
||||
notify(&title, &body);
|
||||
}
|
||||
NotificationEvent::AppQuit => {
|
||||
notify(&t("AppQuitTitle").await, &t("AppQuitBody").await);
|
||||
let title = rust_i18n::t!("notifications.appQuit.title").to_string();
|
||||
let body = rust_i18n::t!("notifications.appQuit.body").to_string();
|
||||
notify(&title, &body);
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
NotificationEvent::AppHidden => {
|
||||
notify(&t("AppHiddenTitle").await, &t("AppHiddenBody").await);
|
||||
let title = rust_i18n::t!("notifications.appHidden.title").to_string();
|
||||
let body = rust_i18n::t!("notifications.appHidden.body").to_string();
|
||||
notify(&title, &body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数,带参数的i18n
|
||||
async fn t_with_args(key: &str, mode: &str) -> String {
|
||||
t(key).await.replace("{mode}", mode)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"resources": ["resources", "resources/locales/*"],
|
||||
"resources": ["resources"],
|
||||
"publisher": "Clash Verge Rev",
|
||||
"externalBin": ["sidecar/verge-mihomo", "sidecar/verge-mihomo-alpha"],
|
||||
"copyright": "GNU General Public License v3.0",
|
||||
|
||||
Reference in New Issue
Block a user