Swift Internationalization
Expert-level Swift i18n patterns for macOS/iOS applications. Covers string localization, semantic key naming, and best practices.
When: to Use
Use this skill when:
- - Adding localized strings to SwiftUI views
- Creating new localization keys
- Writing String(localized:) calls
- Organizing Localizable.strings files
- Reviewing i18n implementation in Swift projects
Core Principles
1. String(localized:) Pattern
CODEBLOCK0
2. Semantic Key Naming
Use domain.feature.key pattern:
CODEBLOCK1
3. Localizable.strings Organization
Group by domain with MARK comments:
CODEBLOCK2
Key Naming Conventions
| Domain | Feature | Examples |
|---|
| INLINECODE1 | - | INLINECODE2 |
| INLINECODE3 |
delete, save, cancel |
common.delete,
common.save |
|
sidebar | today, settings, search |
sidebar.today,
sidebar.settings |
|
home today, progress, timeline | home.today
, home.progress
|
| gtd
| inbox, next, projects | gtd.inbox
, gtd.next
|
| settings
| theme, language, sync | settings.theme.title
|
| sync
| idle, syncing, failed | sync.idle
, sync.syncing
|
---
## SwiftUI Usage Patterns
### Text Component
CODEBLOCK3
### Button with Localized String
CODEBLOCK4
### Navigation Titles
CODEBLOCK5
---
## Best Practices
| Practice | Reason |
|----------|--------|
| Use String(localized:)
| Prevents hardcoding, enables i18n |
| Semantic key names | Self-documenting, easier maintenance |
| Group with // MARK:
| Organized, searchable strings files |
| Use domain.feature.key | Clear ownership, prevents collisions |
| Update all languages together | Prevents missing translations |
| Avoid format strings in keys | Use Swift interpolation instead |
---
## String Interpolation
CODEBLOCK6
---
## Common Pitfalls
| Pitfall | Consequence | Prevention |
|---------|-------------|------------|
| Hardcoded strings | Can't localize | Always use String(localized:)
|
| Non-semantic keys | Difficult to maintain | Use domain.feature.key` pattern |
| Missing translations | Shows key name | Add entries to all .strings files |
| Format strings in keys | Ambiguous values | Use Swift interpolation |
| Duplicate keys | Confusing maintenance | Search before adding |
Testing Patterns
CODEBLOCK7
Running Tests
CODEBLOCK8
Swift 国际化
适用于 macOS/iOS 应用的专业级 Swift i18n 模式。涵盖字符串本地化、语义键命名和最佳实践。
使用时机
在以下情况下使用此技能:
- - 向 SwiftUI 视图添加本地化字符串
- 创建新的本地化键
- 编写 String(localized:) 调用
- 组织 Localizable.strings 文件
- 审查 Swift 项目中的 i18n 实现
核心原则
1. String(localized:) 模式
swift
// 面向用户的文本始终使用 String(localized:)
Text(String(localized: common.save))
Button(String(localized: sidebar.today))
// 切勿硬编码字符串
Text(Save) // ❌ 错误
2. 语义键命名
使用 domain.feature.key 模式:
swift
// 正确:语义键
app.name = TimeFlow
common.save = Save
sidebar.today = Today
settings.theme.title = Theme
// 错误:非语义键
saveButton = Save
viewTitle1 = Today
themeTitle = Theme
3. Localizable.strings 组织
使用 MARK 注释按域分组:
swift
/*
Localizable.strings
TimeFlow
*/
// MARK: - App
app.name = TimeFlow;
// MARK: - Common
common.delete = Delete;
common.save = Save;
common.cancel = Cancel;
// MARK: - Sidebar
sidebar.today = Today;
sidebar.settings = Settings;
sidebar.daily_note = Daily Note;
// MARK: - GTD Navigation
gtd.inbox = Inbox;
gtd.today = Today;
gtd.projects = Projects;
键命名约定
delete, save, cancel | common.delete, common.save |
| sidebar | today, settings, search | sidebar.today, sidebar.settings |
| home | today, progress, timeline | home.today, home.progress |
| gtd | inbox, next, projects | gtd.inbox, gtd.next |
| settings | theme, language, sync | settings.theme.title |
| sync | idle, syncing, failed | sync.idle, sync.syncing |
SwiftUI 使用模式
文本组件
swift
struct TodayView: View {
var body: some View {
VStack {
Text(String(localized: home.today))
.font(.title)
Text(String(localized: home.no_events))
.foregroundStyle(.secondary)
}
}
}
带本地化字符串的按钮
swift
Button(String(localized: common.save)) {
// 保存操作
}
.disabled(isSaving)
导航标题
swift
NavigationLink(destination: SettingsView()) {
Label(String(localized: sidebar.settings), systemImage: .gear)
}
最佳实践
| 实践 | 原因 |
|---|
| 使用 String(localized:) | 防止硬编码,启用 i18n |
| 语义键名 |
自文档化,易于维护 |
| 使用 // MARK: 分组 | 组织有序,字符串文件可搜索 |
| 使用 domain.feature.key | 所有权明确,防止冲突 |
| 同时更新所有语言 | 防止缺少翻译 |
| 避免键中包含格式字符串 | 改用 Swift 插值 |
字符串插值
swift
// 正确:使用 Swift 插值
let message = String(localized: sync.completed.count)
.replacingOccurrences(of: {count}, with: \(count))
// 替代方案:对本地化格式字符串使用 String(format:)
let formatted = String(
localized: sync.completed.count,
comment: Number of items synced
)
// Localizable.strings 条目:
// sync.completed.count = Synced %d items;
常见陷阱
| 陷阱 | 后果 | 预防措施 |
|---|
| 硬编码字符串 | 无法本地化 | 始终使用 String(localized:) |
| 非语义键 |
难以维护 | 使用 domain.feature.key 模式 |
| 缺少翻译 | 显示键名 | 向所有 .strings 文件添加条目 |
| 键中包含格式字符串 | 值不明确 | 使用 Swift 插值 |
| 重复键 | 维护混乱 | 添加前先搜索 |
测试模式
swift
func testLocalizationKeys() {
// 验证所有键在 Localizable.strings 中存在
let keys = [app.name, common.save, sidebar.today]
for key in keys {
let localized = String(localized: key)
XCTAssertNotEqual(localized, key, Key not found: \(key))
}
}
运行测试
bash
测试本地化
xcodebuild test -scheme YourApp \
-destination platform=macOS \
-only-testing:YourAppTests/LocalizationTests/testKeysExist