使用easy_localization切换Locale时UI未更新问题排查
问题:调用
context.setLocale()切换语言后UI未更新,仅热重载时生效 问题详情
在项目中使用flutter_bloc、go_router和easy_localization,调用context.setLocale(<locale>)切换Locale时,Language Cubit的状态已发生变化,但UI并未更新。只有保存文件触发热重载时,UI才会更新。
包版本
flutter_bloc: ^8.1.6 easy_localization: ^3.0.7 go_router: ^14.2.3
翻译用法示例
Text(LocaleKeys.hello.tr())
Easy Localization配置
static const _translationAssets = 'assets/translations'; AppLocalizationConfig({required super.child, super.key}) : super( supportedLocales: AppLocale.supportedLocales, path: _translationAssets, fallbackLocale: AppLocale.de.locale, startLocale: AppLocale.de.locale, useFallbackTranslations: true, useOnlyLangCode: true, assetLoader: const CodegenLoader(), ); }
核心代码示例
class App extends StatefulWidget { const App({super.key}); @override State<App> createState() => _App(); } class _App extends State<App> { @override Widget build(BuildContext superContext) { return BlocListener<AuthBloc, AuthState>( listener: (context, state) { appRouter.refresh(); }, child: AppLocalizationConfig( child: GlobalLoaderOverlay( child: FlutterSizer( builder: (context, orientation, screenType) { // 语言变更时此代码总会执行 final locale = context.watch<LanguageCubit>(); return MaterialApp.router( debugShowCheckedModeBanner: false, routerConfig: appRouter, localizationsDelegates: context.localizationDelegates, supportedLocales: AppLocale.supportedLocales, locale: locale.state.locale, // context.locale同样无效 theme: context.read<ThemeBloc>().state.themeData, builder: BotToastInit(), ); }, ), ), ), ); } }
解决方案
核心原因
MaterialApp.router层级问题:MaterialApp被嵌套在FlutterSizer的builder内部,context.watch<LanguageCubit>()的监听上下文是局部的,状态变化无法触发全局路由树的重建,导致页面无法感知locale更新。- Easy Localization与Cubit状态未联动:直接给
MaterialApp的locale赋值Cubit状态,没有同步Easy Localization内部的locale状态,tr()方法无法获取新的locale信息。
修复步骤
调整状态监听层级,触发全局重建
将LanguageCubit的监听提到FlutterSizer外层,确保状态变化能触发整个App组件的重建,从而更新MaterialApp的locale:class _App extends State<App> { @override Widget build(BuildContext superContext) { // 外层监听Cubit状态,确保状态变化触发全局重建 final localeState = superContext.watch<LanguageCubit>().state; return BlocListener<AuthBloc, AuthState>( listener: (context, state) { appRouter.refresh(); }, child: AppLocalizationConfig( child: GlobalLoaderOverlay( child: FlutterSizer( builder: (context, orientation, screenType) { return MaterialApp.router( debugShowCheckedModeBanner: false, routerConfig: appRouter, localizationsDelegates: context.localizationDelegates, supportedLocales: AppLocale.supportedLocales, locale: localeState.locale, theme: context.read<ThemeBloc>().state.themeData, builder: BotToastInit(), ); }, ), ), ), ); } }联动Easy Localization与Cubit的locale更新
在LanguageCubit的切换方法中,先调用Easy Localization的setLocale,再更新Cubit状态,最后刷新路由确保页面重建:class LanguageCubit extends Cubit<LanguageState> { final BuildContext context; LanguageCubit(this.context) : super(LanguageState.initial()); void switchLocale(Locale locale) { // 同步Easy Localization的locale context.setLocale(locale); // 更新Cubit状态 emit(state.copyWith(locale: locale)); // 强制刷新所有路由页面 appRouter.refresh(); } }之后
MaterialApp可以直接使用Easy Localization提供的locale:locale: context.locale,确保go_router页面响应locale变化
对于go_router管理的页面,若使用StatefulWidget,可在页面内部通过context.watch<LanguageCubit>()或监听context.locale变化触发重建;也可使用ShellRoute将locale监听放在shell层,让所有子页面自动感知变化。
关键提示
- 避免在局部builder内部做全局状态监听,否则状态变化可能无法传递到上层组件。
appRouter.refresh()是强制路由页面重建的关键,否则即使locale更新,页面也不会重新加载翻译内容。- Easy Localization的
context.setLocale()本身会更新内部locale,但需要确保MaterialApp的locale同步,且路由页面完成重建。
内容的提问来源于stack exchange,提问作者H.Gndgn
相关产品推荐
相关产品推荐

