Essential Flutter Widgets for Your Apps
Flutter is a mobile app development framework created by Google that has gained popularity for its …
read moreWhen we start developing a new app, we usually focus on functionality, design, and user experience first. However, there’s one important aspect that’s often left for later—or worse, completely overlooked: text internationalization, also known as i18n (short for internationalization).
Internationalization is the process of preparing your app to support multiple languages and regional settings without
having to rewrite the core logic. In Flutter, this is easier than you might think, thanks to the built-in support
provided by packages like flutter_localizations
and intl
.
But why should we care about this?
It’s important to understand that internationalization is not simply about translating texts. It’s about creating a structure that allows those texts to change dynamically based on the device language or the user’s preferences.
There are several things to take into account:
Flutter provides powerful tools to implement a robust and maintainable internationalization strategy. Thanks to the
intl
package, we can load different translation files and access localized texts from anywhere in our app.
In this article, we’ll walk through how to apply text internationalization step by step in a Flutter app, finishing with a practical example you can use as a base for your own projects.
Before we jump into the configuration, it’s important to understand how the project is structured to implement internationalization correctly. Here’s the basic layout we’ll follow:
lib/
├── main.dart // Entry point of the application
├── home_page.dart // Main page with localized texts
├── l10n/ // Folder where translation files are stored
│ ├── app_en.arb // English translations
│ ├── app_es.arb // Spanish translations
│ └── app_fr.arb // French translations
l10n.yaml // Configuration for localization generation
pubspec.yaml // Dependency declarations and project setup
To get started, make sure you have a Flutter project created. If not, you can check out our article on how to get started with Flutter.
Once your project is ready, open the pubspec.yaml
file and add the following dependencies:
name: greeting_app
description: A simple Flutter app with internationalization
version: 1.0.0+1
environment:
sdk: ">=3.0.0 <4.0.0"
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: ^0.19.0
flutter:
uses-material-design: true
generate: true
Next, run the following command to install the dependencies:
flutter pub get
We also need to create a l10n.yaml
file at the root of the project. This file is where we’ll configure the localization setup for our app.
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
This tells Flutter to look for .arb
files inside the lib/l10n
folder, use app_en.arb
as the template file, and generate the localization classes in a file named app_localizations.dart
.
Now, create a folder called l10n
inside the lib
directory. In this folder, you’ll add the .arb
files that contain your app’s translated texts. For example, you can create a file named app_en.arb
for English, app_es.arb
for Spanish, and app_fr.arb
for French. These would be the different files:
{
"@@locale": "en",
"greeting": "Hello, {name}!",
"showDate": "Show Date",
"todayIs": "Today is {date}"
}
{
"@@locale": "es",
"greeting": "¡Hola, {name}!",
"showDate": "Mostrar fecha",
"todayIs": "Hoy es {date}"
}
{
"@@locale": "fr",
"greeting": "Bonjour, {name} !",
"showDate": "Afficher la date",
"todayIs": "Nous sommes le {date}"
}
Open the main.dart
file and configure your MaterialApp
to support localization. This is where you’ll define the languages your app will support and the localization files it will use.
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'home_page.dart';
void main() {
runApp(const GreetingApp());
}
class GreetingApp extends StatefulWidget {
const GreetingApp({super.key});
@override
State<GreetingApp> createState() => _GreetingAppState();
}
class _GreetingAppState extends State<GreetingApp> {
Locale? _locale;
void setLocale(Locale locale) {
setState(() {
_locale = locale;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Greeting App',
debugShowCheckedModeBanner: false,
locale: _locale,
supportedLocales: const [
Locale('en'),
Locale('es'),
Locale('fr'),
],
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
home: HomePage(onLocaleChange: setLocale),
);
}
}
The delegates
are responsible for loading the translations and formatting texts based on the selected language. In this case, we’re using AppLocalizations.delegate
to load our custom translations, and Flutter’s global delegates to handle widget and material localization.
Now, create a file called home_page.dart
inside the lib
folder and add the following code:
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class HomePage extends StatefulWidget {
final void Function(Locale) onLocaleChange;
const HomePage({super.key, required this.onLocaleChange});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
String? _formattedDate;
void _showDate() {
final now = DateTime.now();
final localeName = Localizations.localeOf(context).languageCode;
final formatted = DateFormat.yMMMMd(localeName).format(now);
setState(() {
_formattedDate = AppLocalizations.of(context)!.todayIs(formatted);
});
}
void _changeLanguage(String languageCode) {
final newLocale = Locale(languageCode);
widget.onLocaleChange(newLocale);
}
@override
Widget build(BuildContext context) {
final loc = AppLocalizations.of(context)!;
return Scaffold(
appBar: AppBar(
title: const Text('Greeting App'),
),
body: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
loc.greeting('John'),
style: Theme.of(context).textTheme.headlineMedium,
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: _showDate,
child: Text(loc.showDate),
),
if (_formattedDate != null) ...[
const SizedBox(height: 16),
Text(
_formattedDate!,
style: Theme.of(context).textTheme.bodyLarge,
),
],
const Spacer(),
Text('Change Language:'),
Row(
children: [
TextButton(
onPressed: () => _changeLanguage('en'),
child: const Text('English'),
),
TextButton(
onPressed: () => _changeLanguage('es'),
child: const Text('Español'),
),
TextButton(
onPressed: () => _changeLanguage('fr'),
child: const Text('Français'),
),
],
),
],
),
),
);
}
}
Once we have all the .arb
files created and the l10n.yaml
file properly configured, it’s time to generate the localization classes that we’ll use in our project.
Flutter includes a tool called gen-l10n
, which analyzes the .arb
files and automatically generates the app_localizations.dart
file.
You can run the generation manually using the following command:
flutter gen-l10n
This will generate the app_localizations.dart
file inside the .dart_tool/flutter_gen/gen_l10n/
folder at the root of your project. This file contains the necessary classes to access your app’s translations. The folder is auto-generated (as its name suggests) and should not be modified manually.
At this point, you can run your app and see how the texts are displayed according to the device’s language settings. Additionally, you can change the language directly from within the app without needing to update the device settings.
Now we’re ready to run our application with the following command:
flutter run
In this simple yet functional example, we’ve built a basic Flutter app where the displayed texts change automatically based on the device’s language. Let’s quickly recap the key files and their roles:
pubspec.yaml
: We added the necessary dependencies to use flutter_localizations
and intl
, and enabled automatic localization code generation.l10n.yaml
: Configuration file where we tell Flutter where to find the .arb
files and how to generate the corresponding localization classes.lib/l10n/
folder with .arb
files**: This is where we store all the translations. It allows us to easily add new languages in the future without modifying the app’s logic.main.dart
: We configured MaterialApp
to support multiple languages and declared localization delegates.home_page.dart
: We built the main interface with a personalized greeting and a button that displays a properly formatted date depending on the selected language.This example shows how to organize a Flutter project with multilingual support from the very beginning, following a clean and scalable structure. Internationalizing a Flutter app isn’t as complicated as it may seem, and the benefits are huge. From improving user experience to expanding into new markets, preparing your app for multiple languages is a smart long-term investment.
Flutter also provides powerful and well-integrated tools that make the process much easier, helping you keep your project clean, maintainable, and ready to scale.
It’s also worth mentioning that when launching the app, you may see a warning about the flutter_gen
library being deprecated in future Flutter versions. For apps being created now, it’s best to follow the recommendations in the official documentation.
Whether it’s for personal projects, production apps, or MVPs, having an internationalization-ready structure from the start will save you headaches down the road. Feel free to leave a comment below if you have questions or think we missed something.
Happy Coding!
That may interest you
Flutter is a mobile app development framework created by Google that has gained popularity for its …
read moreAI-powered programming assistants are on everyone’s mind. They are already altering the workflow of …
read moreWe have already talked about Flutter and how it has become one of the most powerful frameworks for …
read moreConcept to value