独立开发之 App 国际化全步骤(七):App 内语言环境搭建

关于我:大厂摸鱼 + 业余独立开发,之后会输出深度技术文章 + 独立开发技巧

我的往期技术文章合集:RickeyBoy - Gitbub

我的独立开发 App:iColors - 设计灵感 配色助手

上一篇:

独立开发之 App 国际化全步骤(一):为什么要做国际化

独立开发之 App 国际化全步骤(二):App 数据翻译

独立开发之 App 国际化全步骤(三):Core Data 模型升级

独立开发之 App 国际化全步骤(四):Core Data 模型解析

独立开发之 App 国际化全步骤(五):提取 App 中文本文案

独立开发之 App 国际化全步骤(六):替换代码中使用的文本

🎯 App 内语言环境搭建

当我们做完上面的一切操作之后,App 目前看起来已经大体上适配了国际化了,我们可以直接看下效果。

修改默认语言

目前我们可以通过直接设置 App 的默认语言,来查看多语言的效果。可以在真机的设置页面,进行修改:

当然,如果是通过 Xcode 直接进行测试,可以通过修改 Scheme 中的 App Language 设置,来选择默认的语言:

如果是通过 SwiftUI Preview,可以这样快速测试多语言:

Swift 复制代码
CustomView()
  .environment(.locale, .init(identifier: "en")) // use English
  .environment(.locale, .init(identifier: "zh-Hans")) // 使用中文

iOS 中的语言体系

再进行接下来的内容之前,我们需要先了解一下 iOS 中的语言体系。在上面的代码中,注意到我们使用了语言代码 "zh-Hans" 和 "en" 指定对应的语言,来调整 SwiftUI Preview 中需要展示的语言。那么这里的代码到底是什么意思?

Locale - Apple

Information about linguistic, cultural, and technological conventions for use in formatting data for presentation.

首先我们需要知道,iOS 中使用 Locale 来记录语言和地区信息。比如 Locale 中,有几个属性,我们可以获取到对应的信息:

那么如何初始化一个 Locale 类型呢?一种最简单的方法,就是通过 identifier 来直接创建,比如 "zh-Hans" 就代表简体中文,而 "en" 就代表英文,更多的还有 "fr" 代表法语等等,详细的对应关系可以参考 ioslocaleidentifiers - Github

支持 App 内语言选择

目前语言选择的逻辑有两个主流的方式,一个是直接在 App 内支持语言选项,另一个是不支持 App 内选择语言,而是直接使用设置中选中的语言。

其实两种方式并没有非常明显的优缺点,支持 App 内切换的话可能灵活一点,但是实现起来相对难一些。可以根据具体 App 诉求进行选择。

我这里主要讲解第一种,即支持语言在 App 内进行选择,我的 App 也是用的这种方式。

要实现这样一个语言选择逻辑,我们要来自定义一下支持的语言。就 iColors App 来说,目前就需要支持三种语言,中文 + 英文,以及使用系统默认的语言。那么通过枚举类型,进行类似于下面的定义即可:

为了方便读者理解,这里罗列的仅是摘要的简单版本。想要详细使用的话,可以参考:LanguageManager-SwiftUI - Github 中的代码

Swift 复制代码
public enum Languages: String {
    case en
    case zhHans = "zh-Hans"
    case deviceLanguage
}

注意,这里 Languages 类型的 rawValue 其实对应的就是前文提到的 Locale 的语言代码。

与此同时,我们需要通过单例,记录当前选择的语言即可:

Swift 复制代码
public class LanguageSettings: ObservableObject {
  @Published public var selectedLanguage: Languages = .deviceLanguage
}

当然我们还需要一个转换逻辑,将我们定义的 Languages 模型和 iOS 的 Locale 模型关联起来。当我们选择 .deviceLanguage 时,直接使用当前默认的 Locale,否则使用我们选择的 language:

Swift 复制代码
public class LanguageSettings: ObservableObject {
    @Published public var selectedLanguage: Languages = .deviceLanguage
  
    public var locale: Locale {
        if selectedLanguage == .deviceLanguage {
            return Locale.current
        } else {
            return Locale(identifier: selectedLanguage.rawValue)
        }
    }
}

这样我们就完成了一个简单的语言选择逻辑系统,我们只需要在 App 初始化时将 LanguageSettings 的单例初始化并通过 environment 进行环境变量的关联,并且将 locale 信息设置给整个 App 即可,这样我们全局的语言就已经设置好了。

Swift 复制代码
@main
struct XXXApp: App {
  @StateObject var settings = LanguageSettings()
  var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(.locale, settings.locale)
                .environmentObject(settings)
        }
    }
}

增加语言选择页面

有了目前的语言管理框架,那么实现一个语言选择页面,就是一个非常简单的逻辑了。我们可以增加一个数组,保存支持的语言:

Swift 复制代码
public class LanguageSettings: ObservableObject {
  ...
  public let supportedLanguages: [Languages] = [.zh, .en, .deviceLanguage]
}

之后,在语言选择页面,展示所有支持的语言,然后在选择后绑定到当前选择的语言 selectedLanguage 即可:

Swift 复制代码
struct MeLanguageSelection: View {
    @EnvironmentObject var languageSettings: LanguageSettings
    
    var body: some View {
        VStack {
            // list all choice
            ForEach(languageSettings.supportedLanguages, id: .rawValue) { language in
                CustomChoiceView(language)
                    .onTapGesture {
                        // binding
                        languageSettings.selectedLanguage = language
                    }
            }
        }
    }
  
    ...
}
相关推荐
Swift社区2 天前
在 Swift 中实现字符串分割问题:以字典中的单词构造句子
开发语言·ios·swift
#摩斯先生2 天前
Swift从0开始学习 对象和类 day3
ios·xcode·swift
没头脑的ht2 天前
Swift内存访问冲突
开发语言·ios·swift
#摩斯先生2 天前
Swift从0开始学习 并发性 day4
ios·xcode·swift
_黎明2 天前
【Swift】类型标注、类型安全和类型推断
swift
没头脑的ht2 天前
Swift闭包的本质
开发语言·ios·swift
今天啥也没干3 天前
使用 Sparkle 实现 macOS 应用自定义更新弹窗
前端·javascript·swift
yngsqq3 天前
037集——JoinEntities连接多段线polyline和圆弧arc(CAD—C#二次开发入门)
开发语言·c#·swift
_黎明3 天前
【Swift】字符串和字符
开发语言·ios·swift
RickeyBoy4 天前
基于 Swift 从零到一开发贪吃蛇游戏(四)
swift