Localize Your App

How to Translate strings.xml into Multiple Languages (Without Breaking Placeholders)

To translate strings.xml into multiple languages, Android wants one values-xx/strings.xml per locale — values-es, values-de, values-ja, and so on. The format is simple; keeping %1$s placeholders, <plurals> blocks, and XML entities intact across 20 parallel files is what breaks people. Here's the full picture, from the manual options to a one-upload workflow.

What has to survive translation

<string name="greeting">Hello, %1$s! You have %2$d messages.</string>
<plurals name="song_count">
    <item quantity="one">%d song</item>
    <item quantity="other">%d songs</item>
</plurals>
<string name="terms">I accept the &amp; terms &#8230;</string>
  • Positional placeholders. %1$s and %2$d must keep their indices even when the target language reorders the sentence. Getting this wrong throws IllegalFormatException at runtime.
  • Plural quantities. Each language has its own set — Polish uses one/few/many/other, Japanese only other. Copying English's two entries produces wrong output.
  • XML entities and CDATA. &amp;, &#8230;, and embedded HTML must come back exactly — a classic failure mode of generic translators, which quietly replace entities with literal characters.

The usual approaches and where they crack

Android Studio's Translations Editor gives you a grid, but you still type every translation yourself. Google Translate scripts (there's a cottage industry of them on GitHub) handle volume but produce translations bad enough that developers publicly warn against them — no context, no glossary, placeholders regularly mangled. Pasting into ChatGPT translates better but hallucinates: missing strings, invented keys, replaced entities. And every one of these leaves you manually assembling N output files.

One upload, every values folder

  1. Upload your strings.xml. Localize Your App parses strings, string-arrays, and plurals in memory; placeholders and entities are detected and locked before translation.
  2. Choose languages. Pick from 39 locales. Plural blocks are generated with the correct quantity set for each target language, and every translation is validated against the source's placeholders — a missing %1$s is caught before you ever see the file.
  3. Review and download. Skim the side-by-side editor (AI output is good, review makes it safe), then download a zip of ready-to-drop-in values-xx/strings.xml files.

On the next release, upload the updated file — translation memory covers unchanged strings at no cost, so incremental releases cost cents, not another full pass. The math versus agencies and subscription TMS platforms is in the localization cost guide.

Two Android-specific tips

  • Watch text expansion. German and Finnish run 40–60% longer than English. Test your layouts with the longest language you ship, not with English.
  • Mind translatable="false". Mark brand names and technical strings with it so they're excluded everywhere, rather than deleting them from each translated file. Formats beyond XML — .arb, i18n JSON, .strings — are compared in the file formats guide.

Ship your app in 39 languages by tonight

Upload your localization file, review side by side, download ready-to-import files for every language. One-time credits from $9 — no subscription.

No subscription. Credits never expire.

Related guides