Flutter:多语言应用程序 - 如何覆盖语言环境?
Posted
技术标签:
【中文标题】Flutter:多语言应用程序 - 如何覆盖语言环境?【英文标题】:Flutter: Multi-lingual application - how to override the locale? 【发布时间】: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(),
);
非常感谢您的帮助。
【问题讨论】:
【参考方案1】:这可以通过
-
创建一个新的 LocalizationsDelegate 来转换为
单一语言环境或完全取决于参数
将基础应用 (MyApp) 转换为有状态小部件并将上面的新委托插入到本地化委托列表中
使用基于某些事件的针对特定语言环境的新委托管理基本应用 (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 应该可以完成这项工作,我对提供者并不十分熟悉,但这让我可以轻松地工作
-
使用 ChangeNotifierProvider 封装您的材料应用程序
return ChangeNotifierProvider(
create: (_) => new LocaleModel(),
child: Consumer<LocaleModel>(
builder: (context, provider, child) => MaterialApp(
title: 'myapp',
locale: Provider.of<LocaleModel>(context).locale
...
...
...
-
创建一个带有 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();
-
更改某些事件的区域设置(按钮单击) 为
Provider.of<LocaleModel>(context).changelocale(Locale("kn"));
在 Provider 中包装材料应用的好处是您可以从应用的任何部分访问区域设置值
【讨论】:
不,这种方法不起作用。它在 Localiyations.offinal _LocalizationsScope scope = context.dependOnInheritedWidgetOfExactType<_LocalizationsScope>();
返回null。最简单的方法是使用 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 加载语言环境首选项
【讨论】:
以上是关于Flutter:多语言应用程序 - 如何覆盖语言环境?的主要内容,如果未能解决你的问题,请参考以下文章
App Languages 批量导入管理flutter多语言文案