# General Translation Knowledge Base: 如何使用 String Catalogs 本地化 iOS 应用？
URL: https://generaltranslation.com/zh/kb/localize-ios-app.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: 在 Xcode 中添加语言，使用 SwiftUI Text 和 String(localized:) 等可本地化 API 编写面向用户的文本，然后执行构建，Xcode 会将这些字符串收集到 String Catalog（.xcstrings）中。翻译可以在 Xcode 中完成，也可以借助 XLIFF；如果希望目录随版本发布同步更新，并与你的网站和 Android 应用共享术语，可以使用 General Translation 的 CLI。
Category: 国际化
Last updated: 2026-10-20
Authors: Kevin Wu, Jackie Chen
Published: 2026-10-20

String Catalog 用单个 JSON 文件保存一张字符串表的所有语言版本，Xcode 会在每次构建时将其与代码同步。这样一来，你只需做好两件事：确保每条面向用户的字符串都进入目录，以及把高质量的译文写回目录。

## 在 Xcode 中配置本地化

### 添加语言

在项目编辑器中选中该项目，打开 **Info**，然后点击 **Localizations** 下方的添加按钮 (String Catalog 编辑器的侧边栏中也有该按钮) 。每个条目都对应一个语言 ID，例如 `de`、`ja` 或 `en-IN` ([Apple：添加对语言和地区的支持](https://developer.apple.com/documentation/xcode/adding-support-for-languages-and-regions)) 。仅当文本确有差异时才需选择地区变体，例如 `pt-BR` 和 `pt-PT`。 (参见[区域设置代码](/docs/platform/core/guides/locale-codes)。)

### 添加 String Catalog 并构建

选择 **File &gt; New &gt; File from Template**，筛选“string”，然后选择 **String Catalog**。默认名称为 `Localizable.xcstrings`。接着选择 **Product &gt; Build**：Xcode 会识别代码中可本地化的字符串并将其添加到目录中，之后每次构建时都会自动更新该目录 ([Apple: Localizing and varying text with a string catalog](https://developer.apple.com/documentation/xcode/localizing-and-varying-text-with-a-string-catalog)) 。

String Catalog 自 Xcode 15 起引入 ([发布说明](https://developer.apple.com/documentation/xcode-release-notes/xcode-15-release-notes)) 。它们会在构建时编译为 `.strings` 和 `.stringsdict` 文件，因此采用 String Catalog 无需提高最低部署目标版本 ([WWDC23: Discover String Catalogs](https://developer.apple.com/videos/play/wwdc2023/10155/)) 。

### 使用可本地化 API 编写文本

Xcode 只会提取传递给可本地化 API 的字符串。在 SwiftUI 中，视图里的字符串字面量属于 [`LocalizedStringKey`](https://developer.apple.com/documentation/swiftui/localizedstringkey) 值，会被自动提取。在其他位置，请使用 `String(localized:)` (参见 [Apple：Preparing your app&#39;s text for translation](https://developer.apple.com/documentation/xcode/preparing-your-apps-text-for-translation)) ：

```swift
import SwiftUI

struct CartView: View {
    let itemCount: Int
    let couponCode: String

    var body: some View {
        VStack {
            // SwiftUI 视图中的字符串字面量是 LocalizedStringKey 值，
            // 因此在构建时 Xcode 会将其添加到 String Catalog 中。
            Text("Your cart")

            // 插值会转换为格式说明符（%lld），可针对不同复数形式分别设置文本。
            Text("\(itemCount) items")

            // 注释用于告知译者该文本的使用位置和方式。
            Text("Checkout", comment: "Button that starts payment for the items in the cart.")

            // String 变量会原样显示，使用 Text(verbatim:) 可明确表达这一意图。
            Text(verbatim: couponCode)
        }
    }
}

// 在 SwiftUI 视图之外，使用 String(localized:) 创建可本地化文本。
let emptyCartMessage = String(
    localized: "Your cart is empty",
    comment: "Shown when the cart has no items."
)
```

最常见的疏漏是 `Text(someString)`：`String` 变量不会到目录中查找。要在视图之间传递可本地化文本，请使用 Apple 推荐的 `LocalizedStringResource`，它还能附带注释和表名。

注释之所以重要，是因为单看 &quot;Checkout&quot; 一词，既可能是名词，也可能是动词。你可以通过 `comment:` 参数添加注释，也可以在目录中按住 Control 键点击某个键，选择 **Generate Comment**，让 Xcode 根据上下文代码自动生成注释。

要找出未进入目录的文本，请打开 **Product &gt; Scheme &gt; Edit Scheme &gt; Run &gt; Options**，开启 **Show non-localized strings**；应用运行时，这些字符串会以全大写形式渲染 ([Apple: Preparing your interface for localization](https://developer.apple.com/documentation/xcode/preparing-your-interface-for-localization)) 。 (参见[如何找到未翻译的硬编码字符串？](/kb/find-hardcoded-strings)) 。

## 处理复数形式、设备与 Info.plist

按住 Control 键点击包含插值数字的键，然后选择 **Vary by Plural**。Xcode 会自动添加每种语言所需的复数类别：英语为 `one` 和 `other`；添加俄语后，则为 `one`、`few`、`many` 和 `other`。**Vary by Device** 可以让同一个键在不同设备上使用不同的值，例如在 iPhone 上显示 &quot;Tap to learn more&quot;，在 Mac 上显示 &quot;Click to learn more&quot;。

在编辑器背后，目录实际上是 JSON 文件，因此在拉取请求中查看差异时一目了然。下面这段简短的摘录包含一个英语复数形式和一条西班牙语翻译：

```json title="Localizable.xcstrings"
{
  "sourceLanguage" : "en",
  "strings" : {
    "%lld items" : {
      "comment" : "Number of items in the shopping cart.",
      "localizations" : {
        "en" : {
          "variations" : {
            "plural" : {
              "one" : {
                "stringUnit" : {
                  "state" : "translated",
                  "value" : "%lld item"
                }
              },
              "other" : {
                "stringUnit" : {
                  "state" : "translated",
                  "value" : "%lld items"
                }
              }
            }
          }
        }
      }
    },
    "Checkout" : {
      "comment" : "Button that starts payment for the items in the cart.",
      "localizations" : {
        "es" : {
          "stringUnit" : {
            "state" : "translated",
            "value" : "Pagar"
          }
        }
      }
    }
  },
  "version" : "1.0"
}
```

`Info.plist` 中面向系统的文本 (例如应用的显示名称，以及权限提示中的用途说明) 需要放在单独的目录中。向 target 添加一个 `InfoPlist.xcstrings` 文件后，Xcode 会在每次构建时自动将已知的可本地化 `Info.plist` 键填入其中。

## 跟踪字符串状态

目录中的每条翻译都有一个状态，显示在编辑器的 **State** 列中：

* **New：**&#x5C1A;未翻译成该语言。
* **Needs Review：**&#x7FFB;译完成后源内容有改动，或有人标记了该条目；选择 **Mark as Reviewed** 即可保留当前值。
* **Translated：**&#x663E;示绿色对勾，无需再做任何处理。
* **Stale：**&#x58;code 已无法在代码中找到该字符串。从代码中消失的未翻译字符串会被移除；已翻译的字符串则会保留并标记为 stale，直到你手动删除。

手动添加的字符串 (例如在运行时动态生成的键) 可以设为手动管理，这样构建时就不会更新或移除它们。

## 从 .strings 和 .stringsdict 迁移

要转换现有项目，请选择 **Edit &gt; Convert &gt; To String Catalog** (或按住 Control 键点按文件，然后选择 **Migrate to String Catalog**) 。迁移以文件和 target 为单位逐个进行，迁移期间，消息目录可以与旧版文件共存。如果同一 target 中同时存在同名的目录和 `.strings` 或 `.stringsdict` 文件，会导致构建错误，因此请先完成一个表的迁移，再处理下一个。迁移 `InfoPlist.strings` 时，其中已有的注释会被保留。

## 选择翻译方式

以下几种方式都可以将译文写入目录：

| 方式                                     | 由谁翻译             | 译者可获得的上下文                           | 能否在每次发布时重复执行                                                    | 留给你的工作                                      |
| -------------------------------------- | ---------------- | ----------------------------------- | --------------------------------------------------------------- | ------------------------------------------- |
| 在目录编辑器中手动输入                            | 你或通晓双语的团队成员      | 整个应用                                | 否                                                               | 手动处理每种语言的每个字符串                              |
| Xcode 编程智能体 (Xcode 27)                 | 你在 Xcode 中启用的智能体 | 每个字符串的使用位置、相似字符串、复数需求、Apple 的语言风格指南 | 在 Xcode 中按需运行                                                   | 配置智能体、审阅机器翻译的字符串、确保术语与 Web 和 Android 应用保持同步 |
| 将 `.xcloc` 和 XLIFF 导出给译者或翻译管理系统 (TMS)  | 专业译者             | 注释，以及你添加到 `Notes` 文件夹中的截图           | 可通过 `xcodebuild` 实现脚本化                                          | 每次发布都要来回交接一轮，并等待结果                          |
| General Translation CLI                | GT 的翻译服务         | 目录注释，以及共享的词汇表和自定义提示词                | 在构建前运行 [`gt translate`](/docs/cli/reference/commands/translate) | 在仪表板或 Xcode 中审阅，然后测试应用                      |
| 编写脚本，对 JSON 调用机器翻译或 LLM                | 模型或翻译 API        | 取决于脚本发送的内容                          | 是                                                               | 变体、替换、各语言的复数类别、格式说明符、状态以及审阅                 |

**导出。** **Product &gt; Export Localizations** 会为每种语言创建一个 Xcode Localization Catalog (即一个 `.xcloc` 文件夹) ，其中包含一个 XLIFF 文件 ([Apple：Exporting localizations](https://developer.apple.com/documentation/xcode/exporting-localizations)) 。请开启 **Use Compiler to Extract Swift Strings** 构建设置，确保导出内容涵盖所有 Swift 字符串。可通过 **Product &gt; Import Localizations** 导回译文，也可以使用 `xcodebuild -exportLocalizations` 和 `xcodebuild -importLocalizations` 将导出和导入都脚本化 ([Apple：Importing localizations](https://developer.apple.com/documentation/xcode/importing-localizations)) 。

**Xcode 27 的新变化。** Xcode 中的智能体现在可以翻译 String Catalogs：Xcode 会添加语言、创建缺失的 String Catalogs，并为智能体提供每个字符串的上下文 ([Xcode 27 发布说明](https://developer.apple.com/documentation/xcode-release-notes/xcode-27-release-notes)，[WWDC26：Translate your app using agents in Xcode](https://developer.apple.com/videos/play/wwdc2026/213/)) 。目录编辑器新增了 **Generate Translations** 按钮，智能体的输出会被标记为 **Machine Translated** 状态，导出的 XLIFF 中则以 `state-qualifier="leveraged-mt"` 标注。如果本地化注释写的是“do not translate”，该字符串现在会在目录中被标记为 **Don&#39;t Translate**，在 XLIFF 中则标记为 `translate="no"`。你可以在 `AGENTS.md` 或 `CLAUDE.md` 中指向一个 `TRANSLATION.md` 文件，并在其中提供词汇表以及智能体不应翻译的字符串列表 ([Apple：Localizing your app using agents](https://developer.apple.com/documentation/xcode/localizing-your-app-using-agents)) 。

如果只需支持你自己掌握的一两种语言，用目录编辑器即可。如果想在 Xcode 内完成机器翻译，可使用 Xcode 的智能体。如果你看重可在代码仓库中重复执行的命令，以及跨产品共享的术语，请选择 General Translation；同时你仍可继续使用 Xcode 和 Apple 原生的本地化 API。如果翻译工作由专业译者或现有的 [TMS](/kb/what-is-a-translation-management-system) 负责，请使用 XLIFF 导出。

## 测试每种语言

选择 **Product &gt; Scheme &gt; Edit Scheme**，选中 **Run**，再选择 **Options**，然后为下一次运行设置 **App Language** 和 **App Region** (参见 [Apple：测试本地化](https://developer.apple.com/documentation/xcode/testing-localizations-when-running-your-app)) 。同一 **App Language** 菜单中还提供了伪语言：**Double-Length** 用于测试文本膨胀，**Right-to-Left** 用于测试镜像布局，**Accented** 和 **Tall** 用于测试较高的字形，**Bounded String** 用于测试截断 (参见[什么是伪本地化？](/kb/pseudo-localization)) 。如需在 SwiftUI 预览中测试，请设置 `.environment(\.locale, .init(identifier: "de"))`。

App Store 元数据 (名称、描述、截图) 需在 [App Store Connect](https://developer.apple.com/help/app-store-connect/manage-app-information/localize-app-information) 中单独进行本地化。

## 使用 General Translation 翻译 String Catalog

如果你希望将翻译作为可重复执行的命令来运行，并让 iOS 应用、网站和 Android 应用的术语保持一致，可以使用 General Translation 的 CLI `gt` 原地翻译 `.xcstrings` 文件 (需要 `gt` 2.21.0 或更高版本) 。在 `gt.config.json` 中添加一个 `xcstrings` 条目，直接指向每个目录：

```json title="gt.config.json"
{
  "defaultLocale": "en",
  "locales": ["es", "ja"],
  "files": {
    "xcstrings": {
      "include": ["Resources/Localizable.xcstrings", "Resources/InfoPlist.xcstrings"]
    }
  }
}
```

所有区域设置都存放在同一个文件中，因此 `include` 路径中不含 `[locale]` 占位符；同时，目录的 `sourceLanguage` 必须与 `defaultLocale` 一致，否则运行会在上传前中止。使用 [`npx gt login`](/docs/cli/reference/commands/login) 登录，设置 `GT_PROJECT_ID` ([CLI 凭据](/docs/cli/guides/configuring#credentials)) ；如果是已有应用，请使用 [`npx gt upload`](/docs/cli/reference/commands/upload) 导入源内容和已审核的译文。然后运行 [`npx gt translate`](/docs/cli/reference/commands/translate) 生成更新。在 CI 中，将具有 **Files &gt; Write** 和 **Translation queue &gt; Enabled** 权限的项目 API 密钥存储为 `GT_API_KEY`。

CLI 只上传源语言部分，并将各目标区域设置合并回该文件，同时保留无关的区域设置和目录结构。处理 String Catalog 时，CLI 会按目标语言的复数类别翻译变体，并保留格式说明符和替换项。 (参见 [`.xcstrings` 参考](/docs/cli/reference/formats/xcstrings-files)。) 对于旧版布局，请改用 `dotStrings` 和 `dotStringsdict` 键来翻译 `.strings` 和 [`.stringsdict`](/docs/cli/reference/formats/dot-stringsdict-files) 文件。

你可以在 Xcode 中审阅目录，也可以使用仪表板的[原始文件编辑器](/docs/platform/dashboard/guides/reviewing-translations)。如果在 Xcode 中编辑了译文，请运行 [`npx gt save-local`](/docs/cli/reference/commands/save-local)，以便后续运行保留这些修改。为 iOS、Web 和 [Android](/docs/cli/reference/formats/android-strings-files) 项目分配同一个[上下文分组](/docs/platform/dashboard/guides/defining-context-for-translations)，套餐名称等词汇表术语就能在所有用户交互界面上保持一致。

Ramp 在其仪表板、落地页和 iOS 应用中使用 GT 支持 11 个以上的区域设置，充分展示了同一翻译平台如何同时服务 Web 和原生产品。 (参见[生产环境部署](https://generaltranslation.com/enterprise)。)

## 要点总结

* 添加 `Localizable.xcstrings` 后先构建一次：Xcode 会提取 SwiftUI 字面量和 `String(localized:)` 文本，但不会提取由 `String` 变量构造的 `Text`。
* 处理计数时使用 **Vary by Plural**；Xcode 会为每种语言添加对应的复数类别，例如俄语有四种。
* 已翻译的字符串从代码中移除后不会消失，而是变为 **Stale** 状态，因此需要主动清理。
* Xcode 27 新增了智能体翻译和 **Machine Translated** 状态，并在导出的 XLIFF 中加入了 `leveraged-mt`。
* General Translation 的 CLI 通过 `"xcstrings": { "include": [...] }` 和 [`npx gt translate`](/docs/cli/reference/commands/translate) 原地翻译目录，在生成目标语言变体的同时，保留无关的区域设置和目录原有的结构。

## Related questions

- [什么是伪本地化？](https://generaltranslation.com/zh/kb/pseudo-localization.mdx): 伪本地化是一种测试方法：将源文本替换为改写后的版本——加上重音符号、长度扩充约 40%，并用方括号包裹——这样在还没有任何翻译之前，硬编码字符串、截断、字体显示异常和句子拼接等问题就会暴露出来。Android 为此内置了 en-XA 和 ar-XB 两个伪区域设置。
- [如何找出未翻译的硬编码字符串？](https://generaltranslation.com/zh/kb/find-hardcoded-strings.mdx): 在 CI 中运行 linter，标记面向用户的字符串字面量，例如 JSX 可使用 eslint-plugin-i18next 的 no-literal-string 规则，Android 可使用 Android Lint 的 HardcodedText 检查，Rails 可使用 erb_lint 的 HardCodedString linter。然后切换到伪区域设置，逐一浏览应用，找出静态检查无法追踪到的文本。
- [如何在 CSS 中支持 RTL（从右到左）语言？](https://generaltranslation.com/zh/kb/right-to-left-css.mdx): 在 html 元素上同时设置 dir="rtl" 和 lang，因为仅设置 lang 并不会改变文本方向；然后将 margin-left 等物理 CSS 属性替换为 margin-inline-start 等逻辑属性。Flex 行、Grid 列和默认文本对齐会自动翻转，而 translateX()、left 和 right 不会。
- [General Translation 与 TMS（Crowdin、Lokalise、Phrase）对比](https://generaltranslation.com/zh/kb/general-translation-vs-tms.mdx): 如果开发者希望译文生成、源自代码的上下文以及审校流程都与产品发布紧密衔接，请选择 General Translation。你可以保留现有的消息目录和渲染库，也可以直接编写内联 JSX，无需翻译键。TMS 适合以语言供应商、CAT 编辑器和 XLIFF 交换为核心的翻译项目，其集成可以自动完成文件传输。

## Previous and next questions

- Previous question: [多语言 SEO：子目录、子域名与 ccTLD 对比](https://generaltranslation.com/zh/kb/multilingual-url-structure.mdx)
- Next question: [如何在 CSS 中支持 RTL（从右到左）语言？](https://generaltranslation.com/zh/kb/right-to-left-css.mdx)

## Sitemap

See the [Knowledge Base sitemap](https://generaltranslation.com/zh/kb/sitemap.md) for every article.
