Implementing Localization in Flutter

 In today's globalized world, app localization has become an essential aspect of software development. By providing translations and adapting to different languages and regions, you can reach a wider audience and enhance user experience. If you're developing a Flutter app and want to add localization support, you've come to the right place. In this blog post, we'll guide you through the process of implementing localization in a Flutter app.

Localization_Screen


Folder Structure

Before we dive into the code, let's discuss the recommended folder structure for managing localization files in a Flutter project:

- lib
  - l10n
    - app_localizations.dart
    - app_localizations_delegate.dart
    - locales
      - locale_en.dart
      - locale_ta.dart
  - main.dart

In the above structure, we have a `l10n` folder that contains the localization-related files. Inside the `l10n` folder, we have the following files:

  • - `app_localizations.dart`: This file defines the `AppLocalizations` class, which handles the translations based on the selected locale.
  • - `app_localizations_delegate.dart`: This file implements the `LocalizationsDelegate` class and loads the appropriate translations based on the selected locale.
  • - `locales` folder: This folder contains the individual locale files (`locale_en.dart` and `locale_ta.dart`). These files define the translations for each supported language.

Now that we have the folder structure in place, let's dive into the code.

https://www.linkedin.com/in/pradeepkumarradhakrishnan/


Code Implementation

main.dart

In the `main.dart` file, we start by importing the necessary dependencies:

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

Next, we define the `MyApp` widget, which is the entry point of our application. This widget represents the root of the widget tree and sets up the localization configuration. Here's the code:

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

In the `MyAppState` class, we define a `_locale` variable of type `Locale` to keep track of the currently selected locale. By default, we set it to English (United States).

In the `build` method of `MyAppState`, we create a `MaterialApp` widget and configure it with the following properties:

  • - `color`: Sets the primary color of the app to orange.
  • - `localizationsDelegates`: Specifies the list of localization delegates required for the app.
  • - `supportedLocales`: Defines the list of supported locales, including English (United States) and Tamil (India).
  • - `locale`: Sets the current locale based on the `_locale` variable.
  • - `title`: Sets the title of the app.
  • - `home`: Sets the home page of the app to `HomePage`, which we'll define later.

class _MyAppState extends State<MyApp> {
  Locale _locale = const Locale('en', 'US');

We also define a private method `_changeLocale` that updates the `_locale` variable whenever the user switches the language. This method will be passed as a callback to the `HomePage` widget.

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      color: Colors.orange,
      localizationsDelegates: const [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        AppLocalizations.delegate,
      ],
      supportedLocales: const [
        Locale('en', 'US'),
        Locale('ta', 'IN'),
      ],
      locale: _locale,
      title: 'Localization Demo',
      home: HomePage(
        onLocaleChange: _changeLocale,
      ),
    );
  }

app_localizations.dart

In the `app_localizations.dart` file, we define the `AppLocalizations` class, which handles the translations for different locales. Here's the code:

  void _changeLocale(Locale locale) {
    setState(() {
      _locale = locale;
    });
  }
}

The `AppLocalizations` class has the following important components:

  • - A constructor that takes a `locale` parameter and assigns it to the `locale` instance variable.
  • - A static method `of` that retrieves the `AppLocalizations` instance from the widget tree.
  • - A `load` method that loads the translation JSON file based on the provided locale and returns an `AppLocalizations` instance.
  • - `greeting` and `switchLanguage` methods that return the translated strings based on the current locale.

app_localizations_delegate.dart

In the `app_localizations_delegate.dart` file, we implement the `LocalizationsDelegate` class to handle the loading and retrieval of translations. Here's the code:

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();

  static Future<AppLocalizations> load(Locale locale) async {
    final jsonString = await rootBundle
        .loadString('assets/locale_${locale.languageCode}.json');
    final Map<String, dynamic> jsonMap = json.decode(jsonString);

    return AppLocalizations(locale);
  }




  String get greeting {
    switch (locale.languageCode) {
      case 'ta':
        return 'வணக்கம்!';
      case 'en':
      default:
        return 'Hello!';
    }
  }

  String get switchLanguage {
    switch (locale.languageCode) {
      case 'ta':
        return 'Switch to English!';
      case 'en':
      default:
        return 'தமிழில் மாற்று!';
    }
  }
}

The `_AppLocalizationsDelegate` class overrides the following methods:

  • - `isSupported`: Checks if the provided locale is supported by the app. In our case, we support English (en) and Tamil (ta).
  • - `load`: Loads the translations based on the provided locale by calling the `load` method in `app_localizations.dart`.
  • - `shouldReload`: Determines if the delegate should reload when the app state changes. In this case, we always return `false` since our translations won't change during runtime.
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/l10n/app_localizations.dart';

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

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

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

  @override
  bool shouldReload(_AppLocalizationsDelegate old) => false;
}

HomePage Widget

In the `home_page.dart` file, we define the `HomePage

` widget, which represents the main page of our app. Here's the code:

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

class HomePage extends StatefulWidget {
  final Function(Locale) onLocaleChange;

  const HomePage({required this.onLocaleChange});

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  AppLocalizations? _appLocalizations;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _appLocalizations = AppLocalizations.of(context);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Localization Demo'),
        backgroundColor: Colors.orange,
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              _appLocalizations!.greeting,
              style: const TextStyle(fontSize: 24, color: Colors.blueGrey),
            ),
            const SizedBox(height: 16),
            ElevatedButton(
              style: ElevatedButton.styleFrom(
                backgroundColor:
                    Colors.orange, // Set the background color to orange
              ),
              onPressed: () {
                if (_appLocalizations!.locale.languageCode == 'ta') {
                  widget.onLocaleChange(const Locale('en', 'US'));
                } else {
                  widget.onLocaleChange(const Locale('ta', 'IN'));
                }
              },
              child: Text(_appLocalizations!.switchLanguage),
            ),
          ],
        ),
      ),
    );
  }
}

In the `HomePage` widget, we have the following components:

  • - A constructor that takes an `onLocaleChange` callback function as a parameter. This callback function is called when the user switches the language.
  • - The `didChangeDependencies` method, which is called when the widget is initialized or when the dependencies change. Here, we retrieve the `AppLocalizations` instance using the `of` method.
  • - The `build` method, which builds the UI of the home page. It displays a greeting text and a button to switch the language. The text and button label are obtained from the `AppLocalizations` instance.

Conclusion

In this blog post, we walked through the process of implementing localization in a Flutter app. We discussed the folder structure and provided the code for setting up localization support. By following these steps, you can easily add translations to your Flutter app and provide a localized experience for your users.

Comments

Popular posts from this blog

Error Handling in Flutter - Gradle issue

How to Make a Dynamic and Trending ListView with Flutter Widgets?

Understanding API integration with Getx State management