You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让iOS 15+/macOS 12+数字格式化器适配自动语法一致?

数字格式化与自动语法一致功能的协同实现(iOS 15+/macOS 12+)

问题场景

在iOS 15+、macOS 12+系统中,使用AttributedString的自动语法一致(inflect: true)功能时,无法同时实现数字的本地化格式化。期望的输出效果如下:

区域标识符输出结果
en-GB1 book
en-GB5,000 books
de-DE1 book
de-DE5.000 books

现有尝试及问题

  1. 直接使用数字变量:语法一致功能正常,但数字无本地化格式化
let count = 5_000
let output = AttributedString(localized: "^[\(count) (\"book\")](inflect: true)")

print(output) // 5000 books
  1. 使用formatted()格式化数字后:数字格式化生效,但自动语法一致失效(单复数不变化)
let count = 5_000.formatted()
let output = AttributedString(localized: "^[\(count) (\"book\")](inflect: true)")

print(output) // 5,000 book
  1. 其他尝试:问题依旧存在
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实现数字格式化:

  1. 创建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>
  1. 在代码中调用:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 06:25:38