SwiftUI版通知栏应用开发(4) ——多语言本地化适配

2,417 阅读2分钟

开发多语言版本的 APP,估计是大家希望的,尤其对于 iOS/Mac APP 的开发,上线 App Store 多希望在其它地区也能使用,所以今天主要想学习怎么基于 SwiftUI 做一些文本和字符串文字多语言化。

相信市面上不少这样的文章可供参考

Project 配置

首先,在 Project Info 选项中,选择 Localization 增加一个「中文」本地化配置,如果你需要其他语言,可以相对应的添加:

接下来,新建对应的 Group 文件夹,如本文的两个 Groupen.lprojzh-Hans.lproj

在这两个 Group 里,同时创建同名的 Strings 文件:Localizable

代码编写

创建完成之后,我们分别创建一个 Preferences demo:

在我们的主 View 上引入变量 locale

popOver.contentViewController?.view = NSHostingView(rootView: MainView().environment(\.locale, .init(identifier: "en")))

然后创建一个 Text

Text("Preferences")
    .font(.customf(22))
    .padding(.bottom, 10.0)

刚开始我们定义的是 en,执行看看效果:

如果我们改为 zh-Hans

MainView().environment(\.locale, .init(identifier: "zh-Hans"))

结果也就不一样了:

Locale 变化功能

基本功能实现了,接下来就是设置一个开关来变化 Locale 了。

首先,创建一个 Picker

Section(header: Text("localization")) {
    Picker("", selection: $localeViewModel.localeString) {
        ForEach(LocaleStrings.allCases) { localeString in
            Text(localeString.rawValue)
                .tag(localeString.suggestedLocalication)
        }
    }
    .pickerStyle(SegmentedPickerStyle())
}

其中,我定义两个 enum 来做选择的类型:

enum Localication: String, CaseIterable, Identifiable {
    case zh_Hans = "zh-Hans"
    case en = "en"
    var id: String { self.rawValue }
}

enum LocaleStrings: String, CaseIterable, Identifiable {
    case zh_Hans = "中文"
    case en = "English"
    var id: String { self.rawValue }
}

extension LocaleStrings {
    var suggestedLocalication: Localication {
        switch self {
            case .zh_Hans: return .zh_Hans
            case .en: return .en
        }
    }
}

这个好理解,因为显示的 String 和提供给 locale 的字符串不一致,如显示的是「中文」,提供给 locale 的是 zh-Hans,这里我借助 suggestedLocalication 做桥梁转换。

最后,我们创建一个 Combine ViewModel 变量 localeString,以供实时变化改变本地化字符串内容。

class LocaleViewModel: ObservableObject {
    @Published var localeString: Localication
}

最后,只需要在具体的 View 里加入 ViewModel 订阅变量 localeString 的更新:

// ContentView.swift

import SwiftUI

struct ContentView: View {
    @ObservedObject private var timerViewModel: TimerViewModel
    @ObservedObject private var localeViewModel: LocaleViewModel
    init(timerViewModel: TimerViewModel, localeViewModel: LocaleViewModel) {
        self.timerViewModel = timerViewModel
        self.localeViewModel = localeViewModel
    }
    
    var body: some View {
        Text("localization")
            .font(.customf(14))
            .padding()
            .environment(\.locale, .init(identifier: localeViewModel.localeString.rawValue))
    }
}

好了,代码编写完毕,我们运行看效果:

localechange2

小结

基本跑通本地化多语言适配流程,接下来就是不断增加新的语言和翻译工作。

未完待续