SwiftUI设置UserDefaults切换语言后,本地化字符串如何生效?
解决SwiftUI语言切换即时生效或重启应用的问题
一、无需重启:实现即时语言切换
直接修改AppleLanguages后,SwiftUI的LocalizedStringKey不会自动刷新——因为它是在视图初始化时读取语言配置的。要实现即时生效,需要自定义本地化管理工具:
1. 自定义本地化管理器
创建可观察的管理器类,负责读取当前语言并提供本地化字符串:
import SwiftUI class LocalizationManager: ObservableObject { static let shared = LocalizationManager() @Published var currentLanguage: Language { didSet { UserDefaults.standard.set([currentLanguage.rawValue], forKey: "AppleLanguages") objectWillChange.send() } } private init() { let savedLang = UserDefaults.standard.string(forKey: "AppleLanguages")?.first ?? "en" currentLanguage = Language(rawValue: savedLang) ?? .en } func localize(_ key: String) -> String { let path = Bundle.main.path(forResource: currentLanguage.rawValue, ofType: "lproj")! let bundle = Bundle(path: path)! return NSLocalizedString(key, bundle: bundle, comment: "") } } extension Language { var displayName: String { LocalizationManager.shared.localize( self.rawValue == "en" ? "english" : self.rawValue == "uk" ? "ukraine" : "russian" ) } }
2. 修改语言切换逻辑
替换原switchLanguage方法,改为更新管理器的当前语言:
func switchLanguage(to language: Language) { LocalizationManager.shared.currentLanguage = language }
3. 更新LanguageView视图
将所有LocalizedStringKey替换为自定义本地化方法,让视图监听语言变化:
struct LanguageView: View { @ObservedObject private var localizationManager = LocalizationManager.shared @Injected private var userDefaultsManager: UserDefaultsManaging @State private var showingAlert = false @State var selected: Language? @State var original: Language? var body: some View { ZStack { AppBackground() List { Section(localizationManager.localize("language")) { languageButton(to: .en) languageButton(to: .ru) languageButton(to: .uk) } } .scrollContentBackground(.hidden) } .alert(localizationManager.localize("change_language_message"), isPresented: $showingAlert) { Button(localizationManager.localize("choose")) { userDefaultsManager.switchLanguage(to: selected ?? .en) } Button(localizationManager.localize("cancel"), role: .cancel) { withAnimation(.easeIn) { selected = original ?? .en } } } .navigationTitle(localizationManager.localize("change_language")) .onAppear { self.original = userDefaultsManager.getLanguage() self.selected = userDefaultsManager.getLanguage() } } @ViewBuilder func languageButton(to language: Language) -> some View { Button { withAnimation(.easeIn) { if selected != language { selected = language showingAlert = true } } } label: { HStack { Text(language.displayName) if selected == language { Spacer() Image(systemName: "checkmark") } } .foregroundColor(.jmkBlue) .fontWeight(selected == language ? .semibold : .regular) } } }
修改后,切换语言时所有使用localize()方法的文本会自动刷新,无需重启。
二、如果必须重启应用的实现方式
iOS没有官方重启API,可通过以下两种方式实现:
1. 模拟重启(推荐)
重新设置App的根视图,模拟重启效果:
func restartApp() { guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, let window = windowScene.windows.first else { return } let rootView = ContentView() // 替换为你的初始根视图 window.rootViewController = UIHostingController(rootView: rootView) window.makeKeyAndVisible() UIView.transition(with: window, duration: 0.5, options: .transitionCrossDissolve, animations: nil) }
在Alert确认按钮中调用:
Button(localizationManager.localize("choose")) { userDefaultsManager.switchLanguage(to: selected ?? .en) restartApp() }
2. 强制退出(不推荐)
使用exit(0)强制退出应用,用户需手动重新打开,体验较差,且可能引发审核关注:
func forceRestart() { exit(0) }
内容的提问来源于stack exchange,提问作者Jan Janovec
相关产品推荐
相关产品推荐

