ios-localization
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseiOS Localization & Internationalization
iOS 本地化与国际化
Localize iOS 26+ apps using String Catalogs, modern string types, FormatStyle, and RTL-aware layout. Localization mistakes cause App Store rejections in non-English markets, mistranslated UI, and broken layouts. Ship with correct localization from the start.
使用 String Catalogs、现代字符串类型、FormatStyle 和 RTL 适配布局来本地化 iOS 16+ 应用。本地化错误会导致应用在非英语市场被 App Store 驳回、UI 翻译错误、布局错乱等问题。请从开发初期就确保本地化正确性。
String Catalogs (.xcstrings)
String Catalogs (.xcstrings)
String Catalogs replaced and files starting in Xcode 15 / iOS 17. They unify all localizable strings, pluralization rules, and device variations into a single JSON-based file with a visual editor.
.strings.stringsdictWhy String Catalogs exist:
- files required manual key management and fell out of sync
.strings - required complex XML for plurals
.stringsdict - String Catalogs auto-extract strings from code, track translation state, and support plurals natively
How automatic extraction works:
Xcode scans for these patterns on each build:
swift
// SwiftUI -- automatically extracted (LocalizedStringKey)
Text("Welcome back") // key: "Welcome back"
Label("Settings", systemImage: "gear")
Button("Save") { }
Toggle("Dark Mode", isOn: $dark)
// Programmatic -- automatically extracted
String(localized: "No items found")
LocalizedStringResource("Order placed")
// NOT extracted -- plain String, not localized
let msg = "Hello" // just a String, invisible to XcodeXcode adds discovered keys to the String Catalog automatically. Mark translations as Needs Review, Translated, or Stale in the editor.
For detailed String Catalog workflows, migration, and testing strategies, see .
references/string-catalogs.md从 Xcode 15 / iOS 17 开始,String Catalogs 取代了 和 文件。它将所有可本地化字符串、复数规则、设备差异化配置统一到单个基于 JSON 的文件中,并提供可视化编辑器。
.strings.stringsdictString Catalogs 诞生的原因:
- 文件需要手动管理键值,容易出现同步问题
.strings - 需要编写复杂的 XML 来处理复数规则
.stringsdict - String Catalogs 支持自动从代码中提取字符串、跟踪翻译状态,原生支持复数规则
自动提取的工作原理:
Xcode 在每次构建时会扫描以下模式的代码:
swift
// SwiftUI -- automatically extracted (LocalizedStringKey)
Text("Welcome back") // key: "Welcome back"
Label("Settings", systemImage: "gear")
Button("Save") { }
Toggle("Dark Mode", isOn: $dark)
// Programmatic -- automatically extracted
String(localized: "No items found")
LocalizedStringResource("Order placed")
// NOT extracted -- plain String, not localized
let msg = "Hello" // just a String, invisible to XcodeXcode 会自动将发现的键添加到 String Catalog 中。你可以在编辑器中将翻译标记为「需要审核」、「已翻译」或「已过时」。
如需了解 String Catalog 的详细工作流、迁移方案和测试策略,请参考 。
references/string-catalogs.mdString Types -- Decision Guide
字符串类型选型指南
LocalizedStringKey (SwiftUI default)
LocalizedStringKey (SwiftUI 默认类型)
SwiftUI views accept for their text parameters. String literals are implicitly converted -- no extra work needed.
LocalizedStringKeyswift
// These all create a LocalizedStringKey lookup automatically:
Text("Welcome back")
Label("Profile", systemImage: "person")
Button("Delete") { deleteItem() }
NavigationTitle("Home")Use when passing strings directly to SwiftUI view initializers. Do not construct manually in most cases.
LocalizedStringKeyLocalizedStringKeySwiftUI 视图的文本参数接受 类型。字符串字面量会被隐式转换,无需额外操作。
LocalizedStringKeyswift
// These all create a LocalizedStringKey lookup automatically:
Text("Welcome back")
Label("Profile", systemImage: "person")
Button("Delete") { deleteItem() }
NavigationTitle("Home")直接向 SwiftUI 视图初始化器传递字符串时请使用 ,绝大多数场景下不要手动构造 。
LocalizedStringKeyLocalizedStringKeyString(localized:) -- Modern NSLocalizedString replacement
String(localized:) -- 现代化 NSLocalizedString 替代品
Use for any localized string outside a SwiftUI view initializer. Returns a plain . Available iOS 16+.
Stringswift
// Basic
let title = String(localized: "Welcome back")
// With default value (key differs from English text)
let msg = String(localized: "error.network",
defaultValue: "Check your internet connection")
// With table and bundle
let label = String(localized: "onboarding.title",
table: "Onboarding",
bundle: .module)
// With comment for translators
let btn = String(localized: "Save",
comment: "Button title to save the current document")用于 SwiftUI 视图初始化器之外的任意本地化字符串场景,返回普通 类型,iOS 16+ 可用。
Stringswift
// Basic
let title = String(localized: "Welcome back")
// With default value (key differs from English text)
let msg = String(localized: "error.network",
defaultValue: "Check your internet connection")
// With table and bundle
let label = String(localized: "onboarding.title",
table: "Onboarding",
bundle: .module)
// With comment for translators
let btn = String(localized: "Save",
comment: "Button title to save the current document")LocalizedStringResource -- Pass localization info without resolving
LocalizedStringResource -- 无需解析直接传递本地化信息
Use when you need to pass a localized string to an API that resolves it later (App Intents, widgets, notifications, system frameworks). Available iOS 16+.
swift
// App Intents require LocalizedStringResource
struct OrderCoffeeIntent: AppIntent {
static var title: LocalizedStringResource = "Order Coffee"
}
// Widgets
struct MyWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(kind: "timer",
provider: Provider()) { entry in
TimerView(entry: entry)
}
.configurationDisplayName(LocalizedStringResource("Timer"))
}
}
// Pass around without resolving yet
func showAlert(title: LocalizedStringResource, message: LocalizedStringResource) {
// Resolved at display time with the user's current locale
let resolved = String(localized: title)
}当你需要将本地化字符串传递给后续才会解析的 API 时使用(App Intents、小组件、通知、系统框架),iOS 16+ 可用。
swift
// App Intents require LocalizedStringResource
struct OrderCoffeeIntent: AppIntent {
static var title: LocalizedStringResource = "Order Coffee"
}
// Widgets
struct MyWidget: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(kind: "timer",
provider: Provider()) { entry in
TimerView(entry: entry)
}
.configurationDisplayName(LocalizedStringResource("Timer"))
}
}
// Pass around without resolving yet
func showAlert(title: LocalizedStringResource, message: LocalizedStringResource) {
// Resolved at display time with the user's current locale
let resolved = String(localized: title)
}When to use each type
各类型适用场景
| Context | Type | Why |
|---|---|---|
| SwiftUI view text parameters | | SwiftUI handles lookup automatically |
| Computed strings in view models / services | | Returns resolved |
| App Intents, widgets, system APIs | | Framework resolves at display time |
| Error messages shown to users | | Resolved in catch blocks |
| Logging / analytics (not user-facing) | Plain | No localization needed |
| 场景 | 类型 | 原因 |
|---|---|---|
| SwiftUI 视图文本参数 | | SwiftUI 会自动处理查找逻辑 |
| 视图模型/服务中的计算字符串 | | 返回已解析的 |
| App Intents、小组件、系统API | | 框架会在展示时自动解析 |
| 展示给用户的错误信息 | | 在 catch 块中完成解析 |
| 日志/埋点(非用户面向) | 普通 | 无需本地化 |
String Interpolation in Localized Strings
本地化字符串的插值用法
Interpolated values in localized strings become positional arguments that translators can reorder.
swift
// English: "Welcome, Alice! You have 3 new messages."
// German: "Willkommen, Alice! Sie haben 3 neue Nachrichten."
// Japanese: "Alice さん、新しいメッセージが 3 件あります。"
let text = String(localized: "Welcome, \(name)! You have \(count) new messages.")In the String Catalog, this appears with and placeholders that translators can reorder:
%@%lld- English:
"Welcome, %@! You have %lld new messages." - Japanese:
"%@さん、新しいメッセージが%lld件あります。"
Type-safe interpolation (preferred over format specifiers):
swift
// Interpolation provides type safety
String(localized: "Score: \(score, format: .number)")
String(localized: "Due: \(date, format: .dateTime.month().day())")本地化字符串中的插值会变成可被翻译人员重排的位置参数。
swift
// English: "Welcome, Alice! You have 3 new messages."
// German: "Willkommen, Alice! Sie haben 3 neue Nachrichten."
// Japanese: "Alice さん、新しいメッセージが 3 件あります。"
let text = String(localized: "Welcome, \(name)! You have \(count) new messages.")在 String Catalog 中,该字符串会以 和 占位符的形式呈现,翻译人员可以调整占位符的顺序:
%@%lld- 英语:
"Welcome, %@! You have %lld new messages." - 日语:
"%@さん、新しいメッセージが%lld件あります。"
类型安全插值(优先于格式说明符使用):
swift
// Interpolation provides type safety
String(localized: "Score: \(score, format: .number)")
String(localized: "Due: \(date, format: .dateTime.month().day())")Pluralization
复数规则处理
String Catalogs handle pluralization natively -- no XML required.
.stringsdictString Catalogs 原生支持复数处理,无需编写 XML 文件。
.stringsdictSetup in String Catalog
在 String Catalog 中配置
When a localized string contains an integer interpolation, Xcode detects it and offers plural variants in the String Catalog editor. Supply translations for each CLDR plural category:
| Category | English example | Arabic example |
|---|---|---|
| zero | (not used) | 0 items |
| one | 1 item | 1 item |
| two | (not used) | 2 items (dual) |
| few | (not used) | 3-10 items |
| many | (not used) | 11-99 items |
| other | 2+ items | 100+ items |
English uses only and . Arabic uses all six. Always supply as the fallback.
oneotherotherswift
// Code -- single interpolation triggers plural support
Text("\(unreadCount) unread messages")
// String Catalog entries (English):
// one: "%lld unread message"
// other: "%lld unread messages"当本地化字符串包含整数插值时,Xcode 会自动识别并在 String Catalog 编辑器中提供复数变体选项。你需要为每个 CLDR 复数分类提供翻译:
| 分类 | 英语示例 | 阿拉伯语示例 |
|---|---|---|
| zero | (不使用) | 0 items |
| one | 1 item | 1 item |
| two | (不使用) | 2 items (双数) |
| few | (不使用) | 3-10 items |
| many | (不使用) | 11-99 items |
| other | 2+ items | 100+ items |
英语仅使用 和 分类,阿拉伯语则需要全部六个分类。请始终提供 作为兜底选项。
oneotherotherswift
// Code -- single interpolation triggers plural support
Text("\(unreadCount) unread messages")
// String Catalog entries (English):
// one: "%lld unread message"
// other: "%lld unread messages"Device Variations
设备差异化配置
String Catalogs support device-specific text (iPhone vs iPad vs Mac):
swift
// In String Catalog editor, enable "Vary by Device" for a key
// iPhone: "Tap to continue"
// iPad: "Tap or click to continue"
// Mac: "Click to continue"String Catalogs 支持设备专属文本(iPhone、iPad、Mac 分别配置):
swift
// In String Catalog editor, enable "Vary by Device" for a key
// iPhone: "Tap to continue"
// iPad: "Tap or click to continue"
// Mac: "Click to continue"Grammar Agreement (iOS 17+)
语法一致性适配(iOS 17+)
Use inflection syntax for automatic grammatical agreement:
^[...]swift
// Automatically adjusts for gender/number in supported languages
Text("^[\(count) \("photo")](inflect: true) added")
// English: "1 photo added" / "3 photos added"
// Spanish: "1 foto agregada" / "3 fotos agregadas"使用 屈折变化语法实现自动语法一致性适配:
^[...]swift
// Automatically adjusts for gender/number in supported languages
Text("^[\(count) \("photo")](inflect: true) added")
// English: "1 photo added" / "3 photos added"
// Spanish: "1 foto agregada" / "3 fotos agregadas"FormatStyle -- Locale-Aware Formatting
FormatStyle -- 区域感知格式化
Never hard-code date, number, or measurement formats. Use (iOS 15+) so formatting adapts to the user's locale automatically.
FormatStyle永远不要硬编码日期、数字或度量单位的格式。使用 (iOS 15+)可以让格式化规则自动适配用户的区域设置。
FormatStyleDates
日期
swift
let now = Date.now
// Preset styles
now.formatted(date: .long, time: .shortened)
// US: "January 15, 2026 at 3:30 PM"
// DE: "15. Januar 2026 um 15:30"
// JP: "2026年1月15日 15:30"
// Component-based
now.formatted(.dateTime.month(.wide).day().year())
// US: "January 15, 2026"
// In SwiftUI
Text(now, format: .dateTime.month().day().year())swift
let now = Date.now
// Preset styles
now.formatted(date: .long, time: .shortened)
// US: "January 15, 2026 at 3:30 PM"
// DE: "15. Januar 2026 um 15:30"
// JP: "2026年1月15日 15:30"
// Component-based
now.formatted(.dateTime.month(.wide).day().year())
// US: "January 15, 2026"
// In SwiftUI
Text(now, format: .dateTime.month().day().year())Numbers
数字
swift
let count = 1234567
count.formatted() // "1,234,567" (US) / "1.234.567" (DE)
count.formatted(.number.precision(.fractionLength(2)))
count.formatted(.percent) // For 0.85 -> "85%" (US) / "85 %" (FR)
// Currency
let price = Decimal(29.99)
price.formatted(.currency(code: "USD")) // "$29.99" (US) / "29,99 $US" (FR)
price.formatted(.currency(code: "EUR")) // "29,99 EUR" (DE)swift
let count = 1234567
count.formatted() // "1,234,567" (US) / "1.234.567" (DE)
count.formatted(.number.precision(.fractionLength(2)))
count.formatted(.percent) // For 0.85 -> "85%" (US) / "85 %" (FR)
// Currency
let price = Decimal(29.99)
price.formatted(.currency(code: "USD")) // "$29.99" (US) / "29,99 $US" (FR)
price.formatted(.currency(code: "EUR")) // "29,99 EUR" (DE)Measurements
度量单位
swift
let distance = Measurement(value: 5, unit: UnitLength.kilometers)
distance.formatted(.measurement(width: .wide))
// US: "3.1 miles" (auto-converts!) / DE: "5 Kilometer"
let temp = Measurement(value: 22, unit: UnitTemperature.celsius)
temp.formatted(.measurement(width: .abbreviated))
// US: "72 F" (auto-converts!) / FR: "22 C"swift
let distance = Measurement(value: 5, unit: UnitLength.kilometers)
distance.formatted(.measurement(width: .wide))
// US: "3.1 miles" (自动转换!) / DE: "5 Kilometer"
let temp = Measurement(value: 22, unit: UnitTemperature.celsius)
temp.formatted(.measurement(width: .abbreviated))
// US: "72 F" (自动转换!) / FR: "22 C"Duration, PersonName, Lists
时长、人名、列表
swift
// Duration
let dur = Duration.seconds(3661)
dur.formatted(.time(pattern: .hourMinuteSecond)) // "1:01:01"
// Person names
let name = PersonNameComponents(givenName: "John", familyName: "Doe")
name.formatted(.name(style: .long)) // "John Doe" (US) / "Doe John" (JP)
// Lists
let items = ["Apples", "Oranges", "Bananas"]
items.formatted(.list(type: .and)) // "Apples, Oranges, and Bananas" (EN)
// "Apples, Oranges et Bananas" (FR)For the complete FormatStyle reference, custom styles, and RTL layout, see .
references/formatstyle-locale.mdswift
// Duration
let dur = Duration.seconds(3661)
dur.formatted(.time(pattern: .hourMinuteSecond)) // "1:01:01"
// Person names
let name = PersonNameComponents(givenName: "John", familyName: "Doe")
name.formatted(.name(style: .long)) // "John Doe" (US) / "Doe John" (JP)
// Lists
let items = ["Apples", "Oranges", "Bananas"]
items.formatted(.list(type: .and)) // "Apples, Oranges, and Bananas" (EN)
// "Apples, Oranges et Bananas" (FR)如需查看完整的 FormatStyle 参考、自定义样式和 RTL 布局相关内容,请参考 。
references/formatstyle-locale.mdRight-to-Left (RTL) Layout
从右到左(RTL)布局
SwiftUI automatically mirrors layouts for RTL languages (Arabic, Hebrew, Urdu, Persian). Most views require zero changes.
SwiftUI 会自动为 RTL 语言(阿拉伯语、希伯来语、乌尔都语、波斯语)镜像布局,绝大多数视图无需任何修改。
What SwiftUI auto-mirrors
SwiftUI 自动镜像的内容
- children reverse order
HStack - /
.leadingalignment and padding swap sides.trailing - back button moves to trailing edge
NavigationStack - disclosure indicators flip
List - Text alignment follows reading direction
- 子元素顺序反转
HStack - /
.leading对齐和内边距自动互换.trailing - 返回按钮移动到右侧
NavigationStack - 展开指示器翻转
List - 文本对齐遵循阅读方向
What needs manual attention
需要手动处理的内容
swift
// Testing RTL in previews
MyView()
.environment(\.layoutDirection, .rightToLeft)
.environment(\.locale, Locale(identifier: "ar"))
// Images that should mirror (directional arrows, progress indicators)
Image(systemName: "chevron.right")
.flipsForRightToLeftLayoutDirection(true)
// Images that should NOT mirror: logos, photos, clocks, music notes
// Forced LTR for specific content (phone numbers, code)
Text("+1 (555) 123-4567")
.environment(\.layoutDirection, .leftToRight)swift
// 在预览中测试 RTL 效果
MyView()
.environment(\.layoutDirection, .rightToLeft)
.environment(\.locale, Locale(identifier: "ar"))
// 需要镜像的图片(方向箭头、进度指示器等)
Image(systemName: "chevron.right")
.flipsForRightToLeftLayoutDirection(true)
// 不需要镜像的图片:logo、照片、时钟、音符等
// 特定内容强制使用 LTR(电话号码、代码等)
Text("+1 (555) 123-4567")
.environment(\.layoutDirection, .leftToRight)Layout rules
布局规则
- DO use /
.leading-- they auto-flip for RTL.trailing - DON'T use /
.left-- they are fixed and break RTL.right - DO use /
HStack-- they respect layout directionVStack - DON'T use absolute for directional positioning
offset(x:)
- 推荐 使用 /
.leading-- 它们会为 RTL 自动翻转.trailing - 不推荐 使用 /
.left-- 它们是固定值,会破坏 RTL 布局.right - 推荐 使用 /
HStack-- 它们会遵循布局方向VStack - 不推荐 使用绝对 进行方向相关的定位
offset(x:)
Common Mistakes
常见错误
DON'T: Use NSLocalizedString in new code
错误:在新代码中使用 NSLocalizedString
swift
// WRONG -- legacy API, verbose, no compiler integration with String Catalogs
let title = NSLocalizedString("welcome_title", comment: "Welcome screen title")swift
// 错误 -- 旧API,冗余,无法和 String Catalogs 进行编译集成
let title = NSLocalizedString("welcome_title", comment: "Welcome screen title")DO: Use String(localized:) or let SwiftUI handle it
正确:使用 String(localized:) 或让 SwiftUI 自动处理
swift
// CORRECT
let title = String(localized: "welcome_title",
defaultValue: "Welcome!",
comment: "Welcome screen title")
// Or in SwiftUI, just:
Text("Welcome!")swift
// 正确
let title = String(localized: "welcome_title",
defaultValue: "Welcome!",
comment: "Welcome screen title")
// 或者在 SwiftUI 中直接写:
Text("Welcome!")DON'T: Concatenate localized strings
错误:拼接本地化字符串
swift
// WRONG -- word order varies by language
let greeting = String(localized: "Hello") + ", " + name + "!"swift
// 错误 -- 不同语言的语序存在差异
let greeting = String(localized: "Hello") + ", " + name + "!"DO: Use string interpolation
正确:使用字符串插值
swift
// CORRECT -- translators can reorder placeholders
let greeting = String(localized: "Hello, \(name)!")swift
// 正确 -- 翻译人员可以重排占位符顺序
let greeting = String(localized: "Hello, \(name)!")DON'T: Hard-code date/number formats
错误:硬编码日期/数字格式
swift
// WRONG -- US-only format
let formatter = DateFormatter()
formatter.dateFormat = "MM/dd/yyyy" // Meaningless in most countriesswift
// 错误 -- 仅适用于美国地区的格式
let formatter = DateFormatter()
formatter.dateFormat = "MM/dd/yyyy" // 在大多数国家没有意义DO: Use FormatStyle
正确:使用 FormatStyle
swift
// CORRECT -- adapts to user locale
Text(date, format: .dateTime.month().day().year())swift
// 正确 -- 自动适配用户区域设置
Text(date, format: .dateTime.month().day().year())DON'T: Use fixed-width layouts
错误:使用固定宽度布局
swift
// WRONG -- German text is ~30% longer than English
Text(title).frame(width: 120)swift
// 错误 -- 德语文本长度比英语长约30%
Text(title).frame(width: 120)DO: Use flexible layouts
正确:使用弹性布局
swift
// CORRECT
Text(title).fixedSize(horizontal: false, vertical: true)
// Or use VStack/wrapping that accommodates expansionswift
// 正确
Text(title).fixedSize(horizontal: false, vertical: true)
// 或者使用支持内容扩展的 VStack/自动换行布局DON'T: Use .left / .right for alignment
错误:使用 .left / .right 做对齐
swift
// WRONG -- does not flip for RTL
HStack { Spacer(); text }.padding(.left, 16)swift
// 错误 -- RTL 场景下不会自动翻转
HStack { Spacer(); text }.padding(.left, 16)DO: Use .leading / .trailing
正确:使用 .leading / .trailing
swift
// CORRECT
HStack { Spacer(); text }.padding(.leading, 16)swift
// 正确
HStack { Spacer(); text }.padding(.leading, 16)DON'T: Put user-facing strings as plain String outside SwiftUI
错误:将用户面向的字符串定义为 SwiftUI 之外的普通 String
swift
// WRONG -- not localized
let errorMessage = "Something went wrong"
showAlert(message: errorMessage)swift
// 错误 -- 未本地化
let errorMessage = "Something went wrong"
showAlert(message: errorMessage)DO: Use LocalizedStringResource for deferred resolution
正确:使用 LocalizedStringResource 实现延迟解析
swift
// CORRECT
let errorMessage = LocalizedStringResource("Something went wrong")
showAlert(message: String(localized: errorMessage))swift
// 正确
let errorMessage = LocalizedStringResource("Something went wrong")
showAlert(message: String(localized: errorMessage))DON'T: Skip pseudolocalization testing
错误:跳过伪本地化测试
Testing only in English hides truncation, layout, and RTL bugs.
仅在英语环境下测试会隐藏文本截断、布局、RTL 相关的Bug。
DO: Test with German (long) and Arabic (RTL) at minimum
正确:至少使用德语(长文本)和阿拉伯语(RTL)进行测试
Use Xcode scheme settings to override the app language without changing device locale.
使用 Xcode scheme 设置可以覆盖应用语言,无需修改设备区域设置。
Localization Review Checklist
本地化评审检查清单
- All user-facing strings use localization (in SwiftUI or
LocalizedStringKey)String(localized:) - No string concatenation for user-visible text
- Dates and numbers use , not hardcoded formats
FormatStyle - Pluralization handled via String Catalog plural variants (not manual if/else)
- Layout uses /
.leading, not.trailing/.left.right - UI tested with long text (German) and RTL (Arabic)
- String Catalog includes all target languages
- Images needing RTL mirroring use
.flipsForRightToLeftLayoutDirection(true) - App Intents and widgets use
LocalizedStringResource - No usage in new code
NSLocalizedString - Comments provided for ambiguous keys (context for translators)
- used for spacing that must scale with Dynamic Type
@ScaledMetric - Currency formatting uses explicit currency code, not locale default
- Pseudolocalization tested (accented, right-to-left, double-length)
- Ensure localized string types are Sendable; use @MainActor for locale-change UI updates
- 所有用户面向的字符串都使用了本地化方案(SwiftUI 中使用 或
LocalizedStringKey)String(localized:) - 用户可见文本没有使用字符串拼接
- 日期和数字使用 格式化,没有硬编码格式
FormatStyle - 复数规则通过 String Catalog 复数变体处理(而非手动 if/else 判断)
- 布局使用 /
.leading,而非.trailing/.left.right - UI 已通过长文本(德语)和 RTL(阿拉伯语)场景测试
- String Catalog 包含所有目标语言
- 需要 RTL 镜像的图片使用了
.flipsForRightToLeftLayoutDirection(true) - App Intents 和小组件使用
LocalizedStringResource - 新代码中没有使用
NSLocalizedString - 为有歧义的键添加了注释(为翻译人员提供上下文)
- 需要随 Dynamic Type 缩放的间距使用了
@ScaledMetric - 货币格式化使用了明确的货币代码,而非区域默认值
- 已完成伪本地化测试(重音字符、从右到左、双倍长度)
- 确保本地化字符串类型符合 Sendable 要求;区域变更后的 UI 更新使用 @MainActor 处理
MCP Integration
MCP 集成
The apple-docs MCP can verify current API signatures for , , , and related types when the service is available:
LocalizedStringResourceFormatStyleString(localized:)fetchAppleDocumentation path: "/documentation/foundation/localizedstringresource"
fetchAppleDocumentation path: "/documentation/foundation/formatstyle"
fetchAppleDocumentation path: "/documentation/swiftui/localizedstringkey"服务可用时,apple-docs MCP 可以校验 、、 和相关类型的当前 API 签名:
LocalizedStringResourceFormatStyleString(localized:)fetchAppleDocumentation path: "/documentation/foundation/localizedstringresource"
fetchAppleDocumentation path: "/documentation/foundation/formatstyle"
fetchAppleDocumentation path: "/documentation/swiftui/localizedstringkey"