'How to change a Flutter app language without restarting the app?
In the settings page of my app, I would like to add an option that controls the app language.
I can set the language before starting the app like this:
@override
Widget build(BuildContext context) {
return MaterialApp(
// other arguments
locale: Locale('ar'),
);
}
But is it possible to change the language without restarting the app?
Solution 1:[1]
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.
Solution 2:[2]
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
Solution 3:[3]
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.
Solution 4:[4]
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', ''));
Solution 5:[5]
You can use the most popular GetX library as well.
Call Get.updateLocale(locale)
to update the locale. Translations then automatically use the new locale.
var locale = Locale('en', 'US');
Get.updateLocale(locale);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Lennaert Bel |
Solution 2 | Void |
Solution 3 | Dpedrinha |
Solution 4 | |
Solution 5 | krsakju |