Flutter Localization Tutorial


In this tutorial, we will see how to internationalize and localize your content according to language selection

As shown in below application, I am using English, Telugu and Hindi as my language content. The content is automatically loaded from language.properties file w.r.t. the user language selection.

pubspec.yaml file

name: Sample localization app
description: Sample localization app.
publish_to: 'none'

version: 1.0.0+1
environment:
  sdk: ">=2.12.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
   sdk: flutter
  cupertino_icons: ^1.0.2
  youtube_player_flutter: ^8.0.0
  intl: ^0.17.0
  provider: ^6.0.1
  http: ^0.13.4
  animations: ^2.0.1
  convex_bottom_bar: ^3.0.0
  shared_preferences: ^2.0.8
  connectivity_plus: ^1.2.0
  firebase_core: ^1.7.0
  firebase_auth: ^3.1.2
  cloud_firestore: ^2.5.3
  flutter_font_icons: ^2.2.3
  path: ^1.8.0
  sqflite: ^2.0.0+4

  
  
dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^1.0.0
  flutter_launcher_icons: ^0.9.2

flutter_icons:
  android: true
  ios: true
  image_path: "assets/images/app_icon.png"



flutter:
  uses-material-design: true
  assets:
    - locale/en.json 
    - locale/te.json
    - locale/hin.json 
    - assets/images/
  fonts:
    - family: Roboto
      fonts:
        - asset: assets/fonts/Roboto-Regular.ttf
        - asset: assets/fonts/Roboto-Bold.ttf
        - asset: assets/fonts/Roboto-Medium.ttf
        - asset: assets/fonts/Roboto-Thin.ttf
          weight: 700
    

en.json

{
    "APP_TITLE":"Sample Locale APP",
    "GREETING":"Hi Hello Jayaram!!!"
}

te.json(Telugu)

{
    "APP_TITLE":"టెస్తింగ్ ఆప్",
    "GREETING":"హెల్లౌ జయరం"
}

hi.json (Hindi Language)

{
    "APP_TITLE":"Hindhi Testing APP",
    "GREETING":"Hindhi text greeting"
}

locale_provider.dart

import 'package:flutter/cupertino.dart';

import 'package:flutter/material.dart';

class AppLocale with ChangeNotifier {
  Locale? _locale = Locale("te", "IN");
  Locale? get locale => _locale;
  void setLocale(Locale locale) {
    _locale = locale;
    notifyListeners();
  }
}

main.dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/foundation.dart';
import 'package:provider/provider.dart';
import './model/auth.dart';
import './screens/signup_screen.dart';
import '../util/app_theme.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import './localization/app_translation.dart';
import './model/locale_provider.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await SystemChrome.setPreferredOrientations(<DeviceOrientation>[
    DeviceOrientation.portraitUp,
    DeviceOrientation.portraitDown
  ]).then((_) => runApp(MyApp()));
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

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

class _MyAppState extends State<MyApp> {
  late AppLocalizationsDelegate localizationsDelegate;
  Locale locale = Locale("te", "IN");
  @override
  void initState() {
    localizationsDelegate = AppLocalizationsDelegate(locale);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
        providers: [
          ChangeNotifierProvider(create: (ctx) => UserAuthentication()),
          ChangeNotifierProvider(create: (ctx) => AppLocale()),
        ],
        child: Consumer<AppLocale>(builder: (context, provider, snapshot) {
          return MaterialApp(
            locale: provider.locale,
            title: "Sample Localization App",
            localizationsDelegates: [
              GlobalMaterialLocalizations.delegate,
              GlobalWidgetsLocalizations.delegate,
              GlobalCupertinoLocalizations.delegate,
              localizationsDelegate,
            ],
            supportedLocales: [
              const Locale('en', 'IN'),
              const Locale('te', 'IN'),
            ],
            localeResolutionCallback: (loc, supportedLocales) {
              // Check if the current device locale is supported
              for (var supportedLocale in supportedLocales) {
                if (supportedLocale.languageCode == loc?.languageCode &&
                    supportedLocale.countryCode == loc?.countryCode) {
                  return supportedLocale;
                }
              }
              // If the locale of the device is not supported, use the first one
              // from the list (English, in this case).
              return supportedLocales.first;
            },
            theme: AppTheme,
            initialRoute: "/",
            routes: {'/': (content) => const LoginScreen()},
          );
        }));
  }
}

app_transalation.dart => AppLocalizations, AppLocalizationsDelagate

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

class AppLocalizations {
  AppLocalizations(this.locale);

  final Locale locale;
  static Map<String, dynamic> localizedValues = {};
  static AppLocalizations of(BuildContext context) {
    return Localizations.of<AppLocalizations>(context, AppLocalizations)!;
  }

  Future<bool> load() async {
    // Load the language JSON file from the "lang" folder
    String jsonString =
        await rootBundle.loadString('locale/${locale.languageCode}.json');
    Map<String, dynamic> jsonMap = json.decode(jsonString);

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

    return true;
  }

  String translate(String key) {
    return localizedValues[key];
  }
}

class AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
  final Locale locale;
  AppLocalizationsDelegate(this.locale);

  final List<String> supportedLanguagesCodes = [
    "en", // English
    "te", //telugu
    'hi' // hindi
  ];
  @override
  bool isSupported(Locale locale) {
    return supportedLanguagesCodes.contains(locale.languageCode);
  }

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

  @override
  bool shouldReload(AppLocalizationsDelegate old) => true;
}

signup_screen.dart

import 'package:flutter/material.dart';
import '../localization/app_translation.dart';
import 'package:provider/provider.dart';
import '../model/locale_provider.dart';

class LoginScreen extends StatelessWidget {
  const LoginScreen({Key? key}) : super(key: key);

  static final List<Locale> supportedLanguagesCodes = [
    Locale("en", "IN"),
    Locale("te", "IN"),
  ];
  @override
  Widget build(BuildContext context) {
    var lang = Provider.of<AppLocale>(context);
    _title(String val) {
      switch (val) {
        case 'en':
          return Text(
            'English',
            style: TextStyle(fontSize: 16.0),
          );
        case 'te':
          return Text(
            'telugu',
            style: TextStyle(fontSize: 16.0),
          );

        default:
          return Text(
            'English',
            style: TextStyle(fontSize: 16.0),
          );
      }
    }

    return Scaffold(
      appBar: AppBar(
        title: Text(AppLocalizations.of(context).translate("APP_TITLE")),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              AppLocalizations.of(context).translate("GREETING"),
              style: TextStyle(
                fontSize: 20.0,
                fontWeight: FontWeight.w500,
              ),
            ),
            SizedBox(height: 85.0),
            DropdownButton(
                value: lang.locale,
                onChanged: (Locale? val) {
                  lang.setLocale(val!);
                },
                items: supportedLanguagesCodes
                    .map((e) => DropdownMenuItem(
                          value: e,
                          child: _title(e.languageCode),
                        ))
                    .toList())
          ],
        ),
      ),
    );
  }
}