在 Xcode 中移除未使用的本地化键时,应将 Stale 条目视为待审核项。删除前检查运行时键的构造方式,将必要的动态消息保留为手动管理的条目,并在清理后测试受影响的 Mac app 界面。
本指南适用于维护使用 String Catalog 的 SwiftUI Mac app 的开发者。这里要进行一次目录清理:找出可以移除的消息,同时保留 app 仍会显示的标签和计数消息。下面的决策参考将提取证据与运行时行为区分开来。
过期的本地化键究竟是什么意思?
Xcode 会在构建期间发现可本地化字符串。Apple 说明,提取范围涵盖当前方案和平台。当先前提取的字符串消失时,Xcode 可以自动移除尚未翻译的条目;已有翻译的条目则会保留下来,并标记为 Stale。该状态表示 Xcode 已无法在代码中找到此字符串。Apple 明确指出,只有确认不再需要该字符串后,才能将其删除。发现 String Catalog
实际操作中,找不到源代码引用只是调查的起点。精确搜索 panel.compact 可以找到字面量引用,但无法确定代码是否会将 panel. 与所选模式拼接起来构造该键。应同时检查候选键和生成查询键的代码。
对每个候选项使用下面这份建议审核表。这是根据文档说明的提取范围整理出的决策参考,并非 Xcode 的额外功能。
| 审核时发现的证据 | 决策 | 后续操作 |
|---|---|---|
| 某个已移除界面是唯一使用方;不再有运行时键生成器 | 删除候选项 | 移除条目,然后重新构建并检查更改 |
| 运行时代码仍可能生成这个确切的键 | 保留 | 通过手动管理保留该条目,或将查询改为明确的可本地化引用 |
| 该键仍在另一个目标或构建条件中被引用 | 保留 | 构建并检查相关配置 |
| 另一个表中存在名称相似的键 | 单独调查 | 确认每次查询使用的表和资源包 |
| 未找到使用方,但键的生成代码不明确 | 暂缓 | 先追踪生成逻辑,再决定是否删除 |
如何在 Xcode 中建立有用的基线?
首先,保存一份可恢复的目录副本,或提交其当前状态。然后打开 app 项目,选择要审核的 Mac 方案。记录哪些目标和条件配置可能向受影响的界面提供消息;这样审核范围就明确了。
在项目导航器中选择目录,然后选取 Product > Build。Apple 说明,构建会根据可本地化的源文本填充并更新 String Catalog。选中目录后,选择 Editor > Assistant,再选择某个键以查看其源位置。也可以从目录跳转回源代码。使用字符串目录本地化和调整文本
如果预期的 Swift 字符串缺失,请检查目标的 Use Compiler to Extract Swift Strings 构建设置是否已启用。Apple 将其列为编译器提取的前提条件。提取不完整的目录不适合作为决定移除内容的可靠基线。本地化你的 SwiftUI app
对每个候选项,记录键、目录、可能的使用方和决定。先搜索完整键,再搜索稳定前缀和相关的本地化封装。检查传入这些封装的模型值和捆绑查询数据。如果其他目标或编译条件会改变包含的源代码,请重新运行相关构建。
不要仅仅因为两个条目显示相同文本就合并处理。Apple 的本地化 API 接受表名,而主 app 以外的资源可能需要不同的资源包。将另一个条目视为替代项之前,先追踪查询所用的表和资源包。为 app 文本做好翻译准备
如何保留动态引用的消息?
Apple 专门针对动态构造键的字符串说明了手动管理方式。选择所需条目,然后使用检查器将其设为手动管理。Xcode 的构建后本地化同步不会更新或移除这类条目。对于缺失的动态条目,Apple 也展示了如何使用目录中的加号按钮添加手动字符串。发现 String Catalog
手动管理需要明确的维护规则。在选择有效键的代码或数据旁记录这些键,并在目录注释中说明用途。之后移除某个受支持模式时,也要检查对应的手动条目;自动提取不会替你完成这项清理。
检查 SwiftUI 是否真的执行了查询
传给 Text 的 String 变量会直接显示,不会进行本地化。若要将变量用作查询键,Apple 说明应从它构造 LocalizedStringKey。直接传给 Text 的字面量会自动走可本地化路径。这些重载可能产生相同的源语言输出,但行为不同。LocalizedStringKey
下面这个完整的演示 app 将运行时选择的键与插值计数分开处理。在一个使用 Xcode 15 或更高版本、最低部署目标为 macOS 13 的临时 SwiftUI Mac app 项目中,用这段代码替换生成的 app 声明。只保留一个 @main 声明。已根据文档中的 API 检查此代码;由于这里没有 Swift 工具链,因此未进行编译。
import SwiftUI
@main
struct CatalogReviewDemoApp: App {
var body: some Scene {
WindowGroup {
CatalogReviewView()
}
}
}
struct CatalogReviewView: View {
@State private var compact = true
@State private var itemCount = 2
private var selectedKey: String {
"panel." + (compact ? "compact" : "expanded")
}
var body: some View {
VStack(alignment: .leading, spacing: 12) {
Toggle("Compact layout", isOn: $compact)
Text(LocalizedStringKey(selectedKey))
Text("\(itemCount) items",
comment: "Number of items in the sample panel.")
Button("Add item") {
itemCount += 1
}
}
.padding()
.frame(minWidth: 320)
}
}
将 Localizable.xcstrings 添加到 app 目标。添加 panel.compact 和 panel.expanded 这两个手动管理的条目,源值分别设为 Compact panel 和 Expanded panel。构建项目以提取字面量消息。显式转换为 LocalizedStringKey 会请求运行时查询,但不会向提取器提供所有可能构造出的键的字面量声明。
对于少量、有限的选项,可以考虑将键构造改为各分支中明确的可本地化字面量。对于需要在组件之间传递消息的自定义界面,Apple 推荐使用 LocalizedStringResource;它会携带表、注释和默认值等本地化信息。选择一种能让完整的受支持消息集最易于检查的表示方式。为 app 文本做好翻译准备
为什么变化的计数与变化的键不同?
在演示中,选择布局会改变 app 查询的消息键。更改 itemCount 则会为一条可本地化消息提供不同的参数。SwiftUI 插值会将嵌入的值转换为供本地化使用的格式占位符;运行时渲染时再填入相应的值。本地化你的 SwiftUI app
因此,你不需要为渲染出的 2 items、3 items 和 4 items 标签分别创建键。构建示例,找到提取出的计数消息,按住 Control 键并点按其键,然后选择 Vary by Plural。对于英语源语言本地化,使用 Xcode 显示的整数占位符,为 One 输入 %lld item,为 Other 输入 %lld items。Apple 说明了这种计数消息工作流程,以及为其他受支持的本地化添加适当复数变体的方法。使用字符串目录本地化和调整文本
清理期间,应将计数消息作为完整资源检查,包括其各种变体。源代码中没有出现 4 items 这样的渲染文本,并不能说明底层的插值消息是否在使用。同样,保留计数模板也不会因为它和无关的动态键出现在同一面板中,就让该动态键一并得到保留。
清理时究竟应移除哪些条目?
以审核 24 个候选项为例。这些数量仅用于构造示例,并非实际项目的测量结果。
| 审核结果 | 条目数 | 操作 |
|---|---|---|
| 唯一使用方属于已移除的面板 | 9 | 确认面板及其查询数据均已移除后,再删除 |
| 运行时选择仍可访问这些键 | 8 | 保留并记录手动管理情况 |
| 引用属于另一个目标或条件构建 | 5 | 保留并验证相应构建范围 |
| 键的来源仍未确定 | 2 | 暂时保留,等待调查 |
| 已审核总数 | 24 | 9 个删除候选项 |
这项计算让清理决策可供审查:审核 24 个条目并不意味着要删除 24 个。对 9 个删除候选项中的每一个,都应简要说明已移除的使用方,以及检查过的运行时查询路径。对于 8 个动态条目,记录允许使用的键集合,以便下次审核时重复验证。
只移除已确认的候选项,然后检查目录差异。确认更改只包含预期的键及其相关翻译,没有误删无关的复数变体或设备变体。重新构建相关配置。如果被删除的键又通过提取出现,请先重新检查其使用方,再次决定是否删除。
如何在 Mac 上验证保留的消息?
使用 Product > Scheme > Edit Scheme,选择 Run,然后打开 Options。在 App Language 中选择一种现有的受支持本地化,关闭编辑器,然后运行 Mac 目标。Apple 说明了如何使用这些方案控件测试本地化构建。对 app 支持的本地化重复此操作。运行 app 时测试本地化
尝试每种允许的动态选择,包括演示中的两种布局。确认 app 显示的是预期目录值,而不是标识符。对于计数消息,检查 0、1、2 和 12 等示例值;如果受支持的本地化需要其他复数类别,也要检查它们。只需更改示例中的初始计数,就能测试这些值。
保留的消息显示不正确时,请先检查确切的键、表、资源包和 Text 初始化方式,再修改目录。Apple 较新的生成符号工作流程也能让手动资源更易于引用:Xcode 26 引入了 String Catalog 符号生成,可通过 Generate String Catalog Symbols 为现有项目启用。这是一种可选的重构方式,未被引用的手动资源并不会因此就被证明为未使用。跟着代码探索 Xcode 本地化
最后保留一组精简且理由清晰的删除项,并记录保留的动态消息列表。理想的结果是目录中每个剩余条目都有明确的使用方,同时运行时选择的键和格式化计数消息仍能在 Mac 界面中正常工作。
来源
- 发现 String Catalog — Apple Developer
- 使用字符串目录本地化和调整文本 — Apple Developer
- 为 app 文本做好翻译准备 — Apple Developer
- LocalizedStringKey — Apple Developer
- 本地化你的 SwiftUI app — Apple Developer
- 运行 app 时测试本地化 — Apple Developer
- 跟着代码探索 Xcode 本地化 — Apple Developer