← Back to Blog

Flutter intl Package: Complete Setup and Usage Guide 2025

flutterintlinternationalizationdate-formatnumber-formati18n

Flutter intl Package: Complete Setup and Usage Guide 2025

The intl package is the foundation of Flutter internationalization. Whether you're building a simple app or a complex multilingual platform, understanding how to use flutter_intl and the intl package is essential for every Flutter developer.

What is the Flutter intl Package?

The intl package provides internationalization and localization support for Dart applications. It includes:

  • Message formatting with placeholders
  • Date and time formatting
  • Number and currency formatting
  • Plural and gender support
  • Bidirectional text handling

Quick Setup Guide

Step 1: Add Dependencies

# pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  intl: ^0.19.0

flutter:
  generate: true

Step 2: Configure l10n.yaml

Create l10n.yaml in your project root:

arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
output-class: AppLocalizations

Step 3: Create Your First ARB File

Create lib/l10n/app_en.arb:

{
  "@@locale": "en",
  "appTitle": "My App",
  "@appTitle": {
    "description": "The application title"
  },
  "welcomeMessage": "Welcome, {username}!",
  "@welcomeMessage": {
    "description": "Welcome message with user name",
    "placeholders": {
      "username": {
        "type": "String",
        "example": "John"
      }
    }
  }
}

Step 4: Configure MaterialApp

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Intl Demo',
      localizationsDelegates: const [
        AppLocalizations.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: const [
        Locale('en'),
        Locale('es'),
        Locale('fr'),
        Locale('ar'),
      ],
      home: const HomePage(),
    );
  }
}

Step 5: Use Translations in Widgets

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

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

    return Scaffold(
      appBar: AppBar(
        title: Text(l10n.appTitle),
      ),
      body: Center(
        child: Text(l10n.welcomeMessage('John')),
      ),
    );
  }
}

Date and Time Formatting with intl

The intl package excels at locale-aware date formatting:

import 'package:intl/intl.dart';

class DateFormattingExample {
  void formatDates() {
    final now = DateTime.now();

    // Short date format
    final shortDate = DateFormat.yMd('en_US').format(now);
    // Output: 12/4/2025

    // Long date format
    final longDate = DateFormat.yMMMMd('en_US').format(now);
    // Output: December 4, 2025

    // Time format
    final time = DateFormat.jm('en_US').format(now);
    // Output: 3:30 PM

    // Custom pattern
    final custom = DateFormat('EEEE, MMMM d, y').format(now);
    // Output: Thursday, December 4, 2025

    // Different locale
    final frenchDate = DateFormat.yMMMMd('fr_FR').format(now);
    // Output: 4 décembre 2025
  }
}

Number and Currency Formatting

import 'package:intl/intl.dart';

class NumberFormattingExample {
  void formatNumbers() {
    // Number formatting
    final number = NumberFormat('#,##0.00', 'en_US').format(1234567.89);
    // Output: 1,234,567.89

    // Currency formatting
    final usd = NumberFormat.currency(locale: 'en_US', symbol: '\$').format(99.99);
    // Output: $99.99

    final euro = NumberFormat.currency(locale: 'de_DE', symbol: '€').format(99.99);
    // Output: 99,99 €

    // Compact numbers
    final compact = NumberFormat.compact(locale: 'en_US').format(1500000);
    // Output: 1.5M

    // Percentage
    final percent = NumberFormat.percentPattern('en_US').format(0.75);
    // Output: 75%
  }
}

Message Formatting with Placeholders

Simple Placeholders

{
  "greeting": "Hello, {name}!",
  "@greeting": {
    "placeholders": {
      "name": {"type": "String"}
    }
  }
}

Numeric Placeholders

{
  "itemsInCart": "You have {count} items in your cart",
  "@itemsInCart": {
    "placeholders": {
      "count": {"type": "int"}
    }
  }
}

Date Placeholders

{
  "lastLogin": "Last login: {date}",
  "@lastLogin": {
    "placeholders": {
      "date": {
        "type": "DateTime",
        "format": "yMMMd"
      }
    }
  }
}

Plural Support with intl

Handle complex plural rules correctly:

{
  "messageCount": "{count, plural, =0{No messages} =1{One message} other{{count} messages}}",
  "@messageCount": {
    "placeholders": {
      "count": {"type": "int"}
    }
  }
}

For languages with complex plural rules like Arabic:

{
  "messageCount": "{count, plural, =0{لا رسائل} =1{رسالة واحدة} =2{رسالتان} few{{count} رسائل} many{{count} رسالة} other{{count} رسالة}}",
  "@messageCount": {
    "placeholders": {
      "count": {"type": "int"}
    }
  }
}

Gender Support

{
  "userWelcome": "{gender, select, male{Welcome, Mr. {name}} female{Welcome, Ms. {name}} other{Welcome, {name}}}",
  "@userWelcome": {
    "placeholders": {
      "gender": {"type": "String"},
      "name": {"type": "String"}
    }
  }
}

intl_utils vs flutter_intl: Which to Choose?

Feature intl_utils flutter_intl (IDE Plugin)
CLI support Yes No
IDE integration No Yes (VS Code, Android Studio)
Watch mode Yes Yes
ARB generation Yes Yes
Best for CI/CD, Teams Individual developers

Common intl Package Errors and Fixes

Error: "Getter not found: 'of'"

Solution: Run flutter gen-l10n to generate localization files.

flutter gen-l10n

Error: "The argument type 'String' can't be assigned"

Solution: Check your placeholder types match the ARB definition.

Error: "LocalizationsDelegate not found"

Solution: Ensure you've added the delegate to MaterialApp:

localizationsDelegates: [
  AppLocalizations.delegate,
  // ... other delegates
],

Performance Best Practices

1. Lazy Load Locales

supportedLocales: AppLocalizations.supportedLocales,
localeResolutionCallback: (locale, supportedLocales) {
  return supportedLocales.firstWhere(
    (supported) => supported.languageCode == locale?.languageCode,
    orElse: () => supportedLocales.first,
  );
},

2. Cache DateFormat Instances

class DateFormatters {
  static final Map<String, DateFormat> _cache = {};

  static DateFormat getFormatter(String pattern, String locale) {
    final key = '$pattern-$locale';
    return _cache.putIfAbsent(key, () => DateFormat(pattern, locale));
  }
}

3. Use const Constructors

const Locale('en'); // Good - creates compile-time constant
Locale('en');       // Works but creates new instance each time

FlutterLocalisation: The Better Way

While the intl package is powerful, managing ARB files manually across multiple languages becomes tedious. FlutterLocalisation automates the entire workflow:

  • Visual editor for translations (no JSON editing)
  • AI-powered translations across 50+ languages
  • Automatic ARB file generation
  • Git integration for seamless syncing
  • Real-time collaboration for teams

Conclusion

The intl package is essential for Flutter internationalization, providing robust support for message formatting, dates, numbers, plurals, and more. While it's powerful, the complexity grows with each language you add.

For professional apps targeting multiple markets, consider using FlutterLocalisation to automate translation management while still leveraging the intl package under the hood.


Ready to simplify your Flutter internationalization? Try FlutterLocalisation free and automate your intl workflow with AI-powered translations and visual editing.