SwiftUI - 应用内切换语言

889 阅读1分钟

首先添加多语言文件 Localizable.xcstrings

如果希望在 iOS 17 之前使用 @EnvironmentObject,但不想在 ContentView 中手动传递 languageState,可以在 WindowGroup 上直接使用 .environmentObject 来设置。这样可以确保在整个应用中都能访问到 languageState。以下是如何实现的示例:

1. 更新 LanguageState

首先,保持之前的 LanguageState 类,它会在启动时从 UserDefaults 加载语言设置,并在语言更改时保存到 UserDefaults 中:

import Combine
import SwiftUI

class LanguageState: ObservableObject {
    @Published var localeIdentifier: String {
        didSet {
            saveLanguage() // 每次语言改变时保存
        }
    }
    
    init() {
        localeIdentifier = UserDefaults.standard.string(forKey: "selectedLanguage") ?? Locale.current.identifier
    }
    
    func switchLanguage(to identifier: String) {
        localeIdentifier = identifier
    }
    
    private func saveLanguage() {
        UserDefaults.standard.set(localeIdentifier, forKey: "selectedLanguage")
    }
}

2. 在应用入口设置 @EnvironmentObject

在应用的入口文件中,直接将 languageState 作为环境对象传递给 WindowGroup,而不是通过构造函数传递给 ContentView

@main
struct MyApp: App {
    @StateObject private var languageState = LanguageState()

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(languageState) // 在这里设置环境对象
                .environment(\.locale, Locale(identifier: languageState.localeIdentifier)) // 设置语言环境
        }
    }
}

3. 在 LanguageChangeView 中使用 @EnvironmentObject

LanguageChangeView 中使用 @EnvironmentObject 直接访问 languageState

struct LanguageChangeView: View {
    
    @EnvironmentObject var languageState: LanguageState
    @State private var selectedLanguage: String = ""
    let languages = ["zh-Hans", "en"]
    
    var body: some View {
        List(languages, id: \.self) { language in
            HStack {
                Text(language == "zh-Hans" ? "简体中文" : "English")
                Spacer()
                if language == selectedLanguage {
                    Image(systemName: "checkmark")
                        .foregroundColor(.black)
                }
            }
            .contentShape(Rectangle())
            .onTapGesture {
                selectedLanguage = language
                languageState.switchLanguage(to: language)
            }
        }
        .navigationTitle("语言切换")
        .onAppear {
            selectedLanguage = languageState.localeIdentifier
        }
    }
}

struct LanguageChangeView_Previews: PreviewProvider {
    static var previews: some View {
        // 创建一个测试用的 LanguageState 对象并传入预览
        LanguageChangeView()
            .environmentObject(LanguageState())
    }
}

总结

  • 使用 @EnvironmentObject:在 WindowGroup 中直接设置环境对象,确保整个应用都可以访问。
  • 简化传递:不需要在每个视图中手动传递 languageState,使代码更加简洁。

这样,当你在应用中切换语言时,languageState 会自动更新,并且所有使用了 @EnvironmentObject 的视图会相应地更新。