To add a language to a Flutter app, you translate one file: your template ARB. Everything else, the Dart classes included, is generated from it.
This guide is for that one file, app_en.arb, and for the three things that go wrong in it: the @ metadata, the placeholders and the plurals. For the other app formats, see how to translate your app’s language files.
What an ARB file is
An ARB file is JSON with a convention on top of it. Flutter’s localization tool reads ARB files from lib/l10n by default, uses app_en.arb as the template, and generates the Dart classes when you run flutter gen-l10n. One file holds one language.
Entries come in pairs: a key with its text, and an @ entry that describes it. Only the text is for translating.
Which option should you use?
| Good for | Where it stops | |
|---|---|---|
| AI Glot | A new locale or five, a glossary that must hold, every release | Not needed for ten strings |
| A translation management platform (Crowdin, Lokalise, Phrase, Localizely) | A team with reviewers and a repository connection | You set up a project and connect your repository first |
| DeepL | XLIFF files, which are on its list | ARB is not on that list, so you convert first |
| ChatGPT, Claude or another assistant | A handful of strings | You write the prompt and carry your glossary into every chat. Each run risks a changed key, a broken {placeholder} or a mangled ICU plural, so you diff every file |
| A freelancer or an agency | Your App Store and Play Store text | Slow, priced per word, and you still prepare the file |
Pay a person for the store listing and the first screen. Run the long tail of labels and messages through an engine.
Why AI Glot fits an ARB file
- Keys and
@metadata are structure. They can be left exactly as they are. - Placeholders and ICU syntax are kept.
{name}and{count, plural, ...}stay in the message while the words inside each branch are translated. - Several languages in one job, instead of the same strings five times.
- One glossary across every locale, and the files you add later.
- A plan before any spend, with a sample you can check.
The path of one file
- 1Uploadapp_en.arb as it isUp to 8 MB
- 2Say what you needLanguages and what to leaveFree
- 3Read the planStrings, languages, costFree
- 4ApproveThe only step that spendsSpends credits
- 5DownloadOne ARB file per languageDrop it in
What a translated entry looks like
{ "@@locale": "en", "@@locale": "fr", "welcome": "Welcome back, {name}", "welcome": "Bon retour, {name}", "@welcome": { "description": "Greeting on the home screen" }, "cartItems": "{count, plural, one{1 item} other{{count} items}}" "cartItems": "{count, plural, one{1 article} other{{count} articles}}"}What to check after
Plurals in languages with more forms. English needs two branches. Russian and Arabic need more, and the translated message may need branches the English source does not have. Read those messages once.
@@locale. If you did not ask for it to be updated, it comes back as it was, so set it to the target locale before you ship.
Length. Look at the screens with the longest strings for text that overflows a button or a card.
How to do it, step by step
1. Try a file for free. The ARB translator needs no account and takes files up to 2 MB and 5,000 words.
2. Upload app_en.arb in the app, or send it from the command line, below.
3. Say what you need in one sentence.
Translate this file into French, German and Spanish.
Leave the @ metadata entries alone. Set @@locale to the target language.
The sentence decides what is translated across the whole file. A rule about wording, such as “keep every {placeholder} and ICU plural syntax exactly as written” or “use the informal register”, goes into the second box at approval, because it is applied to each message as it is written.
4. Add a glossary for the app name, feature names and the words your app always says one way. How to build one.
5. Read the plan and choose a quality level.
Lite gives about three times more words per credit and is faster: right for a first pass on a new locale. Standard is for the strings a user reads first. One credit is one word in Standard.
6. Approve and download.
7. Put the files in lib/l10n next to app_en.arb, then run:
flutter gen-l10n
One file, several locales
The file names and counts are an example. An ARB file holds one language, so each locale is its own file.
Three ways to run it
From the command line is the one Flutter developers keep, because it runs again at every release:
id=$(aiglot batches create lib/l10n/app_en.arb \
--instruction "Translate into French. Leave the @ metadata entries alone. Set @@locale to the target language." \
--json | jq -r '.data.id')
aiglot batches get "$id" --json | jq '.data.plan'
aiglot batches approve "$id" --quality lite \
--instructions "Keep every {placeholder} and ICU plural syntax exactly as written."
aiglot batches download "$id" --output lib/l10n/app_fr.arb
With your AI agent: connect AI Glot as an MCP server. The agent can read your project, propose glossary terms, run the job, save the files in lib/l10n and run flutter gen-l10n for you.
In the app: upload, click, download. Good for a one-off.
For an API integration, see the API documentation.
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: 8 MB per ARB file, and 2 MB and 5,000 words in the free tool. The Flutter defaults come from Flutter’s own documentation and can change. DeepL’s list comes from its own documentation. File names and string counts in the diagrams are examples. Your plan shows the real figures for your own file, and it is free to read.
