Flutter Localization for Mobile Apps: Strings, Numbers, and More
When building an app for a global audience, localization ensures that text, numbers, dates, and currencies are presented in a way that feels natural to users based on their locale. Localization isn’t just about translating strings — it’s about formatting data in a way that conforms to regional conventions.
In the previous article, titled Boosting Flutter App Efficiency: Best Practices for Performance Optimization, we explored how to enhance your app’s performance. This series is designed specifically for those new to Flutter, and all examples are prepared for use in DartPad to save you from the hassle of setting up an IDE.
In this article, we’ll walk through how to use the intl
package in Flutter to localize strings, numbers, currencies, and dates for multiple locales, including correct handling of the Indian numbering system for currencies.
Let’s dive into how you can localize your Flutter apps efficiently!
Localizing Strings
In Flutter, string localization can be handled by storing translations for each supported language in a map and dynamically loading the correct translation based on the user’s locale.
Here’s an example of a translation map:
Map<String, Map<String, String>> translations = {
'en': {
'greeting': 'Hello, {name}!',
},
'es': {
'greeting': '¡Hola, {name}!',
},
'hi': {
'greeting': 'नमस्ते, {name}!',
}
};
// Helper function to get translated text
String getTranslatedText(String key, Locale locale) {
return translations[locale.languageCode]![key]!;
}
To display a translated greeting, we can dynamically fetch the correct string based on the user’s locale:
Text(getTranslatedText('greeting', _locale).replaceFirst('{name}', 'Flutter Developer')),
This function retrieves the appropriate greeting for the selected language and replaces the {name}
placeholder with the user’s name.
Localizing Numbers
Different regions format numbers differently. For example:
- US (en):
247,884,528.51
- Spain (es):
247.884.528,51
- Germany (de):
247.884.528,51
- France (fr):
247 884 528,51
- India (hi):
247,884,528.51
Here’s how to localize a number in Flutter:
final number = 247884528.51;
final formattedNumber = NumberFormat("#,##0.00", _locale.toLanguageTag()).format(number);
Localizing Currencies
Currency formats can vary even more than numbers. In Here’s how currencies are formatted in different locales:
- US (en):
$720,361,177.62
- Spain (es):
720.361.177,62 €
- Germany (de):
720.361.177,62 €
- France (fr):
720 361 177,62 €
- India (hi):
₹72,03,61,177.62
To localize currency values:
final amount = 720361177.62;
final formattedCurrency = NumberFormat.simpleCurrency(locale: _locale.toLanguageTag()).format(amount);
Localizing Dates
Date formats also vary greatly between locales. In the US, a date like October 22, 2024
would be formatted as 22 अक्टूबर 2024
in Hindi.
To format dates correctly in Flutter:
final formattedDate = DateFormat.yMMMMd(_locale.toLanguageTag()).format(DateTime.now());
This ensures that dates are displayed in the correct format and language based on the locale.
Complete Example Code
Here is the full example that localizes strings, numbers, currencies, and dates based on the user’s locale:
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:intl/date_symbol_data_local.dart';
void main() async {
// Initializes date formatting for all locales
await initializeDateFormatting();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
// Default locale is English
Locale _locale = Locale('en');
void _changeLanguage(Locale locale) {
setState(() {
_locale = locale;
});
}
// Translation map for English, Spanish, German, French, and Hindi
Map<String, Map<String, String>> translations = {
'en': {
'title': 'Localization Demo',
'greeting': 'Hello, {name}!',
'date_label': 'Date: {date}',
'number': 'Number: {value}',
'currency': 'Price: {amount}',
},
'es': {
'title': 'Demostración de Localización',
'greeting': '¡Hola, {name}!',
'date_label': 'Fecha: {date}',
'number': 'Número: {value}',
'currency': 'Precio: {amount}',
},
'de': {
'title': 'Lokalisierungsdemo',
'greeting': 'Hallo, {name}!',
'date_label': 'Datum: {date}',
'number': 'Nummer: {value}',
'currency': 'Preis: {amount}',
},
'fr': {
'title': 'Démonstration de localisation',
'greeting': 'Bonjour, {name}!',
'date_label': 'Date: {date}',
'number': 'Numéro : {value}',
'currency': 'Prix : {amount}',
},
'hi': {
'title': 'स्थानीयकरण डेमो',
'greeting': 'नमस्ते, {name}!',
'date_label': 'तारीख: {date}',
'number': 'संख्या: {value}',
'currency': 'मूल्य: {amount}',
}
};
// Helper function to get translated text
String getTranslatedText(String key) {
return translations[_locale.languageCode]![key]!;
}
@override
Widget build(BuildContext context) {
final name = 'Flutter Developer';
final number = 247884528.5136995904;
final amount = 720361177.6184808451;
// Format the number according to the locale
final formattedNumber = NumberFormat("#,##0.00", _locale.toLanguageTag()).format(number);
// Format the currency according to the locale
final formattedCurrency = NumberFormat.simpleCurrency(locale: _locale.toLanguageTag()).format(amount);
// Format the date according to the locale
final formattedDate = DateFormat.yMMMMd(_locale.toLanguageTag()).format(DateTime.now());
return MaterialApp(
debugShowCheckedModeBanner: false,
locale: _locale,
home: Scaffold(
appBar: AppBar(
title: Text(getTranslatedText('title')),
actions: [
DropdownButton<Locale>(
value: _locale,
icon: Icon(Icons.language),
onChanged: (Locale? newLocale) {
if (newLocale != null) _changeLanguage(newLocale);
},
items: [
DropdownMenuItem(
value: Locale('en'),
child: Text('English'),
),
DropdownMenuItem(
value: Locale('es'),
child: Text('Español'),
),
DropdownMenuItem(
value: Locale('de'),
child: Text('Deutsch'),
),
DropdownMenuItem(
value: Locale('fr'),
child: Text('Français'),
),
DropdownMenuItem(
value: Locale('hi'),
child: Text('हिन्दी'),
),
],
),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(getTranslatedText('greeting').replaceFirst('{name}', name)),
SizedBox(height: 10),
Text(getTranslatedText('number').replaceFirst('{value}', formattedNumber)),
SizedBox(height: 10),
Text(getTranslatedText('currency').replaceFirst('{amount}', formattedCurrency)),
SizedBox(height: 10),
Text(getTranslatedText('date_label').replaceFirst('{date}', formattedDate)),
],
),
),
),
);
}
}
Conclusion
In this article, we explored how to localize a Flutter app using the intl
package. We covered how to localize strings, numbers, currencies, and dates, focusing on the correct formats for various regions, including the Indian numbering system for currencies.
By using intl
, your app can automatically adapt to different locales, ensuring that users around the world see content in formats that are familiar to them. This improves user experience and makes your app more accessible globally.
Great work! You’ve just unlocked another key skill in your Flutter toolkit. Keep pushing forward, try applying localization to your own apps, and don’t hesitate to share your progress. Your experience could inspire others, so feel free to spread the word and stay connected for more tips and insights. We’re excited to see what you achieve — keep going strong!