Localization & RTL (Java)

Localization means translating an app's visible text so people in different regions see it in their own language. Android builds this in using the same resource-qualifier system already seen for night mode in the previous lesson — just applied to language instead of theme.

1. strings.xml Per Language

The default res/values/strings.xml holds your base-language text (typically English). A parallel folder named with a language code — res/values-hi/strings.xml for Hindi, res/values-es/ for Spanish, and so on — holds the same string names translated into that language. Android automatically loads whichever file matches the device's active language setting.

<!-- res/values/strings.xml (default / English) -->
<resources>
    <string name="add_recipe_button">Add Recipe</string>
</resources>
<!-- res/values-hi/strings.xml (Hindi) -->
<resources>
    <string name="add_recipe_button">नई रेसिपी जोड़ें</string>
</resources>
// Referencing it in RecipeBox — same code, any language
Button btnAddRecipe = findViewById(R.id.btnAddRecipe);
btnAddRecipe.setText(R.string.add_recipe_button);
Explanation:
  • R.string.add_recipe_button is the same identifier in Java regardless of language — only the resolved text changes.
  • If a device's language has no matching values-XX folder, Android silently falls back to the default values/strings.xml.
  • This mirrors the exact qualifier pattern used for values-night in the previous lesson — Android's resource system reuses the same idea for language, theme, screen size, and more.

2. Formatted Strings with Placeholders

When a message needs to embed a dynamic value — like a count — resist the urge to build it with Java string concatenation. Word order and grammar vary by language, so a string built by gluing pieces together in Java (e.g. count + " recipes found") can produce grammatically broken sentences once translated, because some languages need the number in a different position, or need different word forms depending on the count. Defining the entire sentence as one translatable string, with a placeholder, solves this correctly.

<!-- res/values/strings.xml -->
<resources>
    <string name="recipe_count">%1$d recipes found</string>
</resources>
// RecipeBox's search-results screen
int count = recipeList.size();
String message = getString(R.string.recipe_count, count);
tvResultsSummary.setText(message);
Explanation:
  • %1$d marks where the first integer argument is inserted; getString(int, Object...) fills it in.
  • A translator working on values-hi/strings.xml can freely reposition %1$d anywhere in the Hindi sentence — the placeholder mechanism doesn't force English word order onto other languages.
  • Hardcoding count + " recipes found" in Java bakes English grammar into the app and cannot be fixed by a translator at all, since there's no string resource to translate.

3. Right-to-Left (RTL) Language Support

Languages like Arabic and Hebrew read right-to-left, which means an entire layout should mirror: content that starts on the left in English should start on the right in Arabic. Android handles this automatically — but only if layouts are written using direction-aware attributes instead of literal left/right ones.

<!-- Avoid: hardcodes a physical side, never mirrors -->
<TextView
    android:paddingLeft="16dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

<!-- Prefer: describes a logical side, mirrors automatically in RTL -->
<TextView
    android:paddingStart="16dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

start means "the side text begins from" — the left in English, the right in Arabic — while end is the opposite. Using paddingStart/paddingEnd (and similarly layout_marginStart/layout_marginEnd) instead of paddingLeft/paddingRight lets Android flip RecipeBox's recipe cards, icons, and text alignment automatically the moment the device's language is RTL — no separate layout file needed.

The manifest must also opt in to RTL layout mirroring:

<!-- AndroidManifest.xml -->
<application
    android:supportsRtl="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name">
    ...
</application>
Note: without android:supportsRtl="true", Android will not mirror the layout at all, even if every attribute is written with start/end.

4. Previewing Languages and RTL Without Switching Devices

Android Studio's Layout Editor includes a "Preview" panel that can render the same layout in multiple configured locales side by side, and a dedicated "Right-to-Left" preview mode that simulates RTL mirroring — all without changing the emulator or device's actual system language. This is the fastest way to catch a mistranslated string or a layout that didn't mirror correctly, long before testing on a real device set to Arabic or Hebrew.

Localization Flow

Device language = English → res/values/strings.xml (default) Device language = Hindi → res/values-hi/strings.xml Device language = Arabic → res/values-ar/strings.xml + RTL layout mirroring (requires android:supportsRtl="true")

Troubleshooting

Translated text not showing up? → Confirm the string name in values-XX/strings.xml matches exactly — a typo silently falls back to the default language.

Layout not mirroring in RTL? → Check for leftover paddingLeft/paddingRight or layout_alignParentLeft-style attributes; these never mirror, only start/end variants do.

Placeholder shows the wrong grammar? → Let a native speaker review the translated string; the placeholder mechanism handles word order, but grammar (like pluralization) may still need language-specific string variants.

Localization makes an app understandable to more people; the next lesson, Accessibility, covers making it usable by more people, regardless of ability.