An app’s language files are one job with thirteen file extensions. You are holding a JSON file, a strings.xml, a PO file or a String Catalog, and you want the same strings in five more languages without breaking the build.
The format changes. The job does not: keep the keys, keep the placeholders, translate the values, and do it again at the next release.
Which option should you use?
| Good for | Where it stops | |
|---|---|---|
| AI Glot | Any of the formats below, several languages in one job, a glossary that must hold, every release | Not needed for ten strings |
| A translation management platform (Crowdin, Lokalise, Phrase) | A team with a continuous workflow, reviewers and a repository connection | You set up a project and connect your repository before the first string moves |
| DeepL | XLIFF files up to 10 MB | It takes XLIFF but not the other formats here, and its glossary swaps terms without understanding why they are fixed |
| ChatGPT, Claude or another assistant | A handful of strings | You write the prompt and carry your glossary into every chat. A long file writes out token by token, slowly, and uses up your usage limit. Each run risks a changed key or a mangled placeholder |
| A freelancer or an agency | The App Store page, your onboarding | Slow, priced per word, and you still prepare the files |
Pay a person for the five strings that sell your app: the store listing and the first screen. Run the thousands of strings behind them through an engine.
Pick your file
Every format has its own page with a free tool and the details. Here is the one thing to know for each.
| File | Where it lives | What to know |
|---|---|---|
| JSON | locales/en.json |
Keys come back in the same order. Placeholders such as {count} are protected by your instructions |
| ARB (Flutter) | lib/l10n/app_en.arb |
The @ metadata entries are copied across. Set @@locale to the target language |
| YAML | config/locales/en.yml |
Rails-style %{name} placeholders are read. Comments are dropped when the file is written back |
| TOML | i18n/en.toml (Hugo) |
Only text values change. Comments survive in the normal case |
| XLIFF | exports from your tools | Versions 1.2 and 2.0. Inline tags are rebuilt from the source |
| PO and POT | locale/fr/LC_MESSAGES/app.po |
Plural entries get the forms of the target language, and the Plural-Forms header is rewritten |
| Qt Linguist | app_fr.ts |
Plural (numerus) messages are not translated yet. Run lrelease afterwards |
| String Catalog | Localizable.xcstrings |
Every language lives in one file. Substitutions and device variations are left alone |
| iOS .strings | fr.lproj/Localizable.strings |
Comes back as UTF-8 with comment blocks kept. .stringsdict plurals are handled too |
| Android XML | res/values-fr/strings.xml |
Plurals and string arrays are handled. translatable="false" is respected |
| RESX and RESW | Resources.fr.resx |
You get one file per language. Developer comments stay in English |
| Java .properties | messages_fr.properties |
UTF-8 only. Put a value that continues on a second line on a single line first |
Not every format is equal in how it holds languages. A String Catalog keeps all languages in one file. Most of the others, including JSON, Android and iOS, hold one language per file, so each target language is its own file.
What a translated file looks like
Only the values change.
{ "cart.title": "Your cart", "cart.title": "Votre panier", "cart.items": "{count} items", "cart.items": "{count} articles", "cart.checkout": "Go to checkout" "cart.checkout": "Passer à la caisse"}The path of one file
- 1UploadThe file as it isOr a ZIP of many
- 2Say what you needLanguages and scopeFree
- 3Read the planStrings, words, costFree
- 4ApproveThe only step that spendsSpends credits
- 5DownloadOne file per languageDrop it in
Nothing is spent before step four, and a plan that is wrong costs nothing to fix.
How to do it, step by step
1. Try a file for free. Each format page has a free tool that needs no account.
2. Upload the file in the app, or send it from the command line, which is covered below.
3. Say what you need in one sentence.
Translate this file into French.
Skip every key that starts with "internal.".
The sentence decides what gets translated, across the whole file. Rules about the wording itself, such as “keep every {placeholder} exactly as written” or “use the informal register”, go into the second box at approval, because they are applied to each string as it is written.
4. Add a glossary for the product name, the feature names and the words your app always says the same way. How to build one.
5. Choose a quality level.
Lite gives about three times more words per credit and is faster: right for the long tail of settings and help text. Standard is for the strings a user reads first. One credit is one word in Standard.
6. Approve and download.
One file, many languages
The file names are an example. For a whole folder of locale files, put them in a ZIP: up to 200 files and 20 MB go through as one job.
Three ways to run it
From the command line is the one developers keep. It is the same four steps, in a script:
# 1. Create the job. Free. Returns a plan and an id.
id=$(aiglot batches create locales/en.json \
--instruction "Translate into French. Skip every key that starts with internal." \
--json | jq -r '.data.id')
# 2. Read the plan for free, then commit.
aiglot batches get "$id" --json | jq '.data.plan'
aiglot batches approve "$id" --quality lite \
--instructions "Keep every {placeholder} exactly as written."
# 3. When the status is completed, bring the file back.
aiglot batches download "$id" --output locales/fr.json
With your AI agent: connect AI Glot as an MCP server. The agent can read your repository, propose the glossary terms it finds, write them into your workspace, run the job and put the files back where they belong.
In the app: upload, click, download. Good for a one-off.
For an API integration, see the API documentation.
Check the result
Build the app in one translated language and open the three screens with the longest strings. Then run your usual lint or a missing-key check, because a changed key shows up as a missing string. Translated text is often longer than the English, so look for buttons and labels that overflow.
Pricing lists what a larger volume costs, and a free account comes with credits to run a real file.
The limits quoted here are the ones in force when this was written: 200 files and 20 MB per ZIP. DeepL’s limit comes from its own documentation. File names and string counts in the diagrams are examples. Your plan shows the real figures for your own files, and it is free to read.
