Skip to main content

Panduan Lengkap Lokalisasi Aplikasi Android

Dari strings.xml hingga metadata Play Store: lokalkan aplikasi Android dengan Kotlin, Jetpack Compose, Fastlane, dan penerjemahan AI otomatis.

1

Siapkan Proyek Android untuk Lokalisasi

Android menggunakan konvensi berbasis folder untuk lokalisasi. String default berada di res/values/strings.xml dan string terjemahan ditempatkan di folder spesifik bahasa seperti res/values-de/, res/values-ja/, dan seterusnya.

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/ adalah bahasa fallback. Jika string tidak ada dalam folder spesifik bahasa, Android memuatnya dari folder default. Namun, jika string tidak ada dalam folder default, aplikasi akan berhenti di bahasa yang tidak didukung.
2

Buat strings.xml

Sumber daya string Android menggunakan XML dengan elemen '<string>' di dalam root '<resources>'. Gunakan %s untuk placeholder string, %d untuk bilangan bulat, serta %1$s/%2$s untuk argumen posisi yang dapat diurutkan ulang oleh penerjemah.

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>
Apostrof yang tidak di-escape membuat parser XML berhenti tanpa pesan. Gunakan \' atau bungkus nilai dengan tanda kutip ganda. Selain itu, string yang tidak ada dalam values/strings.xml default membuat aplikasi langsung berhenti—bukan fallback yang baik seperti 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

Tangani Bentuk Jamak

Android menggunakan elemen '&lt;plurals&gt;' dengan atribut quantity: zero, one, two, few, many, other. Setiap bahasa target mungkin memerlukan kategori berbeda—bahasa Arab menggunakan keenam kategori, Rusia memerlukan few/many, dan Jepang hanya menggunakan 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
) -->
Atribut quantity memilih bentuk jamak berdasarkan aturan CLDR untuk bahasa perangkat. Selalu sertakan 'other' sebagai fallback—ini satu-satunya kategori yang dijamin ada dalam setiap bahasa.
4

Gunakan dalam Kode: Kotlin dan Jetpack Compose

Android tradisional menggunakan getString(R.string.key) dan resources.getQuantityString(). Jetpack Compose menggunakan stringResource(R.string.key) dan pluralStringResource(). Keduanya memilih terjemahan yang benar berdasarkan bahasa perangkat saat runtime.

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)—parameter count diteruskan dua kali. Yang pertama memilih bentuk jamak dan yang kedua menjadi argumen format. Menghilangkan count kedua adalah bug bentuk jamak Compose yang paling umum.
5

Array String dan String Berformat

Gunakan '&lt;string-array&gt;' untuk daftar berurutan (misalnya opsi dropdown, langkah orientasi). Gunakan argumen format posisi (%1$s, %2$d) dalam string berformat agar penerjemah dapat mengurutkan ulang kata tanpa merusak struktur kalimat.

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>
Argumen posisi seperti %1$s memungkinkan penerjemah mengurutkan ulang parameter dengan bebas. 'Hello %1$s, you have %2$d items' dapat menjadi '%2$d items for %1$s' dalam bahasa dengan urutan kata berbeda—tanpa mengubah kode.
6

Lokalkan Metadata Google Play dengan Fastlane

Gunakan perintah supply Fastlane untuk mengelola metadata Play Store—judul, deskripsi singkat, deskripsi lengkap, dan changelog—sebagai file teks biasa yang disusun menurut bahasa dalam repositori.

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
Melokalkan listing Play Store meningkatkan unduhan lebih dari 30% di pasar non-Inggris. Judul, deskripsi singkat, dan deskripsi lengkap diindeks untuk pencarian—menerjemahkannya adalah lokalisasi dengan ROI tertinggi yang dapat Anda lakukan.
Google Play

Otomatiskan Lokalisasi Listing Play Store

Lewati salin-tempel manual. Terjemahkan judul, deskripsi, dan catatan rilis Play Store ke lebih dari 175 bahasa dengan memperhatikan batas karakter.

Jelajahi Integrasi Google Play
7

Uji Lokalisasi Anda

Uji dengan pengalihan bahasa emulator, preview Compose menggunakan LocaleList khusus, dan pseudolocale di Developer Options. Gunakan resConfigs di Gradle untuk menghapus sumber daya bahasa yang tidak diinginkan dari library pihak ketiga.

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
Uji dengan bahasa Jerman (teks memanjang sekitar 30%) dan Jepang (memendek sekitar 50%) untuk menemukan masalah tata letak. Aktifkan pseudolocale (en-XA untuk aksen, ar-XB untuk RTL) di Developer Options untuk menguji tata letak secara ekstrem tanpa terjemahan asli.

Otomatiskan Kualitas Terjemahan

Temukan kunci hilang, placeholder rusak, dan masalah bentuk jamak sebelum dirilis dengan i18n-validate. Uji UI dengan terjemahan semu menggunakan i18n-pseudo sebelum terjemahan asli tersedia.
8

Otomatiskan Penerjemahan

Terjemahkan strings.xml, bentuk jamak, array string, dan metadata Fastlane Supply dengan AI. Otomatiskan penerjemahan string dalam aplikasi dan metadata Play Store untuk menghadirkan pengalaman yang sepenuhnya dilokalkan.

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 menangani escape XML Android, mempertahankan penanda translatable="false", mematuhi kategori bentuk jamak CLDR untuk setiap bahasa target, dan menjaga argumen format posisi tetap utuh.
JetBrains

Plugin Android Studio Tersedia

Terjemahkan sumber daya XML Android langsung dari IDE dengan plugin i18n Agent untuk IntelliJ / Android Studio.

Install
+

Bonus: Fallback Bahasa Cerdas dengan LocaleChain

Fallback sumber daya Android dikendalikan OS. Saat terjemahan pt-BR tidak ada, Android melewati pt-PT sepenuhnya dan menampilkan bahasa Inggris. LocaleChain mencegat pencarian string dan menelusuri rantai fallback yang dapat dikonfigurasi—sehingga pengguna regional melihat terjemahan terdekat yang tersedia.

LocaleChain untuk Android adalah library Kotlin sumber terbuka. Lihat di GitHub

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

Kesalahan Umum

String Default yang Hilang Membuat Aplikasi Berhenti

Tidak seperti iOS yang menampilkan kunci mentah, Android berhenti dengan ResourceNotFoundException jika string tidak ada dalam res/values/strings.xml default. Selalu pastikan setiap kunci ada dalam file default.

Pemisahan Bahasa App Bundle Merusak Pengalihan dalam Aplikasi

Google Play App Bundle memisahkan APK menurut bahasa—pengguna hanya menerima string bahasa perangkat mereka. Jika Anda menawarkan pengalihan bahasa dalam aplikasi, tambahkan bundle '{ language { enableSplit = false } }' ke build.gradle.kts.

Tata Letak RTL Rusak

Menggunakan left/right alih-alih start/end dalam tata letak atau tidak menyertakan android:supportsRtl="true" di AndroidManifest.xml. Gunakan Refactor > Add RTL Support di Android Studio untuk mengonversi tata letak yang ada secara otomatis.

Kontaminasi Sumber Daya Library

Library pihak ketiga menyertakan file values-XX/strings.xml sendiri sehingga Android mengira aplikasi mendukung bahasa yang sebenarnya tidak didukung. Gunakan resConfigs di build.gradle.kts untuk membatasi bahasa yang disertakan hanya pada bahasa yang benar-benar Anda terjemahkan.

Struktur File yang Disarankan

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

Coba i18n Agent Sekarang

Lepaskan file terjemahan Anda di sini

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

atau klik untuk menjelajahi

Bahasa target

Tidak perlu mendaftarEstimasi instan

Fallback Bahasa dengan locale-chain-android

Saat kunci terjemahan tidak ada dalam bahasa regional seperti pt-BR, Android langsung beralih ke folder sumber daya default alih-alih memeriksa bahasa induk pt terlebih dahulu.

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

Lihat Panduan Fallback Bahasa kami untuk daftar lengkap framework yang didukung dan 75 rantai bawaan. Learn more →

FAQ Lokalisasi Android