Add in-app language picker to App Settings
This commit is contained in:
@@ -7,16 +7,21 @@ import SwiftUI
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
public struct AppView: View {
|
public struct AppView: View {
|
||||||
|
private static let supportedLanguages: [(code: String?, name: String)] = [
|
||||||
|
(nil, String(localized: "System Default")),
|
||||||
|
("en", "English"),
|
||||||
|
("zh-Hans", "简体中文"),
|
||||||
|
]
|
||||||
|
|
||||||
@State private var isLoading = true
|
@State private var isLoading = true
|
||||||
|
@State private var selectedLanguage: String?
|
||||||
|
|
||||||
@State private var startAtLogin = false
|
|
||||||
@Environment(\.showMenuBarExtra) private var showMenuBarExtra
|
|
||||||
@Environment(\.menuBarExtraSpeedMode) private var menuBarExtraSpeedMode
|
|
||||||
@State private var menuBarExtraInBackground = false
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
|
@State private var startAtLogin = false
|
||||||
|
@Environment(\.showMenuBarExtra) private var showMenuBarExtra
|
||||||
|
@Environment(\.menuBarExtraSpeedMode) private var menuBarExtraSpeedMode
|
||||||
|
@State private var menuBarExtraInBackground = false
|
||||||
@State private var rootHelperRegistrationStatus: SMAppService.Status = .notRegistered
|
@State private var rootHelperRegistrationStatus: SMAppService.Status = .notRegistered
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@State private var alert: AlertState?
|
@State private var alert: AlertState?
|
||||||
@@ -32,6 +37,15 @@ public struct AppView: View {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
FormView {
|
FormView {
|
||||||
|
Picker("Language", selection: $selectedLanguage) {
|
||||||
|
ForEach(Self.supportedLanguages, id: \.code) { language in
|
||||||
|
Text(language.name).tag(language.code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onChangeCompat(of: selectedLanguage) { newValue in
|
||||||
|
updateLanguage(newValue)
|
||||||
|
}
|
||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
FormToggle("Start At Login", "Launch the application when the system is logged in. If enabled at the same time as `Show in Menu Bar` and `Keep Menu Bar in Background`, the application interface will not be opened automatically.", $startAtLogin) { newValue in
|
FormToggle("Start At Login", "Launch the application when the system is logged in. If enabled at the same time as `Show in Menu Bar` and `Keep Menu Bar in Background`, the application interface will not be opened automatically.", $startAtLogin) { newValue in
|
||||||
updateLoginItems(newValue)
|
updateLoginItems(newValue)
|
||||||
@@ -145,6 +159,7 @@ public struct AppView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func loadSettings() async {
|
private func loadSettings() async {
|
||||||
|
selectedLanguage = Self.currentLanguage()
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
startAtLogin = SMAppService.mainApp.status == .enabled
|
startAtLogin = SMAppService.mainApp.status == .enabled
|
||||||
menuBarExtraInBackground = await SharedPreferences.menuBarExtraInBackground.get()
|
menuBarExtraInBackground = await SharedPreferences.menuBarExtraInBackground.get()
|
||||||
@@ -155,6 +170,32 @@ public struct AppView: View {
|
|||||||
isLoading = false
|
isLoading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static func currentLanguage() -> String? {
|
||||||
|
guard let languages = UserDefaults.standard.array(forKey: "AppleLanguages") as? [String],
|
||||||
|
let first = languages.first
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for language in supportedLanguages {
|
||||||
|
if let code = language.code, first.hasPrefix(code) {
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateLanguage(_ language: String?) {
|
||||||
|
if let language {
|
||||||
|
UserDefaults.standard.set([language], forKey: "AppleLanguages")
|
||||||
|
} else {
|
||||||
|
UserDefaults.standard.removeObject(forKey: "AppleLanguages")
|
||||||
|
}
|
||||||
|
alert = AlertState(
|
||||||
|
title: String(localized: "Restart Required"),
|
||||||
|
message: String(localized: "Language will be changed after restarting the app.")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
|
|
||||||
private func updateLoginItems(_ startAtLogin: Bool) {
|
private func updateLoginItems(_ startAtLogin: Bool) {
|
||||||
|
|||||||
@@ -27,11 +27,7 @@ public struct SettingView: View {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#if os(macOS)
|
case app, core, packetTunnel, onDemandRules, profileOverride, sponsors
|
||||||
case app
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case core, packetTunnel, onDemandRules, profileOverride, sponsors
|
|
||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
var page: SettingsPage {
|
var page: SettingsPage {
|
||||||
@@ -58,10 +54,8 @@ public struct SettingView: View {
|
|||||||
|
|
||||||
var title: String {
|
var title: String {
|
||||||
switch self {
|
switch self {
|
||||||
#if os(macOS)
|
case .app:
|
||||||
case .app:
|
return String(localized: "App")
|
||||||
return String(localized: "App")
|
|
||||||
#endif
|
|
||||||
case .core:
|
case .core:
|
||||||
return String(localized: "Core")
|
return String(localized: "Core")
|
||||||
case .packetTunnel:
|
case .packetTunnel:
|
||||||
@@ -77,10 +71,8 @@ public struct SettingView: View {
|
|||||||
|
|
||||||
private var iconImage: String {
|
private var iconImage: String {
|
||||||
switch self {
|
switch self {
|
||||||
#if os(macOS)
|
case .app:
|
||||||
case .app:
|
return "app.badge.fill"
|
||||||
return "app.badge.fill"
|
|
||||||
#endif
|
|
||||||
case .core:
|
case .core:
|
||||||
return "shippingbox.fill"
|
return "shippingbox.fill"
|
||||||
case .packetTunnel:
|
case .packetTunnel:
|
||||||
@@ -98,10 +90,8 @@ public struct SettingView: View {
|
|||||||
var contentView: some View {
|
var contentView: some View {
|
||||||
Group {
|
Group {
|
||||||
switch self {
|
switch self {
|
||||||
#if os(macOS)
|
case .app:
|
||||||
case .app:
|
AppView()
|
||||||
AppView()
|
|
||||||
#endif
|
|
||||||
case .core:
|
case .core:
|
||||||
CoreView()
|
CoreView()
|
||||||
case .packetTunnel:
|
case .packetTunnel:
|
||||||
@@ -165,10 +155,7 @@ public struct SettingView: View {
|
|||||||
public var body: some View {
|
public var body: some View {
|
||||||
FormView {
|
FormView {
|
||||||
Section {
|
Section {
|
||||||
#if os(macOS)
|
ForEach([Tabs.app, Tabs.core, Tabs.packetTunnel, Tabs.onDemandRules, Tabs.profileOverride]) { it in
|
||||||
Tabs.app.navigationLink
|
|
||||||
#endif
|
|
||||||
ForEach([Tabs.core, Tabs.packetTunnel, Tabs.onDemandRules, Tabs.profileOverride]) { it in
|
|
||||||
it.navigationLink
|
it.navigationLink
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+40
-3
@@ -1531,6 +1531,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Language" : {
|
||||||
|
"localizations" : {
|
||||||
|
"zh-Hans" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "语言"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Language will be changed after restarting the app." : {
|
||||||
|
"localizations" : {
|
||||||
|
"zh-Hans" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "重启应用后语言将生效。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Last Updated" : {
|
"Last Updated" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"zh-Hans" : {
|
"zh-Hans" : {
|
||||||
@@ -1830,9 +1850,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"Not installed" : {
|
|
||||||
|
|
||||||
},
|
},
|
||||||
"Ok" : {
|
"Ok" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -2141,6 +2158,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Restart Required" : {
|
||||||
|
"localizations" : {
|
||||||
|
"zh-Hans" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "需要重启"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Resume" : {
|
"Resume" : {
|
||||||
"comment" : "Resume log auto-scroll",
|
"comment" : "Resume log auto-scroll",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@@ -2517,6 +2544,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"System Default" : {
|
||||||
|
"localizations" : {
|
||||||
|
"zh-Hans" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "跟随系统"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"System Extension" : {
|
"System Extension" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"zh-Hans" : {
|
"zh-Hans" : {
|
||||||
|
|||||||
Reference in New Issue
Block a user