You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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信息。

修复步骤

  1. 调整状态监听层级,触发全局重建
    将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(),
                  );
                },
              ),
            ),
          ),
        );
      }
    }
    
  2. 联动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,
    
  3. 确保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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 04:25:13