Drop Locale

ARB translator that runs in your browser

Drop a .arb file in below, pick a target language, download the translated file. The ARB file stays on your device.

Loading translator...

How it works

Drop a .arb file on the page, click to choose one, or paste the contents straight in. The parser reads the file in your browser and tells you how many strings still need translation. Pick a target language and translation starts immediately. The translated file is reassembled from the same parsed structure so @key metadata, placeholder definitions, and the original key order all survive the round trip.

Quality Warning

Please don’t rely on the quality of these translations to ship a finalized product. This is just a starting point. It’s machine translation and there are no guarantees about its quality.

What we do not do

The file itself never leaves your device. We do not see what you are translating, we do not store any of the strings, and there is nothing about your file in our logs. The privacy wedge in DropFormat is structural: the ARB parser, the Google Translate caller, and the file writer all run inside your browser tab.

What does leave your device: the individual strings go to translate.googleapis.com the same way they would if you pasted them into translate.google.com yourself. We are not in the middle. If your file contains internal product strings you do not want a third party to see, do not translate it here; use an offline tool.

What it supports

ARB is the Application Resource Bundle format Flutter and Google Gallery use for localization. It is plain JSON: each key is a message identifier, each @key entry holds metadata for the matching message (description, placeholders), and keys starting with @@ (like @@locale) are file-level metadata. We preserve all of it on round trip: insertion order, descriptions, placeholder definitions, and any @@ fields we did not write to.

ICU plural messages of the shape {count, plural, =0 {No items} other {# items}} are first-class. The parser detects pure ICU plural patterns and fans each case out into its own row in the review pane. Translate each case independently; on download the cases are re-assembled into one ICU pattern under the original key. The plural variable name and the case labels (=0, one, other, etc.) are preserved verbatim.

Placeholders like {userName} pass through the translator unchanged. The protection layer that masks placeholders before translation and restores them after is the same one used for the PO and XLIFF translators.

Not yet: ICU select messages ({gender, select, ...}), nested ICU patterns embedded inside surrounding prose, and CLDR-aware plural-case expansion (today the case set in the output matches the case set in the input).

What we tolerate, and what we reject

Some malformed files we repair on the way in. Others we refuse to load so we do not make things worse. This list is the parser’s actual behaviour, generated from the format module itself, not aspirational copy.

Repaired automatically:

  • UTF-8 byte order mark (BOM) at the start of the file
  • Windows (CRLF) or mixed line endings
  • Trailing JSON commas before } or ] (JSON5-style)

Refused with an explanation:

  • Empty file. Add at least one key/value pair and re-upload.
  • Does not parse as JSON. Fix the JSON syntax so the file parses, then re-upload.
  • Top-level value is not a JSON object (e.g. an array). ARB requires a top-level object; wrap the array in an object keyed by string ids.
  • No translatable entries (only @@metadata keys). Add at least one non-@-prefixed key/value pair.

Common questions

Why is the translation in some cases worse than the Google Translate website? The free endpoint we use is the same one the Google Translate website uses, but the API does not always know about the context the website’s interface provides. For names, branded terms, or jargon, expect to override in the review pane.

What if I am translating something Google’s endpoint will not accept? The free endpoint occasionally returns the source unchanged for content it would rather not translate. Those entries show “kept original” in the review pane so you can hand-translate just those.

Does it cache anything? No. Each run starts fresh.

Will the output be valid JSON? Yes. The compiler serializes through JSON.stringify, so the file is always parseable. It will load cleanly in Flutter’s intl_utils or any ARB-aware tool.

What happens to keys whose value is not a string? ARB values that are not strings (e.g., an accidentally-typed number or array) are left untouched. Only string values are sent for translation.

Why this exists

Most Flutter localization tooling expects you to either pay for a managed service (Phrase, Crowdin, Lokalise) or run a CLI against your local files. This tool sits in between: free, browser-based, no upload, designed for the “I just need a fast first pass on this ARB” workflow. Drop the .arb, pick the language, get back a translated file in the same shape.

What is ARB?

ARB (“Application Resource Bundle”) is a JSON-based format Google maintains for localizing Flutter apps and other internationalized projects. Each translatable string is a top-level JSON key, with optional @key entries holding metadata: a description for translator context, and a placeholders map describing variables embedded in the message. Plural messages use the ICU MessageFormat syntax ({count, plural, =0 {...} other {...}}) so a single key can carry every plural form a target language needs. Flutter’s intl_utils and flutter_localizations read ARB at build time to generate type-safe localization classes.