WWDC Quick Look 💓 By SwiftGGTeam
Enhance your app’s multilingual experience

Enhance your app’s multilingual experience

观看原视频

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 对象,附带 languageregionnumberingSystem 等属性,也能用 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 让选区跟随光标自然移动,把视觉上看似不连续的选区在存储里拆成多段非连续 NSRange12: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 同步升级:shouldChangeTextInRangeseditMenuForTextInRanges 等回调都改为接收 [NSRange]

TextKit2 是前提。 Natural Selection 默认开启,但访问 textView.layoutManager 会让文本引擎回落到 TextKit1,自动失去这一特性。要保留新特性,应使用 textView.textLayoutManager17: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.selectedRangeshouldChangeTextIneditMenuForText,逐个换成 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

评论

GitHub Issues · utterances