FLUTTER ARB · macOS, WINDOWS, LINUX
An ARB editor that shows every locale at once
StringLane opens all of your app_*.arb files together, flags what is missing or broken while you type, and writes back to the same files your flutter gen-l10n already reads.
For macOS, Windows and Linux14-day trial, no email · $49 once

A stray # in a plural, flagged
THE FORMAT
What StringLane opens
Flutter keeps each language in its own app_<locale>.arb file, and only the template needs the @key objects that type each placeholder. That split is what makes the files hard to check by hand: nothing lines a key up across ten files, so a missing string or a dropped {name} sits in a file you never opened. StringLane opens every .arb file in the project and lines the locales up by key, with nothing to configure.
- File layout
- One JSON file per locale, typically
lib/l10n/app_en.arb - Placeholders
{param}, compared between locales by name- Plurals
- ICU MessageFormat inline,
{count, plural, other{...}} - Metadata
@keyobjects:@description,x-max-length,x-guarded- Detected by
- Any
.arbfile in the project folder - Project chip
ARB
WHAT GETS FLAGGED
What gets flagged, and why it matters in ARB
Validation runs when the project loads and again after every edit. These are the checks that apply to ARB specifically. The same checks run from the terminal with stringlane check, and over MCP for a coding agent.
Missing key
The key exists in your template locale but is absent or empty in another. Your build still succeeds and the string ships in English, so this is the failure mode that reaches users. The reverse, a key only a translation holds, is reported at info level, because Flutter never generates it.
missing_keyorphan_keyPlaceholder mismatch
Placeholders are compared by name, parsed from the ICU syntax tree rather than matched with a regex. That distinction matters: in
{count, plural, other{days} one{day}}a regex readsdaysanddayas placeholders, so translating those two words would look like a mismatch. StringLane compares only the real argument,count. Apostrophes are read the waygen_l10nreads them: plain text unlessl10n.yamlsetsuse-escaping: true, so{name}inRemove '{name}'?is still a placeholder.placeholder_mismatchInvalid ICU
Unmatched braces, a plural missing its
othercategory, or a malformedselectclause.gen_l10nparses ICU too and will fail the build on malformed syntax. StringLane shows it while you are still in the file.icu_parse_errorStandalone
#Flutter has no pound token, so a bare
#inside a plural branch renders literally in the UI instead of being replaced by the number. StringLane flags it and the AI fill converts it to a named variable.icu_pound_literalExact plural forms Flutter cannot build
gen_l10nbuilds only=0,=1and=2as exact plural forms. A plural with any other, such as=3{three items}, failsflutter gen-l10non the whole file, so it is an error in every locale, the base included. A plural holding both=1andone(or=0andzero,=2andtwo) has a branch Flutter never shows, because it treats each pair as one form and keeps the later one.icu_plural_selector_unsupportedicu_plural_selector_overriddenLength over the limit
Set
x-max-lengthin a key's@keymetadata and any translation longer than that is flagged. German button labels are the usual reason this exists.max_length_exceededSame as base, and guarded words
A value identical to the template locale usually means it was copied and never translated. Terms you mark as guarded, such as a product name, are flagged the other way round when a locale changes them.
untranslatedguarded_word_violation
What it will not do
StringLane is a file editor, not a translation reviewer. It cannot tell you that a grammatically valid German sentence says the wrong thing. It can tell you the key is missing, the placeholder was dropped, the ICU is malformed and the plural is short a category, which is the part you can check without speaking the language.
YOUR FILES
Your files come back the way you left them
StringLane writes to your source files directly. There is no export step and no project database.
@keymetadata objects are read and written back untouched, including@description,x-max-lengthandx-guarded.- Key order is preserved exactly as it appears in the source file.
- ICU strings are stored as you wrote them, not normalised into a house style.
- Open the file in your editor before and after: the diff shows only the values you actually changed.
lib/l10n/app_en.arb
{
"cartCheckoutCta": "Check out",
"@cartCheckoutCta": {
"x-max-length": 18
},
"cartItemCount": "{count, plural, one {{count} item in cart} other {{count} items in cart}}",
"@cartItemCount": {
"description": "Shown on the cart icon badge.",
"placeholders": { "count": { "type": "int", "example": "3" } }
}
}YOUR TOOLCHAIN
Where it sits in a Flutter project
StringLane is a file editor, not a code generator and not a build tool. It edits the .arb files that gen_l10n and the FlutterIntl extension already consume. Your l10n.yaml, your flutter gen-l10n step and your CI all keep running unchanged.
That matters because the build is not the safety net people assume. gen_l10n reports a count of untranslated messages in the build log and does not fail the build, so a missing German string compiles clean and ships as English. A count also says nothing about a translation that exists but dropped its {placeholder}, and nothing at all about your other formats.
Let your coding agent check the same files.
The free CLI reads the same app_*.arb files.
Read https://stringlane.app/docs/cli/agent-setup.md and set up StringLane for this project.Pay once for the app. The CLI is free.
Desktop app
$49once
- 14-day trial, no email, no card
- macOS, Windows and Linux
- 3 machines, updates in the major version
- Your own AI key, or a local model
Early-adopter price, $79 after launch.
CLI & agents
$0free
- Terminal, CI and MCP
- Claude Code, Cursor, Codex and 5 more
- No key, no activation
- Separate from the app licence
Lokalise starts at $144 a month (checked July 2026). StringLane sells no AI credits.
Flutter ARB questions
Does StringLane replace gen_l10n or FlutterIntl?
.arb files; gen_l10n reads them and generates AppLocalizations exactly as before. Nothing in your l10n.yaml or your build changes.Will it reorder my keys or strip my @description annotations?
@key metadata objects are written back untouched, in every locale file rather than only the template. If you have lost annotations to an editor before, that is the behaviour worth testing first: open a translated locale, save it, and read the diff.Does it handle ICU plurals and select forms?
other category is caught before gen_l10n refuses to generate.What about a bare # inside a plural branch?
# renders literally in the UI. StringLane detects the standalone case and leaves deliberate literal usage such as rank #1 alone.Do I need an account or an internet connection?
Read before you download
Flutter ARB file format
A complete example file, placeholders, plurals and select, and what builds broken.
Working with ARB metadata
@description,x-max-lengthandx-guardedin practice.ICU plurals and select forms
Writing and validating plural categories per locale.
Localize a Flutter app
Start to finish, from an empty
l10nfolder to a translated build.
ARB and i18next are the two ICU formats StringLane validates. If you ship a Flutter app and a React dashboard from one repo, both open in the same window.
i18next JSON editorCheck your locales tonight.
For macOS, Windows and Linux14-day trial, no email · The agent setup is free