---
title: "Flutter quickstart"
description: "Translate the ARB locale files of your Flutter app with verbatra, from install to the first German string on screen."
type: "tutorial"
---
# Flutter quickstart

Translate the ARB locale files of your Flutter app with verbatra, from install to the first German string on screen.

By the end of this page your Flutter app shows a German string that verbatra translated from `lib/l10n/app_en.arb`, and a lock file makes every later run translate only what changed. You need Node.js `^22.18.0 || >=24`, a Flutter project, and about ten minutes. The first four steps need no account and no API key.

Already have locale files and a coding agent? Hand it the prompt on [Set up with an AI agent](https://verbatra.kreitz-webdev.de/docs/start-with-ai.md) instead: it works around the files your project has and stops before it spends anything.

## Steps [#steps]

<Steps>
<Step>

### Install the CLI [#install-the-cli]

```bash
npm install --save-dev @verbatra/cli
```

verbatra is a development tool and never ships in your app. The commands below use `npx`; with pnpm, yarn, or bun, run `pnpm verbatra`, `yarn verbatra`, or `bun run verbatra` instead.

<Callout title="A Flutter app has no package.json">
Your package manager creates one on the first install. Add `node_modules/` to your `.gitignore`.
</Callout>

</Step>
<Step>

### Add a source locale file [#add-a-source-locale-file]

Skip this step if `lib/l10n/app_en.arb` already exists. Otherwise create it with two strings, one of them with a placeholder:

```json title="lib/l10n/app_en.arb"
{
  "@@locale": "en",
  "greeting": "Hello, {name}!",
  "@greeting": {
    "placeholders": { "name": { "type": "String" } }
  },
  "cartEmpty": "Your cart is empty."
}
```

</Step>
<Step>

### Scaffold a config [#scaffold-a-config]

```bash
npx @verbatra/cli init --format arb --provider gemini --yes
```

`--format` `arb` is the file format of `flutter_localizations`. `init` finds your locale files, or writes the pattern `lib/l10n/app_{locale}.arb` when there are none yet. `--yes` takes what `init` detected instead of prompting. The new `verbatra.config.ts` translates from `en` into `de`; add codes to `targetLocales` for more languages.

</Step>
<Step>

### Preview the run without a key [#preview-the-run-without-a-key]

```bash
npx @verbatra/cli translate --dry-run
```

```text output
verbatra: dry run over 1 locale, no provider call
verbatra: de done, 2 would translate
verbatra translate (dry run)
  de: 2 would translate, 0 unchanged
1 succeeded, 0 partial, 0 failed (dry run: nothing written)
[ok] dry run done in 0.0s, nothing written
next: verbatra translate (run it for real)
```

A dry run builds no provider, so it needs no key, spends nothing, and writes nothing.

</Step>
<Step>

### Translate [#translate]

```bash
cp .env.example .env
```

Open `.env` and paste your key after `GEMINI_API_KEY=`. No key yet? Gemini has a free tier: create one in [Google AI Studio](https://aistudio.google.com/apikey). Every other provider and its variable is on [Providers](https://verbatra.kreitz-webdev.de/docs/providers.md).

```bash
npx @verbatra/cli translate
```

verbatra sends the two strings to Gemini, checks that every placeholder survived, and writes `lib/l10n/app_de.arb`. The wording depends on the model, for example:

```json title="lib/l10n/app_de.arb"
{
  "@@locale": "de",
  "greeting": "Hallo, {name}!",
  "cartEmpty": "Dein Warenkorb ist leer."
}
```

</Step>
<Step>

### Check that every locale is in sync [#check-that-every-locale-is-in-sync]

```bash
npx @verbatra/cli check
```

```text output
[ok] checking the locales (0.0s)
verbatra check
  de: 0 missing, 0 stale, 2 up-to-date (in sync)
all locales in sync
```

`check` calls no provider and exits `1` once a locale falls out of sync, so it can gate a pull request.

</Step>
<Step>

### Load the locales in your app [#load-the-locales-in-your-app]

Add `flutter_localizations`:

```bash
flutter pub add flutter_localizations:"{sdk: flutter}" intl:any
```

Then load both files and render the greeting:

```yaml title="pubspec.yaml"
flutter:
  generate: true
```

```yaml title="l10n.yaml"
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
```

```dart title="lib/main.dart"
import 'package:flutter/material.dart';
import 'l10n/app_localizations.dart';

void main() => runApp(
  MaterialApp(
    locale: const Locale('de'),
    localizationsDelegates: AppLocalizations.localizationsDelegates,
    supportedLocales: AppLocalizations.supportedLocales,
    home: Builder(
      builder: (context) => Text(AppLocalizations.of(context)!.greeting('Ada')),
    ),
  ),
);
```

Start your app: the greeting reads `Hallo, Ada!`.

</Step>
</Steps>

## What just happened [#what-just-happened]

- `verbatra.lock.json` records a hash of each source string, so the next run sends only new and changed strings. See [The lock file](https://verbatra.kreitz-webdev.de/docs/the-lock-file.md).
- A result that drops a placeholder is withheld, never written. See [Translation safety](https://verbatra.kreitz-webdev.de/docs/translation-safety.md).

Commit the locale files, `verbatra.lock.json`, and `verbatra.provenance.json` together.

## Optional: connect your coding agent [#optional-connect-your-coding-agent]

<AvailableFrom version="0.12.0" />

```bash
npx @verbatra/cli init --agent
```

With the config in place, `init --agent` keeps it and adds only the agent files: the verbatra rules in `AGENTS.md` (or `CLAUDE.md`, when that is your only instruction file) and the verbatra MCP server, with spending off, in the project config of each coding agent it detects. Which files it writes for which agent, and `--client` to name the agents yourself, are in [Set up coding agents](https://verbatra.kreitz-webdev.de/docs/cli/init.md#set-up-coding-agents). `--dry-run` shows the files without writing them.

Or, without the CLI, add only the MCP server to your VS Code user profile; use one route, never both:

[Add to VS Code](vscode:mcp/install?%7B%22name%22%3A%22verbatra%22%2C%22type%22%3A%22stdio%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40verbatra%2Fmcp%22%5D%7D)

## Next [#next]

<Cards>
  <Card title="Add a language" href="https://verbatra.kreitz-webdev.de/docs/add-a-language.md" description="Add a target locale and let one run fill it in." />
  <Card title="Run verbatra in CI" href="https://verbatra.kreitz-webdev.de/docs/ci-and-exit-codes.md" description="Fail a pull request when a locale drifts." />
  <Card title="Pick your stack" href="https://verbatra.kreitz-webdev.de/docs/pick-your-stack.md" description="The format id and file layout for every other framework." />
</Cards>
