Highlight
iOS 14 改进 Formatter 对语言与地区组合的支持,并通过 DateFormatter、MeasurementFormatter、PersonNameComponentsFormatter、ListFormatter、NumberFormatter 和 stringsdict 帮助 App 生成符合用户习惯的日期、单位、姓名、列表、数字和复数字符串。
核心内容
很多 App 都在显示数据。天气 App 显示温度、风速和气压,健康 App 显示统计趋势,备忘录只是在标题下放一个修改时间。只要这些文本面向用户,就不能把 Date、Double 或数组直接拼成字符串。单位、日期顺序、小数点、百分号位置、姓名顺序都会随语言和地区改变。
这场 session 的入口案例很具体:一个住在阿布扎比、手机语言设为法语的人,过去可能看到更偏法国地区习惯的数字格式。iOS 14 和同代 macOS、watchOS、tvOS 改进了底层算法,让语言和地区组合得到更合适的格式。这个改动覆盖很多语言和地区组合,使用系统 Formatter 的 App 会随系统改进直接受益。
Karan Miśra 接着按“最具体到最通用”的顺序展示 Foundation 的格式化工具:日期和时间、度量单位、姓名、列表、数字,以及 SwiftUI 文本和 stringsdict。主线是少写自定义语言规则,把数据结构交给 Formatter,把复数规则交给 stringsdict,让系统按 locale 组装文本。
详细内容
日期和时间:用样式与模板,不要手写格式
(02:25)Notes 顶部的最后修改时间,可以直接用 DateFormatter 的预设样式。Screen Time 这类界面需要“星期 + 日期 + 月份”或极短星期缩写时,再使用 setLocalizedDateFormatFromTemplate。
// Date with Day/Month/Year and Time
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .medium
dateFormatter.timeStyle = .short
dateFormatter.string(from: Date())
// Day of Week + Date + Month
let dateFormatter = DateFormatter()
dateFormatter.setLocalizedDateFormatFromTemplate("MMMMdEEEE")
dateFormatter.string(from: Date())
// Abbreviated Day of Week
let dateFormatter = DateFormatter()
dateFormatter.setLocalizedDateFormatFromTemplate("ccccc")
dateFormatter.string(from: Date())
关键点:
dateStyle和timeStyle适合常见组合,系统会补上符合 locale 的连接词和顺序。setLocalizedDateFormatFromTemplate("MMMMdEEEE")描述需要哪些字段,字段排列交给 Formatter。ccccc来自 Unicode 日期字段规则,适合独立显示的极短星期名。- transcript 明确提醒不要把 template 直接赋给
dateFormat,那会被字面解释,容易生成错误结果。
(05:56)日期还包括持续时间、时间区间和相对时间。DateComponentsFormatter、DateIntervalFormatter 和 RelativeDateTimeFormatter 分别覆盖这些场景。
// Date and Time Components
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .abbreviated
let components = DateComponents(hour: 2, minute: 26)
formatter.string(from: components)
// Date and Time Intervals
let formatter = DateIntervalFormatter()
formatter.dateTemplate = "dMMM"
formatter.string(from: startDate, to: endDate)
// Relative Dates and Times
let formatter = RelativeDateTimeFormatter()
formatter.dateTimeStyle = .named
formatter.localizedString(from: DateComponents(day: -1))
关键点:
DateComponentsFormatter适合“2 小时 26 分”这种时长。DateIntervalFormatter会避免重复起止日期里相同的元素。RelativeDateTimeFormatter适合过去或未来的自然语言表达,例如昨天这类命名式相对日期。
度量单位:保存一种单位,展示另一种地区习惯
(06:29)Weather 示例里,数据源使用公制,展示给美国用户时会按地区习惯转换为华氏度、英里每小时等格式。开发者不需要自己维护单位换算和本地化字符串。
// Temperature
let formatter = MeasurementFormatter()
let temperature = Measurement<UnitTemperature>(value: 16, unit: .celsius)
formatter.numberFormatter.maximumFractionDigits = 0
formatter.string(from: temperature)
// Speed
let speed = Measurement<UnitSpeed>(value: 14, unit: .kilometersPerHour)
formatter.string(from: speed)
// Pressure
let pressure = Measurement<UnitPressure>(value: 1.01885, unit: .bars)
formatter.string(from: pressure)
关键点:
Measurement保留值和原始单位,MeasurementFormatter决定用户看到的单位和格式。numberFormatter.maximumFractionDigits = 0控制数字精度,单位本地化仍由系统处理。- transcript 提到
MeasurementFormatter支持很多单位,也支持自定义单位。
姓名:姓名顺序和缩写都不能硬编码
(07:49)姓名是非常个人化的数据。PersonNameComponentsFormatter 会结合用户语言设置、联系人设置和姓名本身选择顺序与样式。对于中日韩姓名,即使设备语言是英语,也应保持姓在名前。
let formatter = PersonNameComponentsFormatter()
var nameComponents = PersonNameComponents()
nameComponents.familyName = "Iwasaki"
nameComponents.givenName = "Akiya"
nameComponents.nickname = "Aki-chan"
// Full Name
formatter.string(from: nameComponents)
// Short Name: Respects User Preferences
formatter.style = .short
formatter.string(from: nameComponents)
// Abbreviated Name
formatter.style = .abbreviated
formatter.string(from: nameComponents)
关键点:
PersonNameComponents让姓、名、昵称成为结构化数据。.short会尊重用户偏好,可能使用昵称或短名。.abbreviated适合头像缺失时的 monogram,但 session 提醒要检查长度和实际渲染尺寸。
(08:31)monogram 不能保证所有名字都适合显示。Swift 的 count 按用户可见字符计数,可以先做一层长度检查。
formatter.style = .abbreviated
let monogram = formatter.string(from: nameComponents)
if monogram.count <= 2 {
// Use Monogram
} else {
// Use Icon
}
关键点:
count不是 Unicode code point 数量,跨语言时更贴近用户看到的字符。- 字符数量只是一层保护,最终还要确认文本宽高能放进 UI。
- 超出限制时应回退到通用图标,避免头像区域被长文本撑破。
列表和数字:语法细节交给系统
(10:15)列表连接词会随语言和上下文改变。session 用键盘设置里的语言列表说明,西班牙语里的“and”会根据后一个词改变形式。iOS 14 同代系统更新了 ListFormatter,让它遵守多种语言的语法规则。
let items = ["English", "French", "Spanish"]
ListFormatter.localizedString(byJoining: items)
let items = ["English", "Spanish"]
ListFormatter.localizedString(byJoining: items)
let items = ["Spanish", "English"]
ListFormatter.localizedString(byJoining: items)
关键点:
ListFormatter.localizedString(byJoining:)接收数组,返回用户语言下的自然列表。- 数组顺序改变时,连接词也可能改变。
- 使用系统 API 后,底层实现更新会让 App 获得新的语言规则。
(12:01)数字的风险更隐蔽。32.768 在不同地区可能被理解为三万多或三十二点七六八。NumberFormatter 会处理小数分隔符、数字形状、百分号位置等细节。
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.string(from: 32.768) // French (France)
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.string(from: 32.768) // Arabic (Egypt)
formatter.percentSymbol
formatter.decimalSeparator
关键点:
.decimal让普通数字按语言和地区输出。percentSymbol、decimalSeparator这类属性适合必须读取符号本身的场景。- session 还展示了
.percent,土耳其语环境会把百分号放在数字前面。
SwiftUI 文本:复数规则放进 stringsdict
(13:24)Formatter 覆盖常见数据类型,业务自己的句子仍然需要本地化。SwiftUI 里可以像平时一样写 Text,再用 stringsdict 提供对应 key 的复数规则。
var body: some View {
Text("\(photosCount) Photos Selected")
}
关键点:
photosCount进入本地化字符串后,stringsdict 决定单数、双数、少数、其他等分支。- transcript 用英语和阿拉伯语对比:1、2、3 到 10、11 以上会触发不同语法形式。
- 代码只写一次,新增语言时主要补翻译和复数规则。
核心启发
-
多地区天气卡片:做什么:把温度、风速、气压统一建模为
Measurement。为什么值得做:数据源可以继续用公制,界面按用户地区显示合适单位。怎么开始:先把展示层的手写单位字符串替换为MeasurementFormatter。 -
健康或运动时长摘要:做什么:把“本周训练 2 小时 26 分”“昨天完成训练”这类文案交给日期 Formatter。为什么值得做:持续时间、区间和相对时间在不同语言里有不同顺序和词形。怎么开始:时长用
DateComponentsFormatter,日期范围用DateIntervalFormatter,相对日期用RelativeDateTimeFormatter。 -
联系人头像兜底:做什么:没有头像时展示姓名缩写,过长时回退图标。为什么值得做:姓名顺序、昵称、缩写规则和中日韩姓名显示都不适合硬编码。怎么开始:用
PersonNameComponentsFormatter生成.abbreviated样式,再用字符数和实际布局尺寸做保护。 -
筛选条件自然语言摘要:做什么:把“英语、西班牙语和法语”这类列表显示在设置页或搜索结果页。为什么值得做:列表连接词会随语言和元素顺序变化,手写连接符容易出错。怎么开始:保留数组结构,到展示层调用
ListFormatter.localizedString(byJoining:)。 -
照片选择复数文案:做什么:让“1 Photo Selected”“2 Photos Selected”以及阿拉伯语双数、少数等形式走本地化资源。为什么值得做:复数规则不是简单的单复数切换。怎么开始:SwiftUI 继续使用
Text("\(photosCount) Photos Selected"),为对应 key 配置 stringsdict。
关联 Session
- Build localization-friendly layouts using Xcode — 继续处理翻译长度、从右到左语言和 Xcode 本地化布局预览。
- Swift packages: Resources and localization — 学习把本地化字符串、stringsdict 和资源放进 Swift package。
- Build location-aware enterprise apps — 结合企业场景查看位置、区域格式和全球员工体验如何落到真实 App。
评论
GitHub Issues · utterances