flutter 无背景的扑动定位

w1e3prcc  于 2022-12-05  发布在  Flutter
关注(0)|答案(9)|浏览(142)

我正在尝试在flutter中本地化我的应用程序。我为支持的语言创建了所需的string.arb文件。
为什么AppLocalizations.of(context)需要上下文?
我只是想访问文件/语言环境文件/类中的命名字符串。在应用程序中的某个时候,我构建了一个List,然后通过用一个单独的类覆盖一些字段来填充它。
然而,这个类没有上下文,但是我想在其中使用本地化的字符串。我可以写一个方法来获取我所放入的任何字符串的本地化吗?

31moq8wy

31moq8wy1#

如果你不想使用软件包,那么这里有一个解决方案,它对我很有效。现在,我所见过的大多数AppLocalizationscommon 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
}

请注意,委托上的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
}

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

现在,在您的translate helper方法中,您可以:

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

无需上下文。

o2g1uqev

o2g1uqev2#

我们可以通过使用get_it轻松地解决这个问题,在此设置之后,我们可以在任何地方使用该字符串。
1.将此安装到vscode Flutter Intl VSCode Extension
1.设置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

1.设置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(),
    );
  }
}

1.设置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());
}

1.将它与Get_it一起使用,而不使用上下文

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

efzxgjgh3#

有一个名为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'),),
acruukt9

acruukt94#

如果您知道所需的Locale,则可以用途:

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

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

vjrehmav

vjrehmav5#

**最新版本:**当前的Flutter Intl插件使这种方法过时了,至少如果您使用支持的IDE的话。

S.current.translationKey

**Previous:**从Stuck,的建议开始,这是我找到的最后一个解决方案。它没有简单的上下文查找那么便宜,所以只有在真正必要的时候才使用它,并确保你只调用它一次,并尽可能多次地使用它。但即使你根本没有上下文,这种方法也能工作,例如,你在后台服务或任何其他没有UI的程序部分。

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

它的使用方法与平常一样:

final t = await loadLocalization();
print(t.translationKey);

更新:我在评论中建议的单例可能看起来像这样:

class Localization {
  static final Localization _instance = Localization._internal();
  AppLocalizations? _current;

  Localization._internal();

  factory Localization() => _instance;

  Future<AppLocalizations> loadCurrent() async {
    if (_current == null) {
      final parts = Intl.getCurrentLocale().split('_');
      final locale = Locale(parts.first, parts.last);
      _current = await AppLocalizations.delegate.load(locale);
    }
    return Future.value(_current);
  }

  void invalidate() {
    _current = null;
  }
}

和用法如下:

final t = await Localization().loadCurrent();

要跟踪语言更改,请从主build()调用此函数:

PlatformDispatcher.instance.onLocaleChanged = () => Localization().invalidate();
v7pvogib

v7pvogib6#

在我的例子中,我使用的是Minimal国际化版本。
将chinalloy的答案改编为Minimal internationalization version
应用chinalloy的解决方案,但有以下区别:
从这里:

@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;
  }
bvjveswy

bvjveswy7#

我的2分钱投入其中,只是不要松散的解决方案:)
我完全理解Flutter本地化解决方案为什么需要BuildContext --这完全有道理。但是,如果我明确地不需要运行时语言切换,并且对应用程序重新启动感到满意呢?
这就是我想出的解决办法,似乎效果很好。
假设您已经遵循了Flutter的official localization steps,创建一个用于访问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);
  }
}

现在,在主 Package 器(MaterialApp下面的 Package 器)的某个地方调用为当前选择的语言环境设置本地化:

AppTranslations.init(context);

它可以是主小部件的initState(),甚至build()(显然,多次调用它是安全的)。
现在您只需调用:

import 'package:my_app/i18n.dart'

...
  Text(tr.welcome_text)

  // or

  print(tr.welcome_text);
...
kmpatx3s

kmpatx3s8#

我已经在使用easy_localization包,所以这对我来说很容易。
我用来获取无上下文应用语言的技巧如下

  • 中文.json*
{
   "app_locale":"en"
}
  • ar-SA.json*
{
   "app_locale":"ar"
}

像在实用程序/扩展功能中使用一样

LocaleKeys.app_locale.tr() //will return 'en' for English, 'ar' for Arabic
68de4m5k

68de4m5k9#

最好的方法是使用Flutter Intl(Flutter i18n插件),因为它是由Flutter开发者构建的。它有一个方法可以在没有上下文的情况下使用,如下所示(来自Visual Studio Marketplace details page的代码示例):

Widget build(BuildContext context) {
    return Column(children: [
        Text(
            S.of(context).pageHomeConfirm,
        ),
        Text(
            S.current.pageHomeConfirm,// If you don't have `context` to pass
        ),
    ]);
}

有关official plugin pageVisual Studio Marketplace details page的更多详细信息

相关问题