You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 19:12:52