axiom-localization

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Localization & Internationalization

应用本地化与国际化

Comprehensive guide to app localization using String Catalogs. Apple Design Award Inclusivity winners always support multiple languages with excellent RTL (Right-to-Left) support.
本指南全面介绍如何使用String Catalogs进行应用本地化。获得Apple设计奖包容性奖项的应用始终支持多种语言,并具备出色的RTL(从右到左)布局支持。

Overview

概述

String Catalogs (
.xcstrings
) are Xcode 15's unified format for managing app localization. They replace legacy
.strings
and
.stringsdict
files with a single JSON-based format that's easier to maintain, diff, and integrate with translation workflows.
This skill covers String Catalogs, SwiftUI/UIKit localization APIs, plural handling, RTL support, locale-aware formatting, and migration strategies from legacy formats.
String Catalogs(
.xcstrings
)是Xcode 15推出的统一应用本地化管理格式。它以单一的JSON格式替代了传统的
.strings
.stringsdict
文件,更易于维护、对比差异,且能更好地与翻译工作流集成。
本内容涵盖String Catalogs、SwiftUI/UIKit本地化API、复数处理、RTL支持、区域感知格式设置,以及从传统格式迁移的策略。

When to Use This Skill

适用场景

  • Setting up String Catalogs in Xcode 15+
  • Localizing SwiftUI and UIKit apps
  • Handling plural forms correctly (critical for many languages)
  • Supporting RTL languages (Arabic, Hebrew)
  • Formatting dates, numbers, and currencies by locale
  • Migrating from legacy
    .strings
    /
    .stringsdict
    files
  • Preparing App Shortcuts and App Intents for localization
  • Debugging missing translations or incorrect plural forms
  • 在Xcode 15+中设置String Catalogs
  • 本地化SwiftUI和UIKit应用
  • 正确处理复数形式(对多种语言至关重要)
  • 支持RTL语言(阿拉伯语、希伯来语)
  • 根据区域设置日期、数字和货币格式
  • 从传统的.strings/.stringsdict文件迁移
  • 为App Shortcuts和App Intents准备本地化内容
  • 调试缺失的翻译或错误的复数形式

System Requirements

系统要求

  • Xcode 15+ for String Catalogs (
    .xcstrings
    )
  • Xcode 26+ for automatic symbol generation,
    #bundle
    macro, and AI-powered comment generation
  • iOS 15+ for
    LocalizedStringResource
  • iOS 16+ for App Shortcuts localization
  • Earlier iOS versions use legacy
    .strings
    files

  • Xcode 15+:支持String Catalogs(
    .xcstrings
  • Xcode 26+:支持自动符号生成、
    #bundle
    宏和AI驱动的注释生成
  • iOS 15+:支持
    LocalizedStringResource
  • iOS 16+:支持App Shortcuts本地化
  • 更早的iOS版本需使用传统的.strings文件

Part 1: String Catalogs (WWDC 2023/10155)

第一部分:String Catalogs(WWDC 2023/10155)

Creating a String Catalog

创建String Catalog

Method 1: Xcode Navigator
  1. File → New → File
  2. Choose "String Catalog"
  3. Name it (e.g.,
    Localizable.xcstrings
    )
  4. Add to target
Method 2: Automatic Extraction
Xcode 15 can automatically extract strings from:
  • SwiftUI views (string literals in
    Text
    ,
    Label
    ,
    Button
    )
  • Swift code (
    String(localized:)
    )
  • Objective-C (
    NSLocalizedString
    )
  • C (
    CFCopyLocalizedString
    )
  • Interface Builder files (
    .storyboard
    ,
    .xib
    )
  • Info.plist values
  • App Shortcuts phrases
Build Settings Required:
  • "Use Compiler to Extract Swift Strings" → Yes
  • "Localization Prefers String Catalogs" → Yes
方法1:Xcode导航栏
  1. 文件 → 新建 → 文件
  2. 选择“String Catalog”
  3. 命名(例如
    Localizable.xcstrings
  4. 添加到目标工程
方法2:自动提取
Xcode 15可自动从以下来源提取字符串:
  • SwiftUI视图(
    Text
    Label
    Button
    中的字符串字面量)
  • Swift代码(
    String(localized:)
  • Objective-C(
    NSLocalizedString
  • C语言(
    CFCopyLocalizedString
  • Interface Builder文件(
    .storyboard
    .xib
  • Info.plist值
  • App Shortcuts短语
所需构建设置:
  • "Use Compiler to Extract Swift Strings" → 是
  • "Localization Prefers String Catalogs" → 是

String Catalog Structure

String Catalog结构

Each entry has:
  • Key: Unique identifier (default: the English string)
  • Default Value: Fallback if translation missing
  • Comment: Context for translators
  • String Table: Organization container (default: "Localizable")
Example
.xcstrings
JSON
:
json
{
  "sourceLanguage" : "en",
  "strings" : {
    "Thanks for shopping with us!" : {
      "comment" : "Label above checkout button",
      "localizations" : {
        "en" : {
          "stringUnit" : {
            "state" : "translated",
            "value" : "Thanks for shopping with us!"
          }
        },
        "es" : {
          "stringUnit" : {
            "state" : "translated",
            "value" : "¡Gracias por comprar con nosotros!"
          }
        }
      }
    }
  },
  "version" : "1.0"
}
每个条目包含:
  • Key:唯一标识符(默认:英文字符串)
  • Default Value:翻译缺失时的回退值
  • Comment:给翻译人员的上下文说明
  • String Table:组织容器(默认:"Localizable")
示例
.xcstrings
JSON
:
json
{
  "sourceLanguage" : "en",
  "strings" : {
    "Thanks for shopping with us!" : {
      "comment" : "Label above checkout button",
      "localizations" : {
        "en" : {
          "stringUnit" : {
            "state" : "translated",
            "value" : "Thanks for shopping with us!"
          }
        },
        "es" : {
          "stringUnit" : {
            "state" : "translated",
            "value" : "¡Gracias por comprar con nosotros!"
          }
        }
      }
    }
  },
  "version" : "1.0"
}

Translation States

翻译状态

Xcode tracks state for each translation:
  • New (⚪) - String hasn't been translated yet
  • Needs Review (🟡) - Source changed, translation may be outdated
  • Reviewed (✅) - Translation approved and current
  • Stale (🔴) - String no longer found in source code
Workflow:
  1. Developer adds string → New
  2. Translator adds translation → Reviewed
  3. Developer changes source → Needs Review
  4. Translator updates → Reviewed
  5. Developer removes code → Stale

Xcode会跟踪每个翻译的状态:
  • 新建(⚪):字符串尚未翻译
  • 需审核(🟡):源字符串已更改,翻译可能过时
  • 已审核(✅):翻译已批准且为最新版本
  • 已失效(🔴):源代码中已不再使用该字符串
工作流:
  1. 开发者添加字符串 → 新建
  2. 翻译人员添加翻译 → 已审核
  3. 开发者修改源字符串 → 需审核
  4. 翻译人员更新翻译 → 已审核
  5. 开发者移除代码 → 已失效

Part 2: SwiftUI Localization

第二部分:SwiftUI本地化

LocalizedStringKey (Automatic)

LocalizedStringKey(自动本地化)

SwiftUI views with
String
parameters automatically support localization:
swift
// ✅ Automatically localizable
Text("Welcome to WWDC!")
Label("Thanks for shopping with us!", systemImage: "bag")
Button("Checkout") { }

// Xcode extracts these strings to String Catalog
How it works: SwiftUI uses
LocalizedStringKey
internally, which looks up strings in String Catalogs.
带有
String
参数的SwiftUI视图自动支持本地化:
swift
// ✅ 自动支持本地化
Text("Welcome to WWDC!")
Label("Thanks for shopping with us!", systemImage: "bag")
Button("Checkout") { }

// Xcode会将这些字符串提取到String Catalog
工作原理:SwiftUI内部使用
LocalizedStringKey
,它会在String Catalogs中查找对应的字符串。

String(localized:) with Comments

带注释的String(localized:)

For explicit localization in Swift code:
swift
// Basic
let title = String(localized: "Welcome to WWDC!")

// With comment for translators
let title = String(localized: "Welcome to WWDC!",
                   comment: "Notification banner title")

// With custom table
let title = String(localized: "Welcome to WWDC!",
                   table: "WWDCNotifications",
                   comment: "Notification banner title")

// With default value (key ≠ English text)
let title = String(localized: "WWDC_NOTIFICATION_TITLE",
                   defaultValue: "Welcome to WWDC!",
                   comment: "Notification banner title")
Best practice: Always include
comment
to give translators context.
在Swift代码中显式本地化:
swift
// 基础用法
let title = String(localized: "Welcome to WWDC!")

// 带翻译人员注释
let title = String(localized: "Welcome to WWDC!",
                   comment: "Notification banner title")

// 自定义表
let title = String(localized: "Welcome to WWDC!",
                   table: "WWDCNotifications",
                   comment: "Notification banner title")

// 带默认值(键≠英文文本)
let title = String(localized: "WWDC_NOTIFICATION_TITLE",
                   defaultValue: "Welcome to WWDC!",
                   comment: "Notification banner title")
最佳实践:始终添加
comment
,为翻译人员提供上下文。

LocalizedStringResource (Deferred Localization)

LocalizedStringResource(延迟本地化)

For passing localizable strings to other functions:
swift
import Foundation

struct CardView: View {
    let title: LocalizedStringResource
    let subtitle: LocalizedStringResource

    var body: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 10.0)
            VStack {
                Text(title)      // Resolved at render time
                Text(subtitle)
            }
            .padding()
        }
    }
}

// Usage
CardView(
    title: "Recent Purchases",
    subtitle: "Items you've ordered in the past week."
)
Key difference:
LocalizedStringResource
defers lookup until used, allowing custom views to be fully localizable.
用于将可本地化字符串传递给其他函数:
swift
import Foundation

struct CardView: View {
    let title: LocalizedStringResource
    let subtitle: LocalizedStringResource

    var body: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 10.0)
            VStack {
                Text(title)      // 渲染时解析
                Text(subtitle)
            }
            .padding()
        }
    }
}

// 使用示例
CardView(
    title: "Recent Purchases",
    subtitle: "Items you've ordered in the past week."
)
核心区别
LocalizedStringResource
会延迟查找直到使用时,允许自定义视图完全支持本地化。

AttributedString with Markdown

带Markdown的AttributedString

swift
// Markdown formatting is preserved across localizations
let subtitle = AttributedString(localized: "**Bold** and _italic_ text")

swift
// Markdown格式在本地化中会被保留
let subtitle = AttributedString(localized: "**Bold** and _italic_ text")

Part 3: UIKit & Foundation

第三部分:UIKit & Foundation

NSLocalizedString Macro

NSLocalizedString宏

swift
// Basic
let title = NSLocalizedString("Recent Purchases", comment: "Button Title")

// With table
let title = NSLocalizedString("Recent Purchases",
                             tableName: "Shopping",
                             comment: "Button Title")

// With bundle
let title = NSLocalizedString("Recent Purchases",
                             tableName: nil,
                             bundle: .main,
                             value: "",
                             comment: "Button Title")
swift
// 基础用法
let title = NSLocalizedString("Recent Purchases", comment: "Button Title")

// 带表名
let title = NSLocalizedString("Recent Purchases",
                             tableName: "Shopping",
                             comment: "Button Title")

// 带Bundle
let title = NSLocalizedString("Recent Purchases",
                             tableName: nil,
                             bundle: .main,
                             value: "",
                             comment: "Button Title")

Bundle.localizedString

Bundle.localizedString

swift
let customBundle = Bundle(for: MyFramework.self)
let text = customBundle.localizedString(forKey: "Welcome",
                                        value: nil,
                                        table: "MyFramework")
swift
let customBundle = Bundle(for: MyFramework.self)
let text = customBundle.localizedString(forKey: "Welcome",
                                        value: nil,
                                        table: "MyFramework")

Custom Macros

自定义宏

objc
// Objective-C
#define MyLocalizedString(key, comment) \
    [myBundle localizedStringForKey:key value:nil table:nil]
objc
// Objective-C
#define MyLocalizedString(key, comment) \
    [myBundle localizedStringForKey:key value:nil table:nil]

Info.plist Localization

Info.plist本地化

Localize app name, permissions, etc.:
  1. Select
    Info.plist
  2. Editor → Add Localization
  3. Create
    InfoPlist.strings
    for each language:
// InfoPlist.strings (Spanish)
"CFBundleName" = "Mi Aplicación";
"NSCameraUsageDescription" = "La app necesita acceso a la cámara para tomar fotos.";

本地化应用名称、权限说明等:
  1. 选择
    Info.plist
  2. 编辑器 → 添加本地化
  3. 为每种语言创建
    InfoPlist.strings
// InfoPlist.strings (Spanish)
"CFBundleName" = "Mi Aplicación";
"NSCameraUsageDescription" = "La app necesita acceso a la cámara para tomar fotos.";

Part 4: Pluralization

第四部分:复数处理

Different languages have different plural rules:
  • English: 2 forms (one, other)
  • Russian: 3 forms (one, few, many)
  • Polish: 3 forms (one, few, other)
  • Arabic: 6 forms (zero, one, two, few, many, other)
不同语言有不同的复数规则:
  • 英语:2种形式(单数、其他)
  • 俄语:3种形式(单数、少数、多数)
  • 波兰语:3种形式(单数、少数、其他)
  • 阿拉伯语:6种形式(零、单数、双数、少数、多数、其他)

SwiftUI Plural Handling

SwiftUI复数处理

swift
// Xcode automatically creates plural variations
Text("\(count) items")

// With custom formatting
Text("\(visitorCount) Recent Visitors")
In String Catalog:
json
{
  "strings" : {
    "%lld Recent Visitors" : {
      "localizations" : {
        "en" : {
          "variations" : {
            "plural" : {
              "one" : {
                "stringUnit" : {
                  "state" : "translated",
                  "value" : "%lld Recent Visitor"
                }
              },
              "other" : {
                "stringUnit" : {
                  "state" : "translated",
                  "value" : "%lld Recent Visitors"
                }
              }
            }
          }
        }
      }
    }
  }
}
swift
// Xcode会自动创建复数变体
Text("\(count) items")

// 自定义格式
Text("\(visitorCount) Recent Visitors")
在String Catalog中:
json
{
  "strings" : {
    "%lld Recent Visitors" : {
      "localizations" : {
        "en" : {
          "variations" : {
            "plural" : {
              "one" : {
                "stringUnit" : {
                  "state" : "translated",
                  "value" : "%lld Recent Visitor"
                }
              },
              "other" : {
                "stringUnit" : {
                  "state" : "translated",
                  "value" : "%lld Recent Visitors"
                }
              }
            }
          }
        }
      }
    }
  }
}

XLIFF Export Format

XLIFF导出格式

When exporting for translation (File → Export Localizations):
Legacy (stringsdict):
xml
<trans-unit id="/%lld Recent Visitors:dict/NSStringLocalizedFormatKey:dict/:string">
    <source>%#@recentVisitors@</source>
</trans-unit>

<trans-unit id="/%lld Recent Visitors:dict/recentVisitors:dict/one:dict/:string">
    <source>%lld Recent Visitor</source>
    <target>%lld Visitante Recente</target>
</trans-unit>
String Catalog (cleaner):
xml
<trans-unit id="%lld Recent Visitors|==|plural.one">
    <source>%lld Recent Visitor</source>
    <target>%lld Visitante Recente</target>
</trans-unit>

<trans-unit id="%lld Recent Visitors|==|plural.other">
    <source>%lld Recent Visitors</source>
    <target>%lld Visitantes Recentes</target>
</trans-unit>
导出用于翻译时(文件 → 导出本地化):
传统格式(stringsdict):
xml
<trans-unit id="/%lld Recent Visitors:dict/NSStringLocalizedFormatKey:dict/:string">
    <source>%#@recentVisitors@</source>
</trans-unit>

<trans-unit id="/%lld Recent Visitors:dict/recentVisitors:dict/one:dict/:string">
    <source>%lld Recent Visitor</source>
    <target>%lld Visitante Recente</target>
</trans-unit>
String Catalog格式(更简洁):
xml
<trans-unit id="%lld Recent Visitors|==|plural.one">
    <source>%lld Recent Visitor</source>
    <target>%lld Visitante Recente</target>
</trans-unit>

<trans-unit id="%lld Recent Visitors|==|plural.other">
    <source>%lld Recent Visitors</source>
    <target>%lld Visitantes Recentes</target>
</trans-unit>

Substitutions with Plural Variables

带复数变量的替换

swift
// Multiple variables with different plural forms
let message = String(localized: "\(songCount) songs on \(albumCount) albums")
Xcode creates variations for each variable's plural form:
  • songCount
    : one, other
  • albumCount
    : one, other
  • Total combinations: 2 × 2 = 4 translation entries

swift
// 多个变量,各有不同复数形式
let message = String(localized: "\(songCount) songs on \(albumCount) albums")
Xcode会为每个变量的复数形式创建变体:
  • songCount
    :单数、其他
  • albumCount
    :单数、其他
  • 总组合数:2 × 2 = 4个翻译条目

Part 5: Device & Width Variations

第五部分:设备与宽度变体

Device-Specific Strings

设备特定字符串

Different text for different platforms:
swift
// Same code, different strings per device
Text("Bird Food Shop")
String Catalog variations:
json
{
  "Bird Food Shop" : {
    "localizations" : {
      "en" : {
        "variations" : {
          "device" : {
            "applewatch" : {
              "stringUnit" : {
                "value" : "Bird Food"
              }
            },
            "other" : {
              "stringUnit" : {
                "value" : "Bird Food Shop"
              }
            }
          }
        }
      }
    }
  }
}
Result:
  • iPhone/iPad: "Bird Food Shop"
  • Apple Watch: "Bird Food" (shorter for small screen)
不同平台使用不同文本:
swift
// 同一代码,不同设备显示不同字符串
Text("Bird Food Shop")
String Catalog中的变体:
json
{
  "Bird Food Shop" : {
    "localizations" : {
      "en" : {
        "variations" : {
          "device" : {
            "applewatch" : {
              "stringUnit" : {
                "value" : "Bird Food"
              }
            },
            "other" : {
              "stringUnit" : {
                "value" : "Bird Food Shop"
              }
            }
          }
        }
      }
    }
  }
}
效果:
  • iPhone/iPad:"Bird Food Shop"
  • Apple Watch:"Bird Food"(适配小屏幕的短文本)

Width Variations

宽度变体

For dynamic type and size classes:
swift
Text("Application Settings")
String Catalog can provide shorter text for narrow widths.

适配动态类型和尺寸类:
swift
Text("Application Settings")
String Catalog可为窄屏提供更短的文本。

Part 6: RTL Support

第六部分:RTL支持

Layout Mirroring

布局镜像

SwiftUI automatically mirrors layouts for RTL languages:
swift
// ✅ Automatically mirrors for Arabic/Hebrew
HStack {
    Image(systemName: "chevron.right")
    Text("Next")
}

// iPhone (English): [>] Next
// iPhone (Arabic):  Next [<]
SwiftUI会自动为RTL语言镜像布局:
swift
// ✅ 自动为阿拉伯语/希伯来语镜像布局
HStack {
    Image(systemName: "chevron.right")
    Text("Next")
}

// iPhone(英语): [>] Next
// iPhone(阿拉伯语):  Next [<]

Leading/Trailing vs Left/Right

前导/尾随 vs 左/右

Always use semantic directions:
swift
// ✅ Correct - mirrors automatically
.padding(.leading, 16)
.frame(maxWidth: .infinity, alignment: .leading)

// ❌ Wrong - doesn't mirror
.padding(.left, 16)
.frame(maxWidth: .infinity, alignment: .left)
始终使用语义化方向:
swift
// ✅ 正确 - 自动镜像
.padding(.leading, 16)
.frame(maxWidth: .infinity, alignment: .leading)

// ❌ 错误 - 不会镜像
.padding(.left, 16)
.frame(maxWidth: .infinity, alignment: .left)

Images and Icons

图片与图标

Mark images that should/shouldn't flip:
swift
// ✅ Directional - mirrors for RTL
Image(systemName: "chevron.forward")

// ✅ Non-directional - never mirrors
Image(systemName: "star.fill")

// Custom images
Image("backButton")
    .flipsForRightToLeftLayoutDirection(true)
标记需要/不需要翻转的图片:
swift
// ✅ 方向敏感 - RTL时镜像
Image(systemName: "chevron.forward")

// ✅ 非方向敏感 - 从不镜像
Image(systemName: "star.fill")

// 自定义图片
Image("backButton")
    .flipsForRightToLeftLayoutDirection(true)

Testing in RTL Mode

测试RTL模式

Xcode Scheme:
  1. Edit Scheme → Run → Options
  2. Application Language: Arabic / Hebrew
  3. OR: App Language → Right-to-Left Pseudolanguage
Simulator: Settings → General → Language & Region → Preferred Language Order
SwiftUI Preview:
swift
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .environment(\.layoutDirection, .rightToLeft)
            .environment(\.locale, Locale(identifier: "ar"))
    }
}

Xcode Scheme:
  1. 编辑Scheme → 运行 → 选项
  2. 应用语言:阿拉伯语/希伯来语
  3. 或:应用语言 → 从右到左伪语言
模拟器: 设置 → 通用 → 语言与地区 → 首选语言顺序
SwiftUI预览:
swift
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .environment(\.layoutDirection, .rightToLeft)
            .environment(\.locale, Locale(identifier: "ar"))
    }
}

Part 7: Locale-Aware Formatting

第七部分:区域感知格式设置

DateFormatter

DateFormatter

swift
let formatter = DateFormatter()
formatter.locale = Locale.current  // ✅ Use current locale
formatter.dateStyle = .long
formatter.timeStyle = .short

let dateString = formatter.string(from: Date())

// US: "January 15, 2024 at 3:30 PM"
// France: "15 janvier 2024 à 15:30"
// Japan: "2024年1月15日 15:30"
Never hardcode date format strings:
swift
// ❌ Wrong - breaks in other locales
formatter.dateFormat = "MM/dd/yyyy"

// ✅ Correct - adapts to locale
formatter.dateStyle = .short
swift
let formatter = DateFormatter()
formatter.locale = Locale.current  // ✅ 使用当前区域
formatter.dateStyle = .long
formatter.timeStyle = .short

let dateString = formatter.string(from: Date())

// 美国: "January 15, 2024 at 3:30 PM"
// 法国: "15 janvier 2024 à 15:30"
// 日本: "2024年1月15日 15:30"
切勿硬编码日期格式字符串:
swift
// ❌ 错误 - 在其他区域会失效
formatter.dateFormat = "MM/dd/yyyy"

// ✅ 正确 - 适配区域
formatter.dateStyle = .short

NumberFormatter for Currency

NumberFormatter(货币)

swift
let formatter = NumberFormatter()
formatter.locale = Locale.current
formatter.numberStyle = .currency

let priceString = formatter.string(from: 29.99)

// US: "$29.99"
// UK: "£29.99"
// Japan: "¥30" (rounds to integer)
// France: "29,99 €" (comma decimal, space before symbol)
swift
let formatter = NumberFormatter()
formatter.locale = Locale.current
formatter.numberStyle = .currency

let priceString = formatter.string(from: 29.99)

// 美国: "$29.99"
// 英国: "£29.99"
// 日本: "¥30"(取整为整数)
// 法国: "29,99 €"(逗号作为小数点,符号前加空格)

MeasurementFormatter

MeasurementFormatter

swift
let distance = Measurement(value: 100, unit: UnitLength.meters)

let formatter = MeasurementFormatter()
formatter.locale = Locale.current

let distanceString = formatter.string(from: distance)

// US: "328 ft" (converts to imperial)
// Metric countries: "100 m"
swift
let distance = Measurement(value: 100, unit: UnitLength.meters)

let formatter = MeasurementFormatter()
formatter.locale = Locale.current

let distanceString = formatter.string(from: distance)

// 美国: "328 ft"(转换为英制单位)
// 公制国家: "100 m"

Locale-Specific Sorting

区域特定排序

swift
let names = ["Ångström", "Zebra", "Apple"]

// ✅ Locale-aware sort
let sorted = names.sorted { (lhs, rhs) in
    lhs.localizedStandardCompare(rhs) == .orderedAscending
}

// Sweden: ["Ångström", "Apple", "Zebra"]  (Å comes first in Swedish)
// US: ["Ångström", "Apple", "Zebra"]      (Å treated as A)

swift
let names = ["Ångström", "Zebra", "Apple"]

// ✅ 区域感知排序
let sorted = names.sorted { (lhs, rhs) in
    lhs.localizedStandardCompare(rhs) == .orderedAscending
}

// 瑞典: ["Ångström", "Apple", "Zebra"]  (Å在瑞典语中排最前)
// 美国: ["Ångström", "Apple", "Zebra"]      (Å被视为A)

Part 8: App Shortcuts Localization

第八部分:App Shortcuts本地化

Phrases with Parameters

带参数的短语

swift
import AppIntents

struct ShowTopDonutsIntent: AppIntent {
    static var title: LocalizedStringResource = "Show Top Donuts"

    @Parameter(title: "Timeframe")
    var timeframe: Timeframe

    static var parameterSummary: some ParameterSummary {
        Summary("\(.applicationName) Trends for \(\.$timeframe)") {
            \.$timeframe
        }
    }
}
String Catalog automatically extracts:
  • Intent title
  • Parameter names
  • Phrase templates with placeholders
Localized phrases:
English: "Food Truck Trends for this week"
Spanish: "Tendencias de Food Truck para esta semana"
swift
import AppIntents

struct ShowTopDonutsIntent: AppIntent {
    static var title: LocalizedStringResource = "Show Top Donuts"

    @Parameter(title: "Timeframe")
    var timeframe: Timeframe

    static var parameterSummary: some ParameterSummary {
        Summary("\(.applicationName) Trends for \(\.$timeframe)") {
            \.$timeframe
        }
    }
}
String Catalog自动提取:
  • Intent标题
  • 参数名称
  • 带占位符的短语模板
本地化短语:
English: "Food Truck Trends for this week"
Spanish: "Tendencias de Food Truck para esta semana"

AppShortcutsProvider Localization

AppShortcutsProvider本地化

swift
struct FoodTruckShortcuts: AppShortcutsProvider {
    static var appShortcuts: [AppShortcut] {
        AppShortcut(
            intent: ShowTopDonutsIntent(),
            phrases: [
                "\(.applicationName) Trends for \(\.$timeframe)",
                "Show trending donuts for \(\.$timeframe) in \(.applicationName)",
                "Give me trends for \(\.$timeframe) in \(.applicationName)"
            ]
        )
    }
}
Xcode extracts all 3 phrases into String Catalog for translation.

swift
struct FoodTruckShortcuts: AppShortcutsProvider {
    static var appShortcuts: [AppShortcut] {
        AppShortcut(
            intent: ShowTopDonutsIntent(),
            phrases: [
                "\(.applicationName) Trends for \(\.$timeframe)",
                "Show trending donuts for \(\.$timeframe) in \(.applicationName)",
                "Give me trends for \(\.$timeframe) in \(.applicationName)"
            ]
        )
    }
}
Xcode会将所有3个短语提取到String Catalog中进行翻译。

Part 9: Migration from Legacy

第九部分:从传统格式迁移

Converting .strings to .xcstrings

将.strings转换为.xcstrings

Automatic migration:
  1. Select
    .strings
    file in Navigator
  2. Editor → Convert to String Catalog
  3. Xcode creates
    .xcstrings
    and preserves translations
Manual approach:
  1. Create new String Catalog
  2. Build project (Xcode extracts strings from code)
  3. Import translations via File → Import Localizations (XLIFF)
  4. Delete old
    .strings
    files
自动迁移:
  1. 在导航栏中选择.strings文件
  2. 编辑器 → 转换为String Catalog
  3. Xcode创建.xcstrings并保留现有翻译
手动方法:
  1. 创建新的String Catalog
  2. 构建项目(Xcode从代码中提取字符串)
  3. 通过文件 → 导入本地化(XLIFF)导入翻译
  4. 删除旧的.strings文件

Converting .stringsdict

将.stringsdict转换为.xcstrings

Plural files automatically merge:
  1. Keep
    .strings
    and
    .stringsdict
    together
  2. Convert → Both merge into single
    .xcstrings
  3. Plural variations preserved
复数文件自动合并:
  1. 保留.strings和.stringsdict文件在一起
  2. 转换 → 两者合并为单个.xcstrings文件
  3. 复数变体将被保留

Gradual Migration Strategy

逐步迁移策略

Phase 1: New code uses String Catalogs
  • Create
    Localizable.xcstrings
  • Write new code with
    String(localized:)
  • Keep legacy
    .strings
    files for old code
Phase 2: Migrate existing strings
  • Convert one
    .strings
    table at a time
  • Test translations after each conversion
  • Update code using old
    NSLocalizedString
    calls
Phase 3: Remove legacy files
  • Delete
    .strings
    and
    .stringsdict
    files
  • Verify all strings in String Catalog
  • Submit to App Store
Coexistence:
.strings
and
.xcstrings
work together - Xcode checks both.

阶段1:新代码使用String Catalogs
  • 创建
    Localizable.xcstrings
  • 新代码使用
    String(localized:)
  • 保留旧代码使用的传统.strings文件
阶段2:迁移现有字符串
  • 一次转换一个.strings表
  • 每次转换后测试翻译
  • 更新使用旧
    NSLocalizedString
    调用的代码
阶段3:移除传统文件
  • 删除.strings和.stringsdict文件
  • 验证所有字符串都在String Catalog中
  • 提交到App Store
共存:.strings和.xcstrings可同时工作——Xcode会检查两者。

Common Mistakes

常见错误

Hardcoded Strings

硬编码字符串

swift
// ❌ Wrong - not localizable
Text("Welcome")
let title = "Settings"

// ✅ Correct - localizable
Text("Welcome")  // SwiftUI auto-localizes
let title = String(localized: "Settings")
swift
// ❌ 错误 - 不支持本地化
Text("Welcome")
let title = "Settings"

// ✅ 正确 - 支持本地化
Text("Welcome")  // SwiftUI自动本地化
let title = String(localized: "Settings")

Concatenating Localized Strings

拼接本地化字符串

swift
// ❌ Wrong - word order varies by language
let message = String(localized: "You have") + " \(count) " + String(localized: "items")

// ✅ Correct - single localizable string with substitution
let message = String(localized: "You have \(count) items")
Why wrong: Some languages put numbers before nouns, some after.
swift
// ❌ 错误 - 词序因语言而异
let message = String(localized: "You have") + " \(count) " + String(localized: "items")

// ✅ 正确 - 单个带替换的可本地化字符串
let message = String(localized: "You have \(count) items")
错误原因:有些语言把数字放在名词前,有些放在后。

Missing Plural Forms

缺失复数形式

swift
// ❌ Wrong - grammatically incorrect for many languages
Text("\(count) item(s)")

// ✅ Correct - proper plural handling
Text("\(count) items")  // Xcode creates plural variations
swift
// ❌ 错误 - 对多种语言语法不正确
Text("\(count) item(s)")

// ✅ 正确 - 正确处理复数
Text("\(count) items")  // Xcode创建复数变体

Ignoring RTL

忽略RTL

swift
// ❌ Wrong - breaks in RTL languages
.padding(.left, 20)
HStack {
    backButton
    Spacer()
    title
}

// ✅ Correct - mirrors automatically
.padding(.leading, 20)
HStack {
    backButton  // Appears on right in RTL
    Spacer()
    title
}
swift
// ❌ 错误 - 在RTL语言中会失效
.padding(.left, 20)
HStack {
    backButton
    Spacer()
    title
}

// ✅ 正确 - 自动镜像
.padding(.leading, 20)
HStack {
    backButton  // 在RTL中显示在右侧
    Spacer()
    title
}

Wrong Date/Number Formats

错误的日期/数字格式

swift
// ❌ Wrong - US-only format
let formatter = DateFormatter()
formatter.dateFormat = "MM/dd/yyyy"

// ✅ Correct - adapts to locale
formatter.dateStyle = .short
formatter.locale = Locale.current
swift
// ❌ 错误 - 仅适用于美国区域
let formatter = DateFormatter()
formatter.dateFormat = "MM/dd/yyyy"

// ✅ 正确 - 适配区域
formatter.dateStyle = .short
formatter.locale = Locale.current

Forgetting Comments

缺失注释

swift
// ❌ Wrong - translator has no context
String(localized: "Confirm")

// ✅ Correct - clear context
String(localized: "Confirm", comment: "Button to confirm delete action")
Impact: "Confirm" could mean "verify" or "acknowledge" - context matters for accurate translation.

swift
// ❌ 错误 - 翻译人员无上下文
String(localized: "Confirm")

// ✅ 正确 - 清晰的上下文
String(localized: "Confirm", comment: "Button to confirm delete action")
影响:"Confirm"可能表示"验证"或"确认"——上下文对准确翻译至关重要。

Troubleshooting

故障排除

Strings not appearing in String Catalog

字符串未出现在String Catalog中

Cause: Build settings not enabled
Solution:
  1. Build Settings → "Use Compiler to Extract Swift Strings" → Yes
  2. Clean Build Folder (Cmd+Shift+K)
  3. Build project
原因:构建设置未启用
解决方案:
  1. 构建设置 → "Use Compiler to Extract Swift Strings" → 是
  2. 清理构建文件夹(Cmd+Shift+K)
  3. 构建项目

Translations not showing in app

翻译未在应用中显示

Cause 1: Language not added to project
  1. Project → Info → Localizations → + button
  2. Add target language
Cause 2: String marked as "Stale"
  • Remove stale strings or verify code still uses them
原因1:项目未添加目标语言
  1. 项目 → 信息 → 本地化 → +按钮
  2. 添加目标语言
原因2:字符串标记为"已失效"
  • 移除失效字符串或验证代码仍在使用它们

Plural forms incorrect

复数形式不正确

Cause: Using
String.localizedStringWithFormat
instead of String Catalog
Solution: Use String Catalog's automatic plural handling:
swift
// ✅ Correct
Text("\(count) items")

// ❌ Wrong
Text(String.localizedStringWithFormat(NSLocalizedString("%d items", comment: ""), count))
原因:使用
String.localizedStringWithFormat
而非String Catalog
解决方案:使用String Catalog的自动复数处理:
swift
// ✅ 正确
Text("\(count) items")

// ❌ 错误
Text(String.localizedStringWithFormat(NSLocalizedString("%d items", comment: ""), count))

XLIFF export missing strings

XLIFF导出缺失字符串

Cause: "Localization Prefers String Catalogs" not set
Solution:
  1. Build Settings → "Localization Prefers String Catalogs" → Yes
  2. Export Localizations again
原因:"Localization Prefers String Catalogs"未设置
解决方案:
  1. 构建设置 → "Localization Prefers String Catalogs" → 是
  2. 重新导出本地化

Generated symbols not appearing (Xcode 26+)

生成的符号未显示(Xcode 26+)

Cause 1: Build setting not enabled
Solution:
  1. Build Settings → "Generate String Catalog Symbols" → Yes
  2. Clean Build Folder (Cmd+Shift+K)
  3. Rebuild project
Cause 2: String not manually added to catalog
Solution: Symbols only generate for manually-added strings (+ button in String Catalog). Auto-extracted strings don't generate symbols.
原因1:构建设置未启用
解决方案:
  1. 构建设置 → "Generate String Catalog Symbols" → 是
  2. 清理构建文件夹(Cmd+Shift+K)
  3. 重新构建项目
原因2:字符串未手动添加到Catalog
解决方案:仅手动添加到Catalog的字符串(+按钮)会生成符号。自动提取的字符串不会生成符号。

#bundle macro not working (Xcode 26+)

#bundle宏不工作(Xcode 26+)

Cause: Wrong syntax or missing import
Solution:
swift
import Foundation  // Required for #bundle
Text("My Collections", bundle: #bundle, comment: "Section title")
Verify you're using
#bundle
not
.module
.
原因:语法错误或缺失导入
解决方案:
swift
import Foundation  // 使用#bundle需要导入
Text("My Collections", bundle: #bundle, comment: "Section title")
确认使用的是
#bundle
而非
.module

Refactoring to symbols fails (Xcode 26+)

重构为符号失败(Xcode 26+)

Cause 1: String not in String Catalog
  1. Ensure string exists in
    .xcstrings
    file
  2. Build project to refresh catalog
  3. Try refactoring again
Cause 2: Build setting not enabled
  • Enable "Generate String Catalog Symbols" in Build Settings
  • Clean and rebuild

原因1:字符串不在String Catalog中
  1. 确保字符串存在于.xcstrings文件中
  2. 构建项目以刷新Catalog
  3. 再次尝试重构
原因2:构建设置未启用
  • 在构建设置中启用"Generate String Catalog Symbols"
  • 清理并重新构建

Part 10: Xcode 26 Localization Enhancements

第十部分:Xcode 26本地化增强

Xcode 26 introduces type-safe localization with generated symbols, automatic comment generation using on-device AI, and improved Swift Package support with the
#bundle
macro. Based on WWDC 2025 session 225 "Explore localization with Xcode".
Xcode 26引入了类型安全本地化(带生成符号)、使用设备端AI自动生成注释,以及改进的Swift Package支持(通过
#bundle
宏)。基于WWDC 2025会议225 "Explore localization with Xcode"。

Generated Symbols (Type-Safe Localization)

生成符号(类型安全本地化)

The problem: String-based localization fails silently when typos occur.
swift
// ❌ Typo - fails silently at runtime
Text("App.HomeScren.Title")  // Missing 'e' in Screen
The solution: Xcode 26 generates type-safe symbols from manually-added strings.
问题:基于字符串的本地化在出现拼写错误时会静默失败。
swift
// ❌ 拼写错误 - 运行时静默失败
Text("App.HomeScren.Title")  // Screen缺失'e'
解决方案:Xcode 26从手动添加的字符串生成类型安全符号。

How It Works

工作原理

  1. Add strings manually to String Catalog using the + button
  2. Enable build setting: "Generate String Catalog Symbols" (ON by default in new projects)
  3. Use symbols instead of strings
swift
// ✅ Type-safe - compiler catches typos
Text(.appHomeScreenTitle)
  1. 手动添加字符串到String Catalog(使用+按钮)
  2. 启用构建设置:"Generate String Catalog Symbols"(新项目默认开启)
  3. 使用符号替代字符串
swift
// ✅ 类型安全 - 编译器捕获拼写错误
Text(.appHomeScreenTitle)

Symbol Generation Rules

符号生成规则

String TypeGenerated Symbol TypeUsage Example
No placeholdersStatic property
Text(.introductionTitle)
With placeholdersFunction with labeled arguments
.subtitle(friendsPosts: 42)
Key naming conversion:
  • App.HomeScreen.Title
    .appHomeScreenTitle
  • Periods removed, camel-cased
  • Available on
    LocalizedStringResource
字符串类型生成的符号类型使用示例
无占位符静态属性
Text(.introductionTitle)
带占位符带标签参数的函数
.subtitle(friendsPosts: 42)
命名转换规则:
  • App.HomeScreen.Title
    .appHomeScreenTitle
  • 移除句点,转换为驼峰式
  • 可通过
    LocalizedStringResource
    访问

Code Examples

代码示例

swift
// SwiftUI views
struct ContentView: View {
    var body: some View {
        NavigationStack {
            Text(.introductionTitle)
                .navigationSubtitle(.subtitle(friendsPosts: 42))
        }
    }
}

// Foundation String
let message = String(localized: .curatedCollection)

// Custom views with LocalizedStringResource
struct CollectionDetailEditingView: View {
    let title: LocalizedStringResource

    init(title: LocalizedStringResource) {
        self.title = title
    }

    var body: some View {
        Text(title)
    }
}

CollectionDetailEditingView(title: .editingTitle)

swift
// SwiftUI视图
struct ContentView: View {
    var body: some View {
        NavigationStack {
            Text(.introductionTitle)
                .navigationSubtitle(.subtitle(friendsPosts: 42))
        }
    }
}

// Foundation String
let message = String(localized: .curatedCollection)

// 带LocalizedStringResource的自定义视图
struct CollectionDetailEditingView: View {
    let title: LocalizedStringResource

    init(title: LocalizedStringResource) {
        self.title = title
    }

    var body: some View {
        Text(title)
    }
}

CollectionDetailEditingView(title: .editingTitle)

Automatic Comment Generation

自动生成注释

Xcode 26 uses an on-device model to automatically generate contextual comments for localizable strings.
Xcode 26使用设备端模型自动为可本地化字符串生成上下文注释。

Enabling the Feature

启用功能

  1. Open Xcode Settings → Editing
  2. Enable "automatically generate string catalog comments"
  3. New strings added to code automatically receive generated comments
  1. 打开Xcode设置 → 编辑
  2. 启用"automatically generate string catalog comments"
  3. 添加到代码中的新字符串会自动获得生成的注释

Example

示例

For a button string, Xcode generates:
"The text label on a button to cancel the deletion of a collection"
This context helps translators understand where and how the string is used.
对于按钮字符串,Xcode生成:
"The text label on a button to cancel the deletion of a collection"
该上下文帮助翻译人员理解字符串的使用场景和方式。

XLIFF Export

XLIFF导出

Auto-generated comments are marked in exported XLIFF files:
xml
<trans-unit id="Grand Canyon" xml:space="preserve">
    <source>Grand Canyon</source>
    <target state="new">Grand Canyon</target>
    <note from="auto-generated">Suggestion for searching landmarks</note>
</trans-unit>
Benefits:
  • Saves developer time writing translator context
  • Provides consistent, clear descriptions
  • Improves translation quality

自动生成的注释会在导出的XLIFF文件中标记:
xml
<trans-unit id="Grand Canyon" xml:space="preserve">
    <source>Grand Canyon</source>
    <target state="new">Grand Canyon</target>
    <note from="auto-generated">Suggestion for searching landmarks</note>
</trans-unit>
优势:
  • 节省开发者编写翻译上下文的时间
  • 提供一致、清晰的描述
  • 提升翻译质量

Swift Package & Framework Localization

Swift Package & Framework本地化

The Problem

问题

SwiftUI uses the
.main
bundle by default. Swift Packages and frameworks need to reference their own bundle:
swift
// ❌ Wrong - uses main bundle, strings not found
Text("My Collections", comment: "Section title")
SwiftUI默认使用
.main
bundle。Swift Packages和frameworks需要引用自己的bundle:
swift
// ❌ 错误 - 使用主bundle,无法找到字符串
Text("My Collections", comment: "Section title")

The Solution: #bundle Macro (NEW in Xcode 26)

解决方案:#bundle宏(Xcode 26新增)

The
#bundle
macro automatically references the correct bundle for the current target:
swift
// ✅ Correct - automatically uses package/framework bundle
Text("My Collections", bundle: #bundle, comment: "Section title")
Key advantages:
  • Works in main app, frameworks, and Swift Packages
  • Backwards-compatible with older OS versions
  • Eliminates manual
    .module
    bundle management
#bundle
宏自动引用当前目标的正确bundle:
swift
// ✅ 正确 - 自动使用package/framework bundle
Text("My Collections", bundle: #bundle, comment: "Section title")
核心优势:
  • 适用于主应用、frameworks和Swift Packages
  • 向后兼容旧版OS
  • 无需手动管理
    .module
    bundle

With Custom Table Names

自定义表名

swift
// Main app
Text("My Collections",
     tableName: "Discover",
     comment: "Section title")

// Framework or Swift Package
Text("My Collections",
     tableName: "Discover",
     bundle: #bundle,
     comment: "Section title")

swift
// 主应用
Text("My Collections",
     tableName: "Discover",
     comment: "Section title")

// Framework或Swift Package
Text("My Collections",
     tableName: "Discover",
     bundle: #bundle,
     comment: "Section title")

Custom Table Symbol Access

自定义表符号访问

When using multiple String Catalogs for organization:
当使用多个String Catalogs进行组织时:

Default "Localizable" Table

默认"Localizable"表

Symbols are directly accessible on
LocalizedStringResource
:
swift
Text(.welcomeMessage)  // From Localizable.xcstrings
Note: Xcode automatically resolves symbols from the default "Localizable" table. Explicit table selection is rarely needed—use it only for debugging or testing specific catalogs.
符号可直接通过
LocalizedStringResource
访问:
swift
Text(.welcomeMessage)  // 来自Localizable.xcstrings
注意:Xcode自动解析默认"Localizable"表中的符号。仅在调试或测试特定Catalog时才需要显式选择表。

Custom Tables

自定义表

Symbols are nested in the table namespace:
swift
// From Discover.xcstrings
Text(Discover.featuredCollection)

// From Settings.xcstrings
Text(Settings.privacyPolicy)
Organization strategy for large apps:
  • Localizable.xcstrings - Core app strings
  • FeatureName.xcstrings - Feature-specific strings (e.g., Onboarding, Settings, Discover)
  • Benefits: Easier to manage, clearer ownership, better XLIFF organization

符号嵌套在表命名空间中:
swift
// 来自Discover.xcstrings
Text(Discover.featuredCollection)

// 来自Settings.xcstrings
Text(Settings.privacyPolicy)
大型应用组织策略:
  • Localizable.xcstrings - 核心应用字符串
  • FeatureName.xcstrings - 功能特定字符串(例如Onboarding、Settings、Discover)
  • 优势:更易于管理、所有权更清晰、XLIFF组织更合理

Two Localization Workflows

两种本地化工作流

Xcode 26 supports two complementary workflows:
Xcode 26支持两种互补的工作流:

Workflow 1: String Extraction (Recommended for new projects)

工作流1:字符串提取(推荐用于新项目)

Process:
  1. Write strings directly in code
  2. Use SwiftUI views (
    Text
    ,
    Button
    ) and
    String(localized:)
  3. Xcode automatically extracts to String Catalog
  4. Leverage automatic comment generation
Pros: Simple initial setup, immediate start
Cons: Less control over string organization
swift
// ✅ String extraction workflow
Text("Welcome to WWDC!", comment: "Main welcome message")
流程:
  1. 直接在代码中编写字符串
  2. 使用SwiftUI视图(
    Text
    Button
    )和
    String(localized:)
  3. Xcode自动提取到String Catalog
  4. 利用自动注释生成
优点:初始设置简单,可快速开始
缺点:对字符串组织的控制较少
swift
// ✅ 字符串提取工作流
Text("Welcome to WWDC!", comment: "Main welcome message")

Workflow 2: Generated Symbols (Recommended as complexity grows)

工作流2:生成符号(推荐用于复杂度提升时)

Process:
  1. Manually add strings to String Catalog
  2. Reference via type-safe symbols
  3. Organize into custom tables
Pros: Better control, type safety, easier to maintain across frameworks
Cons: Requires planning string catalog structure upfront
swift
// ✅ Generated symbols workflow
Text(.welcomeMessage)
WorkflowBest ForTrade-offs
String ExtractionNew projects, simple apps, prototypingAutomatic extraction, less control over organization
Generated SymbolsLarge apps, frameworks, multiple teamsType safety, better organization, requires upfront planning

流程:
  1. 手动将字符串添加到String Catalog
  2. 通过类型安全符号引用
  3. 组织到自定义表中
优点:控制更好、类型安全、跨frameworks更易维护
缺点:需要预先规划String Catalog结构
swift
// ✅ 生成符号工作流
Text(.welcomeMessage)
工作流最佳适用场景权衡
字符串提取新项目、简单应用、原型开发自动提取,对组织的控制较少
生成符号大型应用、frameworks、多团队协作类型安全、组织性更好,需要预先规划

Refactoring Between Workflows

工作流之间的重构

Xcode 26 allows converting between workflows without manual rewriting.
Xcode 26允许在工作流之间转换,无需手动重写代码。

Converting Strings to Symbols

将字符串转换为符号

  1. Right-click on a string literal in code
  2. Select "Refactor > Convert Strings to Symbols"
  3. Preview all affected locations
  4. Customize symbol names before confirming
  5. Apply to entire table or individual strings
Example:
swift
// Before
Text("Welcome to WWDC!", comment: "Main welcome message")

// After refactoring
Text(.welcomeToWWDC)
Benefits:
  • Batch conversion of entire String Catalogs
  • Preview changes before applying
  • Maintain localization without code rewrites

  1. 右键点击代码中的字符串字面量
  2. 选择**"Refactor > Convert Strings to Symbols"**
  3. 预览所有受影响的位置
  4. 自定义符号名称后确认
  5. 应用到整个表或单个字符串
示例:
swift
// 转换前
Text("Welcome to WWDC!", comment: "Main welcome message")

// 转换后
Text(.welcomeToWWDC)
优势:
  • 批量转换整个String Catalogs
  • 应用前预览更改
  • 无需重写代码即可维护本地化

Implementation Checklist

实施检查清单

After adopting Xcode 26 generated symbols, verify:
Build Configuration:
  • "Generate String Catalog Symbols" build setting enabled
  • Project builds without "Cannot find 'symbolName' in scope" errors
  • Clean build succeeds (Cmd+Shift+K, then Cmd+B)
String Catalog Setup:
  • Strings manually added to catalog using + button (not auto-extracted)
  • Symbol names follow conventions (camelCase, no periods)
  • Custom tables organized by feature (if using multiple catalogs)
Swift Package Integration:
  • All
    Text()
    and
    String(localized:)
    calls in packages use
    bundle: #bundle
  • Import Foundation added where
    #bundle
    is used
  • Tested package builds independently and as dependency
Refactoring & Migration:
  • Tested refactoring tool on sample strings
  • Preview showed expected changes before applying
  • Old string-based calls still work during transition period
Optional Features:
  • Automatic comment generation enabled in Xcode Settings → Editing (optional)
  • Tested AI-generated comments for accuracy
  • XLIFF export includes auto-generated comments
Testing:
  • Symbols resolve correctly in SwiftUI previews
  • Localization works across all supported languages
  • App runs on minimum supported iOS version

采用Xcode 26生成符号后,验证以下内容:
构建配置:
  • "Generate String Catalog Symbols"构建设置已启用
  • 项目构建无"Cannot find 'symbolName' in scope"错误
  • 清理构建成功(Cmd+Shift+K,然后Cmd+B)
String Catalog设置:
  • 字符串通过+按钮手动添加到Catalog(非自动提取)
  • 符号名称遵循约定(驼峰式,无句点)
  • 自定义表按功能组织(如果使用多个Catalogs)
Swift Package集成:
  • Packages中的所有
    Text()
    String(localized:)
    调用都使用
    bundle: #bundle
  • 使用
    #bundle
    的位置已导入Foundation
  • 已独立测试Package构建,且作为依赖时也能正常工作
重构与迁移:
  • 已在示例字符串上测试重构工具
  • 应用前预览显示预期更改
  • 旧的基于字符串的调用在过渡期间仍能正常工作
可选功能:
  • Xcode设置 → 编辑中已启用自动注释生成(可选)
  • 已测试AI生成注释的准确性
  • XLIFF导出包含自动生成的注释
测试:
  • 符号在SwiftUI预览中正确解析
  • 本地化在所有支持的语言中正常工作
  • 应用在最低支持的iOS版本上可运行

Resources

资源

WWDC: 2025-225, 2023-10155, 2022-10110
Docs: /xcode/localization, /xcode/localizing-and-varying-text-with-a-string-catalog
Skills: axiom-app-intents-ref, axiom-hig, axiom-accessibility-diag
WWDC: 2025-225, 2023-10155, 2022-10110
文档: /xcode/localization, /xcode/localizing-and-varying-text-with-a-string-catalog
相关技能: axiom-app-intents-ref, axiom-hig, axiom-accessibility-diag