Apple 的 Foundation 框架中的 Locale
(在 macOS 和 iOS 开发中,NSLocale
是其 Objective-C 版本)是一个非常重要的组件,它帮助你管理和利用用户的语言与区域设置信息。下面我将为你介绍它的体系结构、使用方式,并提供一些代码案例。
🌐 Apple Foundation 的 Locale 体系结构与使用指南 #
Locale 的核心作用是提供与特定区域相关的语言、文化、技术惯例的信息,帮助你正确地格式化日期、时间、数字、货币等信息,从而为不同地区的用户提供本地化体验。
◾ 核心架构与关键概念 #
Locale 的体系结构主要围绕语言和区域的组合标识以及一套提供特定区域设置信息的接口。
语言和区域标识符 #
Locale 使用 Locale Identifier 来唯一确定一套本地化规则。这个标识符通常由语言代码和地区代码组合而成:
- 语言代码:通常遵循 ISO 639 标准,例如
"en"
(英语),"zh"
(中文),"ja"
(日语)。 - 地区代码:通常遵循 ISO 3166 标准,例如
"US"
(美国),"CN"
(中国),"JP"
(日本)。 - 组合标识符:将语言和地区代码用下划线或连字符连接,例如
"en_US"
(美国英语),"zh_CN"
(简体中文,中国),"zh-Hans"
(简体中文)。
系统会根据用户设备的语言和地区设置,自动选择最匹配的本地化资源(如 .lproj
目录下的字符串文件、图片等)。
层次化回退机制 #
当应用程序请求某个特定区域设置(如 fr_FR
)的资源时,系统会遵循一个清晰的回退策略来寻找最匹配的可用本地化资源:
- 精确匹配(例如
fr_FR.lproj
) - 语言匹配(任何地区)(例如
fr.lproj
) - 开发基础语言(例如
en.lproj
或资源直接放在项目根目录) - 最终,如果都未找到,则使用基础语言。
这个过程是自动的,你通常不需要手动干预。
◾ Locale 的基本使用方式 #
1. 获取 Locale 实例 #
你可以通过多种方式获取 Locale 实例:
import Foundation
// 获取用户当前设置的 Locale
let currentLocale = Locale.current
print("当前区域标识符: \(currentLocale.identifier)") // 例如输出 "zh_CN" 或 "en_US"
// 获取系统固定的 Locale(通常不随用户设置改变)
let systemLocale = Locale.system
// 通过标识符创建特定的 Locale
let specificLocale = Locale(identifier: "ja_JP")
// 获取由所有可用区域标识符组成的数组
let availableLocaleIdentifiers = Locale.availableIdentifiers
在 Objective-C 中,你可以使用 NSLocale
来完成相同的操作:
NSLocale *currentLocale = [NSLocale currentLocale];
NSLog(@"当前区域标识符: %@", [currentLocale localeIdentifier]);
2. 使用 Locale 进行格式化 #
Locale 通常与其他的格式化器(Formatter)协同工作,以确保数据以符合用户习惯的方式展示。
格式化日期和时间
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale.current // 设置 Locale
dateFormatter.dateStyle = .long
dateFormatter.timeStyle = .short
let now = Date()
let formattedDateString = dateFormatter.string(from: now)
print("格式化后的日期和时间: \(formattedDateString)")
// 在 en_US 区域可能输出 "September 7, 2025 at 3:45 PM"
// 在 zh_CN 区域可能输出 "2025年9月7日 下午3:45"
格式化数字和货币
let numberFormatter = NumberFormatter()
numberFormatter.locale = Locale.current // 设置 Locale
numberFormatter.numberStyle = .currency
let price = 1234.56
if let formattedCurrency = numberFormatter.string(from: NSNumber(value: price)) {
print("格式化后的货币: \(formattedCurrency)")
// 在 en_US 区域可能输出 "$1,234.56"
// 在 de_DE 区域可能输出 "1.234,56 €"
// 在 ja_JP 区域可能输出 "¥1,235"
}
3. 获取 Locale 的属性信息 #
你可以从 Locale 实例中查询各种本地化信息:
let currentLocale = Locale.current
// 获取货币代码
if let currencyCode = currentLocale.currencyCode {
print("货币代码: \(currencyCode)") // 例如 USD, CNY, JPY
}
// 获取小数分隔符
let decimalSeparator = currentLocale.decimalSeparator ?? "."
print("小数分隔符: \(decimalSeparator)") // 例如 "." (en_US), "," (fr_FR)
// 获取地区显示名称(本地化)
let displayName = currentLocale.localizedString(forIdentifier: "fr_FR")
print("fr_FR 的显示名称: \(displayName ?? "Unknown")")
// 在中文环境下可能显示 "法文(法国)"
◾ 在 App 内实现语言切换 #
虽然用户可以在系统的“设置”应用中更改设备的语言,但许多应用也提供了应用内切换语言的功能。这通常需要你管理一个自定义的 Locale
设置,并在整个 App 中应用它。
以下是一个简化的实现思路:
定义支持的语言枚举:
enum AppLanguage: String { case systemDefault = "auto" case english = "en" case simplifiedChinese = "zh-Hans" case japanese = "ja" // 添加其他支持的语言... }
创建一个管理器(例如
LocalizationManager
)来持久化用户的选择并提供当前应用的 Locale:import Foundation import Combine class LocalizationManager: ObservableObject { static let shared = LocalizationManager() @Published var currentAppLanguage: AppLanguage = .systemDefault var currentLocale: Locale { switch currentAppLanguage { case .systemDefault: return Locale.current // fall back to system case .english: return Locale(identifier: "en") case .simplifiedChinese: return Locale(identifier: "zh-Hans") case .japanese: return Locale(identifier: "ja") } } private init() { // 可以从 UserDefaults 加载之前保存的语言设置 } func setLanguage(_ language: AppLanguage) { currentAppLanguage = language // 可以保存到 UserDefaults // 通知整个 App 刷新 UI } }
在 SwiftUI 中使用:在你的 App 根部,将自定义的
locale
通过环境变量注入。@main struct MyApp: App { @StateObject private var localizationManager = LocalizationManager.shared var body: some Scene { WindowGroup { ContentView() .environment(\.locale, localizationManager.currentLocale) // 注入自定义 locale .environmentObject(localizationManager) } } }
在需要的地方切换语言:
// 例如在设置界面中 Button("Switch to English") { LocalizationManager.shared.setLanguage(.english) // 通常这里需要更复杂的逻辑来刷新整个 UI }
◾ 关键属性和方法总结 #
下面的表格汇总了 Locale
的一些常用属性和方法:
属性/方法 | 说明 | 示例或常见值 |
---|---|---|
Locale.current | 获取用户当前设置的 Locale 实例。 | (identifier: "zh_CN") |
Locale.system | 获取系统固定的 Locale。 | |
Locale(identifier:) | 通过标识符创建特定的 Locale。 | Locale(identifier: "ja_JP") |
identifier | Locale 的唯一标识符。 | "en_US" , "zh-Hans_CN" |
currencyCode | 该区域的货币代码。 | "USD" , "CNY" , "EUR" |
decimalSeparator | 该区域用于表示小数点的字符。 | "." (美国), "," (法国) |
groupingSeparator | 该区域用于对数字进行分组的字符(如千位分隔符)。 | "," (美国), "." (德国), " " (一些地区) |
localizedString(forIdentifier:) | 获取给定区域标识符的本地化显示名称。 | "中文(中国)" for "zh_CN" |
localizedString(for:value:) | 获取其他区域设置组件(如货币代码、语言代码)的本地化显示名称。 | "美元" for currencyCode: "USD" in zh_CN locale |
availableIdentifiers | 获取所有可用的区域标识符数组。 | ["en_US", "zh_CN", "ja_JP", ...] |
◾ 注意事项 #
- 性能考虑:频繁创建
DateFormatter
和NumberFormatter
实例开销较大。在实际应用中,应考虑缓存和复用这些格式化器。 - 测试:确保充分测试你的 App 在不同区域设置下的表现。Xcode 的 Scheme 设置允许你为每次启动指定特定的语言和地区(
Product > Scheme > Edit Scheme... > Run > Options > App Language
)。 - 尊重用户选择:优先使用用户设备的默认区域设置(
Locale.current
),除非你有充分的理由覆盖它(如应用内语言切换功能)。