SwiftUI本地化-应用内切换语言

现在很多App都有提供多种语言,能够让用户选择自己最熟悉的语言不仅会极大提高用户体验,而且还会提升App的质量。本文将会完整的介绍怎么为一个App添加多种语言支持,并且无需重启系统就可以实现应用内切换语言版本,但是不会详细介绍每一种本地化表达式的规则。

添加语言

Project Navigation 中,点击PROJECT ,选择Info 可以在Localizations中进行语言的添加。

点击+,选择需要添加的语言。这里就是告诉iOS我们的App会支持哪些语言。

创建本地化文本映射字符串文件

在iOS中,系统是通过查找键值对的方式实现本地化的,这个映射文件就是字符串文件,类型是.strings,格式如下:

Swift 复制代码
// en
apple = "Apple";
Swift 复制代码
// zh
apple = "苹果";

右键项目目录或command+N 创建文件,选择Strings File ,命名为Localizable. strings

选中目录中Localizable. strings ,点击右边的按钮Localize... ,选择生成Localizable. strings对应的语言文件。由于我这里已经生成好了,不方便截图,直接看最后的生成结果:

然后在对应的文件中创建需要本地化的文本键值对了,注意每一行都要;结束,最后一行也是。

如果en环境的key和value是一样的,那么en的字符串文件内容可以为空。其实到了这一步,我们的App已经完成了本地化支持了,是跟随系统的语言自动适配。

实现应用内切换

如果我们的App有一个设置页面,里面有一个切换语言的功能,我们希望通过切换语言来实时的改变UI上的文本语言,那现在还远远不够。

@EnvironmentObject

@EnvironmentObjectSwiftUI 的一个属性包装器,用于在整个视图层中传递一个遵循ObservableObject协议的对象来共享数据,在这个对象中,如果一个属性用@Published来修饰,当这个属性值发生变化时,所有依赖这个属性的视图都会收到通知并重新渲染。

我们可以通过这个配合修改视图的Locale环境变量来达到应用内动态的切换语言的目的。先定义一个AppState类,用来保存App的状态:

Swift 复制代码
final class AppState: ObservableObject {
    
    @Published var localeIdentifier: String = "en-US"
    
    init() {
        // 获取系统的Locale
        var id = Locale.current.identifier;
        if let identifier = UserDefaults.standard.string(forKey: "locale_identifier") {
            // 使用用户上次的设置。如果用户有选择语言,就要保存起来
            id = identifier
        }
        
        if id.hasPrefix("zh") {
            _localeIdentifier = Published(initialValue: "zh-CN")
        }
    }
}

初始化App时创建AppState,并使用.environmentObject()保存起来,以便其他View通过@EnvironmentObject获取使用:

Swift 复制代码
@main
struct DingsApp: App {
    
    @StateObject private var appState = AppState()
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                // ContentView()已经加了Locale环境,这个视图就本地化了
                .environment(\.locale, Locale(identifier: appState.localeIdentifier))
                .environmentObject(appState)
        }
    }
}

如果我们需要对MainView本地化,就需要增加属性AppState ,并使用它的localeIdentifier属性来设置视图的environment,这样当localeIdentifier改变了,视图的locale也会变化,视图就会使用新的locale来渲染:

Swift 复制代码
struct MainView: View {

    @EnvironmentObject private var appState: AppState
    
    var body: some View {
        VStack {
            ...
        }
        .environment(\.locale, Locale(identifier: appState.localeIdentifier))
    }
}

切换语言功能

当用户选择不同的语言时,修改AppStatelocaleIdentifier属性值,并保存到用户数据中:

Swift 复制代码
Button {
    select(for: "zh-Hans")
}
    
private func select(for language: String) {
    let localeIdentifier = (language == "zh-Hans") ? "zh-CN" : "en-US"
    appState.localeIdentifier = localeIdentifier
    UserDefaults.standard.set(localeIdentifier, forKey: "locale_identifier")
}

其他

有一些地方比较特殊,比如通过函数取得的字符串key,数组里面取的字符串key等就无法本地化,例如:

Swift 复制代码
private let months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"]

// 无法本地化
Text(months[index])

这个时候我们可以通过拓展String,增加一个方法,来手动调用获取不同环境下的值。

Swift 复制代码
extension String {
    func localizedString(identifier: String = "en-US") -> String {
        let language = identifier == "zh-CN" ? "zh-Hans" : "en"
        if let path = Bundle.main.path(forResource: language, ofType: "lproj") {
            if let bundle = Bundle(path: path) {
                return bundle.localizedString(forKey: self, value: self, table: nil)
            }
        }

        return self
    }
}

然后在调用StringlocalizedString方法就可以了。

Swift 复制代码
Text(months[index].localizedString(identifier: appState.localeIdentifier))

另外,还有Date 的格式化也不是使用视图的environment ,而是使用Textformat ,所以对于Date可以这样处理:

Swift 复制代码
Date().formatted(Date.FormatStyle(date: .abbreviated, time: .omitted, locale: Locale(identifier: appState.localeIdentifier)))

好了,就这些了,现在我们的App应该可以很好的实现应用内切换语言了。谢谢支持,原创不易,转载请注明来源。

相关推荐
DisonTangor2 小时前
苹果发布iOS 18.2首个公测版:Siri接入ChatGPT、iPhone 16拍照按钮有用了
ios·chatgpt·iphone
- 羊羊不超越 -2 小时前
App渠道来源追踪方案全面分析(iOS/Android/鸿蒙)
android·ios·harmonyos
2401_8658548818 小时前
iOS应用想要下载到手机上只能苹果签名吗?
后端·ios·iphone
HackerTom1 天前
iOS用rime且导入自制输入方案
ios·iphone·rime
良技漫谈1 天前
Rust移动开发:Rust在iOS端集成使用介绍
后端·程序人生·ios·rust·objective-c·swift
2401_852403551 天前
高效管理iPhone存储:苹果手机怎么删除相似照片
ios·智能手机·iphone
星际码仔2 天前
【动画图解】是怎样的方法,能被称作是 Flutter Widget 系统的核心?
android·flutter·ios
emperinter2 天前
WordCloudStudio:AI生成模版为您的文字云创意赋能 !
图像处理·人工智能·macos·ios·信息可视化·iphone
关键帧Keyframe2 天前
音视频面试题集锦第 8 期
ios·音视频开发·客户端
pb82 天前
引入最新fluwx2.5.4的时候报错
flutter·ios