Mastering Localization in Flutter: A Comprehensive Guide

Localization in Flutter allows you to build apps adapting to different languages, regions, and cultures. Localizing your app allows you to reach a wider audience and provide a more personalized user experience. This guide will cover everything you need to know about localization in Flutter, including a detailed explanation of the process and example code.

What is Localization?

Localization is the process of adapting an application’s interface and functionality to a specific language or culture. This includes translating text, formatting dates and numbers, and ensuring the app complies with the cultural norms of different regions.

Why is Localization Important?

  • User Experience: Users are more comfortable using an app in their native language.
  • Market Reach: Localizing your app allows you to target a global audience.
  • Compliance: Some regions have legal requirements for supporting local languages.
  • Monetization: Localizing your app can help in monetizing your app in new markets.

Localization in Flutter

Flutter provides robust support for localization through its flutter_localizations package, allowing you to localize text, dates, numbers, and more. You can also use the intl package to manage translations and formatting.

Related read: Localization with React Native i18n: A Comprehensive Guide

Step-by-Step Guide to Localize a Flutter App

1. Add Dependencies

To start with localization in Flutter, you need to include the necessary packages in your pubspec.yaml file:

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations: # Provides localization framework for Flutter
    sdk: flutter
   intl: ^0.17.0 # Helps with localization of strings, numbers, dates, etc.

The flutter_localizations package provides localization for Flutter’s built-in widgets. The intl package is used for message formatting and localization in your app.

2. Define Supported Locales

In your MaterialApp, you need to define the locales (languages) that your app will support. Each locale is defined by a languageCode and optionally a countryCode.

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Localization',
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
        // Add custom localization delegate here later
      ],
      supportedLocales: [
        const Locale('en', ''), // English
        const Locale('es', ''), // Spanish
        const Locale('fr', ''), // French
      ],
      home: MyHomePage(),
    );
  }
}

The localizationsDelegates list includes default Flutter localization delegates for widgets and material components.

3. Create Language Files

Now you need to provide the actual translations for different languages. This can be done using JSON files that map keys to translated strings.

Create a directory for localization files under lib/l10n and add your JSON files for each language:

lib/l10n/en.json (English):

{
  "title": "Welcome",
  "message": "Hello, how are you?"
}

lib/l10n/es.json (Spanish):

{
  "title": "Bienvenido",
  "message": "Hola, ¿cómo estás?"
}

lib/l10n/fr.json (French):

{
  "title": "Bienvenue",
  "message": "Bonjour, comment ça va?"
}

Each key in these JSON files corresponds to a text string used in the app, while the value is the localized translation.

4. Create a Localization Class

You need a helper class to load the JSON files and retrieve the localized strings. Create a new Dart file lib/localization.dart:

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class AppLocalizations {
  final Locale locale;

  AppLocalizations(this.locale);

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

  static const LocalizationsDelegate<AppLocalizations> delegate = _AppLocalizationsDelegate();

  Map<String, String> _localizedStrings;

  Future<bool> load() async {
    String jsonString = await rootBundle.loadString('lib/l10n/${locale.languageCode}.json');
    Map<String, dynamic> jsonMap = json.decode(jsonString);

    _localizedStrings = jsonMap.map((key, value) {
       return MapEntry(key, value.toString());
    });

    return true;
  }

  String translate(String key) {
    return _localizedStrings[key] ?? key;
  }
}

class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
  const _AppLocalizationsDelegate();

  @override
  bool isSupported(Locale locale) {
    return ['en', 'es', 'fr'].contains(locale.languageCode);
  }

  @override
  Future<AppLocalizations> load(Locale locale) async {
    AppLocalizations localizations = AppLocalizations(locale);
    await localizations.load();
    return localizations;
  }

  @override
  bool shouldReload(covariant LocalizationsDelegate<AppLocalizations> old) {
    return false;
  }
}

In this class:

  • load() loads the appropriate JSON file based on the locale.
  • translate() retrieves the localized string using the key from the JSON file.

Optimize Your Flutter App for Global Users – Learn How

5. Register the Localization Delegate

In your MaterialApp, register the custom AppLocalizations delegate and update the localizationsDelegates list:

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'localization.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Localization',
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
        AppLocalizations.delegate, // Custom localization delegate
      ],
      supportedLocales: [
        const Locale('en', ''), // English
        const Locale('es', ''), // Spanish
        const Locale('fr', ''), // French
      ],
      home: MyHomePage(),
    );
  }
}

This registers the AppLocalizations delegate and enables it to load the correct localization data for the current locale.

6. Use Localized Strings in Widgets

Now, instead of hardcoding strings, use the AppLocalizations class to retrieve localized text in your widgets:

import 'package:flutter/material.dart';
import 'localization.dart';

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var localization = AppLocalizations.of(context);

    return Scaffold(
      appBar: AppBar(
        title: Text(localization.translate('title')),
      ),
      body: Center(
        child: Text(localization.translate('message')),
      ),
    );
  }
}

7. Testing Localization

To test how your app looks in different languages, you can manually change the locale in your app by overriding the Locale in the MaterialApp:

return MaterialApp(
  locale: Locale('es', ''), // Spanish
  ...
);

Alternatively, if your device’s language settings change, Flutter will automatically load the appropriate localization.

Advanced: Handling Pluralization and Variables

The intl package is great for handling more complex scenarios, like pluralization and variables in strings.

Example:

en.json

{
  "remainingEmails": "{count, plural, one {You have one email} other {You have {count} emails}}"
}

To display this in your app:

import 'package:intl/intl.dart';

String emailsMessage(int count) {
  return Intl.plural(count,
    one: 'You have one email',
    other: 'You have $count emails',
    locale: 'en',
  );
}

Best Practices for Localization in Flutter

  • Avoid Hardcoding Strings: Always use keys for text that needs to be translated.
  • Plan for Text Expansion: Some languages take up more space than others, so ensure your UI can accommodate longer strings.
  • RTL Support: For languages like Arabic and Hebrew, Flutter automatically handles RTL (Right-To-Left) layouts.
  • Test Regularly: Test your app in different locales to ensure everything looks and works correctly.
coma

Conclusion

Localization is a critical step in the development process, especially if your app is intended to reach a global audience. By localizing your Flutter app, you not only make it accessible to people from different linguistic and cultural backgrounds, but you also enhance user engagement and satisfaction by creating an experience that feels native to them.

In this guide, we’ve walked through the process of setting up localization in Flutter using JSON files, a custom localization class, and Flutter’s intl package for handling translations, pluralization, and formatting. We also covered how to integrate these translations into your widgets and offered best practices to ensure that your app is user-friendly across multiple languages.

By properly localizing your app, you’re doing more than just translating text — you’re respecting cultural differences, accommodating varying layouts (especially for RTL languages), and ensuring that every user, regardless of their language or region, can interact with your app seamlessly. Implementing localization can also make a significant difference in expanding your app’s reach to new markets, improving its adoption rate, and enhancing user retention.

Nandkishor S

Software Engineer

Nandkishor Shinde is a React Native Developer with 5+ years of experience. With a primary focus on emerging technologies like React Native and React.js. His expertise spans across the domains of Blockchain and e-commerce, where he has actively contributed and gained valuable insights. His passion for learning is evident as he always remains open to acquiring new knowledge and skills.

Keep Reading

Keep Reading

  • Service
  • Career
  • Let's create something together!

  • We’re looking for the best. Are you in?