Skip to main content

Ang Kumpletong Gabay sa Android App Localization

Mula strings.xml hanggang Play Store metadata: i-localize ang Android app ninyo gamit ang Kotlin, Jetpack Compose, Fastlane, at automated AI translation.

1

I-set Up ang Android Project Ninyo para sa Localization

Gumagamit ang Android ng folder-based na convention para sa localization. Nasa res/values/strings.xml ang mga default string ninyo, at napupunta ang mga isinaling string sa mga locale-specific na folder tulad ng res/values-de/, res/values-ja/, atbp.

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
Ang res/values/ folder ang fallback locale ninyo. Kung nawawala ang isang string sa locale-specific na folder, ilo-load ito ng Android mula sa default. Ngunit kung nawawala ang isang string sa default, magka-crash ang app ninyo sa mga hindi suportadong locale.
2

Gumawa ng strings.xml

Gumagamit ang Android string resources ng XML na may mga <string> element sa loob ng <resources> root. Gamitin ang %s para sa mga string placeholder, %d para sa mga integer, at %1$s/%2$s para sa mga positional argument na puwedeng i-reorder ng mga tagasalin.

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>
Maaaring magpa-crash nang tahimik sa XML parser ang mga apostrophe na hindi na-escape. Gamitin ang \' o i-wrap ang value sa double quotes. Tandaan din: ang nawawalang string sa default values/strings.xml ay nagdudulot ng hard crash—hindi tulad ng graceful fallback sa 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

Hawakan ang Plurals

Gumagamit ang Android ng <plurals> element na may quantity attribute: zero, one, two, few, many, other. Maaaring magkaiba ang kailangang kategorya ng bawat target na wika—ginagamit ng Arabic ang lahat ng 6, kailangan ng Russian ang few/many, at other lang ang ginagamit ng Japanese.

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
) -->
Pinipili ng quantity attribute ang plural form batay sa CLDR rules para sa device locale. Laging isama ang 'other' bilang fallback—ito lang ang kategoryang garantisadong mayroon sa bawat wika.
4

Gamitin sa Code: Kotlin at Jetpack Compose

Gumagamit ang tradisyonal na Android ng getString(R.string.key) at resources.getQuantityString(). Gumagamit ang Jetpack Compose ng stringResource(R.string.key) at pluralStringResource(). Pareho nitong nireresolba ang tamang pagsasalin batay sa device locale sa 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) — ipinapasa ang count parameter nang dalawang beses. Ang una ang pumipili ng plural form, ang pangalawa ang format argument. Ang nawawalang pangalawang count ang #1 bug sa Compose pluralization.
5

String Arrays at Formatted Strings

Gumamit ng <string-array> para sa mga ordered list (hal., mga opsyon sa dropdown, mga onboarding step). Gumamit ng mga positional format arg (%1$s, %2$d) sa mga formatted string para ma-reorder ng mga tagasalin ang mga salita nang hindi nasisira ang istruktura ng pangungusap.

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>
Pinapahintulutan ng mga positional arg tulad ng %1$s ang mga tagasalin na malayang i-reorder ang mga parameter. Ang 'Hello %1$s, you have %2$d items' ay maaaring maging '%2$d items for %1$s' sa mga wikang may ibang word order—nang walang anumang pagbabago sa code.
6

I-localize ang Google Play Metadata gamit ang Fastlane

Gamitin ang supply command ng Fastlane para i-manage ang Play Store metadata—title, short description, full description, at changelog—bilang mga plain text file na nakaayos ayon sa locale sa repository ninyo.

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
Napapataas ng pag-localize ng Play Store listing ang downloads nang 30%+ sa mga non-English market. Ini-index para sa search ang title, short description, at full description—ang pagsasalin ng mga ito ang pinakamataas ang ROI na localization na maaari ninyong gawin.
Google Play

I-automate ang Localization ng Play Store Listing Ninyo

Laktawan ang manu-manong copy-paste. Isalin ang Play Store title, description, at release notes sa 175+ locale na may awareness sa character limit.

Tuklasin ang Integrasyon sa Google Play
7

I-test ang Inyong Localization

Mag-test gamit ang emulator locale switching, Compose preview na may custom LocaleList, at mga pseudolocale sa Developer Options. Gamitin ang resConfigs sa Gradle para alisin ang hindi gustong locale resource mula sa mga third-party library.

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
Mag-test gamit ang German (lumalawak ang teksto nang ~30%) at Japanese (lumiliit nang ~50%) para mahuli ang mga isyu sa layout. I-enable ang mga pseudolocale (en-XA para sa accented, ar-XB para sa RTL) sa Developer Options para i-stress-test ang mga layout nang hindi gumagamit ng totoong pagsasalin.

I-automate ang Kalidad ng Pagsasalin

Mahuli ang mga nawawalang key, sirang placeholder, at isyu sa plural bago ito ma-ship gamit ang i18n-validate. I-test ang UI ninyo gamit ang mga pseudo-translation sa pamamagitan ng i18n-pseudo bago dumating ang mga totoong pagsasalin.
8

I-automate ang mga Pagsasalin

Isalin ang strings.xml, plurals, string array, at Fastlane Supply metadata ninyo gamit ang AI. I-automate ang pagsasalin ng parehong in-app string at Play Store metadata para sa ganap na na-localize na presensya.

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
Hinahawakan ng i18n Agent ang Android XML escaping, pinapanatili ang translatable="false" markers, sinusunod ang CLDR plural categories ayon sa bawat target na wika, at pinananatiling buo ang mga positional format argument.
JetBrains

Available ang Android Studio Plugin

Isalin ang Android XML resource nang direkta mula sa inyong IDE gamit ang i18n Agent plugin para sa IntelliJ / Android Studio.

Install
+

Bonus: Smart Locale Fallback gamit ang LocaleChain

OS-controlled ang Android resource fallback. Kapag nawawala ang mga pagsasalin sa pt-BR, nilalaktawan ng Android ang pt-PT at ipinapakita ang English. Hinahadlangan ng LocaleChain ang mga string lookup at sinusundan ang isang configurable fallback chain—kaya nakikita ng mga regional user ang pinakamalapit na magagamit na pagsasalin.

Ang LocaleChain para sa Android ay isang open-source Kotlin library. View on 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"))
)

Mga Karaniwang Pitfall

Nagdudulot ng Pagka-crash ang Nawawalang Default String

Hindi tulad ng iOS na nagpapakita ng raw key, nagka-crash ang Android at naglalabas ng ResourceNotFoundException kapag nawawala ang isang string sa default res/values/strings.xml. Tiyaking umiiral ang bawat key sa default file.

Nasasira ng App Bundle Language Split ang In-App Switching

Hinahati ng Google Play App Bundles ang mga APK ayon sa wika—tanging resources ng device language ng user ang natatanggap. Kung nag-aalok kayo ng in-app language switching, idagdag ang bundle '{ language { enableSplit = false } }' sa inyong build.gradle.kts.

Nasirang RTL Layout

Dulot ito ng paggamit ng left/right sa halip na start/end sa mga layout, o ng nawawalang android:supportsRtl="true" sa AndroidManifest.xml. Gamitin ang Refactor > Add RTL Support ng Android Studio para awtomatikong ma-convert ang mga umiiral na layout.

Kontaminasyon ng Resource ng Library

Nagba-bundle ang mga third-party library ng sarili nilang values-XX/strings.xml file, kaya iniisip ng Android na sinusuportahan ng app ninyo ang mga wikang hindi naman ninyo sinusuportahan. Gamitin ang resConfigs sa build.gradle.kts para i-restrict ang mga kasama na locale sa mga wikang talagang isinasalin ninyo.

Iminungkahing File Structure

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

Subukan ang i18n Agent Ngayon

I-drop dito ang inyong translation file

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

o i-click para mag-browse

Mga target language

Hindi kailangan ang signupInstant na estimate

Locale Fallback gamit ang locale-chain-android

Kapag nawawala ang translation key sa isang regional locale tulad ng pt-BR, diretsong tumatalon ang Android sa default resource folder sa halip na i-check muna ang parent locale na 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"),
    )
)

Tingnan ang aming Locale Fallback Guide para sa buong listahan ng mga sinusuportahang framework at 75 built-in chain. Learn more →

FAQ sa Android Localization