Each day, an increasing number of people are learning English. Still, a large number of people do not understand or speak English. Even if you have a compelling app, people may not use it. They may not be fluent in English or prefer to have it available in their native language.
You may be losing the game in non-English regions, regardless of how much the app can help them. For example, if you have an app that tells the steps to perform the specific exercise and a user is unable to understand the language, the user will simply opt for another app (which may be mediocre but available in the user's language).
What is localisation?
Adapting an application to different languages and regions. This involves translating the text, images, and other resources in the app to make it accessible and understandable to users from various country backgrounds.
It is also referred to as l10n. 10 represents the count of all letters between L and N.
Let's setup a simple project which will have two screens and we will implement a toggle between two languages(I chose English and French)
Locale app
In this we'll also be usmain.darting Provider to update the state of the two screens:
Provider
Let me give you a taste of what provider is:
- Provider is a state management technique in Flutter.
- Provide data from a single source to multiple widgets in your app.
- When the data changes, Provider automatically notifies the widgets that depend on it.
- Creates a widget tree where widgets can access the provided data without having to pass it down manually through every widget.
- Simplifies the process of managing and sharing data across Flutter app, making your code more organized and easier to maintain.
Now let's build the app.
Let's add the dependencies in pubspec.yaml
:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: any
provider: ^6.1.2
Then import the flutter_localizations library and specify localizationsDelegates and supportedLocales for your *MaterialApp *
main.dart
import 'package:flutter_localizations/flutter_localizations.dart';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('en'), // English
const Locale('fr'), // French
],
locale: context.watch<LocaleProvider>().locale,
home: const HomePage(),
);
}
}
To add localized text to the application:
- In the
pubspec.yaml
, add a generate flag and set it true.
# The following section is specific to Flutter packages.
flutter:
generate: true
- Create a new file called
l10n.yaml
in the root directory of the file and add add the below code
arb-dir: lib/l10n
template-arb-file: app_en.arb //name can vary depending on the language used
output-localization-file: app_localizations.dart
-
In the lib folder, create a folder named
l10n
and the add the 2 files as below.- The data written in this file is similar to JSON. So, it will be
key: value
pairs
- The data written in this file is similar to JSON. So, it will be
app_en.arb
{
"title1": "Hello World!",
"description1": "Hello, world! Greetings from the digital realm, where innovation meets imagination.",
"title2": "How Are You",
"description2": "Hey newbie coder! How's the coding journey treating you? Making any byte-sized progress?",
"title3": "It works",
"description3": "Fantastic to hear it works! Need further tweaks or just basking in the glory of functional code? Keep coding!",
"details": "Details page",
"home": "Home page"
}
app_fr.arb
Note:I have used the google translate to transalte the words.
{
"title1": "Bonjour le monde!",
"description1": "Bonjour, monde! Salutations depuis le domaine numérique, où l'innovation rencontre l'imagination.",
"title2": "Comment ça va",
"description2": "Salut nouveau programmeur! Comment se passe le voyage de programmation? Faites-vous des progrès en bytes?",
"title3": "Ça marche",
"description3": "Fantastique d'entendre que ça marche! Besoin d'autres ajustements ou juste profiter de la gloire du code fonctionnel? Continuez à coder!",
"details": "Page de détails",
"home": "Page d'accueil"
}
- Now restart the app and you'll see the files generated in the
.dart_tool
- Now in the
main.dart
, add a import statement and AppLocalizations.delegate
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; //this line
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
localizationsDelegates: [
AppLocalizations.delegate, //New line
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('en'), // English
const Locale('fr'), // French
],
locale: context.watch<LocaleProvider>().locale,
home: const HomePage(),
);
}
}
- Once it is loaded, use the AppLocalizations in the app using:
Text(AppLocalizations.of(context)!.<Key of the text>)
local_provider
- This piece of code will update the main tree and the display the needed language when toggled.
import 'package:provider/provider.dart';
class LocaleProvider with ChangeNotifier {
late Locale _locale = const Locale('en');
Locale get locale => _locale;
void toggleLocale() {
_locale =
_locale.languageCode == 'en' ? const Locale('fr') : const Locale('en');
notifyListeners();
}
}
- update the
main()
function to listen to changes using ChangeNotifierProvider.
void main() {
runApp(
ChangeNotifierProvider<LocaleProvider>(
create: (_) => LocaleProvider(),
child: MyApp(),
),
);
}
Home screen
In the home screen we will display a appbar with a Icon button which will toggle between languages on pressed.
We will also list cards with titles on it, which when pressed will display the details screen.
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.home),
actions: [
IconButton(
onPressed: () {
context.read<LocaleProvider>().toggleLocale();
},
tooltip: 'Language',
icon: const Icon(Icons.language),
)
],
),
body: ListView(
children: [
buildCard(context,
title: AppLocalizations.of(context)!.title1,
details: AppLocalizations.of(context)!.description1),
buildCard(context,
title: AppLocalizations.of(context)!.title2,
details: AppLocalizations.of(context)!.description2),
buildCard(context,
title: AppLocalizations.of(context)!.title3,
details: AppLocalizations.of(context)!.description3),
// Add more CardItems as needed
],
),
);
}
Widget buildCard(BuildContext context,
{required String title, required String details}) {
return GestureDetector(
onTap: () {
Navigator.pushNamed(context, '/details',
arguments: {'title': title, 'details': details});
},
child: Card(
margin: const EdgeInsets.all(16.0),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
title,
style: const TextStyle(fontSize: 20.0),
),
),
),
);
}
}
Details screen
- In this screen, we will just display the title and description in the page.
class DetailsPage extends StatelessWidget {
const DetailsPage({super.key});
@override
Widget build(BuildContext context) {
final Map<String, String> args = ModalRoute.of(context)!.settings.arguments as Map<String, String>;
final String title = args['title']!;
final String details = args['details']!;
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.details),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8.0),
Text(
details,
style: const TextStyle(fontSize: 16.0),
),
],
),
),
);
}
}
Full code
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
ChangeNotifierProvider<LocaleProvider>(
create: (_) => LocaleProvider(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('en'), // English
const Locale('fr'), // French
],
locale: context.watch<LocaleProvider>().locale,
home: const HomePage(),
routes: {
'/details': (context) => const DetailsPage(),
},
);
}
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.home),
actions: [
IconButton(
onPressed: () {
context.read<LocaleProvider>().toggleLocale();
},
tooltip: 'Language',
icon: const Icon(Icons.language),
)
],
),
body: ListView(
children: [
buildCard(context,
title: AppLocalizations.of(context)!.title1,
details: AppLocalizations.of(context)!.description1),
buildCard(context,
title: AppLocalizations.of(context)!.title2,
details: AppLocalizations.of(context)!.description2),
buildCard(context,
title: AppLocalizations.of(context)!.title3,
details: AppLocalizations.of(context)!.description3),
// Add more CardItems as needed
],
),
);
}
Widget buildCard(BuildContext context,
{required String title, required String details}) {
return GestureDetector(
onTap: () {
Navigator.pushNamed(context, '/details',
arguments: {'title': title, 'details': details});
},
child: Card(
margin: const EdgeInsets.all(16.0),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
title,
style: const TextStyle(fontSize: 20.0),
),
),
),
);
}
}
class DetailsPage extends StatelessWidget {
const DetailsPage({super.key});
@override
Widget build(BuildContext context) {
final Map<String, String> args = ModalRoute.of(context)!.settings.arguments as Map<String, String>;
final String title = args['title']!;
final String details = args['details']!;
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.details),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(fontSize: 24.0, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8.0),
Text(
details,
style: const TextStyle(fontSize: 16.0),
),
],
),
),
);
}
}
class LocaleProvider with ChangeNotifier {
late Locale _locale = const Locale('en');
Locale get locale => _locale;
void toggleLocale() {
_locale =
_locale.languageCode == 'en' ? const Locale('fr') : const Locale('en');
notifyListeners();
}
}
Hope it helps!!
Top comments (0)