Android XML
Android strings.xml, from strings to plurals
strings.xml is mandatory for native Android: the
resource system picks values-de, values-fr and friends by
device locale on billions of devices. The format carries more than key and value:
<plurals> blocks, translator comments, positional format
arguments, and escaping rules that XML and the Android build both enforce.
This page covers the syntax and its traps: apostrophes, quantity classes, and the resources that should never reach a translator.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Title of the checkout screen -->
<string name="checkout_title">Bestellübersicht</string>
<string name="menu_home">Startseite</string>
<plurals name="cart_items">
<item quantity="one">%d Artikel</item>
<item quantity="other">%d Artikel</item>
</plurals>
</resources> Cheatsheet
strings.xml syntax in six rows
l\'article Apostrophes must be escaped or the Android build fails; the classic broken string is a French translation typed by hand. %1$s, %d Positional format arguments. With more than one argument, positions are required so translators can reorder them. <plurals> with quantity Native plural syntax. Quantities map to CLDR categories, and which categories a locale needs comes from CLDR, not guesswork. translatable="false" Marks a resource that should never reach translators. Importers are expected to skip it. <string-array> Not imported: an indexed array has no stable key per item. Strings that need translation belong in individual <string> entries. <!-- comment --> The comment above a string imports as its note and is written back above it on export. Untranslated keys, three spellings
Dropping the key is usually right on Android, because the resource system falls back to the default locale at runtime.
<string name="checkout_confirm"></string> <!-- key not exported --> <string name="checkout_confirm">Confirm purchase</string> Conventions
Where strings.xml lives
res/values/strings.xml res/values-de/strings.xml res/values-fr-rCA/strings.xml stringResource(R.string.checkout_title)
Typical flow: the repo keeps one file per locale under res/values-*,
GitHub or GitLab
imports new keys when developers push, and translated files return as a pull
request formatted exactly like the source.
Positional arguments across languages
With two or more format arguments, positions let each language reorder them.
<string name="added_by">%1$s added by %2$s</string> <string name="added_by">%2$s hat %1$s hinzugefügt</string> German swaps the arguments; the positions keep them attached to the right values.
Plurals
Plurals in strings.xml
Android has real plural syntax, and locamorph reads it as such: each
quantity becomes a CLDR form a translator fills in separately.
<plurals name="cart_items">
<item quantity="one">%d article</item>
<item quantity="other">%d articles</item>
</plurals> <plurals name="cart_items">
<item quantity="one">%d item</item>
<item quantity="other">%d items</item>
</plurals> <plurals name="cart_items">
<item quantity="one">%d artykuł</item>
<item quantity="few">%d artykuły</item>
<item quantity="many">%d artykułów</item>
<item quantity="other">%d artykułu</item>
</plurals> <plurals name="cart_items">
<item quantity="zero">لا عناصر</item>
<item quantity="one">عنصر واحد</item>
<item quantity="two">عنصران</item>
<item quantity="few">%d عناصر</item>
<item quantity="many">%d عنصرًا</item>
<item quantity="other">%d عنصر</item>
</plurals> Which quantities a locale needs comes from CLDR: Polish uses four, Arabic all six, Japanese only other. Android ignores quantities a locale never uses.
See the same plural in every format locamorph exports; the Android block converts losslessly to ICU and back.
In locamorph
How locamorph handles strings.xml
Quantities become CLDR forms
quantity="one" through "other" map onto the same
plural model every other format uses, so a plural authored for Android exports
cleanly to JSON or ARB.
Comments ride along
The comment above a string imports as its note and is written back above the string on export. Context written for translators stays in the file.
Escaping handled, not hoped for
Apostrophes, backslashes and characters XML cannot represent are escaped the way Android expects. No more build breaks from a French apostrophe.
Convert
Convert strings.xml to and from other formats
Conversion is import plus export, with plurals mapped through CLDR forms instead of copied as text.
strings.xml to JSON
Android strings shared with a React Native or web build.
- Import
strings.xml; comments become notes. pluralsblocks become CLDR forms.- Export as JSON with ICU plurals.
strings.xml to ARB
An Android app migrating to Flutter.
- Import each
values-*file into its locale. - Notes become ARB descriptions; plurals become ICU.
- Export
app_*.arbready forgen-l10n.
JSON to strings.xml
Web translations reused in the native app.
- Import the JSON locales.
- Dotted keys flatten to resource names.
- Export strings.xml with Android escaping applied.
Related
Keep going
iOS Strings
The other half of a mobile release, with UTF-16 files handled correctly.
ARB
Shipping with Flutter instead? The plural model converts either way.
GitHub integration
values folders synced automatically, translations back as pull requests.
Further reading
- Android string resources, the official reference
- Quantity strings, Android’s plural documentation
- CLDR plural rules, which categories each locale needs
Bring your values folder
Import a strings.xml on the free plan and watch plurals, comments and escaping arrive intact. Exports drop straight into res/values.