# ARB Desk > A desk for Flutter ARB files. Paste a template (app_en.arb) and any translation, and the browser > checks them with a JavaScript port of Flutter gen-l10n's own ICU message parser and placeholder > rules and shows what every plural prints for each count in each language - free. A paid run > annotates the template for translators or translates it into a new locale (or fills only the keys > a locale is missing), and the page re-checks every message it returns. - URL: https://arb-desk.skillsafe.ai/ - API tutorial: https://arb-desk.skillsafe.ai/api.html - Token management: https://arb-desk.skillsafe.ai/tokens.html - Notices and licences: https://arb-desk.skillsafe.ai/NOTICE.txt - Platform: SkillSafe (https://skillsafe.ai/) - Model: `gpt-terra` (an alias; currently `gpt-5.6-terra`), publisher markup 1000 bps - Derived from the agent skill `@flutter/flutter-localizing-apps` (flutter/agent-plugins, BSD-3-Clause). The checker ports code from Flutter's flutter_tools (BSD-3-Clause). Flutter is a trademark of Google LLC; ARB Desk is not affiliated with or endorsed by Google or the Flutter project. ## What the free check does - Reads the ARB as gen-l10n does: JSON errors with line and column, duplicate keys (JSON keeps the last), `@@locale` against the file name, resource names that are not valid Dart method names. - Parses every message with the ported gen-l10n parser: the same syntax errors (a plural without `other`, an unknown plural keyword, unbalanced braces, unmatched quotes with `use-escaping`). - Applies gen-l10n's placeholder rules: a plural placeholder must be `int` or `num`, a select one `String`, a date argument `DateTime`; a `DateTime` shown directly needs a DateFormat skeleton; a `format` on a non-numeric placeholder is never applied; only `=0`, `=1`, `=2` are valid and they are the zero, one and two cases. - Compares a translation with the template: missing keys (they fall back to the template text), keys gen-l10n never reads, renamed or dropped placeholders, select cases, and every CLDR plural category the language needs (from the browser's Intl.PluralRules). - Previews each plural: the text Flutter shows for 0, 1, 2, 3, 5, 11, 21, 22, 25, 101 and 1000000. In gen-l10n `=1` is the `one` case, so in Russian it is also shown for 21 and 31. - Writes the setup for Flutter 3.35 and later (l10n.yaml, pubspec lines, MaterialApp), where the synthetic `package:flutter_gen` is gone. ## The two paid lanes | `task` | Produces | | --- | --- | | `annotate` | For up to 40 messages per run that lack metadata: a description for translators and every placeholder declared with gen-l10n's own inferred type and an example. Message text is never changed; rewrites (an `(s)` plural, an ambiguous word) come back as suggestions. | | `translate` | For up to 60 messages per run: the target locale's text, with every placeholder kept, one plural case per CLDR category of the language, select case names unchanged. With an existing translation pasted, only its missing keys are sent. | Both return one JSON object: `task`, `headline`, `notes`, `suggestions`, `arb`. The page merges `arb` into your file (never overwriting an existing translation) and re-checks the result. Because a fill run sends only missing keys, a template message edited after it was translated would keep its old translation. When a signed-in user's history has an earlier translate run to the same locale, the page lists the keys whose English changed since then and can drop their old translations so the next run sends them again. Downloads follow the template's own file prefix (`intl_de.arb` for an `intl_en.arb` template), and a cut-short result is marked PARTIAL in the page and in every file name. ## What it does not do It never runs Flutter, fetches nothing from your project, and cannot judge whether a translation reads well - have a native speaker review it. Runs need a SkillSafe account and cost credits; the check, the preview, the setup and every export are free.