skip to Main Content

I am using GoRouter for navigation and GetX for multiple things, including updating the app’s locale.

It is updating the language perfectly fine, but the problem is that somehow my navigation stack is getting reset after the call.

I’ve made a Screenvideo for a better understanding but you can also test it yourself here.

I update my locale by simply calling:

  Locale locale = Locale(languageCode);
  await Get.updateLocale(locale);

And my routing looks like this:

final rootNavigatorKey = GlobalKey<NavigatorState>();

class AppRouter {
  static final _shellNavigatorKey = GlobalKey<NavigatorState>();

  static final router = GoRouter(
    initialLocation: IntroView.path,
    debugLogDiagnostics: true,
    navigatorKey: rootNavigatorKey,
    routes: [
      ShellRoute(
        navigatorKey: _shellNavigatorKey,
        pageBuilder: (context, state, child) {
          return NoTransitionPage(
            child: ScaffoldView(
              child: child,
            ),
          );
        },
        routes: [
          GoRoute(
            name: ProjectsView.name,
            path: '/projects',
            parentNavigatorKey: _shellNavigatorKey,
            pageBuilder: (context, state) {
              return const FadePageTransition(
                page: ProjectsView(),
              );
            },
            routes: [
              GoRoute(
                parentNavigatorKey: rootNavigatorKey,
                path: ':projectTitle',
                pageBuilder: (context, state) {
                  return FadePageTransition(
                    page: ProjectDetailScaffold(
                      project: Projects.values.byName(
                        state.params['projectTitle']!,
                      ),
                    ),
                  );
                },
              ),
            ],
          ),

What am I missing here?

Let me know if you need any more info!

2

Answers


  1. Chosen as BEST ANSWER

    For now I found a workaround that is not very clean but it works for me:

    Right after I call await Get.updateLocale(locale); I am calling this:

      if (mounted) {
        while (context.canPop()) {
          context.pop();
        }
        context.pushReplacement('/projects/localizeIt');
      }
    

    The problem is that GoRouter loses the state because updateLocale forces the app to rebuild. As workaround, I am popping all views and going to the location where I am calling updateLocale from.

    Like I said, this is no ideal and more of a workaround. If anyone know a better solution, please let me know.


  2. Your current workaround involves essentially restarting the navigation stack and redirecting to a specific page after changing the locale, and while this might work, it does seem a bit rough and could potentially lead to user experience issues.

    In Flutter, the locale change does indeed cause a rebuild of the widget tree. However, it seems unusual that the navigation stack is getting cleared in this process. Generally, the navigation stack should be maintained across rebuilds unless explicitly cleared or modified.

    The issue could potentially be related to how GetX and GoRouter interact with each other.

    • GetX is a state management solution, and it seems to be causing a full rebuild of the widget tree when the locale changes.
    • GoRouter on the other hand, manages navigation and should maintain its state across widget tree rebuilds.

    So you can try and ensure the GoRouter instance is not being recreated on each rebuild. The router should be created once and maintained for the duration of the app’s lifetime.

    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      final router = AppRouter.router;
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp.router(
          routerDelegate: router.routerDelegate,
          routeInformationParser: router.routeInformationParser,
        );
      }
    }
    

    And consider separating your localization and routing concerns.
    Instead of calling Get.updateLocale directly, you could create a separate service that wraps this call and also preserves your navigation state. This service could listen for locale changes and update the locale without causing a full rebuild of the widget tree.

    class LocaleService extends GetxController {
      void updateLocale(String languageCode) async {
        Locale locale = Locale(languageCode);
        Get.updateLocale(locale);
        update();
      }
    }
    
    class LocaleSwitcher extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return GetBuilder<LocaleService>(
          init: LocaleService(),
          builder: (controller) {
            return DropdownButton<String>(
              value: Get.locale?.languageCode,
              items: <String>['en', 'fr', 'de'].map((String value) {
                return DropdownMenuItem<String>(
                  value: value,
                  child: Text(value),
                );
              }).toList(),
              onChanged: (newValue) {
                controller.updateLocale(newValue!);
              },
            );
          },
        );
      }
    }
    

    LocaleService is a service that wraps the Get.updateLocale call.
    LocaleSwitcher is a widget that uses GetBuilder to listen for changes in LocaleService, and rebuilds itself when the locale is updated.
    This way, only the LocaleSwitcher widget is rebuilt when the locale changes, not the entire widget tree.


    Or: consider using GetMaterialApp which integrates GetX with the Flutter MaterialApp widget (as illustrated here). This might help with preserving the navigation state when changing locale.
    See also "What is the difference between GetMaterialApp of GetX and MaterialApp of Flutter?".
    That would also mean you are relying on GetX for routing instead of GoRouter. If you want to stick with GoRouter for routing, the first two points are enough.
    However, if you are okay with transitioning to GetX for routing, using GetMaterialAp.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search