The Complete Guide to iOS App Localization

From Localizable.strings to App Store metadata: localize your iOS app with Xcode, SwiftUI, Fastlane, and automated AI translation.

1

Set Up Localizable.strings

Start with the standard iOS localization file. Create Localizable.strings in your Base.lproj folder and add your app's user-facing strings as key-value pairs.

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

"welcome_title" = "Welcome to MyApp";
"login_button" = "Sign In";
"settings_label" = "Settings";
"greeting" = "Hello, %@!";
2

Configure String Catalogs (Xcode 15+)

Xcode 15 introduced String Catalogs (.xcstrings) — a modern replacement for .strings files. Xcode automatically extracts localizable strings from your SwiftUI views and manages translations in a visual editor.

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")
3

Use NSLocalizedString in Code

Access localized strings in SwiftUI with automatic string literal localization, or use NSLocalizedString for UIKit. SwiftUI's Text view localizes strings by default — no extra wrapper needed.

ContentView.swift
import SwiftUI

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

            // With variables
            Text("Hello, \(userName)!")

            // UIKit style
            let title = NSLocalizedString(
                "settings_label",
                comment: "Settings screen title"
            )
        }
    }
}
4

Handle Plurals and Variables

iOS uses .stringsdict files for plural rules, supporting all CLDR plural categories (zero, one, two, few, many, other). String Catalogs handle plurals visually in Xcode's editor.

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>one</key>
            <string>%d item</string>
            <key>other</key>
            <string>%d items</string>
        </dict>
    </dict>
</dict>
</plist>
5

Manage App Store Metadata with Fastlane

Use Fastlane's deliver tool to keep App Store metadata — app name, description, keywords, release notes — version-controlled in your repo. Translate metadata files alongside your app strings for a fully localized App Store presence.

Gemfile + Terminal
# Gemfile
source "https://rubygems.org"
gem "fastlane"

# Terminal
$ bundle install
$ bundle exec fastlane deliver init

# Directory structure created:
# fastlane/metadata/en-US/
#   ├── name.txt
#   ├── subtitle.txt
#   ├── description.txt
#   ├── keywords.txt
#   ├── release_notes.txt
#   └── promotional_text.txt
# fastlane/metadata/de-DE/
#   ├── ...
# fastlane/metadata/ja/
#   ├── ...

# Push metadata to App Store Connect:
$ bundle exec fastlane deliver
6

Automate with i18n Agent

With your localization files and App Store metadata in place, automate translation of both .strings files and Fastlane metadata directories directly from your IDE.

Terminal
# Translate your .strings files to multiple languages
> 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
+

Optional: Smart Locale Fallback with LocaleChain

By default, iOS falls back to your development language when a user's exact locale isn't available. A pt-BR user with only pt-PT translations sees English instead of Portuguese. LocaleChain is an open-source Swift package that fixes this by walking a configurable fallback chain — so regional variants always find the closest available translation.

Works with NSLocalizedString, SwiftUI Text(), Storyboard/XIB, and .stringsdict plurals. Includes pre-configured chains for 8+ language families. View on 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"]]
)

Try i18n Agent Now

Drop your translation file here

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

or click to browse

Target languages

No signup requiredInstant estimate

iOS Localization FAQ