You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

198 lines
6.0 KiB

import Foundation
import SwiftUI
import Combine
//
enum Language: String, CaseIterable {
case system = "system"
case english = "en"
case chinese = "zh-Hans"
case thai = "th"
var displayName: String {
switch self {
case .system:
return "system_language".localized
case .english:
return "English"
case .chinese:
return "chinese_language".localized
case .thai:
return "ไทย"
}
}
var flag: String {
switch self {
case .system:
return "🌐"
case .english:
return "🇺🇸"
case .chinese:
return "🇨🇳"
case .thai:
return "🇹🇭"
}
}
}
//
class LanguageManager: ObservableObject {
static let shared = LanguageManager()
@Published var currentLanguage: Language = .english
@Published var refreshTrigger = UUID() // UI
private let languageKey = "selected_language"
private let systemLanguageKey = "system_language"
private init() {
loadLanguage()
}
//
private func detectSystemLanguage() -> Language {
// iOS 15+
let systemLanguage = Locale.current.languageCode ?? "en"
//
if systemLanguage.hasPrefix("zh") {
return .chinese
}
//
if systemLanguage == "th" {
return .thai
}
// 使
return .english
}
//
private func loadLanguage() {
//
let hasManualLanguage = UserDefaults.standard.object(forKey: languageKey) != nil
if hasManualLanguage {
// 使
if let savedLanguage = UserDefaults.standard.string(forKey: languageKey),
let language = Language(rawValue: savedLanguage) {
if language == .system {
//
let systemLanguage = detectSystemLanguage()
currentLanguage = systemLanguage
} else {
currentLanguage = language
}
} else {
currentLanguage = .english
}
} else {
// 使
currentLanguage = .system
let systemLanguage = detectSystemLanguage()
//
UserDefaults.standard.set("system", forKey: languageKey)
UserDefaults.standard.set(true, forKey: systemLanguageKey)
//
switchLanguage(to: .system)
}
}
//
func switchLanguage(to language: Language) {
currentLanguage = language
if language == .system {
//
resetToSystemLanguage()
} else {
//
UserDefaults.standard.set(language.rawValue, forKey: languageKey)
UserDefaults.standard.set(false, forKey: systemLanguageKey)
// UI
refreshTrigger = UUID()
//
NotificationCenter.default.post(name: .languageChanged, object: language)
}
}
//
func resetToSystemLanguage() {
let systemLanguage = detectSystemLanguage()
currentLanguage = systemLanguage
UserDefaults.standard.set(systemLanguage.rawValue, forKey: languageKey)
UserDefaults.standard.set(true, forKey: systemLanguageKey)
// UI
refreshTrigger = UUID()
//
NotificationCenter.default.post(name: .languageChanged, object: systemLanguage)
}
// 使
var isUsingSystemLanguage: Bool {
return UserDefaults.standard.bool(forKey: systemLanguageKey)
}
//
func localizedString(for key: String) -> String {
let bundle = Bundle.main
// 使
let languageToUse: String
if currentLanguage == .system {
//
let systemLanguage = detectSystemLanguage()
languageToUse = systemLanguage.rawValue
} else {
languageToUse = currentLanguage.rawValue
}
if let path = bundle.path(forResource: languageToUse, ofType: "lproj"),
let languageBundle = Bundle(path: path) {
return languageBundle.localizedString(forKey: key, value: key, table: nil)
}
//
if let path = bundle.path(forResource: "en", ofType: "lproj"),
let languageBundle = Bundle(path: path) {
return languageBundle.localizedString(forKey: key, value: key, table: nil)
}
return key
}
}
//
extension String {
var localized: String {
return LanguageManager.shared.localizedString(for: self)
}
}
//
struct LocalizedText: View {
let key: String
@ObservedObject private var languageManager = LanguageManager.shared
init(_ key: String) {
self.key = key
}
var body: some View {
Text(languageManager.localizedString(for: key))
.id(languageManager.refreshTrigger) //
}
}
//
extension Notification.Name {
static let languageChanged = Notification.Name("languageChanged")
}