Skip to content
Blog

ARB Files for Translations in Flutter: The Complete Guide

Learn how ARB (Application Resource Bundle) files work in Flutter localization. Master message formatting, placeholders, plurals, and code generation.

Published on September 19, 2026

AI Assistant

ARB Files for Translations in Flutter: The Complete Guide

ARB (Application Resource Bundle) files are the standard format for defining translatable strings in Flutter. They’re JSON-based, human-readable, and integrate directly with Flutter’s code generation tooling to produce type-safe localization classes.

What is an ARB File?

ARB files are JSON files with a specific structure that defines translatable messages, their descriptions, and metadata. Flutter’s code generator reads these files and produces Dart classes with strongly-typed accessor methods for each message.

Basic ARB Structure

{
  "@@locale": "en",
  "appTitle": "My Application",
  "@appTitle": {
    "description": "The title displayed in the app bar",
    "placeholders": {}
  },
  "greeting": "Hello, {name}!",
  "@greeting": {
    "description": "A greeting message with a user's name",
    "placeholders": {
      "name": {
        "type": "String",
        "example": "World",
        "description": "The user's display name"
      }
    }
  }
}

ARB File Naming Convention

Flutter expects ARB files to follow this pattern:

lib/l10n/
  app_en.arb      # English (template)
  app_es.arb      # Spanish
  app_fr.arb      # French
  app_ja.arb      # Japanese
  app_ar.arb      # Arabic

The app_ prefix is configurable in l10n.yaml, and the locale code must match the supported locale in your app.

Message Types and Formatting

Simple Strings

{
  "loginButton": "Log In",
  "logoutButton": "Log Out",
  "settingsTitle": "Settings"
}

Placeholder-Based Messages

{
  "welcomeUser": "Welcome back, {username}!",
  "@welcomeUser": {
    "description": "Greeting shown when user logs in",
    "placeholders": {
      "username": {
        "type": "String",
        "example": "john_doe"
      }
    }
  }
}

Pluralization

{
  "unreadCount": "{count, plural, =0{No unread messages} =1{1 unread message} other{{count} unread messages}}",
  "@unreadCount": {
    "description": "Number of unread messages",
    "placeholders": {
      "count": {
        "type": "int",
        "example": "5"
      }
    }
  }
}

Gender Select

{
  "userGreeting": "{gender, select, male{Hello, sir!} female{Hello, ma'am!} other{Hello there!}}",
  "@userGreeting": {
    "description": "Gender-aware greeting",
    "placeholders": {
      "gender": {
        "type": "String",
        "example": "male"
      }
    }
  }
}

Number Formatting

{
  "priceMessage": "Total: {amount, number, currency}",
  "@priceMessage": {
    "description": "Displays a formatted price",
    "placeholders": {
      "amount": {
        "type": "double",
        "example": "1234.56"
      }
    }
  }
}

Configuring l10n.yaml

The l10n.yaml file controls how Flutter generates localization code:

arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
output-class: AppLocalizations
preferred-supported-locales: ["en"]
nullable-localization: false
synthetic-package: false
output-dir: lib/generated/l10n

Key Configuration Options

OptionDescriptionDefault
arb-dirDirectory containing ARB fileslib/l10n
template-arb-fileThe template ARB fileapp_en.arb
output-localization-fileGenerated Dart file nameapp_localizations.dart
output-className of the generated classAppLocalizations
nullable-localizationWhether of() can return nulltrue

Using Generated Code

After running code generation, you get type-safe access to all messages:

import 'package:flutter_gen/gen_l10n/app_localizations.dart';

class MyWidget extends StatelessWidget {
  const MyWidget({super.key});

  @override
  Widget build(BuildContext context) {
    final l10n = AppLocalizations.of(context)!;

    return Column(
      children: [
        Text(l10n.appTitle),
        Text(l10n.welcomeUser('john_doe')),
        Text(l10n.unreadCount(5)),
        Text(l10n.userGreeting('male')),
        Text(l10n.priceMessage(1234.56)),
      ],
    );
  }
}

Running Code Generation

# Generate localization code
flutter gen-l10n

# Or run pub get (automatically triggers generation)
flutter pub get

Testing ARB Files

Verify Completeness

Ensure all locales have all keys from the template:

// In a test file
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

void main() {
  test('all locales have all keys', () {
    for (final locale in AppLocalizations.supportedLocales) {
      // Verify no missing translations
      expect(() => AppLocalizations.delegate.load(locale),
          isA<Future<AppLocalizations>>());
    }
  });
}

Best Practices

  1. Always create a template ARB file — it’s the source of truth for all translations
  2. Provide descriptions — translators need context to translate accurately
  3. Use placeholders with examples — helps translators understand format expectations
  4. Keep ARB files versioned — they’re part of your source code
  5. Run flutter gen-l10n after changes — keeps generated code in sync

ARB files are the backbone of Flutter’s localization system. By mastering their structure and capabilities, you can create maintainable, type-safe, and fully localized applications.