Easy and Fast internationalizing your Flutter Apps
easy_localization
Easy and Fast internationalizing your Flutter Apps, this package simplify the internationalizing process using Json file
Why easy_localization
- simplify and easy the internationalizing process in Flutter.
- Using JSON Files .
- Load translations from remote or backend.
- save App state.
- Supported
plural
- Supported
gender
- Supported Flutter extension.
Changelog
[1.4.1]
-
optimized and clean code
-
fixed many issues
-
added extension for Strings
// after 1.4.1 Text('title'.tr()), Text('switch'.tr( gender: _gender ? "female" : "male")), Text('counter'.plural(counter)),
[1.4.0]
-
refactor code changed call
AppLocalizations.of(context).tr()
toAppLocalizations.of(context).plural()
tr()
andplural()
// after 1.4.0 Text( tr('switch', gender: _gender ? "female" : "male"), ),
// before 1.4.0 Text( AppLocalizations.of(context).tr('switch', gender: _gender ? "female" : "male"), ),
-
added Flutter extension for Text widget
// after 1.4.0 Text('switch').tr( gender: _gender ? "female" : "male"), Text('counter').plural(counter),
[1.3.5]
-
merge
gender()
andtr()
.{ "switch":{ "male": "Hi man ;)", "female": "Hello girl :)" } }
Text( AppLocalizations.of(context).tr('switch', gender: _gender ? "female" : "male"), ),
-
use parameters
args
for gender.{ "switch":{ "male": "Hi man ;) {}", "female": "Hello girl :) {}" } }
Text( AppLocalizations.of(context).tr('switch', args:["Naama"] gender: _gender ? "female" : "male"), ),
[1.3.4]
-
adeed Gender [female,male]
gender()
.{ "switch":{ "male": "Hi man ;)", "female": "Hello girl :)" } }
Text( AppLocalizations.of(context).gender('switch', _gender ? "female" : "male"), ),
[1.3.3+1]
-
updated
plural()
thanks shushper .{ "text": { "day": { "zero":"{} дней", "one": "{} день", "two": "{} дня", "few": "{} дня", "many": "{} дней", "other": "{} дней" } } }
[1.3.3]
- removed
data.savedLocale
. - optimized and clean code
- fixed many issues
[1.3.2]
-
plural()
added property resolver for nested key translations{ "text": { "day": { "zero": "day", "one": "day", "other": "days" } } }
new Text( AppLocalizations.of(context).plural("text.day", 2), ),
-
fixed many issues
[1.3.1]
- add useOnlyLangCode flag
[1.3.0]
- Load translations from remote or backend
- fixed many issues
[1.2.1]
- supported shared_preferences
- Save selected localization
[1.2.0]
- Added property resolver for nested key translations
- return translate key if the element or path not exist
{
"title": "Hello",
"msg": "Hello {} in the {} world ",
"clickMe": "Click me",
"profile": {
"reset_password": {
"title": "Reset Password",
"username": "Username",
"password": "password"
}
},
"clicked": {
"zero": "You clicked {} times!",
"one": "You clicked {} time!",
"two":"You clicked {} times!",
"few":"You clicked {} times!",
"many":"You clicked {} times!",
"other": "You clicked {} times!"
}
}
new Text(
AppLocalizations.of(context).tr('profile.reset_password.title'),
),
[1.0.4]
- Added Support country codes
[1.0.3]
- Updated
tr()
function added Multi Argument
[1.0.2]
- Added string pluralisation .
- Added Argument to
tr()
function.
Getting Started
Configuration
Add this to your package's pubspec.yaml file:
dependencies:
# stable version install from https://pub.dev/packages
easy_localization: <last_version>
# Dev version install from git REPO
easy_localization:
git: https://github.com/aissat/easy_localization.git
Load translations from local assets
You must create a folder in your project's root: the path
. Some examples:
/assets/"langs" , "i18n", "locale" or anyname ...
/resources/"langs" , "i18n", "locale" or anyname ...
Inside this folder, must put the json files containing the translated keys :
path
/${languageCode}-${countryCode}.json
example:
- en.json to en-US.json
- ar.json to ar-DZ.json
- zh.json to zh-CN.json
- zh.json to zh-TW.json
must declare the subtree in your pubspec.yaml as assets:
flutter:
assets:
- {`path`/{languageCode}-{countryCode}.json}
The next step :
import 'package:example/my_flutter_app_icons.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:easy_localization/easy_localization.dart';
void main() => runApp(EasyLocalization(child: MyApp()));
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
var data = EasyLocalizationProvider.of(context).data;
return EasyLocalizationProvider(
data: data,
child: MaterialApp(
title: 'Flutter Demo',
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
//app-specific localization
EasyLocalizationDelegate(
locale: data.locale,
path: 'resources/langs',
//useOnlyLangCode: true,
// loadPath: 'https://raw.githubusercontent.com/aissat/easy_localization/master/example/resources/langs'
),
],
supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')],
locale: data.locale,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Easy localization'),
),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int counter = 0;
bool _gender = true;
incrementCounter() {
setState(() {
counter++;
});
}
switchGender(bool val) {
setState(() {
_gender = val;
});
}
@override
Widget build(BuildContext context) {
var data = EasyLocalizationProvider.of(context).data;
return EasyLocalizationProvider(
data: data,
child: Scaffold(
appBar: AppBar(
title: Text(tr("title")),
actions: <Widget>[
FlatButton(
child: Text("English"),
color: Localizations.localeOf(context).languageCode == "en"
? Colors.lightBlueAccent
: Colors.blue,
onPressed: () {
this.setState(() {
data.changeLocale(Locale("en", "US"));
print(Localizations.localeOf(context).languageCode);
});
},
),
FlatButton(
child: Text("عربي"),
color: Localizations.localeOf(context).languageCode == "ar"
? Colors.lightBlueAccent
: Colors.blue,
onPressed: () {
this.setState(() {
data.changeLocale(Locale("ar", "DZ"));
print(Localizations.localeOf(context).languageCode);
});
},
)
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Spacer(
flex: 1,
),
Text(
'switch.with_arg',
style: TextStyle(
color: Colors.grey.shade600,
fontSize: 19,
fontWeight: FontWeight.bold),
).tr(args: ["aissat"], gender: _gender ? "female" : "male"),
Text(
tr('switch', gender: _gender ? "female" : "male"),
style: TextStyle(
color: Colors.grey.shade600,
fontSize: 15,
fontWeight: FontWeight.bold),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(MyFlutterApp.male_1),
Switch(value: _gender, onChanged: switchGender),
Icon(MyFlutterApp.female_1),
],
),
Spacer(
flex: 1,
),
Text(tr('msg', args: ['aissat', 'Flutter'])),
// Text(plural('clicked', counter)),
Text('clicked').plural(counter),
FlatButton(
onPressed: () {
incrementCounter();
},
child: Text('clickMe').tr(),
),
SizedBox(height: 15,),
Text(
plural('amount', counter,
format: NumberFormat.currency(
locale: Localizations.localeOf(context).toString(),
symbol: "€")),
style: TextStyle(
color: Colors.grey.shade900,
fontSize: 18,
fontWeight: FontWeight.bold)
),
SizedBox(height: 20,),
Text('profile.reset_password.title').tr(),
Spacer(
flex: 2,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: incrementCounter,
child: Text('+1'),
),
),
);
}
}
Load translations from backend
You need to have backend endpoint (loadPath
) where resources get loaded from and your endpoint must containing the translated keys.
example:
String loadPath = 'https://raw.githubusercontent.com/aissat/easy_localization/master/example/resources/langs'
'${
loadPath
}/${languageCode}-${countryCode}.json'
- 'https://raw.githubusercontent.com/aissat/easy_localization/master/example/resources/langs/en-US.json'
- 'https://raw.githubusercontent.com/aissat/easy_localization/master/example/resources/langs/ar-DZ.json'
The next step :
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:easy_localization/easy_localization.dart';
void main() => runApp(EasyLocalization(child: MyApp()));
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
var data = EasyLocalizationProvider.of(context).data;
return EasyLocalizationProvider(
data: data,
child: MaterialApp(
title: 'Flutter Demo',
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
//app-specific localization
EasyLocalizationDelegate(
locale: data.locale,
loadPath: 'https://raw.githubusercontent.com/aissat/easy_localization/master/example/resources/langs'),
],
supportedLocales: [Locale('en', 'US'), Locale('ar', 'DZ')],
locale: data.locale,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Easy localization'),
),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int counter = 0;
incrementCounter() {
setState(() {
counter++;
});
}
@override
Widget build(BuildContext context) {
var data = EasyLocalizationProvider.of(context).data;
return EasyLocalizationProvider(
data: data,
child: Scaffold(
appBar: AppBar(
title: Text(tr('title')),
actions: <Widget>[
FlatButton(
child: Text("English"),
color: Localizations.localeOf(context).languageCode == "en"
? Colors.lightBlueAccent
: Colors.blue,
onPressed: () {
this.setState(() {
data.changeLocale(Locale("en","US"));
print(Localizations.localeOf(context).languageCode);
});
},
),
FlatButton(
child: Text("عربي"),
color: Localizations.localeOf(context).languageCode == "ar"
? Colors.lightBlueAccent
: Colors.blue,
onPressed: () {
this.setState(() {
data.changeLocale(Locale("ar","DZ"));
print(Localizations.localeOf(context).languageCode);
});
},
)
],
),
body: Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(AppLocalizations.of(context)
.tr('msg', args: ['aissat', 'Flutter'])),
new Text(plural('clicked', counter)),
new FlatButton(
onPressed: () async {
incrementCounter();
},
child: new Text(tr('clickMe')),
),
new Text(
tr('profile.reset_password.title'),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: incrementCounter,
child: Text('+1'),
),
),
);
}
}
Screenshots
Arbic RTL | English LTR |
---|---|