Skip to content
All posts
May 30, 20264 min read

Localizing Your Android App: A Practical Guide to Reaching More Users

Localization is one of the highest-ROI features for solo developers. Adding support for 5-10 languages can double your potential market. Here's how to implement localization correctly in an Android app with Compose.

AndroidPlay StoreKotlin
Share:

My apps see 2-3x more installs from non-English markets after adding localization. For a solo developer, it's one of the most efficient growth levers — you're not building new features, you're opening existing ones to a larger audience.

Here's how to do it right.


The Foundation: strings.xml

All user-facing text belongs in

code
res/values/strings.xml
. Never hardcode strings in code:

xml
<!-- res/values/strings.xml — English (default) -->
<resources>
    <string name="app_name">TaskFlow</string>
    <string name="add_task">Add Task</string>
    <string name="task_completed">Task completed</string>
    <string name="delete_task_confirmation">Delete this task? This cannot be undone.</string>
    
    <!-- Plurals -->
    <plurals name="task_count">
        <item quantity="one">%d task</item>
        <item quantity="other">%d tasks</item>
    </plurals>
</resources>

<!-- res/values-es/strings.xml — Spanish -->
<resources>
    <string name="app_name">TaskFlow</string>
    <string name="add_task">Agregar tarea</string>
    <string name="task_completed">Tarea completada</string>
    <string name="delete_task_confirmation">¿Eliminar esta tarea? Esto no se puede deshacer.</string>
</resources>

Using Strings in Compose

kotlin
// String resource
Text(text = stringResource(R.string.add_task))

// String with format argument
Text(text = stringResource(R.string.welcome_user, userName))

// Plural
Text(
    text = pluralStringResource(R.plurals.task_count, taskCount, taskCount)
)

// Annotation strings (rich text)
val annotatedString = buildAnnotatedString {
    append(stringResource(R.string.terms_prefix))
    withStyle(SpanStyle(color = MaterialTheme.colorScheme.primary)) {
        append(stringResource(R.string.terms_link_text))
    }
}

Which Languages to Prioritize

For global distribution, prioritize by potential market × effort:

LanguageMarket PotentialCode
SpanishVery Highes
Portuguese (Brazilian)Highpt-rBR
GermanHighde
FrenchHighfr
JapaneseHighja
KoreanMedium-Highko
HindiHigh (growing)hi
ArabicHigh (RTL challenge)ar

English + these 7-8 languages covers 70%+ of Android users worldwide.


RTL Language Support

Arabic and Hebrew are right-to-left. Android handles most layout mirroring automatically, but you need to use the right attributes:

kotlin
// Use start/end instead of left/right
modifier = Modifier.padding(start = 16.dp, end = 8.dp) // Not padding(left, right)

// Row with gravity — use Arrangement.Start not Arrangement.Left
Row(horizontalArrangement = Arrangement.Start) { ... }
xml
<!-- In Manifest -->
<application android:supportsRtl="true">

Test RTL with: Settings → Developer Options → Force RTL layout direction.


Using Machine Translation as a Starting Point

Google Translate can produce a rough initial translation. For professional apps, have a native speaker review the output — machine translation often produces technically correct but unnatural text.

For validation without hiring translators, post in Reddit communities for each language (r/es, r/de, r/france) asking for translation feedback. Many users are happy to help if you ask nicely.

Android Studio has a built-in translation editor:

Open any

code
strings.xml
→ Open Editor (top right of file view) → View all languages side by side and fill in translations.


Locale-Specific Resources

Different locales need different resources beyond strings:

Date and time formats:

code
DateTimeFormatter.ofLocalizedDate()
uses the device locale automatically.

Number formats:

code
NumberFormat.getInstance()
for locale-appropriate number formatting.

Currency:

code
NumberFormat.getCurrencyInstance()
— but for IAP, always use Play's
code
formattedPrice
.

Images: Some regions have different cultural norms for imagery. Put locale-specific images in

code
res/drawable-es/
,
code
res/drawable-ja/
, etc.


Detecting the Device Locale

kotlin
// Current locale
val locale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    context.resources.configuration.locales[0]
} else {
    @Suppress("DEPRECATION")
    context.resources.configuration.locale
}

val languageCode = locale.language // "en", "es", "ja"
val countryCode = locale.country   // "US", "MX", "JP"

For most apps, you don't need to detect the locale — Android applies the right strings.xml automatically based on the device language setting.


In-App Language Switcher (Android 13+)

Android 13 introduced per-app language preferences. Users can set a different language for your app than their system language:

kotlin
// Check the current app language
val currentLocale = AppCompatDelegate.getApplicationLocales().get(0)

// Change the app language
AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags("es"))

Implement an in-app language picker in Settings if you want to support this explicitly. Otherwise, Android 13+ users can change the app language from system Settings → Apps → Your App → Language.


Play Store Listing Localization

Don't forget to localize the Play Store listing itself:

  1. Play Console → Store Presence → Store Listing
  2. Select a language → Translate title, short description, long description
  3. Add locale-specific screenshots if possible

A Spanish user finding your app via a Spanish search sees Spanish listing text — and converts much better than seeing English.


Testing Localization

bash
# Change device locale via ADB
adb shell settings put system language es
adb shell settings put system user_locales es-ES

# Restart the launcher for changes to take effect
adb shell am broadcast -a android.intent.action.LOCALE_CHANGED

Or change in Settings → System → Language.

Walk through your app's main flows in each supported language. Look for:

  • Text that doesn't fit in buttons (German is notably long)
  • Untranslated strings (defaulting to English)
  • RTL layout issues (Arabic, Hebrew)

Takeaways

  • All strings in
    code
    strings.xml
    from day one — retrofitting is expensive
  • English + Spanish, Portuguese, German, French, Japanese covers 70%+ of Android users
  • Enable
    code
    supportsRtl="true"
    and use
    code
    start/end
    instead of
    code
    left/right
  • Machine translate as a starting point, native speaker review for shipped apps
  • Localize your Play Store listing — it directly affects search ranking in those markets
Share:
S

Sudarshan Chaudhari

AI Systems Builder / Product Engineer

Bangkok, Thailand

Solo Android developer with 13+ years in QA, building Android apps, AI automation systems, and developer tools at SudarshanTechLabs.

Stay updated

Get new posts on Android, Kotlin, and solo dev straight to your inbox.

Newsletter preferences

Related Apps

MyFamilyTracker

Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.

Building something? Available for Android dev and QA consulting.

Work with me

Comments — powered by Giscus

Apps tagged with this