如何让iOS 15+/macOS 12+数字格式化器适配自动语法一致?
数字格式化与自动语法一致功能的协同实现(iOS 15+/macOS 12+)
问题场景
在iOS 15+、macOS 12+系统中,使用AttributedString的自动语法一致(inflect: true)功能时,无法同时实现数字的本地化格式化。期望的输出效果如下:
| 区域标识符 | 输出结果 |
|---|---|
| en-GB | 1 book |
| en-GB | 5,000 books |
| de-DE | 1 book |
| de-DE | 5.000 books |
现有尝试及问题
- 直接使用数字变量:语法一致功能正常,但数字无本地化格式化
let count = 5_000 let output = AttributedString(localized: "^[\(count) (\"book\")](inflect: true)") print(output) // 5000 books
- 使用
formatted()格式化数字后:数字格式化生效,但自动语法一致失效(单复数不变化)
let count = 5_000.formatted() let output = AttributedString(localized: "^[\(count) (\"book\")](inflect: true)") print(output) // 5,000 book
- 其他尝试:问题依旧存在
let count = 5_000 let formatted = String(format: String(localized: "%@"), count.formatted()) let output = AttributedString(localized: "^[\(formatted) (\"book\")](inflect: true)") print(output) // 5,000 book
解决思路与方案
核心问题:inflect: true仅能识别**数值类型(如Int、Double)**的插值参数,若先将数字转为格式化后的字符串,参数会被当作普通文本,无法触发单复数屈折变化。因此需保留数值类型参数,同时对其应用格式化规则。
方案1:使用Swift FormatStyle结合本地化插值
直接在AttributedString的本地化模板中,为数值参数指定格式化样式,既实现数字的本地化显示,又保留数值类型供inflect功能识别:
let count = 5_000 // 使用系统内置的数字格式化样式,自动适配当前区域 let output = AttributedString(localized: "^[\(count, format: .number) (\"book\")](inflect: true)") print(output) // en-GB 环境输出:5,000 books // de-DE 环境输出:5.000 books
若需要自定义数字格式(如强制千位分隔、指定小数位数),可自定义FormatStyle:
let count = 5_000 // 自定义千位分隔的数字格式 let customNumberFormat: FormatStyle<Int> = .number.grouping(.always) let output = AttributedString(localized: "^[\(count, format: customNumberFormat) (\"book\")](inflect: true)") print(output)
方案2:使用stringsdict实现复杂本地化规则
若需要更灵活的本地化配置(如不同区域的单复数规则差异),可创建Localizable.stringsdict文件,同时结合NumberFormatter实现数字格式化:
- 创建
Localizable.stringsdict文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>book_count</key> <dict> <key>NSStringLocalizedFormatKey</key> <string>%#@count_rule@</string> <key>count_rule</key> <dict> <key>NSStringFormatSpecTypeKey</key> <string>NSStringPluralRuleType</string> <key>NSStringFormatValueTypeKey</key> <string>d</string> <key>one</key> <string>%@ book</string> <key>other</key> <string>%@ books</string> </dict> </dict> </dict> </plist>
- 在代码中调用:
let count = 5_000 // 初始化数字格式化器,适配当前区域 let formatter = NumberFormatter() formatter.numberStyle = .decimal formatter.locale = Locale.current guard let formattedCount = formatter.string(from: NSNumber(value: count)) else { fatalError("数字格式化失败") } // 从stringsdict获取本地化字符串,传递格式化后的数字和原始数值 let output = String(localized: "book_count", arguments: [formattedCount, count]) let attributedOutput = AttributedString(output) print(attributedOutput)
内容的提问来源于stack exchange,提问作者user10711707
相关产品推荐
相关产品推荐

