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

Flutter多语言应用:如何强制覆盖Locale并动态切换语言?

Flutter 手动切换应用Locale并动态刷新翻译的实现方案

我太懂你这个需求了——已经按官方文档搞定了跟随系统的多语言适配,但现在想让用户手动选EN、FR、ES这些语言,还要切换后立刻刷新所有界面的翻译,官方文档这块确实没给出直接方案,我给你基于你现有的代码改造一下,完美实现这个功能。

核心思路

要实现手动切换Locale并动态刷新,关键是用状态管理保存用户选择的Locale,然后让App能监听这个Locale的变化,重新加载对应的翻译资源并刷新界面。咱们用Flutter自带的ChangeNotifier来做状态管理就足够,不用额外引入第三方库。


步骤1:创建Locale状态管理类

先写一个全局的状态类,用来保存当前选中的Locale,并且提供切换方法:

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

class AppLocaleProvider extends ChangeNotifier {
  Locale? _selectedLocale;

  Locale? get selectedLocale => _selectedLocale;

  // 切换Locale的方法
  void setLocale(Locale locale) {
    _selectedLocale = locale;
    notifyListeners(); // 通知所有监听的组件刷新
  }
}

步骤2:修改你的TranslationsDelegate

原来的Delegate是固定依赖系统Locale的,现在要让它能使用我们自定义的Locale,所以需要改成可接收外部Locale的版本:

class TranslationsDelegate extends LocalizationsDelegate<Translations> {
  final Locale? customLocale; // 新增:自定义Locale参数

  const TranslationsDelegate({this.customLocale});

  @override
  bool isSupported(Locale locale) => ['en', 'fr', 'es'].contains(locale.languageCode);

  @override
  Future<Translations> load(Locale locale) {
    // 如果有自定义Locale,就用它,否则 fallback 到系统Locale
    final targetLocale = customLocale ?? locale;
    return SynchronousFuture<Translations>(Translations(targetLocale));
  }

  @override
  bool shouldReload(covariant TranslationsDelegate old) {
    // 当自定义Locale变化时,触发重新加载翻译资源
    return old.customLocale != customLocale;
  }
}

步骤3:改造MaterialApp的配置

把App的根组件用ChangeNotifierProvider包裹,这样整个App都能访问Locale状态,同时监听Locale变化来更新MaterialApp的配置:

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (_) => AppLocaleProvider(),
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    final localeProvider = Provider.of<AppLocaleProvider>(context);
    return MaterialApp(
      title: 'Multi-Language Demo',
      // 使用用户选择的Locale,否则用系统默认
      locale: localeProvider.selectedLocale,
      supportedLocales: const [
        Locale('en'),
        Locale('fr'),
        Locale('es'),
      ],
      localizationsDelegates: [
        // 传入自定义的Delegate,带上当前选中的Locale
        TranslationsDelegate(customLocale: localeProvider.selectedLocale),
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      home: const HomePage(),
    );
  }
}

步骤4:写一个切换语言的UI组件

在你的首页或者设置页,添加几个按钮来切换语言:

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    final translations = Translations.of(context);
    final localeProvider = Provider.of<AppLocaleProvider>(context, listen: false);
    return Scaffold(
      appBar: AppBar(title: Text(translations.text('title'))),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(translations.text('title'), style: const TextStyle(fontSize: 24)),
            const SizedBox(height: 30),
            ElevatedButton(
              onPressed: () => localeProvider.setLocale(const Locale('en')),
              child: const Text('English'),
            ),
            ElevatedButton(
              onPressed: () => localeProvider.setLocale(const Locale('fr')),
              child: const Text('Français'),
            ),
            ElevatedButton(
              onPressed: () => localeProvider.setLocale(const Locale('es')),
              child: const Text('Español'),
            ),
          ],
        ),
      ),
    );
  }
}

步骤5:保留你原来的Translations类

你的Translations类基本不用改,直接复用就行:

class Translations {
  Translations(this.locale);
  final Locale locale;

  static Translations of(BuildContext context) {
    return Localizations.of<Translations>(context, Translations)!;
  }

  static Map<String, Map<String, String>> _localizedValues = {
    'en': {
      'title': 'Hello',
    },
    'fr': {
      'title': 'Bonjour',
    },
    'es': {
      'title': 'Hola',
    }
  };

  String text(String key) {
    return _localizedValues[locale.languageCode]?[key] ?? '** ${key} not found';
  }
}

为什么这样能行?

  • AppLocaleProvider保存用户选择的Locale,调用notifyListeners()会触发依赖它的组件(也就是MyApp)重新构建,从而更新MaterialApp的locale参数和TranslationsDelegate的customLocale。
  • TranslationsDelegate的shouldReload返回true时,Flutter会重新调用load方法加载新的翻译资源。
  • 所有使用Translations.of(context)获取翻译的组件,都会因为Locale变化而自动刷新。

如果你的App比较复杂,也可以考虑用Localizations.override来局部刷新,但上面的全局方案已经足够应对大多数场景啦。

内容的提问来源于stack exchange,提问作者boeledi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:44:49