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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 09:45:53