Skip to main content

Kompletny przewodnik po lokalizacji aplikacji na Androida

Od strings.xml po metadane Play Store: lokalizuj aplikację na Androida za pomocą Kotlina, Jetpack Compose, Fastlane i automatycznych tłumaczeń AI.

1

Przygotuj projekt Androida do lokalizacji

Android organizuje lokalizację według folderów. Domyślne teksty znajdują się w res/values/strings.xml, a przetłumaczone trafiają do folderów właściwych dla języka, takich jak res/values-de/, res/values-ja/ itd.

Android Project Structure
// Android project structure for localization:
// res/
// ├── values/              ← Default (fallback) locale
// │   └── strings.xml
// ├── values-de/           ← German
// │   └── strings.xml
// ├── values-ja/           ← Japanese
// │   └── strings.xml
// └── values-es/           ← Spanish
//     └── strings.xml
//
// Folder naming: values-{language} or values-{language}-r{Region}
// Examples: values-pt-rBR, values-zh-rCN, values-zh-rTW
Folder res/values/ zawiera język rezerwowy. Jeśli w folderze danego języka brakuje tekstu, Android wczytuje go z folderu domyślnego. Jeśli jednak tekstu brakuje w folderze domyślnym, aplikacja ulegnie awarii przy nieobsługiwanych ustawieniach regionalnych.
2

Utwórz strings.xml

Zasoby tekstowe Androida używają XML z elementami '<string>' wewnątrz głównego elementu '<resources>'. Używaj %s dla tekstowych symboli zastępczych, %d dla liczb całkowitych oraz %1$s/%2$s dla argumentów pozycyjnych, których kolejność tłumacze mogą zmieniać.

res/values/strings.xml
<!-- res/values/strings.xml -->
<resources>
    <string name="welcome_title">Welcome to MyApp</string>
    <string name="login_button">Sign In</string>
    <string name="settings_label">Settings</string>
    <string name="greeting">Hello, %s!</string>        <!-- %s = string -->
    <string name="item_count">%d items</string>          <!-- %d = integer -->
    <string name="app_name" translatable="false">MyApp</string>
</resources>
Apostrofy bez znaków ucieczki powodują cichą awarię parsera XML. Użyj \' albo umieść wartość w podwójnym cudzysłowie. Ponadto brak tekstu w domyślnym values/strings.xml powoduje twardą awarię, a nie bezpieczne użycie wartości rezerwowej jak w iOS.
Common strings.xml Mistakes
<!-- ❌ Common mistakes in strings.xml: -->

<!-- Unescaped apostrophe — crashes XML parser silently -->
<string name="message">It's a great day</string>

<!-- Missing from default values/strings.xml — app crashes -->
<!-- (only exists in values-de/strings.xml) -->

<!-- ✅ Correct versions: -->
<string name="message">It\'s a great day</string>
<!-- Or wrap in double quotes: -->
<string name="message">"It's a great day"</string>
3

Obsłuż liczbę mnogą

Android używa elementów '&lt;plurals&gt;' z atrybutami quantity: zero, one, two, few, many, other. Każdy język docelowy może wymagać innych kategorii — arabski używa wszystkich 6, rosyjski wymaga few/many, a japoński używa tylko other.

res/values/strings.xml
<!-- res/values/strings.xml -->
<resources>
    <plurals name="items_count">
        <item quantity="zero">No items</item>
        <item quantity="one">%d item</item>
        <item quantity="other">%d items</item>
    </plurals>
</resources>

<!-- Usage in Kotlin: -->
<!-- val text = resources.getQuantityString(
    R.plurals.items_count,
    count,    // selects plural form
    count     // format argument
) -->
Atrybut quantity wybiera formę liczby mnogiej na podstawie reguł CLDR dla ustawień regionalnych urządzenia. Zawsze dodawaj 'other' jako wartość rezerwową — to jedyna kategoria, która na pewno istnieje w każdym języku.
4

Używaj w kodzie: Kotlin i Jetpack Compose

Tradycyjny Android używa getString(R.string.key) oraz resources.getQuantityString(). Jetpack Compose używa stringResource(R.string.key) oraz pluralStringResource(). Oba rozwiązania podczas działania wybierają właściwe tłumaczenie na podstawie ustawień regionalnych urządzenia.

WelcomeScreen.kt
// Traditional Android (Activity/Fragment)
val title = getString(R.string.welcome_title)
val greeting = getString(R.string.greeting, userName)
val items = resources.getQuantityString(
    R.plurals.items_count, count, count
)

// Jetpack Compose
@Composable
fun WelcomeScreen(userName: String, itemCount: Int) {
    // ✅ stringResource — Compose-aware, triggers recomposition
    Text(text = stringResource(R.string.welcome_title))

    // ✅ With format arguments
    Text(text = stringResource(R.string.greeting, userName))

    // ✅ Plurals — count passed TWICE
    Text(text = pluralStringResource(
        R.plurals.items_count,
        itemCount,    // selects plural form
        itemCount     // format argument
    ))
}
pluralStringResource(R.plurals.items, count, count) — parametr count jest przekazywany dwukrotnie. Pierwszy wybiera formę liczby mnogiej, a drugi jest argumentem formatującym. Brak drugiego count to najczęstszy błąd obsługi liczby mnogiej w Compose.
5

Tablice tekstów i teksty formatowane

Używaj '&lt;string-array&gt;' do uporządkowanych list (np. opcji list rozwijanych i kroków wdrożenia). W tekstach formatowanych używaj pozycyjnych argumentów formatu (%1$s, %2$d), aby tłumacze mogli zmieniać kolejność słów bez naruszania struktury zdania.

res/values/strings.xml
<!-- res/values/strings.xml -->
<resources>
    <!-- String array for dropdown/list -->
    <string-array name="sort_options">
        <item>Most Recent</item>
        <item>Most Popular</item>
        <item>Price: Low to High</item>
        <item>Price: High to Low</item>
    </string-array>

    <!-- Positional format args for reordering -->
    <string name="welcome_message">
        Hello %1$s, you have %2$d new messages
    </string>
    <!-- Translators can reorder: -->
    <!-- %2$d neue Nachrichten für %1$s -->
</resources>
Argumenty pozycyjne takie jak %1$s pozwalają tłumaczom dowolnie zmieniać kolejność parametrów. 'Hello %1$s, you have %2$d items' może zmienić się w '%2$d items for %1$s' w językach o innej kolejności słów — bez żadnych zmian w kodzie.
6

Lokalizuj metadane Google Play za pomocą Fastlane

Użyj polecenia supply z Fastlane, aby zarządzać metadanymi Play Store — tytułem, krótkim opisem, pełnym opisem i dziennikami zmian — jako zwykłymi plikami tekstowymi uporządkowanymi według języka w repozytorium.

Terminal
# Install Fastlane
$ gem install fastlane

# Initialize supply for Play Store metadata
$ fastlane supply init

# Directory structure created:
# fastlane/metadata/android/
# ├── en-US/
# │   ├── title.txt              # App name (50 chars)
# │   ├── short_description.txt  # Short desc (80 chars)
# │   ├── full_description.txt   # Full desc (4000 chars)
# │   └── changelogs/
# │       └── default.txt        # What's New
# ├── de-DE/
# │   └── ...
# └── ja-JP/
#     └── ...

# Push metadata to Play Store:
$ fastlane supply
Lokalizacja strony aplikacji w Play Store zwiększa liczbę pobrań o ponad 30% na rynkach nieanglojęzycznych. Tytuł, krótki opis i pełny opis są indeksowane w wyszukiwarce — ich tłumaczenie zapewnia najwyższy zwrot z inwestycji w lokalizację.
Google Play

Zautomatyzuj lokalizację strony aplikacji w Play Store

Pomiń ręczne kopiowanie i wklejanie. Przetłumacz tytuł, opis i informacje o wydaniu w Play Store na ponad 175 ustawień regionalnych z uwzględnieniem limitów znaków.

Poznaj integrację z Google Play
7

Przetestuj lokalizację

Testuj przez zmianę ustawień regionalnych emulatora, podglądy Compose z niestandardowym LocaleList oraz pseudojęzyki w Opcjach programisty. Użyj resConfigs w Gradle, aby usunąć niepotrzebne zasoby językowe z bibliotek zewnętrznych.

Testing Localization
// 1. Emulator: Settings > System > Language > Add language

// 2. Compose Preview with locale:
@Preview
@Composable
fun WelcomePreview() {
    val config = Configuration(resources.configuration).apply {
        setLocale(Locale("de"))
    }
    val localContext = LocalContext.current
    val localizedContext = localContext.createConfigurationContext(config)
    CompositionLocalProvider(
        LocalContext provides localizedContext
    ) {
        WelcomeScreen()
    }
}

// 3. Restrict library locales in build.gradle.kts:
android {
    defaultConfig {
        // Only include locales you actually translate
        resourceConfigurations += listOf("en", "de", "ja", "es", "fr")
    }
}

// 4. Enable pseudolocales in Developer Options:
// en-XA (accented) — detects hardcoded strings
// ar-XB (RTL) — tests layout mirroring
Testuj po niemiecku (tekst wydłuża się o około 30%) i japońsku (skraca się o około 50%), aby wykrywać problemy z układem. Włącz pseudojęzyki w Opcjach programisty (en-XA z akcentami, ar-XB dla RTL), aby przeprowadzać testy obciążeniowe 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 strings.xml, formy liczby mnogiej, tablice tekstów i metadane Fastlane Supply za pomocą AI. Zautomatyzuj tłumaczenie zarówno tekstów w aplikacji, jak i metadanych Play Store, aby zapewnić w pełni zlokalizowaną obecność.

Terminal
# Translate strings.xml files
> Translate res/values/strings.xml
  to Japanese, German, and Spanish

# Translate Play Store metadata too
> Translate fastlane/metadata/android/en-US/
  to de-DE, ja-JP, es-ES

✓ 6 files translated in 3.2s
i18n Agent obsługuje znaki ucieczki XML Androida, zachowuje znaczniki translatable="false", przestrzega kategorii liczby mnogiej CLDR dla każdego języka docelowego i utrzymuje argumenty formatu pozycyjnego bez zmian.
JetBrains

Dostępna jest wtyczka do Android Studio

Tłumacz zasoby XML Androida bezpośrednio w IDE za pomocą wtyczki i18n Agent do IntelliJ / Android Studio.

Install
+

Bonus: inteligentny język rezerwowy z LocaleChain

Mechanizmem zasobów rezerwowych Androida steruje system operacyjny. Gdy brakuje tłumaczeń pt-BR, Android całkowicie pomija pt-PT i wyświetla angielski. LocaleChain przechwytuje wyszukiwanie tekstów i przechodzi przez konfigurowalny łańcuch rezerwowy — dzięki temu użytkownicy regionalnych wariantów widzą najbliższe dostępne tłumaczenie.

LocaleChain for Android to biblioteka o otwartym kodzie źródłowym napisana w języku Kotlin. Zobacz na GitHubie

build.gradle.kts
// build.gradle.kts (app module)
dependencies {
    implementation("com.i18nagent:locale-chain-android:0.1.0")
}
MyApp.kt / BaseActivity.kt
// 1. Application.onCreate() — configure chains once
class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        LocaleChain.configure()
    }
}

// 2. BaseActivity — wrap context per Activity
open class BaseActivity : AppCompatActivity() {
    override fun attachBaseContext(newBase: Context) {
        super.attachBaseContext(LocaleChain.wrap(newBase))
    }
}

// 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 = mapOf("es-MX" to listOf("es-419", "es"))
)

Typowe pułapki

Brak domyślnych tekstów powoduje awarie

W przeciwieństwie do iOS, który wyświetla surowy klucz, Android ulega awarii z ResourceNotFoundException, jeśli tekstu brakuje w domyślnym res/values/strings.xml. Zawsze upewnij się, że każdy klucz istnieje w pliku domyślnym.

Podział językowy App Bundle psuje zmianę języka w aplikacji

Pakiety Google Play App Bundle dzielą pliki APK według języka — użytkownicy otrzymują tylko teksty w języku swojego urządzenia. Jeśli aplikacja umożliwia zmianę języka, dodaj bundle '{ language { enableSplit = false } }' do pliku build.gradle.kts.

Nieprawidłowe układy RTL

Przyczyną jest używanie left/right zamiast start/end w układach lub brak android:supportsRtl="true" w AndroidManifest.xml. Użyj Refactor > Add RTL Support w Android Studio, aby automatycznie przekonwertować istniejące układy.

Zanieczyszczenie zasobami bibliotek

Biblioteki zewnętrzne dołączają własne pliki values-XX/strings.xml, przez co Android uznaje, że aplikacja obsługuje języki, których w rzeczywistości nie obsługuje. Użyj resConfigs w build.gradle.kts, aby ograniczyć dołączone ustawienia regionalne tylko do tych, które faktycznie tłumaczysz.

Zalecana struktura plików

Project Structure
MyApp/
├── app/
│   └── src/main/
│       ├── res/
│       │   ├── values/
│       │   │   ├── strings.xml          # Default (source) strings
│       │   │   └── plurals.xml          # Plural rules
│       │   ├── values-de/
│       │   │   └── strings.xml
│       │   ├── values-ja/
│       │   │   └── strings.xml
│       │   └── values-es/
│       │       └── strings.xml
│       ├── java/com/example/myapp/
│       └── AndroidManifest.xml
├── fastlane/
│   └── metadata/android/
│       ├── en-US/
│       │   ├── title.txt
│       │   ├── short_description.txt
│       │   ├── full_description.txt
│       │   └── changelogs/default.txt
│       ├── de-DE/
│       └── ja-JP/
├── build.gradle.kts
└── settings.gradle.kts

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 locale-chain-android

Gdy brakuje klucza tłumaczenia w regionalnym wariancie języka, takim jak pt-BR, Android przechodzi bezpośrednio do domyślnego folderu zasobów, zamiast najpierw sprawdzić język nadrzędny pt.

Terminal
implementation("com.i18nagent:locale-chain-android:0.1.0")
Configuration
import com.i18nagent.localechain.LocaleChain

LocaleChain.configure(
    overrides = mapOf(
        "pt-BR" to listOf("pt", "en"),
        "zh-Hant-HK" to listOf("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ę Androida