Skip to content
Mobile
Skill

/internationalization

Best practices for internationalization (i18n) and localization (l10n) in Flutter, using the built-in `flutter_localizations` and `intl` setup with ARB files as the single source of truth. Use when adding, modifying, or reviewing ARB translations, locale setup (`l10n.yaml`,

BOOST
From plugin
vgv-ai-flutter-plugin
17315 skills1 agent3 hooks2 MCP
Install
$ npx -y skills add VeryGoodOpenSource/vgv-ai-flutter-plugin --skill internationalization --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/internationalization

Context preview

The summary Claude sees to decide when to auto-load this skill.

Best practices for internationalization (i18n) and localization (l10n) in Flutter, using the built-in `flutter_localizations` and `intl` setup with ARB files as the single source of truth. Use when adding, modifying, or reviewing ARB translations, locale setup (`l10n.yaml`,

SKILL.md

internationalization.SKILL.md
name: internationalization
description: >
  Best practices for internationalization (i18n) and localization (l10n) in Flutter, using the
  built-in `flutter_localizations` and `intl` setup with ARB files as the single source of
  truth. Use when adding, modifying, or reviewing ARB translations, locale setup (`l10n.yaml`,
  `generate: true` in `pubspec.yaml`, `flutter gen-l10n`, `localizationsDelegates`,
  `supportedLocales`), BuildContext l10n extensions such as `context.l10n`, hardcoded
  user-facing strings that should be localized, localized strings passed into shared or
  reusable widgets, or RTL/directional layout support with `EdgeInsetsDirectional`. Also use
  when asked to add or configure any third-party i18n or translation package
  (easy_localization, slang, flutter_i18n, or intl_utils), and when shipping or fixing a
  screen for a right-to-left language such as Arabic, Hebrew, Farsi, or Urdu,
  including mirroring padding, alignment, icons, or images, and replacing `EdgeInsets`
  left/right.
allowed-tools: Read Glob Grep

Internationalization

Internationalization (i18n) and localization (l10n) best practices for Flutter applications using Flutter's built-in localization system with ARB files as the single source of truth.

Core Standards

Apply these standards to all internationalization work:

  • **Never hardcode user-facing strings** — all text must go through the l10n system
  • **Use Flutter's built-in localization system** — `flutter_localizations` + `intl`, never third-party i18n libraries
  • **ARB files are the single source of truth** for all translations
  • **`BuildContext` extension for cleaner l10n access** — use `context.l10n` instead of `AppLocalizations.of(context)`
  • **Pass localized strings as parameters to reusable widgets** — never couple shared widgets directly to `AppLocalizations`
  • **Use `EdgeInsetsDirectional` (start/end) instead of `EdgeInsets` (left/right)** — ensures correct layout in RTL languages
  • **Handle RTL layout properly** — use directional widgets for padding, positioning, and alignment
  • **Implement i18n early** — even if only one language is planned initially, the overhead is small and the long-term benefit is significant
  • **Dart 3.13 primary constructors** — on a Dart 3.13+ baseline, declare a reusable widget's localized-string fields as primary-constructor declaring parameters (`class const ConfirmDialog({required final String title, super.key}) extends StatelessWidget`) rather than `this.field`; keep the classic form only below 3.13

Setup Pipeline and ARB File Format

Add `flutter_localizations` and `intl` as dependencies, enable `generate: true` in `pubspec.yaml`, configure `l10n.yaml`, create ARB files in `lib/l10n/arb/`, run `flutter gen-l10n`, and wire up `MaterialApp` with `localizationsDelegates` and `supportedLocales`. ARB files support simple strings, placeholders, and ICU plural syntax.

BuildContext Extension

Create an extension for ergonomic l10n access throughout the codebase:

extension AppLocalizationsX on BuildContext {
  AppLocalizations get l10n => AppLocalizations.of(this);
}

Usage:

// Preferred
Text(context.l10n.helloWorld);

// Avoid
Text(AppLocalizations.of(context).helloWorld);

Reusable Widget Strategy

Shared widgets that live in separate packages should not depend on `AppLocalizations` directly. Instead, pass localized strings as constructor parameters:

When someone asks to add `AppLocalizations` to a shared package, decline and say why — the package would carry its own translations and every consuming app would be locked to them — then rewrite their widget with the label as a `final String` constructor parameter and show the call site supplying `context.l10n`. Give both as Dart code; describing the change in prose leaves the caller to guess the signature.

// Shared widget — no l10n dependency
class const ConfirmDialog({
  required final String title,
  required final String message,
  required final String confirmLabel,
  required final String cancelLabel,
  super.key,
}) extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: Text(title),
      content: Text(message),
      actions: [
        TextButton(onPressed: () => Navigator.pop(context), child: Text(cancelLabel)),
        FilledButton(onPressed: () => Navigator.pop(context, true), child: Text(confirmLabel)),
      ],
    );
  }
}

// App-level usage — passes localized strings
showDialog<bool>(
  context: context,
  builder: (_) => ConfirmDialog(
    title: context.l10n.deleteTitle,
    message: context.l10n.deleteMessage,
    confirmLabel: context.l10n.confirm,
    cancelLabel: context.l10n.cancel,
  ),
);

Text Directionality

Use `EdgeInsetsDirectional` (start/end) instead of `EdgeInsets` (left/right) for all padding and margins. Use directional widget variants (`PositionedDirectional`, `AlignDirectional`, `BorderDirectional`) for RTL-aware layouts. Icons mirror automatically in RTL; images require `matchTextDirection: true`.

Backend Considerations

Store backend content with per-locale translations and require clients to transmit the user's locale. For error messages, map HTTP status codes or custom backend error constants to l10n keys on the frontend.

Common Patterns

Adding a New Locale

1. Create `app_<locale>.arb` in `lib/l10n/arb/` (e.g., `app_fr.arb`) 2. Add translations for all keys from the template ARB file 3. Run `flutter gen-l10n` 4. The new locale is automatically available through `AppLocalizations.supportedLocales`

Adding a New String

1. Add the key-value pair to the template ARB file (`app_en.arb`) 2. Add the `@key` metadata with description and placeholders if needed 3. Add translations in all other ARB files 4. Run `flutter gen-l10n` 5. Use via `context.l10n.newKey`

Pluralization

1. Define the plural string in the template ARB file using ICU message syntax 2. Provide placeholder metadata wit

Read more
Ships withvgv-ai-flutter-plugin

A Claude Code plugin that accelerates Flutter & Dart development with best-practices skills from Very Good Ventures. Developed with 💙 by Very Good Ventures 🦄

Get the whole plugin

Other skills on vgv-ai-flutter-plugin.