Complete Guide to Flutter .arb Files in 2025
Flutter's .arb (Application Resource Bundle) files are the foundation of app internationalization. If you've ever struggled with managing translations across multiple languages, you're not alone. This comprehensive guide will teach you everything you need to know about .arb files in 2025.
What are .arb Files?
.arb files are JSON-based files that store your app's translatable strings. They follow the ICU MessageFormat standard and are Flutter's preferred way to handle internationalization. Think of them as the bridge between your code and your translators.
Here's a simple example:
{
"@@locale": "en",
"appTitle": "My Flutter App",
"@appTitle": {
"description": "The title of the application"
},
"welcomeMessage": "Welcome, {name}!",
"@welcomeMessage": {
"description": "Welcome message with user name",
"placeholders": {
"name": {
"type": "String"
}
}
}
}
Setting Up Flutter Localization
1. Add Dependencies
First, add the necessary dependencies to your pubspec.yaml:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: any
flutter:
generate: true
2. Configure l10n.yaml
Create an l10n.yaml file in your project root:
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
3. Create Your First .arb File
Create lib/l10n/app_en.arb:
{
"@@locale": "en",
"helloWorld": "Hello World!",
"@helloWorld": {
"description": "The conventional newborn programmer greeting"
},
"loginButton": "Login",
"@loginButton": {
"description": "Button text for user login"
}
}
Advanced .arb File Features
Pluralization
Handle singular and plural forms correctly:
{
"itemCount": "{count, plural, =0{No items} =1{One item} other{{count} items}}",
"@itemCount": {
"description": "Number of items in the list",
"placeholders": {
"count": {
"type": "int"
}
}
}
}
Gender Support
{
"welcomeUser": "{gender, select, male{Welcome Mr. {name}} female{Welcome Ms. {name}} other{Welcome {name}}}",
"@welcomeUser": {
"description": "Welcome message with gender consideration",
"placeholders": {
"gender": {
"type": "String"
},
"name": {
"type": "String"
}
}
}
}
Date and Number Formatting
{
"currentDate": "Today is {date}",
"@currentDate": {
"description": "Shows the current date",
"placeholders": {
"date": {
"type": "DateTime",
"format": "yMd"
}
}
},
"priceTag": "Price: {price}",
"@priceTag": {
"description": "Product price display",
"placeholders": {
"price": {
"type": "double",
"format": "currency"
}
}
}
}
Best Practices for .arb Files
1. Use Descriptive Keys
❌ Bad:
{
"button1": "Submit",
"text2": "Welcome"
}
✅ Good:
{
"submitButton": "Submit",
"welcomeMessage": "Welcome"
}
2. Always Add Descriptions
{
"logoutConfirmation": "Are you sure you want to logout?",
"@logoutConfirmation": {
"description": "Confirmation dialog when user attempts to logout"
}
}
3. Organize by Feature
{
"@@locale": "en",
// Authentication
"loginTitle": "Login",
"loginButton": "Sign In",
"forgotPassword": "Forgot Password?",
// Profile
"profileTitle": "My Profile",
"editProfile": "Edit Profile",
"saveChanges": "Save Changes"
}
4. Handle Long Text
{
"privacyPolicy": "By using this app, you agree to our Privacy Policy and Terms of Service. We take your privacy seriously and will never share your personal information without your consent.",
"@privacyPolicy": {
"description": "Privacy policy agreement text shown during registration"
}
}
Common Pitfalls and How to Avoid Them
1. Missing Descriptions
Always provide context for translators:
{
"save": "Save",
"@save": {
"description": "Button to save user profile changes"
}
}
2. Hardcoded Plurals
❌ Don't do this:
{
"items": "items",
"itemsText": "You have {count} items"
}
✅ Do this:
{
"itemCount": "{count, plural, =0{No items} =1{One item} other{{count} items}}",
"@itemCount": {
"placeholders": {
"count": {"type": "int"}
}
}
}
3. Concatenating Strings
❌ Avoid:
{
"hello": "Hello",
"username": "Username:",
"fullGreeting": "Hello, Username: John"
}
✅ Better:
{
"userGreeting": "Hello, {username}!",
"@userGreeting": {
"placeholders": {
"username": {"type": "String"}
}
}
}
Using Generated Localizations in Your Code
After running flutter gen-l10n, use your translations like this:
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Scaffold(
appBar: AppBar(
title: Text(l10n.appTitle),
),
body: Column(
children: [
Text(l10n.welcomeMessage('John')),
Text(l10n.itemCount(5)),
ElevatedButton(
onPressed: () {},
child: Text(l10n.loginButton),
),
],
),
);
}
}
Managing Multiple Languages
Directory Structure
lib/
l10n/
app_en.arb # English (template)
app_es.arb # Spanish
app_fr.arb # French
app_de.arb # German
Spanish Example (app_es.arb)
{
"@@locale": "es",
"appTitle": "Mi Aplicación Flutter",
"welcomeMessage": "¡Bienvenido, {name}!",
"loginButton": "Iniciar Sesión",
"itemCount": "{count, plural, =0{Sin elementos} =1{Un elemento} other{{count} elementos}}"
}
Validating Your .arb Files
1. Check JSON Syntax
Ensure your .arb files are valid JSON. Use a JSON validator or your IDE's JSON validation.
2. Verify Placeholders Match
Make sure all placeholders in translations match the template:
// app_en.arb
{
"greeting": "Hello, {name} from {city}!",
"@greeting": {
"placeholders": {
"name": {"type": "String"},
"city": {"type": "String"}
}
}
}
// app_es.arb
{
"greeting": "¡Hola, {name} de {city}!"
}
3. Test Pluralization
Test your plural forms with different values:
// Test with 0, 1, 2, 5, 100
Text(l10n.itemCount(0)), // "No items"
Text(l10n.itemCount(1)), // "One item"
Text(l10n.itemCount(5)), // "5 items"
Automation and Tools
1. FlutterLocalisation Platform
Instead of managing .arb files manually, consider using FlutterLocalisation to:
- Automatically sync .arb files with your Git repository
- Collaborate with translators in a visual interface
- Use AI-powered translation suggestions
- Validate your .arb files automatically
- Manage team access with role-based permissions
2. VS Code Extensions
Install helpful extensions:
- Flutter Intl: Generates boilerplate code
- i18n Ally: Visualizes your translations
- JSON Tools: Formats and validates JSON
3. CI/CD Integration
Add .arb validation to your CI pipeline:
# .github/workflows/flutter.yml
- name: Validate ARB files
run: |
find lib/l10n -name "*.arb" -exec python -m json.tool {} \;
flutter gen-l10n
Performance Considerations
1. Lazy Loading
For large apps, consider lazy loading translations:
class AppLocalizations {
static Future<AppLocalizations> load(Locale locale) async {
// Load only the required locale
return AppLocalizations._();
}
}
2. Caching
Cache frequently used translations:
class TranslationCache {
static final Map<String, String> _cache = {};
static String get(String key, AppLocalizations l10n) {
return _cache[key] ??= _getTranslation(key, l10n);
}
}
Debugging Translation Issues
1. Missing Translations
class DebugLocalizations extends AppLocalizations {
@override
String getString(String key) {
final value = super.getString(key);
if (value == key) {
print('Missing translation for: $key');
}
return value;
}
}
2. Placeholder Issues
String safeFormat(String template, Map<String, dynamic> args) {
try {
return template.replaceAllMapped(
RegExp(r'\{(\w+)\}'),
(match) => args[match.group(1)]?.toString() ?? match.group(0)!,
);
} catch (e) {
print('Format error in: $template');
return template;
}
}
Real-World Example: E-commerce App
Here's a complete .arb file for an e-commerce app:
{
"@@locale": "en",
// Navigation
"homeTab": "Home",
"searchTab": "Search",
"cartTab": "Cart",
"profileTab": "Profile",
// Product Listing
"productCount": "{count, plural, =0{No products found} =1{1 product} other{{count} products}}",
"@productCount": {
"description": "Number of products in search results",
"placeholders": {
"count": {"type": "int"}
}
},
"priceRange": "Price: {minPrice} - {maxPrice}",
"@priceRange": {
"description": "Price range for products",
"placeholders": {
"minPrice": {"type": "double", "format": "currency"},
"maxPrice": {"type": "double", "format": "currency"}
}
},
// Shopping Cart
"addToCart": "Add to Cart",
"@addToCart": {
"description": "Button to add product to shopping cart"
},
"cartTotal": "Total: {amount}",
"@cartTotal": {
"description": "Total amount in shopping cart",
"placeholders": {
"amount": {"type": "double", "format": "currency"}
}
},
// Checkout
"checkoutTitle": "Checkout",
"shippingAddress": "Shipping Address",
"paymentMethod": "Payment Method",
"orderSummary": "Order Summary",
"estimatedDelivery": "Estimated delivery: {date}",
"@estimatedDelivery": {
"description": "Expected delivery date",
"placeholders": {
"date": {"type": "DateTime", "format": "MMMd"}
}
}
}
Conclusion
Mastering .arb files is crucial for creating truly international Flutter apps. By following these best practices, you'll create maintainable, translator-friendly, and robust internationalization systems.
Remember:
- Always provide context with descriptions
- Use semantic key names
- Handle pluralization properly
- Validate your files regularly
- Consider automation tools for larger projects
Ready to streamline your Flutter localization workflow? Try FlutterLocalisation for automated .arb file management with Git integration, team collaboration, and AI-powered translations.
Next Steps:
- Set up your first .arb files using this guide
- Test with multiple languages
- Integrate validation into your development workflow
- Consider automation tools as your project grows
Have questions about Flutter localization? Feel free to reach out - we're here to help!