Skip to main content

iOS 应用本地化完整指南

从 Localizable.strings 到 App Store 元数据:使用 Xcode、SwiftUI、Fastlane 和自动化 AI 翻译来本地化 iOS 应用。

1

在 Xcode 中启用本地化

打开 Xcode 项目设置,前往 Info > Localizations,然后添加要支持的语言。Xcode 会自动为每种语言创建 .lproj 目录。

Xcode Project Settings
// In Xcode:
// 1. Select your project in the navigator
// 2. Go to Info tab > Localizations
// 3. Click + to add languages (e.g., German, Japanese)
// 4. Select which files to localize
//
// Xcode creates .lproj directories automatically:
// en.lproj/Localizable.strings
// de.lproj/Localizable.strings
// ja.lproj/Localizable.strings
Base 本地化会将 UI 与字符串分离。添加语言时,Xcode 会建议为 storyboard、XIB 和字符串文件创建本地化版本。
2

创建 Localizable.strings

标准 iOS 本地化文件使用等号分隔的键值对,每行以分号结束。请将源语言文件放入 Base.lproj 文件夹。

Base.lproj/Localizable.strings
// Base.lproj/Localizable.strings

"welcome_title" = "Welcome to MyApp";
"login_button" = "Sign In";
"settings_label" = "Settings";
"greeting" = "Hello, %@!";    // %@ = string placeholder
"item_count" = "%d items";     // %d = integer placeholder
缺少分号会导致无提示失败:文件加载时不报错,但译文为空。还要确保文件已添加到目标的 Copy Bundle Resources 构建阶段,否则不会包含在应用包中。
Common .strings Mistakes
// ❌ Common mistakes in .strings files:

// Missing semicolon — file loads but translations are empty
"welcome_title" = "Welcome"

// Unescaped quotes — causes parse error
"message" = "Click "here" to continue";

// ✅ Correct versions:
"welcome_title" = "Welcome";
"message" = "Click \"here\" to continue";
3

迁移到 String Catalog(Xcode 15+)

String Catalog(.xcstrings)是 Apple 对 .strings 文件的现代替代方案,提供 Xcode 可视化编辑器、从 SwiftUI 视图自动提取字符串以及内置复数支持。

Localizable.xcstrings
// Xcode 15+ String Catalog (Localizable.xcstrings)
// Xcode automatically extracts strings from your code
// and manages translations in a visual editor.

// In SwiftUI, strings are automatically localizable:
Text("Welcome to MyApp")
Text("Hello, \(userName)!")

// Mark strings explicitly:
let title = String(localized: "welcome_title")
String Catalog 会把所有语言存储在单个 .xcstrings JSON 文件中。对于团队而言,多人添加字符串时会频繁产生 Git 合并冲突。大型项目可考虑每个模块使用一个 catalog。
4

在 SwiftUI 和 UIKit 中使用本地化字符串

SwiftUI 的 Text 视图会自动本地化字符串字面量,UIKit 则使用 NSLocalizedString。iOS 16+ 可使用现代 String(localized:comment:) API,以更简洁的语法获得内置编译器支持。

ContentView.swift
import SwiftUI

struct ContentView: View {
    let userName: String

    var body: some View {
        VStack {
            // ✅ SwiftUI auto-localizes string literals
            Text("welcome_title")

            // ⚠️ This does NOT localize (String interpolation)
            // Text("Hello, \(userName)")

            // ✅ Use String(localized:) for dynamic strings
            Text(String(localized: "greeting \(userName)"))

            // ✅ UIKit style (works everywhere)
            let title = NSLocalizedString(
                "settings_label",
                comment: "Settings screen title"
            )

            // ✅ Modern API (iOS 16+)
            let modern = String(
                localized: "welcome_title",
                comment: "Main screen title"
            )
        }
    }
}
当 name 是普通 String 变量时,Text("Hello \(name)") 会在没有提示的情况下无法本地化。SwiftUI 字符串插值会创建 LocalizedStringKey,但只有特定类型(Int、Double 等)能正确插值。对于 String 变量,请先使用 String(localized:) 构建本地化字符串。
5

处理复数

iOS 使用 .stringsdict 文件处理复数规则,并支持全部 CLDR 复数类别:zero、one、two、few、many、other。String Catalog 可通过 Xcode 的可视化编辑器处理复数,比手写 stringsdict XML 简单得多。

Localizable.stringsdict
<!-- Localizable.stringsdict -->
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
    <key>items_count</key>
    <dict>
        <key>NSStringLocalizedFormatKey</key>
        <string>%#@count@</string>
        <key>count</key>
        <dict>
            <key>NSStringFormatSpecTypeKey</key>
            <string>NSStringPluralRuleType</string>
            <key>NSStringFormatValueTypeKey</key>
            <string>d</string>
            <key>zero</key>
            <string>No items</string>
            <key>one</key>
            <string>%d item</string>
            <key>other</key>
            <string>%d items</string>
        </dict>
    </dict>
</dict>
</plist>

// Usage in Swift:
String(format: NSLocalizedString("items_count", comment: ""),
       itemCount)
阿拉伯语有 6 种复数形式,俄语有 3 种,日语只有 1 种。请始终定义目标语言需要的全部 CLDR 类别。String Catalog 的可视化复数编辑器让这项工作更加简单。
6

使用 Fastlane 本地化 App Store 元数据

使用 Fastlane 的 deliver 工具,将 App Store 元数据,包括应用名称、副标题、描述、关键词和发布说明,以按语言组织的纯文本文件形式纳入仓库版本控制。

Terminal
# Install Fastlane
$ gem install fastlane

# Initialize deliver for App Store metadata
$ fastlane deliver init

# Directory structure created:
# fastlane/metadata/
# ├── en-US/
# │   ├── name.txt            # App name (30 chars)
# │   ├── subtitle.txt        # Subtitle (30 chars)
# │   ├── description.txt     # Full description
# │   ├── keywords.txt        # Search keywords (100 chars)
# │   ├── release_notes.txt   # What's New
# │   └── promotional_text.txt
# ├── de-DE/
# │   └── ...
# └── ja/
#     └── ...

# Push metadata to App Store Connect:
$ fastlane deliver
交叉本地化:美国 App Store 会同时索引英语和西班牙语关键词。将元数据本地化为西班牙语,无需面向单独市场也能覆盖美国西语裔用户的搜索。
7

测试本地化

无需更改设备语言即可测试本地化内容。使用 Xcode scheme 覆盖以任意语言运行应用,通过语言环境预览 SwiftUI,并为 XCUITest 提供启动参数以执行自动化测试。

Testing Localization
// 1. Xcode Scheme Override:
// Edit Scheme > Run > Options > App Language > Choose language

// 2. SwiftUI Preview with locale:
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .environment(\.locale, Locale(identifier: "de"))

        ContentView()
            .environment(\.locale, Locale(identifier: "ja"))

        ContentView()
            .environment(\.locale, Locale(identifier: "ar"))
    }
}

// 3. XCUITest with language override:
let app = XCUIApplication()
app.launchArguments += ["-AppleLanguages", "(de)"]
app.launchArguments += ["-AppleLocale", "de_DE"]
app.launch()
使用德语(字符串比英语约长 30%)和日语(字符串约缩短 50%)进行测试,尽早发现布局问题。使用 Xcode 伪本地化,无需真实译文即可对布局进行压力测试。

自动保证翻译质量

使用 i18n-validate 在发布前发现缺失键、损坏的占位符和复数问题。真实译文完成前,可使用 i18n-pseudo 生成伪译文来测试 UI。
8

自动翻译

使用 AI 翻译 .strings、.xcstrings 和 Fastlane 元数据文件。自动翻译应用内字符串和 App Store 元数据,打造完整的本地化展示。

Terminal
# Translate .strings files
> Translate Base.lproj/Localizable.strings
  to Japanese, German, and Spanish

# Translate App Store metadata too
> Translate fastlane/metadata/en-US/
  to de-DE, ja, es-MX

✓ 6 files translated in 3.2s
本地化 App Store 页面可让非英语市场的下载量提升 30% 以上。请在翻译应用字符串的同时翻译元数据,这是投资回报率最高的本地化工作。
+

额外功能:使用 LocaleChain 实现智能语言回退

默认情况下,如果用户的确切语言不可用,iOS 会回退到开发语言。只有 pt-PT 译文时,pt-BR 用户会看到英语而非葡萄牙语。LocaleChain 通过可配置回退链修复此问题。

LocaleChain 是开源 Swift Package。在 GitHub 上查看

Package Dependencies
// Swift Package Manager
// File > Add Package Dependencies >
// https://github.com/i18n-agent/ios-localechain.git
MyApp.swift
import LocaleChain

// In your App init or AppDelegate:
LocaleChain.configure()  // Activates all default chains

// pt-BR user with only pt-PT translations?
// → Shows Portuguese instead of falling back to English

// Custom overrides for your specific locales:
LocaleChain.configure(
    overrides: ["es-MX": ["es-419", "es"]]
)

常见问题

.strings 文件语法错误

缺少分号、引号未转义或编码不正确会导致无提示失败。文件虽能加载,译文却显示为空。提交前务必验证 .strings 文件。

SwiftUI Text 插值未本地化

Text("Hello \(stringVar)") 未按预期本地化。计算字符串应使用 String(localized:);也可确保插值变量使用 LocalizedStringKey.StringInterpolation 支持的正确类型。

小组件或扩展显示原始键

应用扩展拥有单独的 bundle。请确保 .strings 或 .xcstrings 文件已添加到扩展目标的 Copy Bundle Resources 阶段,而不只是主应用目标。

缺失译文在生产环境中显示键

如果某个键没有用户语言对应的译文,iOS 会显示键本身。请采用回退语言策略,并在发布前测试所有受支持的语言。

推荐的文件结构

Project Structure
MyApp/
├── MyApp.xcodeproj
├── MyApp/
│   ├── Base.lproj/
│   │   ├── Localizable.strings       # Source strings
│   │   └── Localizable.stringsdict   # Plural rules
│   ├── en.lproj/
│   │   └── Localizable.strings
│   ├── de.lproj/
│   │   └── Localizable.strings
│   ├── ja.lproj/
│   │   └── Localizable.strings
│   ├── Localizable.xcstrings          # OR String Catalog
│   └── Info.plist
├── MyAppTests/
├── fastlane/
│   ├── Fastfile
│   └── metadata/
│       ├── en-US/
│       │   ├── name.txt
│       │   ├── description.txt
│       │   └── keywords.txt
│       ├── de-DE/
│       └── ja/
└── Package.swift

立即试用 i18n Agent

将翻译文件拖放到此处

JSON, YAML, PO, XML, CSV, Markdown, Properties

或点击选择文件

目标语言

无需注册即时估价

使用 ios-localechain 实现语言回退

如果 de-AT 等区域语言缺少翻译键,iOS 会直接跳到开发语言,而不会先检查父语言 de。

Terminal
// Swift Package Manager
// https://github.com/i18n-agent/ios-localechain
Configuration
import LocaleChain

LocaleChain.configure(overrides: [
    "de": ["en-GB", "en"],
    "pt-BR": ["pt", "en"],
    "zh-Hant-HK": ["zh-Hant", "zh", "en"],
])

查看语言回退指南,了解受支持框架的完整列表和 75 条内置回退链。 Learn more →

iOS 本地化常见问题