StringLane

Browse docsWhat Is an ARB File? Flutter's Localization Format
Concept

What Is an ARB File? Flutter's Localization Format

ARB is the JSON-based translation format Flutter uses for app localization. How the format works (keys, placeholders and @ metadata) and how to edit it.

Last updated

ARB stands for Application Resource Bundle. It is a JSON-based file format for storing localized strings, and it is the format Flutter's flutter_localizations and gen-l10n toolchain reads when you translate an app. One ARB file holds all the strings for a single locale: app_en.arb for English, app_es.arb for Spanish, and so on.

What an ARB file looks like#

An ARB file is plain JSON. Each translation is a key/value pair, and Flutter generates a typed Dart getter for every key:

{
  "@@locale": "en",
  "helloWorld": "Hello, World!",
  "greeting": "Hello, {name}!",
  "@greeting": {
    "description": "Greeting shown on the home screen",
    "placeholders": {
      "name": { "type": "String" }
    }
  }
}

Three things are happening here:

  • @@locale: a reserved key that declares which language this file holds.
  • Translation keys: helloWorld and greeting are the strings your app renders.
  • @ metadata: @greeting is an annotation object describing the greeting key. It carries a description (context for translators and AI) and placeholders (the typed variables in the string).

Placeholders and ICU#

ARB values can contain placeholders like {name} and full ICU MessageFormat plurals and select forms:

"itemCount": "{count, plural, one {# item} other {# items}}"

The placeholders block in the @ annotation tells Flutter the type of each variable so it generates a correctly-typed Dart method. If a placeholder appears in your English source but goes missing in a translation, the generated code breaks at runtime, which is exactly the kind of error a side-by-side editor catches before it ships.

Why ARB is awkward to edit by hand#

The format is simple, but managing it across many locales is not. Each language is a separate file, so confirming that every locale has every key means opening five, ten, or twenty JSON files and reading them in parallel. A missing key, a stray comma, or a placeholder typo is easy to introduce and hard to spot.

How StringLane works with ARB#

StringLane is a desktop editor built for exactly this. It opens your lib/l10n/ folder, loads every app_*.arb file, and shows all locales side-by-side for each key, so gaps and mismatches are visible at a glance instead of buried in JSON. It reads and preserves your @ metadata, validates ICU and placeholders in real time, and writes changes straight back to the source files. Nothing is imported or exported.

Next steps#

Frequently asked questions

Can I edit an ARB file by hand?
Yes — it is plain JSON, so any text editor works. The friction is that one locale per file means comparing translations requires opening every file side by side, and a trailing comma or an unescaped brace breaks the build with an error that points at JSON, not at the string you got wrong.
What is the difference between ARB and JSON?
ARB is JSON with conventions layered on top. Keys starting with @@ are file-level attributes such as @@locale; a key starting with a single @ is metadata describing the translation key of the same name. Any ARB file is valid JSON, but not every JSON file is valid ARB.
Do I need @ metadata for every key?
No. Metadata is optional and StringLane works without it. It earns its place on keys with placeholders — declaring a placeholder's type is what lets gen-l10n generate a correctly typed Dart parameter instead of a String — and on keys where a description meaningfully improves translation quality.
What file name does Flutter expect?
By default gen-l10n looks for app_<locale>.arb in lib/l10n — app_en.arb, app_pt_BR.arb. Both the directory and the prefix are configurable in l10n.yaml via arb-dir and template-arb-file.