【问题标题】:Flutter: Multi-lingual application - how to override the locale?Flutter:多语言应用程序 - 如何覆盖语言环境?
【发布时间】:2018-09-01 15:09:49
【问题描述】:

我按照 Flutter 官方页面(参见 here)中给出的说明使我的应用程序可以在不同的语言中运行。

根据文档,它检索用户的语言环境,这工作正常。

现在让我们假设我的应用程序支持不同的语言(例如 EN、FR、ES、...),并且用户可以选择其中一种语言来使用应用程序(然后选择的语言将不同于在手机的设置中定义),我该如何实现?

如何强制应用程序区域设置并动态“重新加载”所有翻译?

Flutter 页面没有解释这一点,我在文档中也没有看到任何对我有帮助的东西......

这是当前的实现:

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';
  }
}

class TranslationsDelegate extends LocalizationsDelegate<Translations> {
  const TranslationsDelegate();

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

  @override
  Future<Translations> load(Locale locale) {
    return new SynchronousFuture<Translations>(new Translations(locale));
  }

  @override
  bool shouldReload(TranslationsDelegate old) => false;
}

在 main.dart 中:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: Translations.of(context).text('title'),
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      localizationsDelegates: [
        const TranslationsDelegate(),
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: [
        const Locale('en', ''), // English
        const Locale('fr', ''), // French
        const Locale('fr', ''), // French
      ],
        home: new LandingPage(),
    );
  }
}

非常感谢您的帮助。

【问题讨论】:

    标签: flutter


    【解决方案1】:

    这可以通过

    1. 创建一个新的 LocalizationsDelegate 来转换为 单一语言环境或完全取决于参数
    2. 将基础应用 (MyApp) 转换为有状态小部件并将上面的新委托插入到本地化委托列表中
    3. 使用基于某些事件的针对特定语言环境的新委托管理基本应用 (MyApp) 状态

    1) 的简单实现可能是:

    class SpecifiedLocalizationDelegate
        extends LocalizationsDelegate<Translations> {
      final Locale overriddenLocale;
    
      const SpecifiedLocalizationDelegate(this.overriddenLocale);
    
      @override
      bool isSupported(Locale locale) => overriddenLocale != null;
    
      @override
      Future<Translations> load(Locale locale) =>
          Translations.load(overriddenLocale);
    
      @override
      bool shouldReload(SpecifiedLocalizationDelegate old) => true;
    }
    

    接下来对于 2) 和 3),将 MyApp 转换为有状态并包含新委托(最初只是推迟所有内容),以及一些事件处理程序以使用指定新区域设置的新委托更改状态。

    class MyApp extends StatefulWidget {
      @override
      _MyAppState createState() => new _MyAppState();
    }
    
    class _MyAppState extends State<MyApp> {
      SpecifiedLocalizationDelegate _localeOverrideDelegate;
    
      @override
      void initState() {
        super.initState();
        _localeOverrideDelegate = new SpecifiedLocalizationDelegate(null);
      }
    
      onLocaleChange(Locale l) {
        setState(() {
          _localeOverrideDelegate = new SpecifiedLocalizationDelegate(l);
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          localizationsDelegates: [
            _localeOverrideDelegate,
            const TranslationsDelegate(),
            GlobalMaterialLocalizations.delegate,
            GlobalWidgetsLocalizations.delegate,
          ],
          supportedLocales: [
            const Locale('en', ''), // English
            const Locale('fr', ''), // French
          ],
          home: new LandingPage(onLocaleSwitch: onLocaleChange),
        );
      }
    }
    

    通过这些更改,您现在可以在子小部件中使用 Translations.of(context).myLocalizedString 来检索翻译。

    更完整的要点:https://gist.github.com/ilikerobots/474b414138f3f99150dbb3d0cc4cc721

    【讨论】:

    • 嘿@ilikerobots,我在实施您的解决方案时遇到了一点问题。在类 Translations 中,方法 load(Locale locale),您调用 initializeMessages,这不是您的要点的一部分。你能告诉我这个方法是做什么的吗?谢谢
    • 抱歉,我假设您使用的是 intl 工具,但我现在意识到可能并非如此。使用 intl/generate_localized.dart 时会生成 initializeMessages 函数,如附录 flutter.io/tutorials/internationalization 中所述
    • 以这种方式从 intl 使用的本地化需要在使用特定语言环境之前进行初始化。如果您的实现不需要这样做,那么您可能会跳过该调用。
    • 我写了一篇完整的文章来描述我的解决方案didierboelens.com/2018/04/…
    【解决方案2】:

    要控制应用的语言环境,您可以使用 MaterialApp 的 locale 属性:

    return MaterialApp(
      ...
      locale: _myLocal,
      ...
    );
    

    这与@ilikerobots StatefulWidget 方法相结合,将为您提供所需的东西。

    【讨论】:

      【解决方案3】:

      使用其中一个Providers 应该可以完成这项工作,我对提供者并不十分熟悉,但这让我可以轻松地工作

      1. 使用 ChangeNotifierProvider 封装您的材料应用程序
          return ChangeNotifierProvider(
              create: (_) => new LocaleModel(),
              child: Consumer<LocaleModel>(
                  builder: (context, provider, child) => MaterialApp(
                      title: 'myapp',
                      locale: Provider.of<LocaleModel>(context).locale
                       ...
                       ...
                       ...
      
      
      1. 创建一个带有 getter 和 setter 的模型类来获取和设置语言环境\
      import 'package:iborganic/const/page_exports.dart';
      
      class LocaleModel with ChangeNotifier {
        Locale locale = Locale('en');
        Locale get getlocale => locale;
        void changelocale(Locale l) {
          locale = l;
          notifyListeners();
        }
      }
      
      
      1. 更改某些事件的区域设置(按钮单击)
      Provider.of<LocaleModel>(context).changelocale(Locale("kn"));
      

      在 Provider 中包装材料应用的好处是您可以从应用的任何部分访问区域设置值

      【讨论】:

      • 不,这种方法不起作用。它在 Localiyations.of 中崩溃,因为小部件树中没有 _LocaliyationsScope。函数final _LocalizationsScope scope = context.dependOnInheritedWidgetOfExactType&lt;_LocalizationsScope&gt;(); 返回null。
      • 我自己尝试后发布了这个答案,我可以向你保证它有效
      • 我进一步深入研究它。崩溃与在我的原型中一些小部件是通过函数生成的事实有关。这通常工作正常。然而,出于某种原因,这并没有提供本地化范围。这里有更详细的解释:stackoverflow.com/questions/53234825/…。在那次改变之后,它也对我有用。谢谢。
      【解决方案4】:

      最简单的方法是使用 locale 属性,奇怪的是在国际化教程中没有提到。 MaterialApp 类的这个属性允许我们立即指定我们希望我们的应用使用什么语言环境

       return MaterialApp(
        locale: Locale('ar', ''),
        localizationsDelegates: [
          MyLocalizationsDelegate,
          GlobalMaterialLocalizations.delegate,
          GlobalWidgetsLocalizations.delegate,
        ],
        supportedLocales: [
          const Locale('en', ''), // English
          const Locale('ar', ''), // Arabic
        ],
        home: HomeScreen()
      );
      

      This tutorial explained it better

      它还解释了如何从 sharedPreferences 加载语言环境首选项

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-08-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多