SwiftUI — 国际化

在 iOS 开发中支持 国际化(Internationalization, i18n) 是现代应用程序的一个重要功能,目的是让应用能够支持多种语言和文化区域,为全球用户提供更加本地化的体验。

以下是 iOS 应用实现 国际化 的主流解决方案和最佳实践:


1. 主流解决方案概览 #

解决方案 / 技术适用场景
Apple 本地化工具(本地化字符串、Localizable.strings应用内主要文本的国际化,适合较简单的需求。例如按钮文本、标签、提示语等。
Localizable.stringsdict用于文本中的复数形式和动态拼接处理。例如,「1个消息」vs「3条消息」。
NSLocalizedStringXcode 提供的国际化标识符管理方式,可动态加载本地化内容。
Bundle 动态加载机制文件、图片、多内容的动态本地化,例如根据语言加载不同的图片或 JSON 文件资源。
第三方库(Swiftgen、Lokalise、Crowdin 等)自动化管理国际化文件/资源,适合大规模或跨团队的国际化协作。

2. Apple 提供的本地化工具 #

2.1 基本流程 #

  1. 启用国际化支持 打开 Xcode 项目:

    • 选择项目 -> Info -> 勾选 Use Base Internationalization
    • 添加支持的语言,例如 EnglishChineseFrench
  2. 本地化字符串文件(Localizable.strings 创建一个专门存放本地化字符串的文件 Localizable.strings

    • 在 Xcode 中右键项目,选择 New File -> iOS -> Strings File。
    • 为每种语言创建一个版本。

示例: #

Localizable.strings(英文版):

"greeting" = "Hello, welcome!";
"exit" = "Exit";

Localizable.strings(中文简体版):

"greeting" = "你好,欢迎!";
"exit" = "退出";
  1. 使用 NSLocalizedString 加载本地化字符串

示例代码: #

Text(NSLocalizedString("greeting", comment: "Welcome message displayed to the user"))
Button(NSLocalizedString("exit", comment: "Exit button title")) {
    print("Exit button tapped")
}
  1. 本地化用户界面(Storyboard/Xib 文件)
    • 打开 Main.storyboard
    • 在右侧的 File Inspector 中勾选 Localize
    • Xcode 会让你为该界面添加对应语言的翻译文本。

2.2 本地化动态复数或字符串拼接 #

如果需要支持复数形式或动态值的拼接,可以使用 Localizable.stringsdict 文件。

示例: #

Localizable.stringsdict:

<dict>
    <key>messages</key>
    <dict>
        <key>NSStringLocalizedFormatKey</key>
        <string>%#@value@</string>
        <key>value</key>
        <dict>
            <key>NSStringFormatSpecTypeKey</key>
            <string>NSStringPluralRuleType</string>
            <key>NSStringFormatValueTypeKey</key>
            <string>d</string>
            <key>one</key>
            <string>%d new message</string>
            <key>other</key>
            <string>%d new messages</string>
        </dict>
    </dict>
</dict>

示例代码: #

let messageCount = 3
let message = String.localizedStringWithFormat(NSLocalizedString("messages", comment: ""), messageCount)
print(message) // "3 new messages"

2.3 本地化支持的文件类型 #

除了文本,Apple 提供的本地化机制也支持其他文件资源。例如:

  • 图片本地化:可以为不同语言添加不同的图片。
  • JSON 文件本地化:加载不同语言的配置文件。

2.4 按需切换语言(动态切换) #

iOS 默认使用系统语言,但也可以动态切换应用语言:

示例代码: #

func changeLanguage(to languageCode: String) {
    UserDefaults.standard.set([languageCode], forKey: "AppleLanguages")
    UserDefaults.standard.synchronize()

    // 重启应用以应用语言切换
    exit(0)
}

3. 第三方国际化工具 #

  1. SwiftGen
    • 自动生成本地化代码(如 Localizable.strings 的命名空间)。
    • 提高代码可维护性,避免使用硬编码的 Key。

示例: #

Text(L10n.greeting) // 自动生成的命名空间
  1. Lokalise

    • 云端管理国际化内容,支持团队协作翻译。
    • 自动生成本地化文件并导入 Xcode。
  2. Crowdin

    • 类似于 Lokalise,但还集成了翻译 API 和自动化内容管理。

4. 国际化中需要注意的内容 #

4.1 UI 适配问题 #

  1. 多语言字数差异

    • 比如英文短,但德文和法文会更长,阿拉伯语会从右往左显示。
    • 可以使用 GeometryReader 动态布局或 SwiftUI.multilineTextAlignment()
  2. 适配从右到左的语言

    • 默认情况下,iOS 会根据语言自动调整布局。
    • 如果需要手动检测语言方向,用 UIView.userInterfaceLayoutDirection(for:) 检查。

4.2 日期、时间和数字本地化 #

iOS 提供了强大的 DateFormatterNumberFormatter 工具来处理区域化差异。

示例代码: #

let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "fr_FR") // 目标语言
dateFormatter.dateStyle = .full

let today = Date()
print(dateFormatter.string(from: today)) // 法语的日期格式

5. 自动测试本地化 #

为确保应用的多语言支持正确,可以通过以下措施测试:

  1. Xcode 中切换语言

    • 在 Xcode 的 Scheme 设置中添加 App 的支持语言进行测试。
    • 可以快速切换语言不用在系统设置中修改语言。
  2. 通过脚本遍历语言

    • 编写自动化脚本加载所有语言以检查缺少的翻译内容。

6. 工作流优化建议 #

最佳实践 #

  1. 命名规范

    • 以模块划分 Key,例如 home.greetingsettings.logout.
    • 避免使用硬编码的 Key。
  2. 自动检查漏翻译

    • 可以用工具(如 Lokalise 或自定义脚本)检查未翻译的 Key。
  3. 双语言并列开发

    • Base 或默认语言旁边显示翻译语言,便于对比。

总结 #

  • 对于小型应用: 使用 Apple 提供的 Localizable.stringsNSLocalizedString 是最主流的解决方案。

  • 对于中大型应用或多团队协作: 可以引入第三方工具(如 SwiftGenLokalise)来提高自动化和协作效率。

国际化的核心是在 技术实现、翻译管理、UI 调整 上三者结合,做好这些步骤即可为你的全球用户提供优质的本地化体验!

SwiftUI 使用国际化 #

在 SwiftUI 中,国际化(Localization)是支持多种语言和地区的应用程序的核心功能。Swift 提供了强大的国际化工具和方法,结合 Xcode 的内置功能,可以轻松地在项目中实现本地化支持。

以下是 SwiftUI 国际化的完整指南,包括实现步骤和详细说明。


1. 什么是国际化(Localization)? #

在 SwiftUI 中,国际化涉及以下核心内容:

  • 翻译文本(Strings Localization):将 UI 上的静态或动态文本翻译为不同语言。
  • 本地化资源:支持不同语言版本的图像、文件等。
  • 日期和货币的本地化格式:根据用户的地区显示日期、时间、货币等格式。

SwiftUI 使用系统提供的本地化机制,其基础是 Localizable.strings 文件和 Xcode 项目的本地化支持。


2. 快速实现本地化支持 #

下面是实现 SwiftUI 国际化的一个完整流程:

步骤 1:启用项目的本地化支持 #

  1. 在 Xcode 中打开项目文件。
  2. 选择你的项目 > 目标(Target) > Info 标签页。
  3. 找到 Localizations 部分。
  4. 点击 “+” 按钮,添加你需要支持的语言(例如 “English”,“Chinese (Simplified)” 等)。
    • 添加后,Xcode 会为项目的主要资源(如 .strings 文件)创建语言分支。

步骤 2:创建 Localizable.strings 文件 #

  1. 在 Xcode 工程中:
    • 右击项目目录 > 新建文件(New File)。
    • 在弹出的窗口中搜索 Strings,选择 Strings File,并将其命名为 Localizable.strings
  2. 选中 Localizable.strings 文件,打开右侧的 File Inspector(⌥ + ⌘ + 1)。
    • 勾选你需要支持的语言(例如 English、Chinese)。
    • Xcode 会自动为每个语言创建对应的 Localizable.strings 文件分支。

步骤 3:编辑 Localizable.strings 文件 #

打开每个语言版本的 Localizable.strings 文件,添加本地化字符串。键值对格式为:

"键" = "翻译内容";

示例: #

  • 英文版 Localizable.strings
"welcome_message" = "Welcome!";
"greeting_message" = "Hello, how are you?";
  • 简体中文 Localizable.strings
"welcome_message" = "欢迎!";
"greeting_message" = "你好,你好吗?";

步骤 4:在 SwiftUI 中使用本地化文本 #

通过 NSLocalizedStringText 直接绑定关键字动态加载翻译。

示例: #

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            // 使用 Text 时会自动加载本地化内容
            Text("welcome_message") // 将根据语言显示本地化结果

            // 直接使用 NSLocalizedString
            Text(NSLocalizedString("greeting_message", comment: "Greeting message to user"))
        }
        .padding()
    }
}

如果用户的设备语言设置为中文(简体),以上代码会显示:

欢迎!
你好,你好吗?

步骤 5:本地化图片和资源 #

Xcode 还支持本地化图像和其他静态资源。

为图像添加本地化版本: #

  1. Assets.xcassets 中选择一个需要本地化的图像(如 Logo)。
  2. 右键图像 > Localization > 选择语言版本。
    • 每种语言版本都会创建一个单独的图像文件夹,你可以为每个语言提供不同的图像。

示例:加载本地化图像 #

Image("Logo") // SwiftUI 会根据当前语言加载对应的 Logo 版本

6. 本地化日期、时间和货币格式 #

Swift 提供了 DateFormatterNumberFormatter 来支持动态的地区格式。

日期的本地化显示 #

import SwiftUI

struct ContentView: View {
    var body: some View {
        let date = Date()
        let formatter = DateFormatter()
        formatter.dateStyle = .long // 显示完整的日期

        Text("Today: \(formatter.string(from: date))")
    }
}

根据用户的设备地区设置,将显示:

  • 英文(美国):Today: January 1, 2023
  • 中文(中国):Today: 2023年1月1日

货币本地化 #

import SwiftUI

struct ContentView: View {
    var body: some View {
        let price = 1234.56
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency // 激活货币格式
        formatter.locale = Locale.current // 使用设备地区设置

        Text("Price: \(formatter.string(from: NSNumber(value: price)) ?? "")")
    }
}

根据用户的地区显示:

  • 英文(美国):Price: $1,234.56
  • 中文(中国):Price: ¥1,234.56

7. 支持动态切换语言 #

在实际应用中,用户可能需要在应用内动态切换语言。这种情况下,可以使用自定义逻辑加载语言。

示例:动态切换语言 #

  1. 创建一个函数用于加载指定语言的 .strings 文件:
class Localizer {
    static func setLanguage(_ language: String) {
        UserDefaults.standard.set([language], forKey: "AppleLanguages")
        UserDefaults.standard.synchronize()
    }
}
  1. App 启动或切换语言时调用:
Localizer.setLanguage("zh-Hans") // 设置为中文显示
  1. 重新启动 App 生效。

8. 调试本地化内容 #

在开发阶段,可以手动切换系统语言用于测试。操作如下:

  1. 点击设备的 设置 > 通用 > 语言与地区
  2. 更改语言(比如英文 -> 中文)。
  3. 返回应用检查 UI 是否正确更新。

如果要更快速测试不同的语言,可以通过模拟器设置 环境语言

  • 在 Xcode 的 Scheme 配置中(Edit Scheme),添加 -AppleLanguages 参数。

9. 本地化的最佳实践 #

  1. 不要硬编码字符串

    • 所有显示在 UI 上的文本都应该放入 Localizable.strings 文件。
    • 避免直接在代码中写硬编码的文本(如 "Hello")。
  2. 为每个语言版本提供完整资源

    • 确保所有支持的语言 Localizable.strings 文件都提供完整且精准的内容。
  3. 测试语言覆盖情况

    • 使用工具(如 Xcode Preview 或真实设备)测试所有语言和地区的显示效果。
  4. 支持 Right-to-Left 语言

    • 比如阿拉伯语和希伯来语,应该在 UI 设计中测试 RTL(从右到左)的界面适配。

总结 #

SwiftUI 的国际化功能基于已有的 Cocoa 本地化机制,结合 Xcode 提供的开发工具非常简单高效。以下是本地化的关键流程:

步骤动作示例
添加 Localizable 文件在项目中创建 Localizable.strings 文件,并适配本地化语言。"key" = "value";
使用本地化翻译在代码中通过 Text("key")NSLocalizedString 加载翻译内容。Text("welcome_message")
日期货币等动态本地化转换使用 DateFormatterNumberFormatter 等进行格式转换。¥123.45
测试国际化显示通过模拟器语言环境或设备实际切换语言检查 UI 效果。更改系统区域语言。

通过上述步骤可以轻松面向全球用户构建多语言的 SwiftUI 应用!

String(localized: “Hello”) #

确实,String(localized:) 是 Swift 中一个现代化的国际化方法,它是在 Swift 5.5 中引入的,结合了 Swift 的类型安全和简洁性,专门用于处理本地化字符串。相比传统的 NSLocalizedString 方法,它更简洁、更易用,尤其适合 SwiftUI 的开发场景。

感谢你的补充!下面我将详细介绍 String(localized:) 的使用及其与传统方法的对比。


1. 什么是 String(localized:) #

String(localized:) 是 Swift 的一种新方式,用于加载本地化字符串。它结合了 Swift 的类型安全和现代化的 API,能够简化国际化代码,同时支持 Xcode 的 .strings 文件。

优点 #

  • 简洁:不需要显式指定 tableNamebundle,只需提供键值即可。
  • 类型安全:支持参数插值,避免拼接错误。
  • 现代化:与 SwiftUI 的语法风格一致,适合 Swift 项目。

2. 使用 String(localized:) 的步骤 #

步骤 1:创建 Localizable.strings 文件 #

  1. 在 Xcode 项目中,右键项目目录 > 新建文件(New File)。
  2. 搜索 Strings File,创建一个名为 Localizable.strings 的文件。
  3. 在文件中添加本地化字符串:

示例: #

  • 英文版 Localizable.strings
"Today" = "Today";
"WelcomeMessage" = "Welcome, %@!";
  • 简体中文版 Localizable.strings
"Today" = "今天";
"WelcomeMessage" = "欢迎, %@!";

步骤 2:使用 String(localized:) 加载本地化字符串 #

在 SwiftUI 或其他 Swift 代码中,直接使用 String(localized:) 方法加载本地化的文本。

示例代码: #

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            // 加载简单的本地化字符串
            Text(String(localized: "Today"))

            // 加载带参数的本地化字符串
            Text(String(localized: "WelcomeMessage", table: nil, bundle: .main, comment: "Welcome message"))
                .font(.headline)
        }
        .padding()
    }
}

运行效果: #

  • 英文环境
Today
Welcome, %@!
  • 简体中文环境
今天
欢迎, %@!

3. 动态参数插值 #

String(localized:) 支持动态参数插值,可以直接将参数嵌入到本地化字符串中。

示例:动态参数 #

import SwiftUI

struct ContentView: View {
    var userName = "Alice"

    var body: some View {
        Text(String(localized: "WelcomeMessage", arguments: [userName]))
    }
}

本地化文件内容: #

  • 英文版 Localizable.strings
"WelcomeMessage" = "Welcome, %@!";
  • 简体中文版 Localizable.strings
"WelcomeMessage" = "欢迎, %@!";

运行效果: #

  • 英文环境Welcome, Alice!
  • 简体中文环境欢迎, Alice!

4. 使用 String(localized:) 的高级功能 #

格式化日期和数字 #

String(localized:) 还支持日期、时间、货币等格式化内容的本地化。

示例:日期本地化 #

import SwiftUI

struct ContentView: View {
    var body: some View {
        let date = Date()
        Text(String(localized: "\(date.formatted(.dateTime.month().day()))"))
    }
}

运行效果: #

  • 英文环境Jan 24
  • 简体中文环境1月24日

自定义翻译表 #

如果你需要使用自定义的 .strings 文件,而不是默认的 Localizable.strings,可以通过指定 table 参数加载。

示例: #

Text(String(localized: "CustomKey", table: "CustomStrings"))
  • 在项目中创建 CustomStrings.strings 文件。
  • 添加对应的键值对:
    • 英文版 CustomStrings.strings
      "CustomKey" = "This is a custom key!";
      
    • 简体中文版 CustomStrings.strings
      "CustomKey" = "这是一个自定义键!";
      

指定 Bundle #

如果本地化资源不在主项目中(例如在动态库或模块中),可以通过 bundle 参数指定加载的资源包。

示例: #

let customBundle = Bundle(path: "path/to/your/bundle")!
Text(String(localized: "Key", bundle: customBundle))

5. String(localized:)NSLocalizedString 的对比 #

特性String(localized:)NSLocalizedString
语法简洁性更简洁,直接使用 String(localized:)需要显式指定键值和注释
参数插值支持类型安全的动态参数插值需要手动拼接字符串
SwiftUI 兼容性与 SwiftUI 风格一致语法稍显冗长
自定义翻译表支持通过 table 参数指定支持通过 tableName 参数指定
现代化支持更现代化,推荐用于新项目传统方法,适合旧项目或兼容性需求

6. 动态切换语言 #

String(localized:) 同样支持动态切换语言的功能,结合 UserDefaultsAppleLanguages 可以实现。

示例:动态切换语言 #

class LanguageManager {
    static func setLanguage(_ language: String) {
        UserDefaults.standard.set([language], forKey: "AppleLanguages")
        UserDefaults.standard.synchronize()
    }
}

// 切换到中文
LanguageManager.setLanguage("zh-Hans")

注意: #

  • 切换语言后,应用需要重新启动才能生效。

7. 注意事项和最佳实践 #

  1. 避免硬编码字符串

    • 将所有用户可见的文本放入 .strings 文件中,避免直接在代码中写硬编码文本。
  2. 测试多语言支持

    • 使用 Xcode 的 模拟器语言设置 或设备的语言设置测试 UI。
    • Edit Scheme 中添加 -AppleLanguages 参数快速切换语言。
  3. 使用动态参数插值

    • 动态参数插值可以减少拼接错误,提升代码的可读性和安全性。
  4. 支持 RTL(从右到左)语言

    • 确保 UI 适配阿拉伯语、希伯来语等从右到左的语言。

总结 #

String(localized:) 是 Swift 国际化的现代解决方案,它更简洁、更安全,特别适合 SwiftUI 项目。以下是它的核心特点:

  • 简化了加载本地化字符串的代码。
  • 支持动态参数插值和格式化。
  • 与 Swift 的类型系统和 SwiftUI 风格高度一致。
  • 更适合新项目的国际化需求。

如果你正在开发一个支持多语言的 SwiftUI 应用,建议优先使用 String(localized:),它可以让你的代码更加简洁和现代化!

国际化其他形式 #

当然,Swift 和 SwiftUI 在国际化(Localization)方面有几个相关的工具和方法,可以适用于不同的场景。除了 String(localized:) 和传统的 NSLocalizedString 方法外,还有一些技巧和方法可能会对你的项目有用,包括动态语言切换、本地化自定义类型、日期和数字本地化以及使用 SwiftUI 的特定支持工具。

以下是 SwiftUI 和 Swift 国际化的其他方法和高级用法:


8. 使用 Environment 的 Locale #

SwiftUI 提供了一个非常强大的 @Environment(\.locale) 属性,可以动态访问和修改设备的区域设置(Locale),从而直接影响视图的显示语言和本地化内容。

示例:动态更新语言 #

import SwiftUI

struct ContentView: View {
    @Environment(\.locale) var locale // 当前的区域

    var body: some View {
        VStack {
            Text("Today") // 自动根据当前区域加载本地化
                .padding()

            Text("Current Locale: \(locale.identifier)") // 输出当前语言的标识符
        }
        .onAppear {
            // 检查当前地区
            print("Current Locale: \(locale)")
        }
    }
}

示例:手动切换语言 #

  • 通过 environment 修饰符主动更改视图的区域设置。
import SwiftUI

struct ContentView: View {
    @State private var selectedLocale: Locale = .current

    var body: some View {
        VStack {
            Text("Today") // 根据区域设置加载本地化

            Button("切换到中文") {
                selectedLocale = Locale(identifier: "zh-Hans") // 切换到中文
            }

            Button("切换到英文") {
                selectedLocale = Locale(identifier: "en") // 切换到英文
            }
        }
        .environment(\.locale, selectedLocale) // 设置动态区域
    }
}

说明: #

  1. Locale(identifier:) 可以指定具体的语言,例如 "en"(英文)或 "zh-Hans"(中文)。
  2. 使用 environment(\.locale, Locale) 动态切换语言,而无需重新启动应用。

9. 对自定义数据类型进行本地化 #

如果你的应用中存在自定义的数据类型(如 enum 或模型对象),也可以为这些类型实现本地化支持。

示例:对枚举进行本地化 #

import SwiftUI

enum TaskStatus: String, CaseIterable {
    case todo = "To Do"
    case inProgress = "In Progress"
    case done = "Done"
}

extension TaskStatus: CustomStringConvertible {
    var description: String {
        switch self {
        case .todo:
            return NSLocalizedString("To Do", comment: "Task status: to do")
        case .inProgress:
            return NSLocalizedString("In Progress", comment: "Task status: in progress")
        case .done:
            return NSLocalizedString("Done", comment: "Task status: done")
        }
    }
}

struct ContentView: View {
    var taskStatus: TaskStatus = .inProgress

    var body: some View {
        Text("Current Status: \(taskStatus.description)") // 将状态根据语言本地化
    }
}

本地化文件内容 (Localizable.strings): #

"To Do" = "待办";
"In Progress" = "进行中";
"Done" = "完成";

10. 使用 LocalizedStringKey #

当你需要将本地化字符串直接绑定到 SwiftUI 的 Text 时,LocalizedStringKey 是一个强大的工具。

LocalizedStringKey 是 SwiftUI 中的一个专用类型,用于解析字符串键并自动从 .strings 文件中加载对应语言的本地化内容。

示例:使用 LocalizedStringKey #

import SwiftUI

struct ContentView: View {
    let welcomeMessage: LocalizedStringKey = "welcome_message"

    var body: some View {
        Text(welcomeMessage) // 会直接显示对应语言的内容
    }
}

优点: #

  1. 和 SwiftUI 组件如 Text 深度集成。
  2. 自动从本地化文件加载内容,避免手动调用 NSLocalizedStringString(localized:)

缺点: #

  • 不支持动态字符串拼接。如果需要动态内容,NSLocalizedStringString(localized:) 是更好的选择。

11. 支持动态语言切换(无需重启应用) #

大多数情况下,改变系统语言后,应用会重新启动以加载新的语言设置。但是,如果你希望用户在应用内动态切换语言,可以结合 UserDefaults 和 SwiftUI 的 @Environment(\.locale) 达成这一目标。

示例:动态切换语言 #

import SwiftUI

class LanguageManager: ObservableObject {
    @Published var currentLocale: Locale = .current // 默认使用当前系统语言

    func switchLanguage(to identifier: String) {
        currentLocale = Locale(identifier: identifier)
    }
}

struct ContentView: View {
    @StateObject private var languageManager = LanguageManager()

    var body: some View {
        VStack {
            Text("Today") // 动态语言切换
                .padding()

            Button("切换到中文") {
                languageManager.switchLanguage(to: "zh-Hans") // 切换到中文
            }

            Button("切换到英文") {
                languageManager.switchLanguage(to: "en") // 切换到英文
            }
        }
        .environment(\.locale, languageManager.currentLocale) // 使用动态 Locale
    }
}

12. 数字和日期的复杂格式化 #

当你需要格式化时间、日期或货币时,可以结合 Foundation 中的 FormatStyle 来完成自动化的本地化处理。

示例:本地化日期显示 #

import SwiftUI

struct ContentView: View {
    var body: some View {
        Text(Date().formatted(.dateTime.weekday().month().day().year()))
            .padding()
    }
}

输出样例: #

  • 在英文环境下:Tuesday, January 24, 2023
  • 在中文环境下:2023年1月24日,星期二

示例:本地化货币显示 #

import SwiftUI

struct ContentView: View {
    var body: some View {
        let price: Double = 1234.56
        Text(price, format: .currency(code: Locale.current.currency?.identifier ?? "USD"))
            .padding()
    }
}

输出样例: #

  • 在英文环境下:$1,234.56
  • 在中文环境下:¥1,234.56

13. 使用 Swift Package 管理本地化 #

在大型项目中,如果本地化字符串较多,可能会使用单独的 Swift 包(Swift Package)来管理本地化资源。

示例:创建自定义模块来管理本地化 #

  1. 创建一个 LocalizationManager 类或 Swift 包,集中管理所有本地化逻辑。
  2. 暴露 API 接口,通过自定义方法返回翻译:
struct LocalizationManager {
    static func localizedString(for key: String) -> String {
        NSLocalizedString(key, comment: "Custom localization manager")
    }
}
  1. 在项目中调用:
Text(LocalizationManager.localizedString(for: "welcome_message"))

这种方式适用于多模块、大型项目的组织和管理。


14. 本地化单词的复数(Pluralization)支持 #

对于需要根据数量变化的文本,String.LocalizationValue 提供了极大的便利。

示例:处理复数文本 #

import SwiftUI

struct ContentView: View {
    var itemCount: Int = 3

    var body: some View {
        Text("\(itemCount) item(s)")
            .padding()
    }
}

本地化配置(Localizable.stringsdict 文件): #

创建一个 Localizable.stringsdict 文件,添加复数规则:

<key>item(s)</key>
<dict>
    <key>NSStringLocalizedFormatKey</key>
    <string>%#@items@</string>
    <key>items</key>
    <dict>
        <key>NSStringFormatSpecTypeKey</key>
        <string>NSStringPluralRuleType</string>
        <key>NSStringFormatValueTypeKey</key>
        <string>d</string>
        <key>zero</key>
        <string>No items</string>
        <key>one</key>
        <string>1 item</string>
        <key>other</key>
        <string>%d items</string>
    </dict>
</dict>

总结 #

在 SwiftUI 中,本地化(Internationalization)的能力远不止简单的键值翻译。综合使用以下方法,可以实现更加现代化和复杂的本地化处理:

  1. String(localized:) 简洁高效,是现代项目首选。
  2. 动态切换语言:结合 @Environment(\.locale)ObservableObject 可实现实时切换。
  3. 本地化资源:支持 Strings 文件、图像资源等多种类型。
  4. 处理时间、货币等复杂格式化:利用 Foundation 的格式化工具。
  5. 支持复数形式:通过 .stringsdict 文件管理。

有了这些工具和方法,SwiftUI 项目可以轻松实现全球化支持,面向多语种、多地区用户。根据项目需求灵活运用吧!

bundle 参数 #

在 SwiftUI 中的 Text(String, bundle:) 是一个用于加载本地化字符串的构造方法,可以指定文本文字的来源 bundle(资源包)。这个方法允许你更精细地控制本地化文本的加载来源,尤其是在多模块项目或动态加载本地资源的场景下非常有用。

bundle 参数的意义 #

bundle 参数告诉 SwiftUI 从哪个 Bundle 中加载对应的本地化字符串。默认值为 .main,即主应用程序的资源包。如果需要从某个自定义的模块或者动态加载的资源包中加载,本地化字符串需要传入特定的 Bundle


默认值为 .main #

在大多数情况下,你的本地化资源(Localizable.strings 或其他文件)都存储在主项目的资源中,默认情况下的 bundle 就是主应用的 Bundle.main

用法示例:

Text("welcome_message")

等价于:

Text("welcome_message", bundle: .main)

如果在你的 Localizable.strings 文件(主资源包中)中有以下内容:

"welcome_message" = "Welcome!";

当当前语言为英语时,Text("welcome_message") 会显示:Welcome!


在多模块中的用法 #

如果你使用了多个模块(如使用 Swift Package Manager 或 CocoaPods 引入的库),有时需要从指定模块的资源中加载本地化内容。此时需要显式指定 bundle 参数。

示例:自定义 Bundle

import Foundation
import SwiftUI

let myCustomBundle = Bundle(identifier: "com.example.MyCustomModule")!

struct ContentView: View {
    var body: some View {
        Text("custom_message", bundle: myCustomBundle)
            .padding()
    }
}

这里的 myCustomBundle 是一个从其他模块加载的资源包(Bundle),从中加载 custom_message 对应的本地化值。

如何确认正确的 Bundle#

  • 从模块中获取 Bundle
    • 如果是 CocoaPods 或 SDL 插件模块,通常可以通过其 Bundle.identifier 直接创建。
    • 如果是 Swift Package Manager,可以通过自定义方法将资源文件附加至包管理并加载。

动态加载其他 Bundle 的场景 #

1. 动态加载不同的本地化资源 #

在某些复杂场景下(比如插件化架构),主应用需要从动态加载的资源包中获取对应的语言内容。

示例:动态获取具体语言版本的 Bundle

let dynamicBundlePath = Bundle.main.path(forResource: "CustomLocalization", ofType: "bundle")!
let dynamicBundle = Bundle(path: dynamicBundlePath)!

Text("welcome_message", bundle: dynamicBundle) // 指定动态加载的资源包

假设 CustomLocalization.bundle 是一个独立的资源包,包含以下内容:

CustomLocalization.bundle/
  en.lproj/Localizable.strings
  zh-Hans.lproj/Localizable.strings

这允许你动态从资源包中加载语言内容,而不是固定依赖在主应用程序中。


2. 在框架中加载本地化资源 #

如果你设计了自己的 Swift 框架并需要加载框架内部的本地化资源,则需要从框架的 bundle 中读取。

示例:加载框架里的本地化资源

// 在你的框架代码中
let frameworkBundle = Bundle(for: MyFrameworkClass.self)

// 通过指定 bundle 加载本地化资源
Text("framework_message", bundle: frameworkBundle)

在这个例子中,Bundle(for:) 确保从框架自身的资源中加载值。


如何使用 SwiftUI 的多模块本地化 #

Swift Package Manager 已支持局部资源清单声明。如果一个模块需要自己的本地化资源,可以在 Package.swift 中添加资源路径,并正确引用 bundle

示例:Package.swift 中声明资源

// Package.swift
let package = Package(
    name: "MyLibrary",
    defaultLocalization: "en",
    targets: [
        .target(
            name: "MyLibrary",
            resources: [
                .process("Resources") // 把 Resources 文件夹下内容标记为资源
            ]
        )
    ]
)

假设 Resources 文件夹下有以下内容:

Resources/
  en.lproj/Localizable.strings
  zh-Hans.lproj/Localizable.strings

在 SwiftUI 中加载资源:

import SwiftUI

let libraryBundle = Bundle.module

struct ContentView: View {
    var body: some View {
        Text("library_message", bundle: libraryBundle)
    }
}

使用 .module 直接指向 SPM 的模块资源包。


小结和适用场景 #

需求场景bundle 参数值说明
主应用加载主资源中的本地化字符串.main(默认省略)如果 Localizable.strings 在主应用资源包中,可以省略 bundle 参数,直接传入 key。
动态加载其他资源包显式传入 Bundle(path:)当本地化资源位于独立的动态包(如 .bundle 文件)中时,使用对应包的路径创建 Bundle。
多模块项目的模块资源使用模块的 Bundle.module如果使用 Swift Package Manager 并声明了资源,使用 .module 从当前模块中加载本地化内容。
框架内的本地化资源使用 Bundle(for: SomeClass.self)如果框架使用返回类方法,指定 for 参数为框架内类,确保获取框架内部的资源包。

使用 bundle 参数可以解决多模块、多资源包、本地化文件分散存储的场景,在复杂项目中非常重要。例如:

  • 如果你有一个插件化系统,每个插件都有独立的语言文件,可以通过指定 bundle 进行加载。
  • 如果你组织了多个 Swift Package 模块,各模块有独立的资源文件,你也可以精准定位语言资源。

bundle 参数结合 SwiftUI 的简洁语法,使得控制本地化资源变得更加灵活和强大。

本文共 8823 字,上次修改于 Jan 24, 2025