How to change a Flutter app language without restarting the app?
If you want to change app language without restarting the app and also without any plugin, you can follow the bellow steps:
In main file of the application, change the default
MyHomePage
to aStatefullWidget
, inStatefullWedget
for exampleMyHomePage
create astatic
methodsetLocal
as followclass MyHomePage extends StatefulWidget { MyHomePage({Key key}) : super(key: key); static void setLocale(BuildContext context, Locale newLocale) async { _MyHomePageState state = context.findAncestorStateOfType<_MyHomePageState>(); state.changeLanguage(newLocale); } @override _MyHomePageState createState() => _MyHomePageState(); }
where _MyHomePageState
is the state
of your MyHomePage
widget
In your
state
create astatic
methodchangeLanguage
:class _MyHomePageState extends State<MyHomePage> { Locale _locale; changeLanguage(Locale locale) { setState(() { _locale = locale; }); } @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Afghanistan', theme: ThemeData(primaryColor: Colors.blue[800]), supportedLocales: [ Locale('fa', 'IR'), Locale('en', 'US'), Locale('ps', 'AFG'), ], locale: _locale, localizationsDelegates: [ AppLocalizationsDelegate(), GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate ], localeResolutionCallback: (locale, supportedLocales) { for (var supportedLocale in supportedLocales) { if (supportedLocale.languageCode == locale.languageCode && supportedLocale.countryCode == locale.countryCode) { return supportedLocale; } } return supportedLocales.first; }, initialRoute: splashRoute, onGenerateRoute: Router.generatedRoute, ); } }
Now from pages of your application you can change the language by calling the
setLocal
method and pass a newLocale
as follow:Locale newLocale = Locale('ps', 'AFG'); MyHomePage.setLocale(context, newLocale);
Please remember you need to create a
LocalizationDelegate
,Here is the link to the Written Tutorial and Demo Application
Wrap your MaterialApp
into a StreamBuilder
which will be responsible for providing the Locale
value to your application. And it will enable you to dynamically change it without restarting your app. This is an example using the rxdart package to implement the stream:
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: setLocale,
initialData: Locale('ar',''),
builder: (context, localeSnapshot) {
return MaterialApp(
// other arguments
locale: localeSnapshot.data,
);
}
);
}
Stream<Locale> setLocale(int choice) {
var localeSubject = BehaviorSubject<Locale>() ;
choice == 0 ? localeSubject.sink.add( Locale('ar','') ) : localeSubject.sink.add( Locale('en','') ) ;
return localeSubject.stream.distinct() ;
}
The above demonstration is just a basic way of how to achieve what you want to, but for a proper implementation of streams in your app you should consider using app-wide BloCs, which will significantly improve the quality of your app by reducing the number of unnecessary builds.
It's easier to use easy_localization package.
For changing language, for example:
onTap: (){
EasyLocalization.of(context).locale = Locale('en', 'US');
}
I learned using this package by this video: Youtube Video Link
UPDATE:
In version 3.0.0:
EasyLocalization.of(context).setLocale(Locale('en', ''));
You can wrap the MaterialApp
widget with a ChangeNotifierProvider
and a Consumer
widgets and control the language from the model.
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
builder: (context) => MainModel(context: context),
child: Consumer<MainModel>(builder: (context, mainModel, child) {
return MaterialApp(
locale: Locale(mainModel.preferredLanguageCode),
....
On the MainModel
, all you need to do is change the preferredLanguageCode
variable to whatever you want ('en', 'ar', 'es', etc). Don't forget to call NotifyListeners()
once you change the language.
This and the other answer have only one problem: Any context
above MaterialApp
can't get the device language (for example when the app is started for the first time) with Localizations.localeOf(context)
. This method required a context
bellow MaterialApp
.
To fix this issue, I used this plugin to get the device language without the need of a context
.
Once the app starts, you can change the language any way you want that this approach will work. I also use SharedPreferences
to store the preferred language once the user changes it.