无上下文的颤振本地化
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<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
//.........
现在在您的翻译助手方法中,您可以:
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
。
【讨论】:
以上是关于无上下文的颤振本地化的主要内容,如果未能解决你的问题,请参考以下文章