构建全球化应用:本地化实战示例
Build global apps: Localization by example
2022年6月6日
一句话判断
如果你在做面向全球市场的 App,这场 Session 用天气应用的实际案例把本地化的坑和最佳实践讲得相当透彻,值得花 20 分钟看完。
这场 Session 讲了什么
Apple 本地化团队的 Andreas 以天气应用为核心案例,从字符串声明、格式化到布局适配,系统性地讲解了如何构建高质量的多语言应用。
内容覆盖三个层次:第一,本地化字符串的声明与加载,包括 String(localized) 的正确用法、同一个英文词在不同语境下需要拆分为不同字符串的原则;第二,从服务端获取内容后如何匹配用户语言偏好,通过 Bundle.preferredLocalizations 实现精准的语言匹配;第三,数字和日期的格式化,以及 SwiftUI 在布局层面新增的国际化支持。
整个 Session 的核心观点很明确:本地化不是翻译文档的事后补丁,而是从写代码第一行就要考虑的架构决策。
值得深挖的点
同一个英文词,不同语言可能需要不同翻译。 Mail 应用里 “Archive” 这个词,作为动作(归档邮件)和作为文件夹名,在西班牙语里对应完全不同的词。解决办法是用两个不同的本地化字符串,通过修改 key 来区分语境。这个细节很容易被忽略,但一旦漏掉,翻译质量会大打折扣。
字符串插值可能破坏语法结构。 一个看似无害的 “Show weather in (location)” 在德语里就出了问题——城市名和”当前位置”需要搭配不同的介词。解决方案不是修补插值逻辑,而是干脆拆成两个独立的字符串。
注释对翻译者至关重要。 Apple 建议每个本地化字符串都应该附带注释,说明它出现在什么 UI 元素里、在屏幕上的什么位置、包含的变量运行时是什么值。翻译者看不到你的 App 运行效果,注释是他们唯一的上下文来源。
代码片段
// 同一英文词在不同语境下需要不同的 key
// 动作按钮
String(localized: "Archive", defaultValue: "Archive", comment: "Context menu action to archive an email")
// 文件夹名称
String(localized: "Archive Folder", defaultValue: "Archive", comment: "Name of the archive folder in the sidebar")
// 从服务端获取内容时匹配用户语言偏好
let supportedLanguages = ["en", "es", "de", "ja", "zh-Hans"]
let preferredLanguages = Bundle.preferredLocalizations(from: supportedLanguages)
let bestLanguage = preferredLanguages.first ?? "en"
// 用 bestLanguage 向服务端请求对应语言的内容
最佳实践
- 永远不要在代码里拼接字符串。 两个独立的本地化字符串拼接在一起,在不同语言里可能需要不同的语序、不同的连接词,甚至不同的标点符号。
- 尽早让母语测试者参与。 很多本地化问题只有在实际语言环境下才能发现,程序员自己很难预判。
- 为翻译者提供充分的上下文。 字符串注释不是可选项,它直接决定了翻译质量。
- 服务端内容也要本地化。 通过
Bundle.preferredLocalizations匹配用户语言偏好,确保从服务端下载的内容始终以用户首选语言呈现。
还有什么值得关注
- SwiftUI 新增了针对不同语言方向的布局适配能力,对于 RTL 语言(如阿拉伯语、希伯来语)的支持更加自动化
- Swift Package 现在可以包含本地化字符串资源,本地化工作流得到了改进
- 推荐搭配观看去年 WWDC 的 “Streamline your localized strings” Session,可以更深入理解字符串管理的完整流程