Formats
strings.xml
Android resource files, one per values folder. Escaping, placeholders and plurals round-trip without hand edits.
What you get
Everything the editor does, through the files you already ship.
Every plural form a language has
Each locale gets exactly the CLDR categories it uses, Arabic six and Japanese one, written in the format's own plural shape.
Placeholders round-trip
%@,%1$sand{count}come back as they went in, and a translation that drops or alters one is flagged before it is verified.AI drafts, a person verifies
Every language is drafted against your glossary and each key's length limit. A draft never ships until someone has verified it.
Runs in CI
Push the source language on merge and pull every language before the release build, on any CI that can run a shell.
CI pipelines
Set it up
From nothing to every language.
Step 1: Reference resources the way the module already does
Nothing changes in code. Key names are written to the file as they are, so name them the way Android wants them:
cart_items, notcart.items. Singulars are read withgetString, plurals withgetQuantityString.CartFragment.kttitleView.text = getString(R.string.paywall_subscribe_cta) countView.text = resources.getQuantityString( R.plurals.cart_items, cart.size, cart.size )Step 2: Install the CLI and log in
Homebrew or the one-line installer, then a token issued per project under Settings, Integrations. The read scope pulls; push writes source files and values; manage creates and deletes keys.
shellbrew install anylocale/tap/anylocale anylocale login --project my-appStep 3: Push the source file
The push is additive: keys missing from the file stay in place, so a truncated file cannot empty a project. Descriptions in the file become translator notes.
shellcurl -fsS -X POST "https://anylocale.com/api/loc/push?project=my-app&format=android-xml" \ -H "Authorization: Bearer $ANYLOCALE_TOKEN" \ --data-binary @app/src/main/res/values/strings.xmlStep 4: Pull each locale into its values folder
One file per locale. Placeholders come back positional, plurals as a
<plurals>block, and a key's description as the comment above it.shellanylocale pull --project my-app --locale de --format android-xml \ --out app/src/main/res/values-de/strings.xmlapp/src/main/res/values-de/strings.xml<?xml version="1.0" encoding="utf-8"?> <resources> <!-- Items in the cart --> <plurals name="cart_items"> <item quantity="one">1 Artikel</item> <item quantity="other">%1$d Artikel</item> </plurals> <!-- Explains why the app needs the location --> <string name="onboarding_location_permission">Standort & Wetter für %1$s erlauben</string> <string name="paywall_subscribe_cta">Jetzt abonnieren</string> </resources>Step 5: Script it over the project's locales
The same command per locale, from a Gradle exec task or the CI job that runs before the build.
shellfor locale in de fr ja; do anylocale pull --project my-app --locale $locale --format android-xml \ --out app/src/main/res/values-$locale/strings.xml done
Good to know
- Key names are written verbatim, so an Android project names its keys with underscores; a dot in a resource name fails the build.
- A string-array is ignored on push and missing from a pulled file. Keep arrays in a resource file the pull does not overwrite.
- formatted="false" does not survive a pull, so use positional placeholders (%1$s, %2$d) in any string that has more than one.
- A string marked translatable="false" in the source file stays that way and is never put in front of a translator.
- Every pull carries the current text of every key, verified or not. Only over-the-air delivery is limited to verified strings.
Questions
- Are string arrays and escaping handled?
- Escaping yes: apostrophes, quotes and the other characters Android needs escaped are written the way the resource compiler expects. String arrays no: a string-array is ignored on push and absent from a pulled file, so keep arrays in a resource file anylocale does not overwrite.
- Which folder does each locale go to?
- The source locale to values/, every other one to its own values-<locale>/ folder. Pull one locale per folder, or script it over the project's locale list.
- Do %d and %1$s survive the round trip?
- Yes. Placeholders are kept as written, positional forms included, and a translation that drops or alters one is flagged before it is verified.
Start with the file your app already ships.
After checkout, import one strings file and read the first drafts within minutes.
Nothing to connect and nothing to install. The CLI is optional.