SKILLS LAUNCH PARTY
skills/madteacher/mad-agents-skills/flutter-internationalization

flutter-internationalization

SKILL.md

Flutter Internationalization

Overview

Comprehensive guide for adding internationalization (i18n) to Flutter applications. Covers setup, configuration, message management, number/date formatting, and advanced topics like locale override and custom language support.

Quick Start

Choose approach based on app needs:

gen-l10n (Recommended) - Modern, automated, code generation

  • Best for: Most new projects, teams, complex apps
  • Uses: ARB files, automated code generation
  • See: Setup gen-l10n

intl package - Manual control, code-based

  • Best for: Simple apps, legacy projects, full control
  • Uses: Intl.message() code, manual translation files
  • See: Setup intl package

Manual/Custom - Maximum flexibility

  • Best for: Very simple apps, custom workflows
  • Uses: Direct Map-based lookups
  • See: Custom localizations

Setup gen-l10n

1. Add Dependencies

Update pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  intl: any

Run:

flutter pub add flutter_localizations --sdk=flutter
flutter pub add intl:any

2. Enable Code Generation

Add to pubspec.yaml:

flutter:
  generate: true

3. Configure l10n.yaml

Create l10n.yaml in project root:

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

For advanced options, see l10n-config.md.

4. Create ARB Files

Create directory lib/l10n/.

Template file lib/l10n/app_en.arb:

{
  "helloWorld": "Hello World!",
  "@helloWorld": {
    "description": "Greeting message"
  }
}

Translation file lib/l10n/app_es.arb:

{
  "helloWorld": "¡Hola Mundo!"
}

For complete ARB format, see arb-format.md.

5. Generate Code

Run:

flutter gen-l10n

Or run app to trigger auto-generation:

flutter run

6. Configure MaterialApp

Import and setup:

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

MaterialApp(
  localizationsDelegates: [
    AppLocalizations.delegate,
    GlobalMaterialLocalizations.delegate,
    GlobalWidgetsLocalizations.delegate,
    GlobalCupertinoLocalizations.delegate,
  ],
  supportedLocales: [
    Locale('en'),
    Locale('es'),
  ],
  home: MyHomePage(),
)

7. Use Localizations

Access in widgets:

Text(AppLocalizations.of(context)!.helloWorld)

Message Types

Simple Messages

No parameters:

{
  "welcome": "Welcome to our app",
  "@welcome": {
    "description": "Welcome message"
  }
}

Placeholder Messages

With parameters:

{
  "greeting": "Hello {userName}!",
  "@greeting": {
    "description": "Personalized greeting",
    "placeholders": {
      "userName": {
        "type": "String",
        "example": "Alice"
      }
    }
  }
}

Use in code:

Text(AppLocalizations.of(context)!.greeting('Alice'))

Plural Messages

Based on count:

{
  "itemCount": "{count, plural, =0{No items} =1{1 item} other{{count} items}}",
  "@itemCount": {
    "placeholders": {
      "count": {
        "type": "int"
      }
    }
  }
}

Use in code:

Text(AppLocalizations.of(context)!.itemCount(5))

Select Messages

Based on string value:

{
  "pronoun": "{gender, select, male{he} female{she} other{they}}",
  "@pronoun": {
    "placeholders": {
      "gender": {
        "type": "String"
      }
    }
  }
}

Use in code:

Text(AppLocalizations.of(context)!.pronoun('male'))

Number and Date Formatting

Numbers

Format numbers automatically:

{
  "price": "Price: {value}",
  "@price": {
    "placeholders": {
      "value": {
        "type": "int",
        "format": "simpleCurrency"
      }
    }
  }
}

Format options: compact, currency, simpleCurrency, decimalPattern, etc.

Dates

Format dates automatically:

{
  "eventDate": "Event on {date}",
  "@eventDate": {
    "placeholders": {
      "date": {
        "type": "DateTime",
        "format": "yMMMd"
      }
    }
  }
}

Format options: yMd, yMMMd, yMMMMd, Hm, etc.

For complete formatting options, see number-date-formats.md.

Advanced Topics

Locale Override

Override locale for specific widgets:

Localizations.override(
  context: context,
  locale: const Locale('es'),
  child: CalendarDatePicker(...),
)

Custom Locale Definitions

For complex locales (Chinese, French regions):

supportedLocales: [
  Locale.fromSubtags(languageCode: 'zh'),
  Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans'),
  Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'TW'),
]

Locale Resolution Callback

Control locale fallback:

MaterialApp(
  localeResolutionCallback: (locale, supportedLocales) {
    // Always accept user's locale
    return locale;
  },
)

Access Current Locale

Get current app locale:

Locale myLocale = Localizations.localeOf(context);

Setup intl Package

Manual Setup

  1. Add dependencies (same as gen-l10n)
  2. Create localization class:
class DemoLocalizations {
  DemoLocalizations(this.localeName);

  static Future<DemoLocalizations> load(Locale locale) {
    final String name = Intl.canonicalizedLocale(locale.toString());
    return initializeMessages(name).then((_) => DemoLocalizations(name));
  }

  static DemoLocalizations of(BuildContext context) {
    return Localizations.of<DemoLocalizations>(context, DemoLocalizations)!;
  }

  String get title {
    return Intl.message(
      'Hello World',
      name: 'title',
      desc: 'Title',
      locale: localeName,
    );
  }
}
  1. Create delegate:
class DemoLocalizationsDelegate extends LocalizationsDelegate<DemoLocalizations> {
  const DemoLocalizationsDelegate();

  
  bool isSupported(Locale locale) => ['en', 'es'].contains(locale.languageCode);

  
  Future<DemoLocalizations> load(Locale locale) => DemoLocalizations.load(locale);

  
  bool shouldReload(DemoLocalizationsDelegate old) => false;
}
  1. Generate ARB files:
dart run intl_translation:extract_to_arb --output-dir=lib/l10n lib/main.dart
dart run intl_translation:generate_from_arb --output-dir=lib/l10n lib/main.dart lib/l10n/intl_*.arb

Custom Localizations

For maximum simplicity:

class DemoLocalizations {
  DemoLocalizations(this.locale);

  final Locale locale;

  static DemoLocalizations of(BuildContext context) {
    return Localizations.of<DemoLocalizations>(context, DemoLocalizations)!;
  }

  static const _localizedValues = <String, Map<String, String>>{
    'en': {'title': 'Hello World'},
    'es': {'title': 'Hola Mundo'},
  };

  String get title {
    return _localizedValues[locale.languageCode]!['title']!;
  }
}

Best Practices

  1. Use gen-l10n for new projects - simpler, safer, better tooling
  2. Add descriptions to ARB entries - provides context for translators
  3. Format numbers/dates with format types - automatic locale handling
  4. Test all locales - verify formatting, RTL, and translations
  5. Use pluralization - handle count variations correctly
  6. Keep messages short - easier to translate, more consistent
  7. Don't concatenate strings - use placeholders instead
  8. Enable nullable-getter to reduce null checks in user code

Resources

references/

l10n-config.md - Complete reference for l10n.yaml configuration options, including output directories, code generation settings, and locale handling.

arb-format.md - Comprehensive guide to ARB file format, covering simple messages, placeholders, plurals, selects, and metadata.

number-date-formats.md - Number and date formatting reference with format types, patterns, and locale-specific examples.

assets/

Example templates and boilerplate code can be added here for common internationalization patterns.

When to Use This Skill

Use this skill when:

  • Adding localization support to a new Flutter app
  • Translating existing Flutter app to multiple languages
  • Configuring number/date formatting for different locales
  • Setting up RTL (right-to-left) language support
  • Implementing locale-specific layouts or widgets
  • Managing ARB files and translations
  • Troubleshooting localization issues
  • Adding custom language support beyond built-in locales
  • Optimizing app bundle size with deferred loading
Weekly Installs
89
First Seen
Jan 22, 2026
Installed on
opencode66
gemini-cli60
codex60
github-copilot52
claude-code51
antigravity46