Closed red-star25 closed 1 year ago
Found the solution. When you change the language use this:
context.setLocale(locale); Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (BuildContext context) => Login()), ModalRoute.withName('/') );
For anyone who's still struggling with this problem. I found a workaround that works for me (at least for now) but I don't know if It may cost some performance issues (in fact I would appreciate an answer to that question)
while I was trying to figure out a solution I found out that some of my widgets are rebuilt when changing the langue while others are not. so the question became why these widgets are being rebuilt instead of why those are not being rebuilt...
The short answer is context
.
The only widgets that are rebuilt in my app and their language are changed are widgets that are depending on context.
here's an example of what I mean.
This is the code of a text widget that was being rebuilt and language being changed normally
Text("best_sellings".tr(), style: Theme.of(context).textTheme.headlineSmall),
and this is the widget that weren't changing at all ( until I hot reload )
ElevatedButton.icon(
label: Text("explore_all_products".tr(), overflow: TextOverflow.ellipsis),
icon: const Icon(Icons.manage_search_rounded),
onPressed: () => context.router.push(const ExploreScreenRoute()),
),
the solution that made the button being forced to rebuild after language change is adding this line to the ElevatedButton
style: Theme.of(context).elevatedButtonTheme.style,
Again, I don't know if this is costly in performancee but it's doing the job for now. I am not sure this will work when changing between two languages that have the same directionality. my case is between arabic(ar) and english(en)
All of the solutions provided above somehow did not work for me and I wasted a whole night for this but I think I found a fix for it finally. In the end it is surprisingly simple but you have to know it - like nearly every time.
For some reasons (which are not obvious to me) the MaterialApp
widget somehow keeps its state even if the top level widget gets rebuild. That is the difference to GetMaterialApp
what is the reason while there are some solutions for it above. I am using GetX but only some features and therefore still have the default MaterialApp
in my widget tree.
Long story short: add key: UniqueKey()
to your MaterialApp
. Then calling context.setLocale()
also leads to a complete rebuild of the MaterialApp
widget and now the new locale is applied.
Maybe it helps someone out there who also struggled with this issue for hours :-)
All of the solutions provided above somehow did not work for me and I wasted a whole night for this but I think I found a fix for it finally. In the end it is surprisingly simple but you have to know it - like nearly every time.
For some reasons (which are not obvious to me) the
MaterialApp
widget somehow keeps its state even if the top level widget gets rebuild. That is the difference toGetMaterialApp
what is the reason while there are some solutions for it above. I am using GetX but only some features and therefore still have the defaultMaterialApp
in my widget tree.Long story short: add
key: UniqueKey()
to yourMaterialApp
. Then callingcontext.setLocale()
also leads to a complete rebuild of theMaterialApp
widget and now the new locale is applied.Maybe it helps someone out there who also struggled with this issue for hours :-)
@FelixMittermeier Your solutions works but if the app is wrapped inside GetMaterialApp
. This soulution will restart the app instantly, which might not be ideal.
I solved this issue with push the same route and remove other routes after setting locale.
await context.setLocale(Locale('ru'));
await Navigator.pushNamedAndRemoveUntil(context, '/main', (route) => false);
The below workaround works for me
localeResolutionCallback: (locale, supportedLocales) { if (supportedLocales.contains(locale)) { context.setLocale(locale!); return locale; } else { context.setLocale(supportedLocales.first); return supportedLocales.first; } },
The above code need to add for material app, this changes app launguage on ddevice launguage changed.
Hmm, I also have this problem. I have a list view with my custom widget tile, It's only change the widget without the const keyword, I can't get this off.
example
@override Widget build(BuildContext context, WidgetRef ref) { return ListView( children: [ const ProfileTile(), const LanguageTile(), const SignOutTile(), ], ); }
Hmm, I also have this problem. I have a list view with my custom widget tile, It's only change the widget without the const keyword, I can't get this off. example
@override Widget build(BuildContext context, WidgetRef ref) { return ListView( children: [ const ProfileTile(), const LanguageTile(), const SignOutTile(), ], ); }
If I remove the const, it will be redrawn and change the text, wonder why
Hmm, I also have this problem. I have a list view with my custom widget tile, It's only change the widget without the const keyword, I can't get this off. example
@override Widget build(BuildContext context, WidgetRef ref) { return ListView( children: [ const ProfileTile(), const LanguageTile(), const SignOutTile(), ], ); }
If I remove the const, it will be redrawn and change the text, wonder why
@quydn720 Yes, I was trying to change language in a dialog. When I removed const, it changed. But for some reason, it was setting the previous locale's strings in the dialog, it sets the other widgets on the screen correctly. I solved this using setState.
await context.setLocale(Locale('ru'));
WidgetsBinding.instance!.addPostFrameCallback((_) {
setState(() {});
});
I solved this by wrapping MaterialApp with a BlocListener, then calling listener: (context, state) async { await context.setLocale(state.locale); }
my texts/Strings are not updating while it is switching to ltr to rtl, but somehow unable to switch texts on screen. I can see the change after hot reload.
Any updates according this issue?
Randomly the layout direction changes but the text translation keep the same! 🤷🏻♂️
Getting this error? any idea?
Unhandled Exception: 'package:easy_localization/src/easy_localization_app.dart': Failed assertion: line 216 pos 14: 'parent.supportedLocales.contains(locale)': is not true.
For me, I was missing supportedLocales: ctx.supportedLocales
inside MaterialApp setup
Just posting again to say that this actually works: https://stackoverflow.com/questions/43778488/how-to-force-flutter-to-rebuild-redraw-all-widgets
@override Widget build(BuildContext context) { rebuildAllChildren(context); return MaterialApp( .... } void rebuildAllChildren(BuildContext context) { void rebuild(Element el) { el.markNeedsBuild(); el.visitChildren(rebuild); } (context as Element).visitChildren(rebuild); }
It was posted by the author of the i18n_extension ( https://pub.dev/packages/i18n_extension ) and even though it shouldn't be recommended it seems to be the only way to inmediately refresh the widget tree to show the new locale properly.
I'm fine with this solution.
I have found a possible solution.
In case you are using
GetMaterialApp
you should when changing the current language callGet.updateLocale()
to informGetMaterialApp
about the language changefinal _newLocale = Locale('ar', 'EG') await context.setLocale(_newLocale); // change `easy_localization` locale Get.updateLocale(_newLocale); // change `Get` locale direction
this one worked for thank you
For anyone who is not using GetX
the solution is basically calling
final engine = WidgetsFlutterBinding.ensureInitialized();
engine.performReassemble();
and that's what GetX
basically do when changing locales as @AhmedAbouelkher mentioned above
same here. Some texts are not changing. Need to refresh the app for change. Not using Get. Any solution?
For anyone who is not using
GetX
the solution is basically callingfinal engine = WidgetsFlutterBinding.ensureInitialized(); engine.performReassemble();
and that's what
GetX
basically do when changing locales as @AhmedAbouelkher mentioned above
This is working for me.
For anyone who is not using
GetX
the solution is basically callingfinal engine = WidgetsFlutterBinding.ensureInitialized(); engine.performReassemble();
and that's what
GetX
basically do when changing locales as @AhmedAbouelkher mentioned above
This worked for me , thanks.
EDIT: ok actually things dont work after second click of the button as they should. It is just that as I am switching between only 2 languages. Everytime after context.setLocale, "tr()" is still using old values of context.locale (or whole context?). So tr() is kind of all the time one step behind...
Similar problem still on 3.0.1. After the startup value is ok. But then I have a button to switch value to other language. on first click value does not change. But on second and further clicks things work. Tried a few solutions above, nothing works.
In my case for example lets say I have on initialization correct values releated to "firstLocale". Then on first click of the button for language switch I have:
context.setLocale(secondLocale);
setState(() {
message = messageId.tr();
});
Then if i go in debug mode and stop right after the last line of code, I check:
context.locale
which is "secondLocale".
However, when I use
messageId.tr()
tr() returns translation for the firstLocale... So somehow tr() does not know yet of the update of context.locale...
But if I click on the button again, then things start to work...
OK, to make things work for me I downloaded the package for version 3.0.1, added it to the project locally and slightly changed easy_localization_controller.dart
.
Note: yes I have no idea if this is correct approach and did not test what would happen when having big json files. So any comment on that is very welcome.
So in easy_localization_controller.dart
I added Localization.load
to loadTranslations()
. For Localization.load
, I also had to add to the top import 'localization.dart'
. So the whole loadTranslations()
looks like this:
Future loadTranslations() async {
Map<String, dynamic> data;
try {
data = await loadTranslationData(_locale);
_translations = Translations(data);
// Added Localization.load. Also needed to add "import 'localization.dart'" at the top.
Localization.load(_locale,translations:_translations);
if (useFallbackTranslations && _fallbackLocale != null) {
data = await loadTranslationData(_fallbackLocale!);
_fallbackTranslations = Translations(data);
// also added as the part of the fix. Did not test this, but I presume it should be here.
Localization.load(_fallbackLocale!,fallbackTranslations:_fallbackTranslations);
}
} on FlutterError catch (e) {
onLoadError(e);
} catch (e) {
onLoadError(FlutterError(e.toString()));
}
}
Then in my main.dart
I have function to change language, which also have to have async. So part of the code which takes care for the language switch would be:
await context.setLocale(changeToLocale);
setState(() {
message = messageId.tr();
});
So now finally, tr()
gets the right translation as assigned by the setLocale
two lines before. Without the fix as mention above, it lags one step behind.
if you are using GetMaterialApp you have 2 solutions that worked for me : 1 : Add key in GetMaterialApp as UniquKey(); GetMaterialApp( key: UniqueKey(), useInheritedMediaQuery: true, locale:context.locale, localizationsDelegates: context.localizationDelegates, supportedLocales: context.supportedLocales,
and it should work but it will rebuild the app tree. 2 : After setting the Locale you need to update the Get Local like this ; await context.setLocale(const Locale("en")); Get.updateLocale( const Locale("en")); and this will keep you on the same screen and update Locale over all the app
Duplicate of #448 #552
the only solution i found is to add context.setLocale(context.locale) in the beginning of build method if you widget does not want to change the locale
...
@override
Widget build(BuildContext context) {
context.setLocale(context.locale);
return ...
I solved it when wrapped the BottomNavigationBar to Localizations.override
bottomNavigationBar: Localizations.override(
context: context,
locale: context.locale,
child: CustomBottomNavigationBar(
),
),
It is also important that the elements are inside build method... for example:
Widget build(BuildContext context) {
List<_BottomNavigationBarItem> items = [
_BottomNavigationBarItem(
iconSelectedPath: AppIcons.report_dark,
iconNoSelectedPath: AppIcons.report_white,
title: LocaleKeys.report.tr(),
),
_BottomNavigationBarItem(
iconSelectedPath: AppIcons.home_dark,
iconNoSelectedPath: AppIcons.home_white,
title: LocaleKeys.home.tr(),
),
_BottomNavigationBarItem(
iconSelectedPath: AppIcons.settings_dark,
iconNoSelectedPath: AppIcons.settings_white,
title: LocaleKeys.settings.tr(),
),
];
...
}
Solved. Using a DropdownButton to set locale
onChanged: (value) async { if (value != null) { await context.setLocale(value); setState(() {}); // very importend } },
I have found a possible solution.
In case you are using
GetMaterialApp
you should when changing the current language callGet.updateLocale()
to informGetMaterialApp
about the language changefinal _newLocale = Locale('ar', 'EG') await context.setLocale(_newLocale); // change `easy_localization` locale Get.updateLocale(_newLocale); // change `Get` locale direction
it works man
For people coming back to this problem.. You wouldn't believe the fix is so easy. I had the exact same problem.
Simply do this:
onChanged: (value) async { await context.setLocale(Locale.fromSubtags(languageCode: value!.languageCode, countryCode: value.countryCode)); setState((){}); }
Remember to call the set state after the setLocale finishes. It's of type Future<void>
and you need to wait. And call setState() after it finishes.
I have found a possible solution. In case you are using
GetMaterialApp
you should when changing the current language callGet.updateLocale()
to informGetMaterialApp
about the language changefinal _newLocale = Locale('ar', 'EG') await context.setLocale(_newLocale); // change `easy_localization` locale Get.updateLocale(_newLocale); // change `Get` locale direction
it works man
Upvoting because of your async answer!
I am currently using Easy Localization 3.0.1 . I tried most of the above solutions.
The method of deleting Const worked for me, but I didn't use it because deleting it throughout the entire application could cause issues. The approach of adding UniqueKey() to MaterialApp also worked, but I didn't like it because it refreshed the entire app as if it had crashed.
But the engine method at the bottom works flawlessly for now. Thank you!
For anyone who is not using
GetX
the solution is basically callingfinal engine = WidgetsFlutterBinding.ensureInitialized(); engine.performReassemble();
and that's what
GetX
basically do when changing locales as @AhmedAbouelkher mentioned above
... the engine method at the bottom works flawlessly for now.
Calling performReassemble
await context.setLocale(locale);
await WidgetsBinding.instance.performReassemble();
works, but at what cost? It says it rebuilds the whole application which is not a big deal if you're 2 screens in but if you're 50 screens away and you change your language from, let's say, a drawer, what could happen?
... the engine method at the bottom works flawlessly for now.
Calling
performReassemble
await context.setLocale(locale); await WidgetsBinding.instance.performReassemble();
works, but at what cost? It says it rebuilds the whole application which is not a big deal if you're 2 screens in but if you're 50 screens away and you change your language from, let's say, a drawer, what could happen?
I agree with what you said, but this solution worked best among the ones I tried.
... the engine method at the bottom works flawlessly for now.
Calling
performReassemble
await context.setLocale(locale); await WidgetsBinding.instance.performReassemble();
works, but at what cost? It says it rebuilds the whole application which is not a big deal if you're 2 screens in but if you're 50 screens away and you change your language from, let's say, a drawer, what could happen?
Ideally speaking this would not be good if you navigated 50 routes, practically i can't see a real case scenario were that can happen.
I have found a possible solution.
In case you are using
GetMaterialApp
you should when changing the current language callGet.updateLocale()
to informGetMaterialApp
about the language changefinal _newLocale = Locale('ar', 'EG') await context.setLocale(_newLocale); // change `easy_localization` locale Get.updateLocale(_newLocale); // change `Get` locale direction
Thanks alot, this worked!
Hi, Is there any update for handle rebuilding internally after setLocale? The solutions I've read about don't seem to be suitable for production applications, and I don't want to use any third-party packages either.
Well... after trying many things out. I finally found a solution:
final myTranslatedHelloWorld = context.tr("my_awesome_key");
final myTranslatedHelloWorld = "my_awesome_key".tr();
final myTranslatedHelloWorld = tr("my_awesome_key");
final myTranslatedHelloWorld = Text("my_awesome_key").tr();
Or...
final myTranslatedHelloWorld = "my_awesome_key".tr(context: context);
final myTranslatedHelloWorld = tr("my_awesome_key", context: context);
final myTranslatedHelloWorld = Text("my_awesome_key").tr(context: context);
... the engine method at the bottom works flawlessly for now.
Calling
performReassemble
await context.setLocale(locale); await WidgetsBinding.instance.performReassemble();
works, but at what cost? It says it rebuilds the whole application which is not a big deal if you're 2 screens in but if you're 50 screens away and you change your language from, let's say, a drawer, what could happen?
Thank you, I was stuck for 3 months with this problem and thanks Allah he caused you to solve my problem.
I solved it when wrapped the BottomNavigationBar to Localizations.override
bottomNavigationBar: Localizations.override(
context: context,
locale: context.locale,
child: CustomBottomNavigationBar(
),
),
It is also important that the elements are inside build method... for example:Widget build(BuildContext context) {
List<_BottomNavigationBarItem> items = [
_BottomNavigationBarItem(
iconSelectedPath: AppIcons.report_dark,
iconNoSelectedPath: AppIcons.report_white,
title: LocaleKeys.report.tr(),
),
_BottomNavigationBarItem(
iconSelectedPath: AppIcons.home_dark,
iconNoSelectedPath: AppIcons.home_white,
title: LocaleKeys.home.tr(),
),
_BottomNavigationBarItem(
iconSelectedPath: AppIcons.settings_dark,
iconNoSelectedPath: AppIcons.settings_white,
title: LocaleKeys.settings.tr(),
),
];
...
}
it is perfect
For anyone who is not using
GetX
the solution is basically callingfinal engine = WidgetsFlutterBinding.ensureInitialized(); engine.performReassemble();
and that's what
GetX
basically do when changing locales as @AhmedAbouelkher mentioned above
this worked for me too, But is that can effect on app's performance ?
For anyone who is not using
GetX
the solution is basically callingfinal engine = WidgetsFlutterBinding.ensureInitialized(); engine.performReassemble();
and that's what
GetX
basically do when changing locales as @AhmedAbouelkher mentioned above
I done this but unfortunately no thing is changed
locale: context.locale,
Damn i feel really dumb rn. Thanks it's worked for me i just forgot to use context
https://stackoverflow.com/questions/78921888/ui-not-updated-when-changing-locale-easy-localization
This one helped me, just passing context to the LocaleKeys generated class does the trick
I've updated easy_localization: 3.0.0 package from easy_localization: ^2.3.3. When i was using easy_localization: ^2.3.3 it is updating my app locale instantly whenever i called
But since I've updated the package version to 3.0.0 it is not updating the locale instantly. I've to hot restart the whole app to see the changes.
Here is what im doing in version 3.0.0
onTap: () async { await homeController .setLanguage("EN") .then((value) async { await context .setLocale( const Locale( "en")); }) },
And here is what im doing in version 2.3.3 (which is working,and updating locale instantly)
onTap: () { homeController .setLanguage("EN"); setState(() { context.locale = const Locale( "en"); }); },