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:

  1. In main file of the application, change the default MyHomePage to a StatefullWidget, in StatefullWedget for example MyHomePage create a static method setLocal as follow

    class 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

  1. In your state create a static method changeLanguage:

     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,
          );
       }
      }
    
  2. Now from pages of your application you can change the language by calling the setLocal method and pass a new Locale as follow:

    Locale newLocale = Locale('ps', 'AFG');
    MyHomePage.setLocale(context, newLocale);
    
  3. Please remember you need to create a LocalizationDelegate,

  4. 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.

Tags:

Flutter