Highlight
iOS 26 用
Locale.preferredLocales替代Locale.preferredLanguages,并为UITextView引入selectedRanges数组以支持双向文本的 Natural Selection。
核心内容
世界上有数十亿人每天在两种以上语言之间切换。Omar 自己的 iPhone 系统语言是英文,但他用阿拉伯语听播客、读新闻、发短信。在 iOS 26 之前,想让设备同时服务这两种语言,只能去「设置」里手动加语言、加键盘——绝大多数用户不会去做这件事,于是 App 推荐的内容永远是错的。
iOS 26 把这件事交给 Siri:基于端侧智能识别多语言使用习惯,主动建议加键盘、切系统语言、换内容推荐。配合这个底层能力,Foundation 把开发者用了多年的 Locale.preferredLanguages(返回 BCP-47 字符串数组)替换为 Locale.preferredLocales(返回 Locale 对象数组),让 App 直接拿到「阿拉伯语-黎巴嫩」这种带区域信息的标识,可以正确选择拼写、日期格式和货币。除此之外,Foundation 新增 11 个日历标识符(含 Gujarati、Marathi、Korean),UITextView 的双向文本选区也从「单一连续范围」升级为「多段非连续范围」,解决了阿拉伯语和英文混排时拖选出现「中间空一段」的老毛病。
详细内容
Language Discovery:从 String 到 Locale。 旧 API 返回的是 ["en", "ar"] 这样的字符串数组,开发者要自己解析 BCP-47。新 API 直接给 Locale 对象,附带 language、region、numberingSystem 等属性,也能用 localizedString(forIdentifier:) 拿到本地化名字。Apple 在 Translate、Calendar、Apple Music 三个内置 App 里都已经切换到 preferredLocales:Translate 把用户常用语言置顶,不再让用户在长列表里翻找;Apple Music 用它来推荐歌词翻译。
// Language discovery
let preferredLanguages = Locale.preferredLanguages
let preferredLocales = Locale.preferredLocales
关键点:
Locale.preferredLanguages:旧 API,返回[String],未来可能弃用。Locale.preferredLocales:iOS 26 新增,返回[Locale],包含语言+区域。- 字符串格式仍可获取,并且可指定 BCP-47 / ICU / CLDR。
把用户偏好语言和 App 支持的语言做匹配,是 Translate 置顶逻辑的核心(07:49):
let preferredLocales = Locale.preferredLocales
// array of available Locale objects to translate from
let availableLocales = getAvailableLocalesForTranslatingFrom()
var matchedLocales: [Locale] = []
for locale in availableLocales {
for preferredLocale in preferredLocales {
if locale.language.isEquivalent(to: preferredLocale.language) {
matchedLocales.append(locale)
break
}
}
}
关键点:
- 外层遍历 App 支持的 locale,内层遍历用户偏好 locale,命中即跳出。
Language.isEquivalent(to:)判断语言等价;如需要更宽松的匹配(如 zh-Hans 与 zh-Hant 视为同源),改用hasCommonParent。- 命中后的
matchedLocales直接置顶,剩余 locale 仍按字母序展示。
Alternate Calendars:日历标识符从 16 增至 27。 新增 11 个,含 Gujarati、Marathi、Korean 等,全部通过 Calendar.Identifier 在 Foundation 里访问,所有平台可用。
Natural Selection:双向文本选区从单 range 变成 range 数组。 在 iOS 18,UITextView.selectedRange 是一个 NSRange。当英文+阿拉伯文混排时,文本在存储里是逻辑顺序,在屏幕上是视觉顺序,两者不一致。从左往右拖选会出现一段「视觉间隙」(12:05),因为单个 NSRange 无法覆盖屏幕上跨方向的多段文字。iOS 26 让选区跟随光标自然移动,把视觉上看似不连续的选区在存储里拆成多段非连续 NSRange(12:53)。macOS 的 NSTextView 早已是这种设计,这次 iOS 终于对齐。
如果原来用 selectedRange 删字,到了 iOS 26 会误删——必须改用 selectedRanges 倒序删除(14:57):
let ranges = textView.selectedRanges.reversed()
for range in ranges {
textView.textStorage.deleteCharacters(in: range)
}
关键点:
selectedRanges是[NSRange],可包含多段非连续区间;旧的selectedRange将在未来版本弃用。.reversed()倒序删除:从后往前删,前面的 range 索引不会被前面的删除操作平移。UITextViewDelegate同步升级:shouldChangeTextInRanges、editMenuForTextInRanges等回调都改为接收[NSRange]。
TextKit2 是前提。 Natural Selection 默认开启,但访问 textView.layoutManager 会让文本引擎回落到 TextKit1,自动失去这一特性。要保留新特性,应使用 textView.textLayoutManager(17:09)。SwiftUI Rich Text Editor 也支持 Natural Selection,选区类型是 RangeSet<AttributedString.Index>,详见「Cook up a rich text experience in SwiftUI with AttributedString」。
Writing Direction 动态判定。 过去段落的书写方向由首段文字方向决定,写完一长段乌尔都语,整段仍按 LTR 排版。iOS 26 改为根据内容动态调整:当英文段落里逐渐出现整句乌尔都语,系统会切到 RTL(18:47)。Apple 提供的 TextView/TextField 自动生效;自定义文本引擎参考 Language Introspector 示例代码自行实现。
核心启发
1. 把语言选择器改造成「常用语言置顶」。
- 为什么值得做:长语言列表是国际化 App 的痛点,多语言用户每次都要翻找;置顶后大幅降低交互成本。
- 怎么开始:用
Locale.preferredLocales拿用户偏好,遍历 App 支持的 locale 做isEquivalent匹配,命中的放在列表顶部,参考 Translate 的实现。
2. 审计 selectedRange 的全部调用点,迁移到 selectedRanges。
- 为什么值得做:iOS 26 的双向文本选区已经是非连续区间,旧代码会在阿拉伯语、希伯来语用户那里产生误删、误替换。
- 怎么开始:搜索
textView.selectedRange、shouldChangeTextIn、editMenuForText,逐个换成 ranges 复数形式;删字时记得.reversed()。
3. 检查文本视图是否被回落到了 TextKit1。
- 为什么值得做:访问
textView.layoutManager会静默禁用 Natural Selection 等新特性,问题不会报错只会表现为「行为不对」。 - 怎么开始:全局搜
.layoutManager,确认每一处是否可以改用.textLayoutManager;保留 TextKit1 的旧逻辑标注// TextKit1注释,便于后续清理。
4. 把新增的 11 个 calendar identifier 纳入日历相关功能的可选项。
- 为什么值得做:Gujarati、Marathi、Korean 等日历覆盖了印度和韩国市场的真实需求。
- 怎么开始:列出 App 中所有
Calendar(identifier:)调用点,确认是否对外暴露选项;UI 上参考 iOS 26 Calendar 的「按当地语言显示日和月」策略。
5. 自定义文本引擎接入新的 writing direction API。
- 为什么值得做:iOS 26 起书写方向按内容动态判定,自定义引擎不接入会显得僵硬。
- 怎么开始:下载 Language Introspector 示例代码,按其中的 API 在每次文本变化时重新计算段落方向。
关联 Session
- Cook up a rich text experience in SwiftUI with AttributedString — SwiftUI 富文本编辑器的 RangeSet 选区与 Natural Selection 支持。
- Get it right (to left) — 双向文本与 RTL 语言基础,是本场推荐的前置阅读。
- Discover machine learning & AI frameworks on Apple platforms — 端侧智能如何驱动 Siri 的多语言识别与建议。
- Elevate the design of your iPad app — iPad 应用设计指南,含国际化排版的视觉规范。
评论
GitHub Issues · utterances