Skip to content
StringLane

FLUTTER ARB

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.

Download for macOS

For macOS, Windows and Linux14-day trial, no email · $49 once

StringLane with a sample Flutter ARB project open: one key side by side across languages with the Japanese cell missing, and the Issues panel listing standalone # warnings in plural forms

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
@key objects: @description, x-max-length, x-guarded
Detected by
Any .arb file 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_key

  • Placeholder 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 reads days and day as placeholders, so translating those two words would look like a mismatch. StringLane compares only the real argument, count. Apostrophes are read the way gen_l10n reads them: plain text unless l10n.yaml sets use-escaping: true, so {name} in Remove '{name}'? is still a placeholder.

    placeholder_mismatch

  • Invalid ICU

    Unmatched braces, a plural missing its other category, or a malformed select clause. gen_l10n parses ICU too and will fail the build on malformed syntax. StringLane shows it while you are still in the file.

    icu_parse_error

  • Standalone #

    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_literal

  • Exact plural forms Flutter cannot build

    gen_l10n builds only =0, =1 and =2 as exact plural forms. A plural with any other, such as =3{three items}, fails flutter gen-l10n on the whole file, so it is an error in every locale, the base included. A plural holding both =1 and one (or =0 and zero, =2 and two) 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_overridden

  • Length over the limit

    Set x-max-length in a key's @key metadata and any translation longer than that is flagged. German button labels are the usual reason this exists.

    max_length_exceeded

  • Same 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.

  • @key metadata objects are read and written back untouched, including @description, x-max-length and x-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?
No. It sits one layer below both, at the file level. StringLane edits .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?
No. Key order is preserved as found, and the @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?
Yes, with a visual editor and a raw tab for the ICU string itself. Invalid syntax is flagged as an error, and a plural missing its other category is caught before gen_l10n refuses to generate.
What about a bare # inside a plural branch?
It is flagged. Flutter's generated code has no pound substitution, so # 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?
No account. The 14-day trial does not ask for an email address, but it checks with StringLane’s licence server at every launch, so it needs a connection. A licensed copy works offline. Your strings and files never go to a StringLane server; AI fill sends them only to the provider you choose.

Check your locales tonight.

Download for macOS

For macOS, Windows and Linux14-day trial, no email · The agent setup is free