Internationalization (i18n) has become a critical consideration for mobile app developers targeting global audiences. Flutter developers have multiple options for implementing multilingual support, but easy_localization stands out as one of the most popular and feature-rich solutions in the Flutter ecosystem. With over 166,000 weekly downloads and 3,750+ likes on pub.dev, this package has earned the trust of developers building cross-platform applications that serve users across different languages and regions.
This comprehensive guide explores how to leverage easy_localization to transform your Flutter application into a truly global product. We'll cover everything from initial setup to advanced features like pluralization, gender support, and code generation, providing you with the knowledge needed to implement professional-grade internationalization in your mobile apps. Our mobile development team specializes in building Flutter applications that scale globally.
Why Choose Easy Localization for Flutter Internationalization
The easy_localization package offers a compelling set of features that address the common pain points developers face when implementing multilingual support in their Flutter applications.
Easy localization provides everything you need for professional Flutter internationalization
Easy Multi-Language Support
Load translations from JSON, CSV, YAML, or XML files with a simple, intuitive API that minimizes boilerplate code.
Persistent Locale Changes
Automatically save and restore user language preferences across app sessions using shared_preferences.
Pluralization & Gender
Handle complex grammatical rules including plural forms, gender agreement, and nested translations automatically.
RTL Language Support
Full support for right-to-left languages like Arabic and Hebrew with automatic layout mirroring.
Code Generation
Generate type-safe translation keys with IDE autocomplete for faster, error-free development.
Fallback Translations
Graceful degradation when translations are missing, with configurable fallback locale support.
Installation and Initial Setup
Getting started with easy_localization involves adding the package to your Flutter project and configuring the basic structure for translation files. This section walks through each step of the setup process to ensure a smooth implementation.
Adding the Dependency
First, add easy_localization to your project's pubspec.yaml file. The package follows semantic versioning, so you can specify a caret constraint to receive non-breaking updates automatically:
dependencies:
easy_localization: ^3.0.8
After updating your pubspec, run flutter pub get to download the package and make it available in your project.
Creating the Translation File Structure
Easy localization expects translation files to reside in a dedicated assets directory:
assets/
└── translations/
├── en.json
├── en-US.json
├── es.json
└── es-MX.json
The package supports both language codes (en.json) and full locale codes (en-US.json), allowing you to provide region-specific translations when necessary.
Declaring Assets in Pubspec
Make the translation files accessible to your Flutter application:
flutter:
assets:
- assets/translations/
Platform-Specific Configuration for iOS
When deploying to iOS, you must declare supported locales in Info.plist:
<key>CFBundleLocalizations</key>
<array>
<string>en</string>
<string>es</string>
<string>ar</string>
</array>
Configuring the Easy Localization Widget
The easy_localization package centers around a widget that wraps your entire application and manages locale state throughout the app lifecycle.
Basic Widget Configuration
Wrap your app with the EasyLocalization widget in your main.dart file:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await EasyLocalization.ensureInitialized();
runApp(
EasyLocalization(
supportedLocales: [Locale('en', 'US'), Locale('de', 'DE')],
path: 'assets/translations',
fallbackLocale: Locale('en', 'US'),
child: MyApp()
),
);
}
Understanding Widget Properties
The EasyLocalization widget accepts several configuration options:
| Property | Default | Description |
|---|---|---|
saveLocale | true | Automatically persists user's language preference |
useFallbackTranslations | false | Uses fallback locale for missing translations |
useOnlyLangCode | false | Uses only language code for file matching |
Integrating with MaterialApp
Your MaterialApp widget must use the delegates provided by easy_localization:
return MaterialApp(
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
home: MyHomePage()
);
Creating and Organizing Translation Files
Translation files form the foundation of your app's multilingual support.
JSON Translation File Structure
Translation files use JSON format with key-value pairs:
{
"app_title": "My Application",
"welcome_message": "Welcome to our app!",
"settings": {
"title": "Settings",
"dark_mode": "Dark Mode",
"language": "Language"
},
"button": {
"submit": "Submit",
"cancel": "Cancel",
"save": "Save"
}
}
Nested objects create hierarchical key paths like settings.title, settings.dark_mode, and button.submit.
Supporting Multiple Languages
Create separate JSON files for each language:
assets/translations/en.json- Englishassets/translations/es.json- Spanishassets/translations/fr.json- Frenchassets/translations/ar.json- Arabic (RTL support)
Each file should contain the same keys with appropriate translations for that language.
Core Translation Functions and Usage
Basic Translation with context.tr()
The tr() method is the primary function for accessing translations:
Text(context.tr('welcome_message'))
This method properly rebuilds widgets when the locale changes.
Static Translation Functions
For situations without a BuildContext, use static functions:
var greeting = tr('welcome_message');
print('welcome_message'.tr());
Text Widget Extension
The package extends the Text widget for convenience:
Text('welcome_message').tr()
Text('welcome_message').tr(
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)
)
Arguments and Placeholders in Translations
Positional Arguments with {}
The args parameter replaces {} placeholders left to right:
{
"msg": "{} are written in the {} language"
}
Text('msg').tr(args: ['Easy localization', 'Dart'])
// Output: "Easy localization are written in the Dart language"
Named Arguments with {key}
The namedArgs parameter uses a map of key-value pairs:
{
"msg_named": "Easy localization is written in the {lang} language"
}
Text('msg_named').tr(namedArgs: {'lang': 'Dart'})
// Output: "Easy localization is written in the Dart language"
Combining Arguments
You can combine positional and named arguments:
{
"msg_mixed": "{} are written in the {lang} language"
}
Text('msg_mixed').tr(
args: ['Easy localization'],
namedArgs: {'lang': 'Dart'}
)
Implementing Pluralization
Different languages handle plural forms differently. Easy localization provides the plural() function to handle these complexities.
Basic Plural Usage
Define plural forms in your JSON file using special keys:
{
"items": {
"zero": "No items",
"one": "{} item",
"two": "{} items",
"few": "{} items",
"many": "{} items",
"other": "{} items"
}
}
Text('items').plural(1) // "1 item"
Text('items').plural(2) // "2 items"
Text('items').plural(0) // "No items"
The other key is required for all plural entries and serves as a fallback.
Number Formatting in Plurals
The plural function supports number formatting:
Text('items').plural(
1000000,
format: NumberFormat.compact(locale: context.locale.toString())
)
// Output: "1M items"
Plural with Arguments
Combine pluralization with arguments for complex translations:
{
"money_args": {
"zero": "{} has no money",
"one": "{} has {} dollar",
"other": "{} has {} dollars"
}
}
Text('money_args').plural(10, args: ['John', '10'])
// Output: "John has 10 dollars"
Gender Support in Translations
Implementing Gender-Based Translations
Define gender variants in your translation file:
{
"greeting": {
"male": "Hello, Mr. {}",
"female": "Hello, Ms. {}",
"other": "Hello, {}"
}
}
Text('greeting').tr(gender: 'female', args: ['Sarah'])
// Output: "Hello, Ms. Sarah"
The gender value is a string that corresponds to keys within the gender object.
Linked Translations
When the same translation appears in multiple places, linked translations allow you to reference one key from another.
Basic Linked Translations
Prefix the linked key with @: to create a reference:
{
"example": {
"hello": "Hello",
"world": "World!",
"helloWorld": "@:example.hello @:example.world"
}
}
print('example.helloWorld'.tr())
// Output: "Hello World!"
Case Modifiers for Linked Translations
Linked messages support modifiers for case transformations:
{
"example": {
"fullName": "Full Name",
"emptyNameError": "Please fill in your @.lower:example.fullName"
}
}
print('example.emptyNameError'.tr())
// Output: "Please fill in your full name"
Available modifiers: upper, lower, capitalize.
Locale Management and Switching
Changing the Current Locale
Use setLocale() to change the app's locale:
context.setLocale(Locale('es', 'MX'));
Getting the Current Locale
Access the current locale through the locale property:
print(context.locale.toString()); // Output: "es_MX"
Resetting to System Locale
Allow users to reset to their device's default language:
ElevatedButton(
onPressed: () {
context.resetLocale();
},
child: Text('settings.reset_language').tr(),
)
Accessing Device Locale
Get the device's default locale:
print(context.deviceLocale.toString()); // Output: "en_US"
Code Generation for Type-Safe Translations
Code generation eliminates string-based key references, providing compile-time safety and IDE autocomplete.
Generating Translation Keys
flutter pub run easy_localization:generate -f keys -o lib/generated/locale_keys.g.dart
This generates a LocaleKeys class with static getters for each translation key:
import 'generated/locale_keys.g.dart';
Text(LocaleKeys.welcome_message.tr())
Generating Codegen Loader
For improved performance, generate a code-based asset loader:
flutter pub run easy_localization:generate -f json -o lib/generated/codegen_loader.g.dart
runApp(
EasyLocalization(
child: MyApp(),
supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')],
path: 'resources/langs',
assetLoader: CodegenLoader()
),
);
Auditing Missing Keys
Identify translation keys that exist in your code but are missing from translation files:
flutter pub run easy_localization:audit
RTL Language Support
Supporting right-to-left languages like Arabic and Hebrew requires both translation files and proper widget layout handling.
RTL Translation Files
Create separate translation files for RTL languages:
{
"items": {
"zero": "لا عناصر",
"one": "عنصر واحد",
"two": "عنصران",
"few": "{} عناصر",
"many": "{} عنصر",
"other": "{} عنصر"
}
}
Enabling Full Plural Rules
By default, easy_localization ignores few and many plural categories. Enable them for languages that require these:
EasyLocalization(
ignorePluralRules: false,
supportedLocales: [Locale('ar'), Locale('en')],
path: 'assets/translations',
fallbackLocale: Locale('en'),
child: MyApp()
)
Setting ignorePluralRules: false enables proper handling of all plural forms, essential for Arabic, Russian, Polish, and other languages with complex pluralization rules.
Best Practices for Flutter Internationalization
Keep Translations Separate from Code
Never embed translated strings directly in widget code. Always use translation keys, even for a single language. This approach ensures your codebase is ready for additional languages and keeps all translation management centralized in one place.
Use Descriptive Key Names
Translation keys should be descriptive enough that developers and translators understand their purpose. Use names like welcome_message or settings_dark_mode rather than abbreviations like t1 or msg2. Clear naming conventions make your codebase more maintainable and reduce errors when adding new translations.
Plan for Text Expansion
Translations in some languages, particularly German, can be significantly longer than English source text. Design your UI layouts with text expansion in mind, avoiding fixed-width containers that might truncate translated strings. Consider flexible layouts that adapt to different text lengths.
Test All Supported Languages
Verify your app in all supported languages, especially RTL languages and languages with complex plural forms. Pay attention to layout issues, truncated text, and proper number, currency, and date formatting. Regular testing across all supported locales ensures a consistent user experience.
Consider Translation Management
For large projects with many languages, consider using translation management platforms like Crowdin, Lokalise, or Phrase. These services provide collaborative interfaces for translators and can sync translations with your codebase, streamlining the localization workflow. Implementing proper SEO services alongside your internationalization strategy ensures your multilingual app reaches global audiences effectively.
Conclusion
Easy localization provides a powerful yet approachable solution for implementing internationalization in Flutter applications. Its combination of JSON-based translation files, intuitive APIs, and robust feature set makes it an excellent choice for projects of any size.
By following the practices outlined in this guide--using proper key organization, leveraging pluralization and gender support, implementing code generation for type safety, and thoroughly testing RTL languages--you can build Flutter applications that serve users worldwide with localized, culturally appropriate experiences.
Our mobile development team has extensive experience building multilingual Flutter applications that scale globally. Whether you're launching your first cross-platform app or expanding an existing product to new markets, we can help you implement professional-grade internationalization that delivers seamless experiences to users around the world. Partner with our web development specialists to create a cohesive digital presence that resonates with international audiences across all platforms.
Frequently Asked Questions
What is the difference between flutter_localizations and easy_localization?
flutter_localizations is the official Flutter package that provides localization delegates for Material and Cupertino widgets. easy_localization is a third-party package that simplifies the translation workflow with JSON files and intuitive APIs. Easy localization builds on top of flutter_localizations to provide a more developer-friendly experience.
How do I add a new language to my app?
Create a new JSON file in your translations directory (e.g., assets/translations/fr.json for French), add all the translation keys with French values, and add the locale to the supportedLocales list in your EasyLocalization widget configuration.
Can I use easy_localization with Flutter web?
Yes, easy_localization fully supports Flutter web. The package works across all Flutter platforms including iOS, Android, web, macOS, Windows, and Linux.
How do I handle missing translations gracefully?
Enable useFallbackTranslations in your EasyLocalization configuration to fall back to a default locale when translations are missing. You can also customize the errorWidget to display a user-friendly message when translation loading fails.
Does easy_localization support currency and date formatting?
Easy localization provides the foundation for translations, while the underlying intl package handles locale-specific formatting. Use NumberFormat from the intl package with the current locale to format currencies, dates, and numbers according to local conventions.
Sources
- Easy Localization Flutter Package - Official package documentation with features, configuration options, and code examples
- Flutter intl Package Guide - Comprehensive guide covering internationalization best practices and Flutter localization fundamentals