没有上下文的 Flutter 本地化

Sal*_*rke 9 localization flutter

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

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

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

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

zap*_*zap 14

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

  1. 将其安装到您的 vscode Flutter Intl VSCode 扩展

  2. 设置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
    
    Run Code Online (Sandbox Code Playgroud)
  3. 设置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(),
        );
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 设置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());
    }
    
    
    Run Code Online (Sandbox Code Playgroud)
  5. 将其与 Get_it 一起使用,无需上下文作为

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


Stu*_*uck 11

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

final locale = Locale('en');
AppLocalizations t = await AppLocalizations.delegate.load(locale);
println(t.someTranslationKey);
Run Code Online (Sandbox Code Playgroud)

Locale('en')您可以实现某种解析器来找出所需的区域设置,而不是硬编码。支持的语言是AppLocalizations.supportedLocales.

  • 无论如何,考虑到我们使用“intl”包,即使没有 UI,以下内容在某些情况下也能工作:“final t = wait AppLocalizations.delegate.load(Locale(Intl.getCurrentLocale()));”,但没有回退。因此,例如,在“en_US”设备上,它不会自动找到“en”本地化。 (2认同)

Ale*_*dar 8

有一个名为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;
      },
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

另外不要忘记将本地化路径放入您的pubspec.yamal文件!

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

Text(tr('someJsonKey'),),
Run Code Online (Sandbox Code Playgroud)

  • 它仍然与上下文相关。 (5认同)
  • 它需要上下文:https://github.com/aissat/easy_localization/issues/210 (3认同)

chi*_*yal 7

如果您不想使用软件包,那么这里有一个对我有用的解决方案。现在最常见的实现AppLocalizations,我平时看到有以下两行:

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

static AppLocalizations of(BuildContext context) {
  return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
//.........
Run Code Online (Sandbox Code Playgroud)

委托的实现看起来像这样:

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
}
Run Code Online (Sandbox Code Playgroud)

请注意委托上的 load 方法返回一个Future<AppLocalizations>. 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
}
Run Code Online (Sandbox Code Playgroud)

那么在你的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
//.........

Run Code Online (Sandbox Code Playgroud)

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

String tr(String key) {
    return AppLocalizations.instance.translate(key);
}
Run Code Online (Sandbox Code Playgroud)

不需要上下文。

  • 当 app_localizations.dart 自动生成并完全覆盖时,每当 arb 文件发生更改时,这应该如何工作? (8认同)
  • 真的希望你能举出一个完整的例子。这对于新的 Dart 开发人员来说是不可能遵循的。 (2认同)

Gáb*_*bor 6

最新:当前的Flutter Intl插件使这种方法变得过时,至少如果您使用受支持的 IDE。你有一个上下文无关的替代方案:

S.current.translationKey
Run Code Online (Sandbox Code Playgroud)

上一篇:从Stuck的建议出发,这是我找到的最终解决方案。它不像使用上下文进行简单查找那么便宜,因此仅在确实必要时才使用它,并确保调用它一次并尽可能多地使用它。但即使您根本没有上下文,例如,您处于后台服务或任何其他没有 UI 的程序部分,这种方法也有效。

S.current.translationKey
Run Code Online (Sandbox Code Playgroud)

使用方法和平常一样:

Future<AppLocalizations> loadLocalization() async {
  final parts = Intl.getCurrentLocale().split('_');
  final locale = Locale(parts.first, parts.last);
  return await AppLocalizations.delegate.load(locale);
}
Run Code Online (Sandbox Code Playgroud)

更新:我在评论中建议的单例可能如下所示:

final t = await loadLocalization();
print(t.translationKey);
Run Code Online (Sandbox Code Playgroud)

并使用如下:

final t = await Localization().loadCurrent();
Run Code Online (Sandbox Code Playgroud)

要跟踪语言更改,请从您的 main 调用此命令build()

PlatformDispatcher.instance.onLocaleChanged = () => Localization().invalidate();
Run Code Online (Sandbox Code Playgroud)


div*_*van 6

我花了 2 美分,只是为了不失去解决方案:)

我完全明白为什么 Flutter 本地化解决方案需要 BuildContext - 完全有道理。但是,如果我明确不希望运行时语言切换,并且对应用程序重新启动感到满意?

这就是我想出的解决方案,看起来效果很好。

假设您已遵循 Flutter 的官方本地化步骤,请创建一个用于访问该类的全局变量AppLocalizations

i18n.dart:

import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

AppLocalizations get tr => _tr!; // helper function to avoid typing '!' all the time
AppLocalizations? _tr; // global variable 

class AppTranslations {
  static init(BuildContext context) {
    _tr = AppLocalizations.of(context);
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,在主包装器(下面的包装器MaterialApp)中的某个位置调用来设置当前所选语言环境的本地化:

    AppTranslations.init(context);
Run Code Online (Sandbox Code Playgroud)

它可能是主部件initState(),甚至build()是主部件的部件(显然,多次调用它是安全的)。

现在您只需调用:

import 'package:my_app/i18n.dart'

...
  Text(tr.welcome_text)

  // or

  print(tr.welcome_text);
...
Run Code Online (Sandbox Code Playgroud)

  • 我似乎无法按预期工作,收到错误: AppLocalizations get tr =&gt; _tr!; 行上的 _CastError (空值检查运算符用于空值) (3认同)

Moh*_*ala 5

我已经在使用easy_localization包,所以这对我来说很容易。

我用来获取没有上下文的应用程序语言的技巧如下

en-US.json

{
   "app_locale":"en"
}
Run Code Online (Sandbox Code Playgroud)

ar-SA.json

{
   "app_locale":"ar"
}
Run Code Online (Sandbox Code Playgroud)

像实用程序/扩展函数中的方式一样使用它

LocaleKeys.app_locale.tr() //will return 'en' for English, 'ar' for Arabic
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

7573 次

最近记录:

4 年,4 月 前