Pourquoi Internationalisation (i18n) avec Flutter ?
L'internationalisation (i18n) est un processus essentiel pour les développeurs Flutter lorsqu'ils veulent créer des applications qui soient accessibles à un large éventail de utilisateurs mondiaux. Dans le contexte réel, un développeur a besoin d'Internationalisation pour répondre aux besoins culturels et linguistiques divers des utilisateurs. Par exemple, une application de commerce électronique doit afficher les prix en différentes devises selon la localité de l'utilisateur.
Prerequis
Avant de commencer avec l'internationalisation (i18n) en Flutter, vous devez avoir les connaissances suivantes :
- Connaissances avancées de Flutter
- Compréhension des concepts de base de Dart
- Connaissance de la structure d'un projet Flutter
Vous devrez également installer les outils suivants :
- Flutter SDK (v2.5 ou ultérieure)
- Android Studio (pour le développement Android)
- Xcode (pour le développement iOS)
Concepts fondamentaux
1. Localisation (l10n)
La localisation est la processus d'adaptation de l'apparence et du comportement de votre application à une culture spécifique. Cela comprend la traduction des chaînes de caractères, la mise en page adaptée aux conventions de la culture, ainsi que la gestion des ressources spécifiques à chaque culture.
Schéma mental :
App
├── locale_en.json (English translations)
├── locale_fr.json (French translations)
└── main.dart (Main application file)
Code fonctionnel :
// Import the localization package
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
Locale('en', 'US'),
Locale('fr', 'FR'),
],
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Welcome")),
body: Center(child: Text("Hello, World!")),
);
}
}
2. Intl (Internationalization)
Intl est une bibliothèque Flutter qui fournit des outils pour gérer les ressources locales et la traduction.
Schéma mental :
lib
├── i18n.dart (Localization file)
└── main.dart (Main application file)
Code fonctionnel :
// Import the intl package
import 'package:intl/intl.dart';
String getLocalizedDate(String locale) {
final formatter = DateFormat.yMMMMd(locale);
return formatter.format(DateTime.now());
}
3. Translation Files
Flutter utilise des fichiers JSON pour stocker les traductions. Ces fichiers sont généralement placés dans un dossier i18n.
Schéma mental :
i18n
├── en.json (English translations)
└── fr.json (French translations)
Code fonctionnel :
// en.json
{
"welcome": "Welcome",
"hello_world": "Hello, World!"
}
// fr.json
{
"welcome": "Bienvenue",
"hello_world": "Bonjour, le monde !"
}
Mise en pratique : projet fil rouge
Nous allons créer un petit gestionnaire de tâches simple avec l'internationalisation.
Étape 1 : Création du projet Flutter
flutter create task_manager
cd task_manager
Étape 2 : Ajout des ressources locales
Créer les fichiers en.json et fr.json dans le dossier i18n.
En/FR JSON Files:
// i18n/en.json
{
"app_title": "Task Manager",
"add_task": "Add Task",
"task_list": "Tasks"
}
// i18n/fr.json
{
"app_title": "Gestionnaire de Tâches",
"add_task": "Ajouter une Tâche",
"task_list": "Liste des Tâches"
}
Étape 3 : Création d'un fichier de traduction
Créer un fichier i18n.dart pour charger les fichiers JSON.
// lib/i18n.dart
import 'package:flutter/material.dart';
import 'dart:convert';
class AppLocalizations {
final Locale locale;
AppLocalizations(this.locale);
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations)!;
}
Map<String, String> _localizedStrings = {};
Future<bool> load() async {
String jsonString = await DefaultAssetBundle.of(context).loadString(
'i18n/${locale.languageCode}.json',
);
_localizedStrings = json.decode(jsonString);
return true;
}
String translate(String key) {
return _localizedStrings[key] ?? key;
}
}
class AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
@override
bool isSupported(Locale locale) {
return ['en', 'fr'].contains(locale.languageCode);
}
@override
Future<AppLocalizations> load(Locale locale) async {
AppLocalizations appLocalizations = AppLocalizations(locale);
await appLocalizations.load();
return appLocalizations;
}
@override
bool shouldReload(AppLocalizationsDelegate old) => false;
}
Étape 4 : Mise à jour du fichier main.dart
// lib/main.dart
import 'package:flutter/material.dart';
import 'i18n.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Task Manager",
localizationsDelegates: [
AppLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
Locale('en', 'US'),
Locale('fr', 'FR'),
],
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final appLocale = AppLocalizations.of(context);
return Scaffold(
appBar: AppBar(
title: Text(appLocale.translate("app_title")),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(appLocale.translate("task_list")),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// Add task logic
},
child: Text(appLocale.translate("add_task")),
),
],
),
),
);
}
}
Erreurs frequentes et debugging
1. Erreur : MissingPluginException lors de l'utilisation d'une ressource locale
Code incorrect :
await DefaultAssetBundle.of(context).loadString('i18n/${locale.languageCode}.json');
Code correct :
await DefaultAssetBundle.of(context).loadString('assets/i18n/${locale.languageCode}.json');
2. Erreur : JsonDecodeException lors de la lecture d'un fichier JSON
Code incorrect :
String jsonString = await DefaultAssetBundle.of(context).loadString('i18n/${locale.languageCode}.json');
Map<String, String> _localizedStrings = json.decode(jsonString);
Code correct :
String jsonString = await DefaultAssetBundle.of(context).loadString('i18n/${locale.languageCode}.json');
Map<String, dynamic> tempJson = json.decode(jsonString);
Map<String, String> _localizedStrings = Map.from(tempJson);
3. Erreur : Null check operator used on a null value lors de la traduction
Code incorrect :
String translate(String key) {
return _localizedStrings[key]!;
}
Code correct :
String translate(String key) {
return _localizedStrings[key] ?? key;
}
Pour aller plus loin
- Gestion des paramètres régionaux et de la langue utilisateur : Explorez comment gérer les préférences utilisateur pour choisir la langue.
- Utilisation de packages tiers pour la localisation : Des packages comme
flutter_localizationsfournissent une couche supplémentaire de fonctionnalités pour la gestion des ressources locales. - Traduction automatique en temps réel : Intégrez des services de traduction automatique (comme Google Translate API) pour permettre aux utilisateurs d'utiliser votre application dans leur langue native.
Défi pratique
Créez une petite application Flutter qui affiche le temps actuel et la date formatées selon les paramètres régionaux de l'utilisateur. Utilisez des fichiers JSON pour stocker les traductions des chaînes de caractères.