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.

314 lines
9.2 KiB

import Foundation
import SwiftUI
import Combine
//
enum Language: String, CaseIterable {
case system = "system"
case english = "en"
case chinese = "zh-Hans"
case japanese = "ja"
case korean = "ko"
case french = "fr"
case german = "de"
case spanish = "es"
case italian = "it"
case portuguese = "pt"
case russian = "ru"
case thai = "th"
var displayName: String {
switch self {
case .system:
return "system_language".localized
case .english:
return "English"
case .thai:
return "ไทย"
case .japanese:
return "日本語"
case .korean:
return "한국어"
case .french:
return "Français"
case .german:
return "Deutsch"
case .spanish:
return "Español"
case .italian:
return "Italiano"
case .portuguese:
return "Português"
case .russian:
return "Русский"
case .chinese:
return "中文"
}
}
var flag: String {
switch self {
case .system:
return "🌐"
case .english:
return "🇺🇸"
case .chinese:
return "🇨🇳"
case .japanese:
return "🇯🇵"
case .korean:
return "🇰🇷"
case .french:
return "🇫🇷"
case .german:
return "🇩🇪"
case .spanish:
return "🇪🇸"
case .italian:
return "🇮🇹"
case .portuguese:
return "🇵🇹"
case .russian:
return "🇷🇺"
case .thai:
return "🇹🇭"
}
}
}
//
class LanguageManager: ObservableObject {
static let shared = LanguageManager()
@Published var currentLanguage: Language = .english
@Published var refreshTrigger = UUID() // UI
@Published var isInitialized = false
private let languageKey = "selected_language"
private let systemLanguageKey = "system_language"
private init() {
loadLanguage()
//
isInitialized = true
}
//
private func detectSystemLanguage() -> Language {
// iOS 15+
let systemLanguage = Locale.current.languageCode ?? "en"
//
if systemLanguage.hasPrefix("zh") {
return .chinese
}
//
if systemLanguage == "ja" {
return .japanese
}
//
if systemLanguage == "ko" {
return .korean
}
//
if systemLanguage == "fr" {
return .french
}
//
if systemLanguage == "de" {
return .german
}
// 西
if systemLanguage == "es" {
return .spanish
}
//
if systemLanguage == "it" {
return .italian
}
//
if systemLanguage == "pt" {
return .portuguese
}
//
if systemLanguage == "ru" {
return .russian
}
//
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
_ = 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 DEBUG
print("🔍 Localization Debug - Key: \(key), Language: \(languageToUse), Current: \(currentLanguage.rawValue)")
#endif
//
if let path = bundle.path(forResource: languageToUse, ofType: "lproj"),
let languageBundle = Bundle(path: path) {
let localizedString = languageBundle.localizedString(forKey: key, value: nil, table: nil)
#if DEBUG
print("🔍 Found bundle at: \(path), Result: \(localizedString)")
#endif
// key
if localizedString != key {
return localizedString
}
} else {
#if DEBUG
print("❌ Bundle not found for language: \(languageToUse)")
#endif
}
// 退
if let path = bundle.path(forResource: "en", ofType: "lproj"),
let languageBundle = Bundle(path: path) {
let englishString = languageBundle.localizedString(forKey: key, value: nil, table: nil)
#if DEBUG
print("🔍 Fallback to English, Result: \(englishString)")
#endif
// key
if englishString != key {
return englishString
}
}
// 退key
#if DEBUG
print("❌ No localization found for key: \(key), returning key itself")
#endif
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")
}