6

Is it possible to listen when the user changes their system language? I need to clear some list when the user changes their language. Now I am detecting the language in the void main() function on startup.


void main() async {
  // Firebase Push Notifications initialization
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  FirebaseMessaging.onBackgroundMessage(backgroundHandler);
  detectLanguageChange();
  WidgetsBinding.instance.addObserver(this);


  runApp(const MyApp());
}

class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
 @override
  void initState() {
    super.initState();
    WidgetsBinding.instance!.addObserver(this);
  }

  @override
  void didChangeLocales(List<Locale>? locales) {
    // TODO: implement didChangeLocales
    super.didChangeLocales(locales);

    print("Locales changed");
  }

It needs to run 'detectLanguage' every time the language changes.

Jay
  • 231
  • 1
  • 12
  • `WidgetsBindingObserver.didChangeLocales` - the docs say: *"Called when the system tells the app that the user's locale has changed. For example, if the user changes the system language settings."* – pskink Apr 06 '22 at 14:18
  • Hey thanks! I am trying to get the syntax right but it does not fit: WidgetsBindingObserver().didChangeLocales((locale) { }); – Jay Apr 06 '22 at 14:31
  • see https://stackoverflow.com/questions/61958437/flutter-widgets-binding-observer or https://stackoverflow.com/questions/64999808/get-widget-observer-for-widgetsbindingobserver – pskink Apr 06 '22 at 14:41
  • I don't see them using didChangeLocales. Do I need to make a new 'widget' and extend it with WidgetsBindingObserver? – Jay Apr 06 '22 at 15:39
  • just mixin `WidgetsBindingObserver` with some of your classes (with `with WidgetsBindingObserver` syntax), call `WidgetsBinding.instance.addObserver(this)` and override methods you want to "watch" – pskink Apr 06 '22 at 15:59
  • I added some code, but I still do not get what you mean... :/ – Jay Apr 07 '22 at 10:00
  • [here](https://stackoverflow.com/a/64999877/2252830) you can see how to add observer inside `initState` method – pskink Apr 07 '22 at 10:10
  • I added it in the init state, but how can I execute a function when the language changes? I edited the question again and added the code – Jay Apr 07 '22 at 11:02
  • override `didChangeLocales` method in `_MyAppState` class then – pskink Apr 07 '22 at 11:20
  • I did that and it works (partly). Now the print method is fired when the user goes back to the app. Is it possible to fire a method at the moment, the language is changed? – Jay Apr 07 '22 at 11:44

3 Answers3

1

It is possible to create a stateful widget which acts as a WidgetsBindingObserver and receive locale changes by the didChangeLocales callback.

Let me provide a minimal example widget:

import 'package:flutter/material.dart';

class LocaleListenerWidget extends StatefulWidget {
  final Locale defaultLocale;
  final Widget? child;
  
  const LocaleListenerWidget({super.key, this.defaultLocale = const Locale('en_US'), this.child});

  @override
  State<LocaleListenerWidget> createState() => _LocaleListenerWidgetState();
}

class _LocaleListenerWidgetState extends State<LocaleListenerWidget>
    with WidgetsBindingObserver {
  @override
  void initState() {
    WidgetsBinding.instance.addObserver(this);
    super.initState();
  }

  @override
  void didChangeLocales(List<Locale>? locales) {
    super.didChangeLocales(locales);

    // Here locales is a list of all the locales enabled on the device.
    // Like: [Locale('en_US'), Locale('ar_SA')]

    // The first locale is the phone's main locale, but in reality you should
    // traverse until you find a supported locale.
    final currentLocale = locales?.first ?? widget.defaultLocale;
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return widget.child ?? const SizedBox.shrink();
  }
}

Then you just have to put this widget high enought in your tree. For example into your MaterialApp's builder:

void main() {
  runApp(MaterialApp(builder: (context, child) => const LocaleListenerWidget(child: child)));
}
slaci
  • 111
  • 4
-1

You can use Getx library and use:

return GetMaterialApp(
     locale: Get.deviceLocale,   //returns Locale('<language code>', '<country code>')
);

from there you can store it in a variable and once the device language update changes so does the var and there you link your desired function.

MendelG
  • 14,885
  • 4
  • 25
  • 52
-2

Yes, it is possible. Take a look on this example:

@override
  Widget build(BuildContext context) {
    Locale myLocale = Localizations.localeOf(context);

_customFunction();

    return Scaffold(
      appBar: AppBar(
        title: 'Title'),
      ),
      body: Text(myLocale.languageCode == 'fr' ? 'Bonjour!' : 'Hello!'),
    );
  }
Erick Lanford Xenes
  • 1,467
  • 2
  • 20
  • 34