Skip to main content

Kompletny przewodnik po lokalizacji aplikacji na iOS

Od Localizable.strings po metadane App Store: lokalizuj aplikację na iOS za pomocą Xcode, SwiftUI, Fastlane i automatycznych tłumaczeń AI.

1

Włącz lokalizację w Xcode

Otwórz ustawienia projektu Xcode, przejdź do Info > Localizations i dodaj języki, które chcesz obsługiwać. Xcode automatycznie utworzy katalogi .lproj dla każdego języka.

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
Lokalizacja bazowa oddziela interfejs od jego tekstów. Po dodaniu języka Xcode proponuje utworzenie zlokalizowanych wersji storyboardów, plików XIB i plików tekstowych.
2

Utwórz Localizable.strings

Standardowy plik lokalizacyjny iOS używa par klucz–wartość rozdzielonych znakami równości, a każdy wiersz kończy się średnikiem. Umieść go w folderze Base.lproj dla języka źródłowego.

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
Brak średników powoduje ciche błędy — plik wczytuje się bez błędu, ale tłumaczenia są puste. Upewnij się też, że plik został dodany do fazy kompilacji Copy Bundle Resources dla targetu, inaczej nie znajdzie się w pakiecie aplikacji.
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

Przejdź na String Catalogs (Xcode 15+)

String Catalogs (.xcstrings) to nowoczesny zamiennik plików .strings firmy Apple. Oferują wizualny edytor w Xcode, automatyczne wyodrębnianie tekstów z widoków SwiftUI i wbudowaną obsługę liczby mnogiej.

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 Catalogs przechowują WSZYSTKIE języki w jednym pliku JSON .xcstrings. W zespołach oznacza to częste konflikty scalania w Git, gdy wiele osób dodaje teksty. W dużych projektach rozważ osobny katalog dla każdego modułu.
4

Używaj zlokalizowanych tekstów w SwiftUI i UIKit

Widok Text w SwiftUI automatycznie lokalizuje literały tekstowe. UIKit używa NSLocalizedString. W systemie iOS 16+ nowoczesne API String(localized:comment:) zapewnia prostszą składnię i wbudowaną obsługę kompilatora.

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"
            )
        }
    }
}
Text("Hello \(name)") po cichu nie zostaje zlokalizowane, gdy name jest zwykłą zmienną String. Interpolacja tekstu w SwiftUI tworzy LocalizedStringKey, ale poprawnie interpolowane są tylko określone typy (Int, Double itd.). W przypadku zmiennych String najpierw zbuduj zlokalizowany tekst za pomocą String(localized:).
5

Obsłuż liczbę mnogą

iOS używa plików .stringsdict do reguł liczby mnogiej i obsługuje wszystkie kategorie CLDR: zero, one, two, few, many, other. String Catalogs obsługują liczbę mnogą za pomocą wizualnego edytora w Xcode — to znacznie prostsze niż ręczne pisanie XML stringsdict.

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)
Języki takie jak arabski mają 6 form liczby mnogiej, rosyjski ma 3, a japoński 1. Zawsze definiuj wszystkie kategorie CLDR wymagane przez języki docelowe. Wizualny edytor liczby mnogiej w String Catalogs to ułatwia.
6

Lokalizuj metadane App Store za pomocą Fastlane

Użyj narzędzia deliver z Fastlane, aby przechowywać metadane App Store — nazwę aplikacji, podtytuł, opis, słowa kluczowe i informacje o wydaniu — w repozytorium pod kontrolą wersji jako zwykłe pliki tekstowe uporządkowane według języka.

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
Lokalizacja krzyżowa: amerykański App Store indeksuje zarówno angielskie, jak i hiszpańskie słowa kluczowe. Lokalizacja metadanych na język hiszpański pozwala dotrzeć do wyszukiwań latynoskich użytkowników w USA bez kierowania oferty na osobny rynek.
7

Przetestuj lokalizację

Testuj zlokalizowane treści bez zmiany języka urządzenia. Używaj ustawień zastępczych schematu Xcode do uruchamiania aplikacji w dowolnym języku, podglądów SwiftUI ze środowiskiem locale oraz XCUITest z argumentami uruchomieniowymi do testów automatycznych.

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()
Testuj po niemiecku (teksty wydłużają się o około 30% względem angielskiego) i japońsku (skracają się o około 50%), aby wcześnie wykrywać problemy z układem. Używaj pseudolokalizacji Xcode do testów obciążeniowych układów bez prawdziwych tłumaczeń.

Zautomatyzuj kontrolę jakości tłumaczeń

Wykrywaj brakujące klucze, uszkodzone symbole zastępcze i problemy z liczbą mnogą przed wydaniem za pomocą i18n-validate. Testuj interfejs z pseudotłumaczeniami przy użyciu i18n-pseudo, zanim pojawią się prawdziwe tłumaczenia.
8

Zautomatyzuj tłumaczenia

Tłumacz pliki .strings i .xcstrings oraz pliki metadanych Fastlane za pomocą AI. Zautomatyzuj tłumaczenie zarówno tekstów w aplikacji, jak i metadanych App Store, aby zapewnić w pełni zlokalizowaną obecność.

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
Zlokalizowana obecność w App Store zwiększa liczbę pobrań o ponad 30% na rynkach nieanglojęzycznych. Tłumacz metadane wraz z tekstami aplikacji — to lokalizacja o najwyższym zwrocie z inwestycji.
+

Bonus: inteligentny język rezerwowy z LocaleChain

Domyślnie iOS wraca do języka deweloperskiego, gdy dokładne ustawienia regionalne użytkownika są niedostępne. Użytkownik pt-BR mający do dyspozycji tylko tłumaczenia pt-PT zobaczy angielski zamiast portugalskiego. LocaleChain rozwiązuje ten problem za pomocą konfigurowalnych łańcuchów rezerwowych.

LocaleChain to pakiet Swift o otwartym kodzie źródłowym. Zobacz na GitHubie

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

Typowe pułapki

Błędy składni pliku .strings

Brak średników, cudzysłowy bez znaków ucieczki lub nieprawidłowe kodowanie powodują ciche błędy. Plik się wczytuje, ale tłumaczenia są puste. Zawsze sprawdzaj poprawność plików .strings przed zatwierdzeniem zmian.

Interpolacja Text w SwiftUI nie jest lokalizowana

Text("Hello \(stringVar)") nie jest lokalizowane zgodnie z oczekiwaniami. Dla obliczanych tekstów użyj String(localized:) lub upewnij się, że interpolowane zmienne mają właściwy typ dla LocalizedStringKey.StringInterpolation.

Widżety i rozszerzenia wyświetlają surowe klucze

Rozszerzenia aplikacji mają osobne pakiety. Upewnij się, że pliki .strings lub .xcstrings dodano do fazy Copy Bundle Resources targetu rozszerzenia, a nie tylko targetu głównej aplikacji.

Brakujące tłumaczenia wyświetlają klucze w wersji produkcyjnej

Gdy klucz nie ma tłumaczenia na język użytkownika, iOS wyświetla sam klucz. Zastosuj strategię języka rezerwowego i przetestuj wszystkie obsługiwane ustawienia regionalne przed wydaniem.

Zalecana struktura plików

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

Wypróbuj i18n Agent

Upuść tutaj plik tłumaczenia

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

lub kliknij, aby go wybrać

Języki docelowe

Rejestracja nie jest wymaganaNatychmiastowa wycena

Rezerwowe ustawienia regionalne z ios-localechain

Gdy brakuje klucza tłumaczenia w regionalnym wariancie języka, takim jak de-AT, iOS przechodzi bezpośrednio do języka deweloperskiego, zamiast najpierw sprawdzić język nadrzędny 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"],
])

Zobacz nasz przewodnik po rezerwowych ustawieniach regionalnych, aby poznać pełną listę obsługiwanych frameworków i 75 wbudowanych łańcuchów. Learn more →

Najczęstsze pytania o lokalizację iOS