Flutter本地化配置异常:初始设为西班牙语却显示英语
Flutter Localization 语言切换异常排查
问题概述
使用flutter_localizations 0.2.0版本,已在main.dart中配置Locale初始语言为'es',初始化阶段检测到languageCode为'es'符合预期,但进入欢迎页面调用LocaleData.getText()方法时,context中的languageCode变为默认的'en_US'。
关键代码片段
1. main.dart 中MainAppState配置
class MainAppState extends ConsumerState<MainApp> { // 设备本地化实例 final FlutterLocalization localization = FlutterLocalization.instance; // SharedPreferences服务实例 final keyValueStorageService = KeyValueStorageServiceImpl(); @override void initState() { super.initState(); // 配置应用支持的语言 configureLocalizaton(); } @override Widget build(BuildContext context) { // 屏幕尺寸变量 final size = MediaQuery.of(context).size; // 路由实例 final appRouter = ref.watch(routerProvider); return MaterialApp( debugShowCheckedModeBanner: false, localizationsDelegates: localization.localizationsDelegates, supportedLocales: localization.supportedLocales, locale: localization.currentLocale, localeResolutionCallback: (locale, supportedLocales) { for (var supportedLocale in supportedLocales) { if (supportedLocale.languageCode == locale?.languageCode) return supportedLocale; } return supportedLocales.first; }, home: AnimatedSplashScreen( splash: Center( child: Lottie.asset('assets/animations/splashscreen_animation.json', width: size.width, height: size.height, fit: BoxFit.cover), ), splashIconSize: 4500, centered: true, nextScreen: MaterialApp.router( debugShowCheckedModeBanner: false, theme: AppTheme(selectedColor: 1, isDarkMode: true).getTheme(), routerConfig: appRouter, ), backgroundColor: colorList[0], ), ); } // 初始化语言配置方法 void configureLocalizaton() { localization.init( mapLocales: locales, initLanguageCode: 'es'); localization.onTranslatedLanguage = onTranslatedLanguage; } void onTranslatedLanguage(Locale? locale) async { // 更新Provider中的语言状态 ref.read(localeProvider(locale!.languageCode).notifier).checkLanguage; setState(() {}); } }
2. LocaleData类代码
// ignore_for_file: constant_identifier_names import 'package:flutter/material.dart'; import 'package:flutter_localization/flutter_localization.dart'; const List<MapLocale> locales = [ MapLocale('es', LocaleData.ES), MapLocale('en', LocaleData.EN), ]; mixin LocaleData { static const String welcomeScreen_welcome = 'welcomeScreen_welcome'; static const String welcomeScreen_begin = "welcomeScreen_begin"; static const String welcomeScreen_question = "welcomeScreen_question"; static const String welcomeScreen_signinB = "welcomeScreen_signinB"; static const String welcomeScreen_signupB = "welcomeScreen_signupB"; static const String siginScreen_title = "siginScreen_title"; static const String siginScreen_welcome = "siginScreen_welcome"; static const String siginScreen_rememberP = "siginScreen_rememberP"; static const String siginScreen_forgottenP = "siginScreen_forgottenP"; static const String siginScreen_signinB = "siginScreen_signinB"; static const String siginScreen_signupRRSST = "siginScreen_signupRRSST"; static const String siginScreen_withoutAccountT = "siginScreen_withoutAccountT"; static const String siginScreen_signupT = "siginScreen_signupT"; static const String signUpScreen_title = "signUpScreen_title"; static const String signUpScreen_fullNameT = "signUpScreen_fullNameT"; static const String signUpScreen_mailT = "signUpScreen_mailT"; static const String signUpScreen_passwordT = "signUpScreen_passwordT"; static const String signUpScreen_rpasswordT = "signUpScreen_rpasswordT"; static const String signUpScreen_agreeT = "signUpScreen_agreeT"; static const String signUpScreen_conditionsT = "signUpScreen_conditionsT"; static const String signUpScreen_signUpB = "signUpScreen_signUpB"; static const String signUpScreen_alreadySignupT = "signUpScreen_alreadySignupT"; static const String signUpScreen_signInT = "signUpScreen_signInT"; // 西班牙语映射 static const Map<String, dynamic> ES = { welcomeScreen_welcome: 'Bienvenido a Roll&Play', welcomeScreen_begin: "Comencemos con tu cuenta", welcomeScreen_question: "¿Qué quieres hacer?", welcomeScreen_signinB: "Login", welcomeScreen_signupB: "Registrar", siginScreen_title: "Login", siginScreen_welcome: "Bienvenido de nuevo", siginScreen_rememberP: "Recordarme", siginScreen_forgottenP: "¿Olvidaste la password?", siginScreen_signinB: "Entrar", siginScreen_signupRRSST: "Loguea con", siginScreen_withoutAccountT: "¿No tienes cuenta?", siginScreen_signupT: "Registrate aquí", signUpScreen_title: "Comencemos", signUpScreen_fullNameT: "Nombre completo", signUpScreen_mailT: "Email", signUpScreen_passwordT: "Password", signUpScreen_rpasswordT: "Repita la password", signUpScreen_agreeT: "Acepto los términos y condiciones de la", signUpScreen_conditionsT: "Política de la aplicación", signUpScreen_signUpB: "Registrar", signUpScreen_alreadySignupT: "¿Ya tienes cuenta?", signUpScreen_signInT: "Ingresa aquí?" }; // 英语映射 static const Map<String, dynamic> EN = { welcomeScreen_welcome: "Welcome to Roll&Play", welcomeScreen_begin: "Let's begin with your account", welcomeScreen_question: "What do you want to do?", welcomeScreen_signinB: "SignIn", welcomeScreen_signupB: "SignUp", siginScreen_title: "SignIn", siginScreen_welcome: "Welcome back", siginScreen_rememberP: "Remember me", siginScreen_forgottenP: "Forgot password?", siginScreen_signinB: "SignIn", siginScreen_signupRRSST: "Sign up with", siginScreen_withoutAccountT: "Don't have an account?", siginScreen_signupT: "Sign up here", signUpScreen_title: "Let's begin!", signUpScreen_fullNameT: "Full name", signUpScreen_mailT: "Email", signUpScreen_passwordT: "Password", signUpScreen_rpasswordT: "Repeat the password", signUpScreen_agreeT: "I agree to the processing of", signUpScreen_conditionsT: "Personal data", signUpScreen_signUpB: "SignUp", signUpScreen_alreadySignupT: "Already have an account?", signUpScreen_signInT: "Sign in here?" }; static String getText(BuildContext context, String key) { String locale = Localizations.localeOf(context).languageCode; if (locale == 'es') { return ES[key] ?? key; } else if (locale == 'en') { return EN[key] ?? key; } else { return key; } } }
3. 欢迎页相关代码
Center( child: RichText( textAlign: TextAlign.center, text: TextSpan( children: [ TextSpan( text: LocaleData.getText(context, LocaleData.welcomeScreen_welcome), style: textstyle.titleLarge!.copyWith(fontSize: 45.0,fontWeight: FontWeight.w600) ), TextSpan( text: LocaleData.welcomeScreen_begin, style: textstyle.titleMedium!.copyWith(fontSize: 25,color: Colors.white)), TextSpan( text: LocaleData.welcomeScreen_question, style: textstyle.titleMedium!.copyWith(fontSize: 20,color: Colors.white54)), ], ), ), ),
问题原因
核心问题是嵌套了两个MaterialApp实例:
- 外层MaterialApp配置了locale、localizationsDelegates等本地化参数,但内层的
MaterialApp.router没有继承这些配置,而是创建了一个全新的Localizations作用域。 - 内层MaterialApp未指定locale,因此默认使用框架默认的'en_US',导致欢迎页context中的languageCode变为'en'。
解决方案
方案1:移除嵌套的MaterialApp(推荐)
将内层MaterialApp的配置(theme、routerConfig)移到外层MaterialApp中,只保留一个MaterialApp实例,确保整个应用共享同一套本地化配置:
修改main.dart的build方法:
@override Widget build(BuildContext context) { final size = MediaQuery.of(context).size; final appRouter = ref.watch(routerProvider); return MaterialApp( debugShowCheckedModeBanner: false, localizationsDelegates: localization.localizationsDelegates, supportedLocales: localization.supportedLocales, locale: localization.currentLocale, localeResolutionCallback: (locale, supportedLocales) { for (var supportedLocale in supportedLocales) { if (supportedLocale.languageCode == locale?.languageCode) return supportedLocale; } return supportedLocales.first; }, theme: AppTheme(selectedColor: 1, isDarkMode: true).getTheme(), routerConfig: appRouter, home: AnimatedSplashScreen( splash: Center( child: Lottie.asset('assets/animations/splashscreen_animation.json', width: size.width, height: size.height, fit: BoxFit.cover), ), splashIconSize: 4500, centered: true, nextScreen: const WelcomeScreen(), // 直接指定欢迎页,后续页面由路由管理 backgroundColor: colorList[0], ), ); }
方案2:同步内层MaterialApp的本地化配置
如果必须保留嵌套结构,需要在内层MaterialApp中同步外层的本地化参数:
nextScreen: MaterialApp.router( debugShowCheckedModeBanner: false, theme: AppTheme(selectedColor: 1, isDarkMode: true).getTheme(), routerConfig: appRouter, // 同步本地化配置 localizationsDelegates: localization.localizationsDelegates, supportedLocales: localization.supportedLocales, locale: localization.currentLocale, ),
额外优化点
- 欢迎页代码中,
LocaleData.welcomeScreen_begin和LocaleData.welcomeScreen_question直接使用了常量字符串,没有调用getText方法,会导致这部分文本不会随语言切换更新,建议统一改为LocaleData.getText(context, LocaleData.welcomeScreen_begin)。
内容的提问来源于stack exchange,提问作者Daniel Salamanca García
相关产品推荐
相关产品推荐

