如何使用 Provider 实现 Flutter 本地化?

Posted

技术标签:

【中文标题】如何使用 Provider 实现 Flutter 本地化?【英文标题】:How to implement Flutter Localization with Provider? 【发布时间】:2020-12-17 06:47:34 【问题描述】:

我想让我的应用程序以 2 种不同的语言运行。 我想问题是我无法在 multiprovider 中处理 Cosumer ,可能吗?

我正在使用flutter_localization 包和flutter 提供程序包;

这是我的代码:

void main() async 
  WidgetsFlutterBinding.ensureInitialized();
  AppLanguage appLanguage = AppLanguage();
  await appLanguage.fetchLocale();
  SharedPreferences.getInstance().then((prefs) 
    var darkModeOn = prefs.getBool('darkMode') ?? true;
    runApp(
      ChangeNotifierProvider<ThemeManager>(
        builder: (_) => ThemeManager(lightTheme),
        child: MyApp(appLanguage: appLanguage),
      ),
    );
  );

分类我的应用

class MyApp extends StatelessWidget 
  final AppLanguage appLanguage;

  MyApp(this.appLanguage);
  @override
  Widget build(BuildContext context) 
    final themeNotifier = Provider.of<ThemeManager>(context);
    return MultiProvider(
      providers: [
        ChangeNotifierProvider.value(value: ApiService()),
        ChangeNotifierProxyProvider<ApiService, StudentData>(
          builder: (ctx, auth, _) => StudentData(auth.token, auth.school),
        )
      ],
      child: Consumer<ApiService>(
        builder: (ctx, auth, _) => ChangeNotifierProvider<AppLanguage>(
          builder: (_) => appLanguage,
          child: Consumer<AppLanguage>(
            builder: (context, model, child) => MaterialApp(
              locale: appLanguage.appLocal,
              supportedLocales: [Locale('ru', 'RU'), Locale('uz', 'UZ')],
              localizationsDelegates: [
                AppLocalization.delegate,
                GlobalMaterialLocalizations.delegate,
                GlobalWidgetsLocalizations.delegate,
              ],
              debugShowCheckedModeBanner: false,
              title: "Socratus |Mobile",
              theme: themeNotifier.getTheme(),
              home: auth.isAuth
                  ? MainScreen()
                  : FutureBuilder(
                      future: auth.tryAutoLogin(),
                      builder: (ctx, authResultSnapshot) => LoginScreen()),
              routes: 
                MainScreen.routeName: (ctx) => MainScreen(),
                ProfilePage.routeName: (ctx) => ProfilePage(),
                SettingsPage.routeName: (ctx) => SettingsPage(
                      appLanguage: appLanguage,
                    ),
                ChangePassword.routeName: (ctx) => ChangePassword(),
                HomeworkScreen.routeName: (ctx) => HomeworkScreen(),
                HWDetails.routeName: (ctx) => HWDetails(),
                NewsPage.routeName: (ctx) => NewsPage(),
                QuestionAndAnswers.routeName: (ctx) => QuestionAndAnswers(),
                MyDownloads.routeName: (ctx) => MyDownloads(),
              ,
            ),
          ),
        ),
      ),
    );
  

这是我尝试实现的方式

class AppLocalization 
  final Locale locale;

  AppLocalization(this.locale);

  static AppLocalization of(BuildContext context) 
    return Localizations.of<AppLocalization>(context, AppLocalization);
  

  static const LocalizationsDelegate<AppLocalization> delegate =
      _AppLocalizationDelegate();

  Map<String, String> _localizedStrings;

  Future<bool> load() async 
    String jsonString = await rootBundle
        .loadString('assets/translations/$locale.languageCode.json');
    Map<String, dynamic> jsonMap = json.decode(jsonString);

    _localizedStrings = jsonMap.map((key, value) 
      return MapEntry(key, value.toString());
    );

    return true;
  

  String translate(String key) 
    return _localizedStrings[key];
  


class _AppLocalizationDelegate extends LocalizationsDelegate<AppLocalization> 
  // This delegate instance will never change (it doesn't even have fields!)
  // It can provide a constant constructor.
  const _AppLocalizationDelegate();

  @override
  bool isSupported(Locale locale) 
    // Include all of your supported language codes here
    return ['ru', 'uz'].contains(locale.languageCode);
  

  @override
  Future<AppLocalization> load(Locale locale) async 
    AppLocalization localizations = new AppLocalization(locale);
    await localizations.load();
    return localizations;
  

  @override
  bool shouldReload(_AppLocalizationDelegate old) => false;

还有我的提供者:

class AppLanguage extends ChangeNotifier 
  Locale _appLocale = Locale('ru');

  Locale get appLocal => _appLocale ?? Locale("ru");
  fetchLocale() async 
    var prefs = await SharedPreferences.getInstance();
    if (prefs.getString('language_code') == null) 
      _appLocale = Locale('ru');
      return Null;
    
    _appLocale = Locale(prefs.getString('language_code'));
    return Null;
  

  void changeLanguage(Locale type) async 
    var prefs = await SharedPreferences.getInstance();
    if (_appLocale == type) 
      return;
    
    if (type == Locale("uz")) 
      _appLocale = Locale("uz");
      await prefs.setString('language_code', 'uz');
      await prefs.setString('countryCode', 'UZ');
     else 
      _appLocale = Locale("ru");
      await prefs.setString('language_code', 'ru');
      await prefs.setString('countryCode', 'RU');
    
    notifyListeners();
  

如果这不是正确的方法,我该如何实现这个功能?

【问题讨论】:

【参考方案1】:

this article 中解释了您尝试实施的方式,如果您想要不同的方法,我建议您查看 pub.dev 中的Easy Localization,它目前处理所有Flutter internationalization features .

【讨论】:

以上是关于如何使用 Provider 实现 Flutter 本地化?的主要内容,如果未能解决你的问题,请参考以下文章

flutter 如何实现文件读写(使用篇)

Flutter Provider 原理解析

Flutter:如何设置 Stream 和 Provider

如何在 Flutter 中使用 Provider 正确获取 API

Flutter Provider实现简单的购物车

Flutter Provider框架实现简单的购物车