What is Internationalization and Localization?

Internationalization (i18n) is the process of designing an app so that it can be easily localized (L10n) for different languages and cultures. Localization involves translating the text, images, and other resources in your app into different languages.

In a Flutter app, you can achieve internationalization and localization by defining string resources in a specific format and then loading the appropriate resources based on the user’s language preference.

Step-by-Step Guide

Here are the steps to implement internationalization and localization in a Flutter app:

Step 1: Add dependencies

In your app’s pubspec.yaml file, add the following dependencies:

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  intl: ^0.17.0

The flutter_localizations package provides the built-in localization support for Flutter, while the intl package provides the tools for internationalization.

Step 2: Define your string resources

Create a new directory in your project’s root directory called i18n. Inside this directory, create a file called messages_en.arb (replace en with the appropriate language code for your base language). This file will contain the string resources for your app in the base language.

Here’s an example of what the messages_en.arb file might look like:

{
  "@@locale": "en",
  "helloWorld": "Hello, world!",
  "greeting": "Welcome, {name}!",
  "buttonText": "Press me"
}

The @@locale key specifies the language code for this file. The other keys correspond to the string resources used in your app.

Step 3: Create a class to load the string resources

Create a new file called i18n.dart in your project’s lib directory. In this file, define a class called AppLocalizations:

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.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();

  late Map<String, String> _localizedStrings;

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

    _localizedStrings =
        jsonMap.map((key, value) => MapEntry(key, value.toString()));

    return true;
  }

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

  String translateFormatted(String key, List<Object> args) {
    return Intl.message(
      translate(key) ?? '',
      name: key,
      args: args,
      locale: locale.toString(),
    );
  }
}

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

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

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

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

The `AppLocalizations` class loads the string resources for the current locale and provides methods to access them. The `_AppLocalizationsDelegate` class is responsible for loading the `AppLocalizations` instance for the current locale. ### Step 4: Load the string resources in your app In your app’s `main.dart` file, wrap your `MaterialApp` widget with a `Localizations` widget:

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      localizationsDelegates: [
        AppLocalizations.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: [
        const Locale('en', ''),
        const Locale('fr', ''),
      ],
      home: MyHomePage(),
    );
  }
}

The localizationsDelegates property specifies the localization delegates to use. In this example, we’re using the AppLocalizations delegate we defined earlier, as well as the built-in material and widget localizations delegates.

The supportedLocales property specifies the list of locales that your app supports.

Step 5: Use the localized strings in your app

In your app’s widgets, use the AppLocalizations class to access the localized strings:

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final AppLocalizations localizations = AppLocalizations.of(context)!;

    return Scaffold(
      appBar: AppBar(
        title: Text(localizations.translate('helloWorld') ?? ''),
      ),
      body: Center(
        child: Text(
          localizations.translateFormatted('greeting', ['John']),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {},
        tooltip: localizations.translate('buttonText'),
        child: Icon(Icons.add),
      ),
    );
  }
}

In this example, we’re using the translate method to retrieve the helloWorld string, and the translateFormatted method to retrieve the greeting string and format it with the name “John”.

Conclusion

Internationalization and localization are essential features for making your Flutter app accessible to users around the world. By following these simple steps, you can easily add support for multiple languages and cultures to your app.

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *