WWDC Quick Look 💓 By SwiftGGTeam
Build localization-friendly layouts using Xcode

Build localization-friendly layouts using Xcode

观看原视频

Highlight

Xcode 12 把伪语言预览、运行时语言选择、Auto Layout 本地化警告和 Grid View/Stack View 修复流程串在一起,让开发者在翻译完成前发现长文本、动态字体和从右到左语言导致的布局问题。

核心内容

很多团队第一次做本地化时,最先处理的是字符串文件。界面布局常被留到最后。问题是,翻译一旦进入 App,原来刚好放下的按钮会截断,原来固定宽度的输入框会撑破窗口,阿拉伯语界面还可能暴露一排只按从左到右设计的约束。

这场 session 从一个更早的时间点切入:不要等翻译完成才检查 UI。Paul Borokhov 在 Xcode 里演示,开发者可以用 Double Length Pseudolanguage(双倍长度伪语言)先把每个控件里的文本拉长,再用 Arabic 这样的运行时语言验证界面是否翻转。这样,问题出现在开发阶段,而不是出现在交付给译者或测试团队之后。

Apple 给出的方案不是为每种语言手工调一份布局。核心做法是让控件依赖内容的自然尺寸,允许文本换行,把固定宽度改成最小宽度,把一组控件交给 Stack View 或 Grid View 管理。Xcode 12 的预览、scheme 选项、Auto Layout fix-it、Embed In 操作一起工作,开发者可以在同一个设计流程里修掉这些问题。

这也是本地化布局最容易被低估的地方。它看起来是翻译问题,实际是 UI 弹性问题。只要英文界面里写死了宽度、间距或单行文本,新的语言只是把隐藏的布局假设暴露出来。

详细内容

先删掉固定宽度,让文本决定自己的空间

00:39)session 一开始列出跨平台规则:包含文本的控件不要使用固定 width 或固定 frame。手写布局要记得调用 sizeToFit,Auto Layout 不要给文本控件加固定宽度约束,SwiftUI 不要给文本视图写死显式 frame。

文本控件布局检查
  -> manual layout: 调用 sizeToFit
  -> Auto Layout: 删除固定 width,或改成 greater than or equal
  -> SwiftUI: 不给文字视图设置只适合英文的 explicit frame
  -> UILabel: 将 number of lines 设为 0,允许翻译后换行

关键点:

  • sizeToFit 对应 transcript 中的 manual layout 建议,用内容计算控件尺寸。
  • number of lines 设为 0 对应 iOS demo,UILabel 默认单行,双倍长度伪语言会让文本截断。
  • 固定宽度约束可以删除,或改成“greater than or equal to”最小宽度。
  • SwiftUI 场景的原则相同:不要把文字控件锁在一个只适合英文的明确宽度里。

01:17)固定间距也会制造问题。演示里的 Publish 和 Cancel 按钮之间有一大片空白。英文看起来正常,Greek 翻译变长后,窗口整体被撑大。更好的做法是让按钮吃掉中间空白,而不是让窗口尺寸跟着翻译增长。

Publish button  >= flexible space >=  Cancel button
Fixed width     -> greater than or equal minimum width
Fixed gap       -> Stack View or flexible constraint

关键点:

  • 远距离控件之间不要依赖固定空白保版面。
  • greater than or equal 约束保留最小尺寸,同时允许较长翻译展开。
  • Stack View 可以管理一组控件之间的弹性分配。
  • 这类修复不会改变业务逻辑,只是在布局层删除英文长度假设。

用伪语言预览,在没有翻译时制造压力测试

03:07)第一个 iOS demo 打开 document preview,选择 Double Length Pseudolanguage。标题和普通标签立刻暴露出问题:它们需要允许换行。修好标签后,按钮仍然截断,于是布局从水平按钮组改成能在空间不足时切换为垂直方向的 stack view。

Document Preview
  -> English
  -> Double Length Pseudolanguage
  -> inspect labels and buttons before real translations exist

关键点:

  • Document Preview 不需要 build 和 run,适合快速检查 storyboard 或 XIB 的视觉变化。
  • Double Length Pseudolanguage 会把控件和 label 内文本加长,用来模拟更 verbose 的语言。
  • 修复标签时,重点是允许换行;修复按钮组时,重点是为较窄宽度提供备用排布。
  • 演讲者还在 Identity Inspector 的 Localizer Hint 里给标题文本加上下文,帮助译者理解字符串用途。

04:03)按钮组的备用排布需要运行时代码参与。演讲者把按钮放进 horizontal stack view,再查询它的 layout fitting size。如果空间不够,就把方向改为 vertical。这个 custom class 已经写好,demo 只是在 storyboard 里设置 class 并连接 stack view 的 leading constraint。

Horizontal Stack View
  -> query layout fitting size
  -> if content no longer fits
  -> switch orientation to vertical

关键点:

  • 这里没有官方代码片段,session 强调的是实现策略。
  • layout fitting size 用来判断当前内容在当前宽度下是否装得下。
  • 方向切换解决四个按钮在双倍长度或窄屏设备上同时截断的问题。
  • 这种逻辑也会服务 Dynamic Type,因为更大的字体和更窄的屏幕会制造相似压力。

用 Scheme、Accessibility Inspector 和 Environment Overrides 做运行时验证

04:59)预览只能覆盖一部分问题。按钮组的方向切换是代码行为,必须 build and run。Xcode 的 Scheme Editor 可以在 Options 里选择 Double Length Pseudolanguage,然后用 Command-Control-R 重新启动已构建版本,验证运行时布局。

Scheme Editor
  -> Run
  -> Options
  -> App Language
  -> Double Length Pseudolanguage

关键点:

  • Scheme 选项把伪语言带到运行时,能测试代码驱动的布局变化。
  • Command-Control-R 用于 relaunch already built version,适合重复验证同一构建产物。
  • demo 中标签正确换行,stack view 也按预期切换成垂直方向。
  • 同一个界面在第一代 iPhone SE 和较大 Dynamic Type 下,也会触发更紧的布局条件。

05:23)Dynamic Type 也是本地化布局的压力来源。演讲者用第一代 iPhone SE 加最大非辅助功能字号测试,即使英文文本也会让按钮组切换为垂直方向。随后用 Accessibility Inspector 和 Xcode 的 Environment Overrides 改回默认字号,布局恢复水平。

Accessibility Inspector / Environment Overrides
  -> change Dynamic Type
  -> verify stack view orientation and text wrapping

关键点:

  • 字体变大和翻译变长都会增加文本占用空间。
  • 小屏设备能提前暴露按钮组、表单和导航栏里的拥挤问题。
  • Accessibility Inspector 适合连接设备时快速调整 Dynamic Type。
  • Environment Overrides 把这些环境变化放进 Xcode 调试流程。

用 Auto Layout fix-it 和 Grid View 修 macOS 表单

07:21)第二个 demo 是一个没有 Auto Layout 约束的 macOS XIB。Xcode 在 document sidebar 里显示本地化问题。打开 Double Length Pseudolanguage 后,控件不会随长文本增长;运行 Arabic 后,UI 也不会翻转。

Resolve Auto Layout Issues
  -> Add Missing Constraints for all views in the window
  -> Remove Constraint for unnecessary fixed width
  -> Set Constraint to Greater Than Or Equal To A Minimum Width
  -> Fixed Leading and Resizing Trailing Constraints

关键点:

  • Add Missing Constraints 可以先补出一套基础约束,但不会自动得到完美本地化布局。
  • Publish 按钮上的固定 width 不需要保留,fix-it 可以直接删除。
  • OK 按钮需要最小宽度,适合改成 greater than or equal,而不是固定 70。
  • Publish 和 Cancel 之间要允许右侧空间弹性变化,避免两个按钮互相覆盖。

09:38)表单上半部分像电子表格:左边是 label,右边是 text field 和 checkbox。演讲者没有继续堆单条约束,而是选中文本字段和 checkbox,点击 Embed In,选择 Grid View。Grid View 接管内部布局,外层只需要给 Grid View 约束到窗口内容视图。

Embed In
  -> Grid View
  -> constrain Grid View top / leading / trailing / bottom
  -> merge first-row cells
  -> move checkbox to second column

关键点:

  • Grid View 适合行列清楚的 macOS 表单。
  • 内部控件放进 Grid View 后,不再需要每个控件都手写外部约束。
  • 顶部标题可以通过 merge cells 横跨两列。
  • checkbox 可以直接拖到目标 cell,让结构反映真实视觉关系。

11:50)Grid View 还需要设置属性。包含文本时,row alignment 设为 First Baseline;xPlacement 设为 Fill;spacing 使用标准 spacing,对应 row spacing 12、column spacing 8。随后把 name 和 description labels 的 horizontal hugging priority 设为 749,让第一列只占必要宽度。

Grid View attributes
  row alignment: First Baseline
  xPlacement: Fill
  row spacing: 12
  column spacing: 8

Labels
  horizontal hugging priority: 749

Grid View
  vertical content hugging priority: 600

关键点:

  • First Baseline 让文本行按基线对齐,表单读起来更整齐。
  • Fill 让内容使用可用水平空间。
  • 标准 spacing 来自 Human Interface Guidelines,避免把间距写成只适合当前语言的硬编码值。
  • 749 低于 label 默认 compression priority 750,高于窗口 holding priority 500,所以第一列会贴紧 label,同时不先压缩文字。

最后仍然要找母语用户测试

13:32)自动化检查只能发现尺寸、截断、翻转这类机械问题。session 结尾强调,母语测试者会发现另一类问题:系统术语不一致、翻译脱离上下文、某些截断或裁切对非母语开发者不明显。

Before release
  -> run pseudo language checks
  -> run right-to-left language checks
  -> test Dynamic Type and small devices
  -> ask native speakers to review real localizations

关键点:

  • 伪语言适合提前修布局,不等于真实翻译质量保证。
  • 从右到左语言需要真实运行时验证,确认约束、图标方向和窗口排布都能翻转。
  • 新增语言或大改 UI 时,母语测试最重要。
  • 本地化上线会给新市场用户留下第一印象,布局质量直接影响信任感。

核心启发

  • 做什么:给所有关键 storyboard 和 XIB 建立伪语言检查清单。为什么值得做:Xcode document preview 可以在没有翻译文件时模拟长文本,提前暴露固定宽度和单行 label。怎么开始:打开 preview,切到 Double Length Pseudolanguage,把截断控件逐个改成可换行、可扩展或可重排。

  • 做什么:为按钮组和工具栏准备窄空间排布。为什么值得做:session 里的四个水平按钮在双倍长度和小屏上都会截断,stack view 可以在空间不足时切到垂直方向。怎么开始:先把同类按钮放入 Stack View,再用 layout fitting size 判断内容是否装得下,失败时切换 axis。

  • 做什么:把 macOS 表单迁移到 Grid View。为什么值得做:行列式表单用单条约束维护成本高,Grid View 能管理 cell、baseline、spacing 和列宽。怎么开始:选中相关输入控件,使用 Embed In > Grid View,然后设置 First Baseline、Fill、standard spacing 和合适的 hugging priority。

  • 做什么:把 Dynamic Type 纳入本地化布局测试。为什么值得做:大字号和长翻译都会扩大文本占用空间,能触发相同类型的截断。怎么开始:用 Accessibility Inspector 或 Environment Overrides 改字体,用小屏 Simulator 运行同一界面。

  • 做什么:给译者写 Localizer Hint。为什么值得做:demo 中标题标签通过 Identity Inspector 添加上下文,减少翻译者误解字符串用途的机会。怎么开始:检查按钮、标题和状态文案,把含义容易歧义的字符串补上 localizer hint。

关联 Session

评论

GitHub Issues · utterances