无上下文的颤振本地化

Posted

技术标签:

【中文标题】无上下文的颤振本地化【英文标题】:Flutter localization without context 【发布时间】:2020-05-02 16:52:58 【问题描述】:

我正在尝试将我的应用本地化。我为支持的语言创建了所需的 string.arb 文件。

为什么AppLocalizations.of(context) 需要上下文?

我只想访问文件/语言环境文件/类中的命名字符串。 在应用程序的某个时刻,我构建了一个列表,稍后通过使用单独的类覆盖某些字段来填充它。

然而,这个类没有上下文,但我想在其中使用本地化字符串。 我可以编写一个方法来获取我输入的任何字符串的本地化吗?

【问题讨论】:

在另一个 *** 线程中,我提出了使用 Flutter Extensions 的解决方案:***.com/a/68754936/7052599 这是我的解决方案:***.com/a/69037938/1034225 【参考方案1】:

我们可以通过使用get_it 轻松解决这个问题,我们可以在此设置后的任何地方使用该字符串。

    将此安装到您的 vscode Flutter Intl VSCode Extension

    设置pubspec.yaml

    dependencies:
    flutter:
      sdk: flutter
    flutter_localizations:                          # Add this line
      sdk: flutter                                  # Add this line
    intl: ^0.17.0                                   # Add this line
    get_it: ^7.2.0                                  # Add this line
    
    
    flutter:
      uses-material-design: true
      generate: true                                # Add this line
    
    
    flutter_intl:                                   # Add this line
      enabled: true                                 # Add this line
      class_name: I10n                              # Add this line
      main_locale: en                               # Add this line
      arb_dir: lib/core/localization/l10n           # Add this line
      output_dir: lib/core/localization/generated   # Add this line
    

    设置main.dart

    import 'package:component_gallery/core/localization/generated/l10n.dart';
    import 'package:component_gallery/locator.dart';
    import 'package:component_gallery/ui/pages/home.dart';
    import 'package:flutter/cupertino.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_localizations/flutter_localizations.dart';
    
    void main() 
      setupLocator();
      runApp(App());
    
    
    class App extends StatelessWidget 
      @override
      Widget build(BuildContext context) 
        return MaterialApp(
          localizationsDelegates: [
            I10n.delegate,
            GlobalMaterialLocalizations.delegate,
            GlobalWidgetsLocalizations.delegate,
            GlobalCupertinoLocalizations.delegate,
          ],
          supportedLocales: I10n.delegate.supportedLocales,
          localeResolutionCallback: (deviceLocale, supportedLocales) 
            if (supportedLocales
                .map((e) => e.languageCode)
                .contains(deviceLocale?.languageCode)) 
              return deviceLocale;
             else 
              return const Locale('en', '');
            
          ,
          home: HomePage(),
        );
      
    
    

    设置locator.dart

    import 'package:component_gallery/core/services/navigation_service.dart';
    import 'package:get_it/get_it.dart';
    
    GetIt locator = GetIt.instance;
    
    void setupLocator() 
      locator.registerLazySingleton(() => I10n());
    
    
    

    在没有上下文的情况下将它与 Get_it 一起使用

    final I10n _i10n = locator<I10n>();
    class MessageComponent extends StatelessWidget 
      @override
      Widget build(BuildContext context) 
        return Text(
          _i10n.sample,
          textAlign: TextAlign.center,
        );
      
    
    
    

【讨论】:

根据 get_it pub.dev/packages/get_it#why-getit ,测试时非常快(O(1)) 你有使用这种方法的示例项目吗?【参考方案2】:

如果您不想使用包,那么这里有一个对我有用的解决方案。现在我见过的AppLocalizations中最多的common implementation通常有这两行:

//.........
static const LocalizationsDelegate<AppLocalizations> delegate =
      _AppLocalizationsDelegate();

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

//.........

委托的实现如下所示:

class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> 
  const _AppLocalizationsDelegate();

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

    return localizations;
  

  //... the rest omitted for brevity

请注意委托上的加载方法返回一个Future&lt;AppLocalizations&gt;。 load 方法通常从 main 调用一次,并且不再调用,因此您可以通过将 AppLocalizations 的静态实例添加到委托来利用它。所以现在你的委托看起来像这样:

class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> 
  const _AppLocalizationsDelegate();

  static AppLocalizations instance;

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

    instance = localizations; // set the static instance here

    return localizations;
  

  //... the rest omitted for brevity

然后在您的 AppLocalizations 课程中,您现在将拥有:

//.........
static const LocalizationsDelegate<AppLocalizations> delegate =
      _AppLocalizationsDelegate();

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


static AppLocalizations get instance => _AppLocalizationsDelegate.instance; // add this
//.........

现在在您的翻译助手方法中,您可以:

String tr(String key) 
    return AppLocalizations.instance.translate(key);

不需要上下文。

【讨论】:

应该如何工作,当 app_localizations.dart 自动生成并完全覆盖时,任何时候更改 arb 文件? 真希望你能举出一个完整的例子。这对于一个新的飞镖开发者来说是不可能的。 很酷的方法,谢谢!【参考方案3】:

有一个名为easy_localization 的库可以在没有上下文的情况下进行本地化,您可以简单地使用它。库还提供了更方便的方法来编写更少的代码并仍然本地化应用程序的所有部分。一个示例主类:

void main() 
  WidgetsFlutterBinding.ensureInitialized();
  SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitUp,
  ]).then((_) 
    runApp(EasyLocalization(
      child: MyApp(),
      useOnlyLangCode: true,
      startLocale: Locale('nl'),
      fallbackLocale: Locale('nl'),
      supportedLocales: [
        Locale('nl'),
        Locale('en'),
      ],
      path: 'lang',
    ));
  );


class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      home: SplashScreen(),
      supportedLocales: EasyLocalization.of(context).supportedLocales,
      locale: EasyLocalization.of(context).locale,
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
        DefaultCupertinoLocalizations.delegate,
        EasyLocalization.of(context).delegate,
      ],
      localeResolutionCallback: (locale, supportedLocales) 
        if (locale == null) 
          EasyLocalization.of(context).locale = supportedLocales.first;
          Intl.defaultLocale = '$supportedLocales.first';
          return supportedLocales.first;
        

        for (Locale supportedLocale in supportedLocales) 
          if (supportedLocale.languageCode == locale.languageCode) 
            EasyLocalization.of(context).locale = supportedLocale;
            Intl.defaultLocale = '$supportedLocale';
            return supportedLocale;
          
        

        EasyLocalization.of(context).locale = supportedLocales.first;
        Intl.defaultLocale = '$supportedLocales.first';
        return supportedLocales.first;
      ,
    );
  

另外不要忘记将本地化路径添加到您的 pubspec.yamal 文件中!

完成所有这些后,您可以像这样在Text 小部件中简单地使用它:

Text(tr('someJsonKey'),),

【讨论】:

好像没有文档。我不确定如何准确地使用它。 没有文档是什么意思?您需要打开链接(打开插件的自述页面),有一个关于如何集成它并在整个应用程序中使用它的教程。主要部分是将它集成到主函数中,而不是通过调用 tr("keyFromJSONFile") 当我将它集成到应用程序中时,我在启动时收到一条错误消息,提示找不到本地化文件。改变它根本没有帮助 这是由于 main.dart 文件中的一些错误,以及插件文档未集成的一些难题。我将用主文件示例更新我的答案,所以请检查你做错了什么。 它仍然与上下文相关。【参考方案4】:

就我而言,我使用的是最小国际化版本。

改编 chinloyal 对Minimal internationalization version 的回答。

应用 chinloyal 的解决方案,但有以下区别:

从这里:

  @override
  Future<AppLocalizations> load(Locale locale) 
    return SynchronousFuture<AppLocalizations>(AppLocalizations(locale));
  

到这里:

  @override
  Future<AppLocalizations> load(Locale locale) async 
    var localizations =
        await SynchronousFuture<AppLocalizations>(AppLocalizations(locale));

    instance = localizations; // set the static instance here

    return localizations;
  

【讨论】:

【参考方案5】:

如果您知道所需的Locale,那么您可以使用:

final locale = Locale('en');
AppLocalizations t = await AppLocalizations.delegate.load(locale);
println(t.someTranslationKey);

代替硬编码Locale('en'),您可以实现某种解析器来找出所需的语言环境是什么。支持的语言是AppLocalizations.supportedLocales

【讨论】:

以上是关于无上下文的颤振本地化的主要内容,如果未能解决你的问题,请参考以下文章

如何在 List 小部件 Flutter 中无上下文导航

颤振错误:'上下文!= null':不正确

寻找提供者上下文的颤振问题

颤振导航未定义的“上下文”

颤振显示上下文操作快捷方式不起作用

未在颤振自定义应用程序栏中获取脚手架上下文