Blogs/Technology

Flutter Internationalization and Localization Guide

Written byTaha
Aug 4, 2026
12 Min Read
Flutter Internationalization and Localization Guide Hero
Too Long? Read This First

- Internationalization prepares the application: It removes hard-coded language and regional assumptions from the codebase.
- Localization adapts the experience: It provides translated content, formatting, assets, and behaviour for a particular locale.
- Use ARB files instead of translation maps inside Dart: Flutter can generate typed localization classes from these resources.
- Declare both framework and application localization delegates: Framework delegates translate built-in controls; the generated app delegate loads your messages.
- Do not concatenate translated sentences: Use placeholders so translators can change word order safely.
- Use locale-aware formatting: Dates, numbers, currencies, plurals, and compact notation vary by region.
- Test layouts, not only translations: Longer text, right-to-left scripts, text scaling, and small screens can expose UI defects.
- Avoid forcing a language without a product requirement: Flutter can resolve the closest supported locale from the user’s device preferences.
- Plan fallback behaviour: Decide what happens when a device requests an unsupported language or regional variant.

A multilingual app requires more than replacing English text with translated strings. Dates, numbers, currencies, plural rules, reading direction, images, and even sentence structure can change between locales.

Treating localization as a final-stage content task often exposes assumptions throughout the codebase. Text may be embedded directly in widgets, layouts may not accommodate longer translations, and user-facing values may be formatted according to only one region.

Flutter provides a structured localization system built around locales, localization delegates, ARB files, generated Dart classes, and the intl package. When this foundation is introduced early, teams can add languages without rewriting the application’s core interface.

This guide explains how Flutter internationalization and localization work, how to set up multilingual resources, and what must be tested before releasing an app in a new market.

Internationalization vs Localization

Although the terms are related, they describe different work.

TermMeaningExample
Internationalization (i18n)Designing the application so it can support different languages and regionsMoving user-facing text out of widgets
Localization (l10n)Adapting the application for a particular localeProviding Spanish translations and euro formatting
LocaleA language and, when needed, script or regional identifieren, en_GB, pt_BR, zh_Hant
TranslationConverting text from one language into another“Welcome” to “Bienvenido”
Regional formattingDisplaying values according to local conventions1,234.50 versus 1.234,50
Internationalization (i18n)
Meaning
Designing the application so it can support different languages and regions
Example
Moving user-facing text out of widgets
1 of 5

Internationalization creates the system. Localization fills that system with market-specific content.

An application can be internationalized while supporting only one language. Conversely, adding a few translated strings does not make an app fully localized if dates, plural rules, layouts, and assets still assume one locale.

Why Localization Matters in Flutter Apps

Language affects whether users can understand navigation, complete forms, interpret errors, and trust a transaction. A technically correct translation can still fail if important text is clipped or if prices and dates use unfamiliar formats.

Localization can improve:

  • Product comprehension
  • Onboarding completion
  • Accessibility
  • Transaction confidence
  • Customer-support efficiency
  • Adoption in new markets

However, translation alone cannot guarantee higher retention or conversions. Product relevance, translation quality, cultural expectations, support, payments, and legal requirements also influence market performance.

The practical reason to localize early is maintainability. Retrofitting it after hundreds of strings have been hard-coded is significantly more difficult than establishing a localization structure at the beginning.

How Flutter Selects a Locale

Flutter represents language preferences with the Locale class. A locale can contain a language code and, when necessary, a script or country code.

The device may provide a preference such as Canadian French. If the application supports that exact locale, Flutter can select it. If not, Flutter attempts to find an appropriate supported match.

The supportedLocales property is therefore more than documentation. It restricts the locales the application can resolve.

Flutter’s default resolution behaviour first looks for a suitable match. If it cannot find one, it falls back to the first locale in the supported list.

This makes the order and completeness of that list important. Applications with more complex requirements can provide custom locale-resolution logic.

Step-by-Step Flutter Localization Setup

The following implementation uses Flutter’s localization packages, ARB resources, and a generated localization class.

Step 1: Add the Localization Dependencies

The original dependency configuration is:

dependencies:
  flutter_localizations:
    sdk: flutter
  intl: ^0.18.1

Run:

flutter pub get

flutter_localizations provides localized strings and behaviour for Flutter’s built-in Material, Widgets, and Cupertino components. The intl package supports locale-aware message, date, number, and currency formatting.

Dependency Compatibility Note

The Flutter SDK can pin a specific compatible version of intl. The preserved ^0.18.1 constraint may be outdated for a current project and can produce dependency-resolution conflicts.

Before publishing this as installation guidance, verify the required version against the Flutter SDK used by the project. Avoid choosing an old intl version solely because it appears in an earlier tutorial.

Step 2: Enable Localization Code Generation

Flutter’s gen_l10n tool converts ARB resources into a typed Dart localization class.

The project must enable Flutter localization generation in pubspec.yaml. Teams can also add an l10n.yaml file when they need to configure the ARB directory, template file, generated class name, output location, untranslated-message report, or nullable lookup behaviour.

This generation step is missing from the original workflow. Without it, adding ARB files alone will not create AppLocalizations.

Current Flutter versions generate localization output into the project’s source tree rather than the old synthetic package:flutter_gen package.

After configuring generation, run the project’s normal Flutter build workflow so that the localization class is created.

Step 3: Configure Localization in MaterialApp

The original configuration provides Flutter’s built-in localization delegates and declares three supported locales:

import 'package:flutter_localizations/flutter_localizations.dart';

MaterialApp(
  localizationsDelegates: const [
    GlobalMaterialLocalizations.delegate,
    GlobalWidgetsLocalizations.delegate,
    GlobalCupertinoLocalizations.delegate,
  ],
  supportedLocales: const [
    Locale('en', ''), // English
    Locale('es', ''), // Spanish
    Locale('fr', ''), // French
  ],
  home: MyHomePage(),
);

These delegates localize framework-provided controls. For example, they supply translated labels and conventions used by Material and Cupertino widgets.

Important Completeness Note

The preserved snippet is not sufficient to load application messages generated from the ARB files. The generated AppLocalizations.delegate must also be included in localizationsDelegates.

Projects can also use the generated AppLocalizations.supportedLocales list instead of maintaining a separate manual list. This reduces the risk that ARB resources and application configuration drift apart.

The empty country-code strings in Locale('en', '') and similar entries are unnecessary in current Dart code, but they remain unchanged here because the developer’s original code is being preserved.

Step 4: Create the ARB Translation Files

Flutter stores Application Resource Bundle files commonly in a localization directory:

lib/
 └── l10n/
     ├── app_en.arb
     ├── app_es.arb
     └── app_fr.arb

Each ARB file contains the same message keys with values translated for its locale.

The English resource is:

{
  "@@locale": "en",
  "hello": "Hello",
  "welcome_message": "Welcome to our Flutter App!"
}

The Spanish resource is:

{
  "@@locale": "es",
  "hello": "Hola",
  "welcome_message": "¡Bienvenido a nuestra aplicación Flutter!"
}

Message keys should remain stable across locales. Changing a key requires updating the generated API and every place where the application uses it.

Let’s Build Your Flutter App Together!

Work with our expert team to turn your app idea into a fast, stunning Flutter product.

Choose keys that describe meaning rather than one language’s wording. A key such as checkoutPaymentFailed is easier to maintain than redErrorText.

Step 5: Access Localized Messages

The original application accesses the generated localization class through BuildContext:

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

Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text(AppLocalizations.of(context)!.hello),
    ),
    body: Center(
      child: Text(AppLocalizations.of(context)!.welcome_message),
    ),
  );
}

AppLocalizations.of(context) finds the localization resource associated with the nearest Localizations widget. MaterialApp creates that widget when its delegates and supported locales are configured correctly.

Current Flutter Import Note

The preserved import uses the legacy synthetic package:flutter_gen path. Current Flutter generates localization output into the application’s source directory.

The correct import depends on the configured output location and application package name. Consult the generated file rather than copying the old synthetic-package path into a new project.

Placeholders: Keep Dynamic Values Inside Messages

Applications often need messages such as:

  • “Welcome, Ramya”
  • “Your order will arrive on Tuesday”
  • “You saved ₹500”

Do not translate the static fragments separately and concatenate them in Dart. Sentence structure and word order vary between languages.

Instead, define one complete message with named placeholders in the ARB resource. Metadata can describe each placeholder’s type and meaning for translators and code generation.

Placeholders give translators control over where dynamic values appear. They also reduce punctuation and spacing errors caused by joining fragments manually.

Use descriptive placeholder names such as customerName, deliveryDate, or discountAmount, rather than value1.

Handle Pluralization Correctly

Pluralization is not simply a choice between adding or removing the letter “s.”

Languages can have zero, one, two, few, many, and other plural categories. Some languages use different grammatical forms depending on the number, while others do not distinguish singular and plural in the same way as English.

Flutter’s localization generation works with ICU message syntax to define plural variants inside ARB messages. The generated method then accepts a count and selects the correct translation for the active locale.

Do not implement pluralization with conditions such as “if count equals one, otherwise use plural.” That logic will not scale reliably beyond English-like rules.

Plural messages should also include the count as a placeholder when users need to see it.

Format Dates, Numbers, and Currencies by Locale

Translation changes words. Localization also changes how values are displayed.

ValuePossible variation
Date08/04/2026, 04/08/2026, 4 Aug 2026
Decimal1,234.50, 1.234,50
Currency$1,299.00, 1 299,00 €, ₹1,299
PercentageSymbol placement and spacing
Time12-hour or 24-hour convention
Compact number1.2K, 1,2 k, locale-specific alternatives
Date
Possible variation
08/04/2026, 04/08/2026, 4 Aug 2026
1 of 6

Avoid assembling these values with manual punctuation or currency symbols. Use locale-aware formatters so grouping, decimals, symbols, and text follow regional conventions.

The application’s language does not always determine currency. A user may use an English interface while paying in Indian rupees. Treat locale, currency, and business region as related but separate decisions.

Design for Longer and Shorter Translations

Translated text rarely occupies the same space as the source language.

A compact English button label may become significantly longer in German or French. Other languages may require different line heights, word-breaking behaviour, or fonts.

Avoid fixed-width containers around translated text unless the design has been tested with the longest supported values. Prefer layouts that can expand, wrap, or reposition elements.

Test:

  • Buttons
  • Tabs
  • Dialog titles
  • Error messages
  • Form labels
  • Navigation items
  • Empty states
  • Notifications
  • Small devices
  • Large accessibility text

Do not solve overflow by reducing every translation’s font size. If the text becomes unreadable, the layout has not truly adapted.

Support Right-to-Left Languages

Languages such as Arabic and Hebrew use right-to-left reading direction.

Flutter can adapt many directional widgets based on the active locale, but layouts must use directional properties correctly. Concepts such as “start” and “end” adapt to text direction; hard-coded “left” and “right” values do not.

Review more than text alignment. Direction can affect:

  • Navigation
  • Row order
  • Padding
  • Back arrows
  • Progress indicators
  • Charts
  • Icons with directional meaning
  • Swipe gestures
  • Mixed-language content

Not every asset should be mirrored. Logos, media controls, clocks, and universally recognized symbols may need to retain their original direction.

Some markets require more than translated UI strings.

Localization may also include:

  • Illustrations containing text
  • Screenshots and tutorials
  • Legal agreements
  • Privacy notices
  • Support information
  • Promotional banners
  • App-store descriptions
  • Store screenshots
  • Email and notification templates
  • Help-centre content

Flutter’s asset system can support localized resources, but the project still needs a content workflow for creating, reviewing, and releasing them.

Avoid embedding text inside images where possible. Separate text is easier to translate, scale, search, and expose to assistive technologies.

Let Users Select a Language When Appropriate

By default, an internationalized Flutter application can follow the device locale. This is convenient but may not match every product requirement.

A language selector is valuable when:

  • Users frequently switch languages
  • The device is shared
  • The user prefers a language different from the system setting
  • The app serves travelers or multilingual communities
  • Account preferences must synchronize across devices

When the user explicitly chooses a language, store the preference and decide whether it belongs only on the device or in the user’s account.

Also provide a clear way to return to the system default. Do not force users to reinstall the app to correct an accidental language choice.

Testing Localization in Flutter

The original example forces Spanish temporarily:

MaterialApp(
  locale: const Locale('es', ''),
  // ...other properties
);

This is useful for manually verifying a particular locale, but it should not be the only testing method.

A complete localization test should cover three separate areas.

Translation Completeness

Verify that every supported locale contains the required keys. Localization generation can surface missing messages, and the project can produce a report of untranslated resources.

Functional Behaviour

Widget tests should render important screens under representative locales and verify that the expected localized messages appear.

Test locale switching if the application supports an in-app selector. Also confirm that the selected locale persists correctly and that unsupported locales follow the intended fallback.

Visual Quality

Review the app on actual target screen sizes with:

  • Long translations
  • Right-to-left scripts
  • Large text scaling
  • Different date and currency values
  • Empty and error states
  • Keyboard-visible layouts

Golden tests can help detect visual changes, but they should complement human linguistic and cultural review rather than replace it.

Translation Workflow for Growing Teams

Editing ARB files manually can work for a small application, but larger products need a defined translation process.

A sustainable workflow normally includes:

  1. Developers add or modify the source message and its metadata.
  2. New strings are sent to translators or a translation-management system.
  3. Translators receive context, screenshots, character constraints, and placeholder descriptions.
  4. Localized ARB files return to the repository.
  5. Generation and automated checks run.
  6. Linguistic and visual QA review the feature in the app.
  7. Approved translations ship with the release.

Let’s Build Your Flutter App Together!

Work with our expert team to turn your app idea into a fast, stunning Flutter product.

Avoid using machine translation as the only review process for legal, financial, medical, safety, or transactional content.

Translation memory and a terminology glossary help keep repeated product terms consistent across screens and releases.

Flutter Localization Best Practices

1. Never Hard-Code User-Facing Strings

Buttons, errors, validation messages, empty states, accessibility labels, notifications, and dialog text should all use the localization system.

2. Avoid Sentence Concatenation

Translate complete messages and insert dynamic values through placeholders. This allows each language to choose its own word order.

3. Keep Message Keys Stable

Changing keys creates unnecessary work for developers and translators. Rename them only when the underlying meaning has changed.

4. Add Translator Context

ARB metadata should explain where a message appears, what it means, and how placeholders are used. A word such as “Save” can mean preserving data or reducing money; translators need to know which meaning applies.

5. Plan Locale Fallbacks

Decide whether regional variants should fall back to the base language and which language appears when no supported match exists.

6. Test Pseudolocalized Content

Pseudolocalization expands and alters source text to expose hard-coded strings, clipping, and layout assumptions before actual translations are complete.

7. Keep Formatting Out of Widgets

Centralize date, number, and currency formatting rather than repeating formatting decisions across screens.

Common Localization Mistakes

Translating Only Visible Screen Text

Validation messages, accessibility labels, notifications, emails, server errors, and app-store content are also part of the user experience.

Assuming Language Equals Country

English is used across several regions with different currencies and date formats. Likewise, one country may contain users who prefer several languages.

Using One Fixed Layout for Every Locale

Text length, reading direction, font metrics, and line breaks vary. Responsive layout is part of localization engineering.

Trusting Raw Machine Translation

A grammatically valid translation may still use the wrong product term, tone, or cultural context. Important content requires human review.

Ignoring Server-Generated Messages

If the backend returns user-visible English errors, localizing only the Flutter client creates an inconsistent experience. Prefer stable error codes that the client can map to localized messages where appropriate.

Treating Launch as the End

Every new feature introduces new strings and states. Localization must remain part of the regular design, development, translation, and QA workflow.

Frequently Asked Questions

1. What is the difference between i18n and l10n in Flutter?

Internationalization prepares the Flutter codebase for multiple languages and regional formats. Localization supplies the translated messages, formatting rules, assets, and behaviour for a specific locale.

2. Does Flutter translate app content automatically?

No. Flutter provides localization infrastructure and translations for its built-in widgets. Product-specific text must be translated and supplied through resources such as ARB files.

3. What are ARB files in Flutter?

ARB files are JSON-based localization resources containing message keys, translated values, locale information, and optional metadata for descriptions, placeholders, pluralization, and formatting.

4. Does a Flutter app need the intl package?

Flutter localization workflows commonly use intl for messages and locale-aware formatting. Use the version compatible with the active Flutter SDK rather than copying an old version constraint.

5. How does Flutter choose the user’s language?

Flutter compares the device’s preferred locales with the app’s supportedLocales. It selects the closest supported match and falls back according to its locale-resolution rules when no exact match exists.

6. Can users change the language inside a Flutter app?

Yes. The app can set its locale from a stored user preference. The product should also decide whether the preference is local to one device or synchronized through the user’s account.

7. How do I support right-to-left languages in Flutter?

Declare the locale correctly, use directional layout properties such as start and end, provide suitable fonts, review directional icons, and test complete workflows under an RTL locale.

8. How should plurals be translated?

Use ICU plural messages in the localization resources. Do not manually apply English singular-versus-plural rules because languages use different plural categories.

Conclusion

Flutter internationalization and localization are not simply mechanisms for replacing strings. They provide the foundation for adapting language, formatting, layout, direction, assets, and content to different users.

A maintainable implementation begins by generating typed localization classes from structured ARB resources. It keeps messages out of widgets, uses placeholders instead of sentence concatenation, formats values by locale, and declares clear supported-locale and fallback behaviour.

The work continues beyond development. Translations need context and review, interfaces must support text expansion and right-to-left layouts, and every new feature must enter the same localization workflow.

When multilingual support is built into the product from the beginning, expanding to another language becomes a controlled content and quality process rather than a codebase-wide repair project.

Author-Taha

Flutter Dev @ F22 Labs, solving mobile app challenges with a cup of coffee and a passion for crafting elegant solutions. Let's build something amazing together!

Share this article

Phone

Next for you

8 Best GraphQL Libraries for Node.js in 2025 Cover

Technology

Aug 4, 202613 min read

8 Best GraphQL Libraries for Node.js in 2025

8 Best GraphQL Libraries for Node.js in 2026 Too Long? Read This First - Choose Apollo Server when you need a mature ecosystem, GraphOS integration, plugins, or Apollo Federation. - Choose GraphQL Yoga for a modern, portable server with Fetch API compatibility and built-in support for subscriptions over Server-Sent Events. - Choose Mercurius when your application already uses Fastify and runtime efficiency is a major priority. - Use GraphQL.js when you need the official JavaScript implementati

9 React Native Animation Libraries and Tools Compared Cover

Technology

Aug 4, 202615 min read

9 React Native Animation Libraries and Tools Compared

Too Long? Read This First - Use React Native Reanimated for gesture-driven, interruptible, and performance-sensitive interface animations. - Use the built-in Animated API for simple fades, transforms, and timed sequences without another dependency. - Pair React Native Gesture Handler with Reanimated for swipes, dragging, pinching, rotation, and other touch-driven experiences. - Use Lottie React Native for non-interactive motion graphics supplied by designers. - Choose React Native Skia for cust

9 Critical Practices for Secure Web Application Development Cover

Technology

Aug 4, 202616 min read

9 Critical Practices for Secure Web Application Development

Too Long? Read This First - Define security requirements and model threats before implementation begins. - Treat authentication, account recovery, and MFA as one complete identity system. - Apply server-side authorization to every protected action and object. - Prevent injection with parameterized APIs, structured validation, safe output handling, and restricted outbound requests. - Protect sessions and tokens throughout their complete lifecycle. - Minimise sensitive data and manage encryption