在Flutter中获取BuildContext以进行本地化

19

我尝试使用Flutter的本地化包来本地化字符串。问题在于需要翻译的位置不涉及UI,而是在我的模型中深处,我无法访问BuildContext。是否有其他可能性仍然可以使用翻译函数?

// I don't have a context variable here
MyLocalizations.of(context).trans("foo")

"Context is missing" 是什么意思? - Rémi Rousselet
但是你所说的“这里”是什么意思?即使隐藏在抽象层后面,你仍然应该有一种方法来访问BuildContext - Rémi Rousselet
如果我的函数中没有声明 BuildContext context,那么它怎么能工作呢? - Daniel Stephens
通过使用抽象类和其他东西。但我不知道你的代码,所以很难回答。 - Rémi Rousselet
我刚刚发现了 BuildContext get context => _element;,所以可以在构建上下文之外使用上下文。这可能确实有所帮助。我会看一下,谢谢! - Daniel Stephens
1
在您的build方法中,它接收一个BuildContext参数,您可以获取本地化内容:Widget build(BuildContext context) { var loc = MyLocalizations.of(context); … } 然后只需将其作为参数传递给从那里调用的任何其他函数。 - Derek Lakin
5个回答

11

有的。你不需要BuildContext来访问字符串。这是我的解决方案:

是的,有。您不需要BuildContext来访问字符串。以下是我的解决方案:

class Strings {
  Strings._(Locale locale) : _localeName = locale.toString() {
    current = this;
  }

  final String _localeName;

  static Strings current;

  static Future<Strings> load(Locale locale) async {
    await initializeMessages(locale.toString());
    final result = Strings._(locale);
    return result;
  }

  static Strings of(BuildContext context) {
    return Localizations.of<Strings>(context, Strings);
  }

  String get title {
    return Intl.message(
      'Hello World',
      name: 'title',
      desc: 'Title for the Demo application',
    );
  }
}

Future<Null> main() async {
  final Locale myLocale = Locale(window.locale);
  await Strings.load(myLocale);
  runApp(MyApplication());
}

现在您可以按照以下方式引用字符串:

final title = Strings.current.title;

使用这种方法会有任何不便吗? - Martyns
3
如果你想通过调用 Strings.load 来在运行时更改当前的语言,那么你需要重新加载存储在类成员数据中的任何字符串。如果你将字符串存储在静态 final 变量中,则需要重新启动应用程序。目前没有其他问题。 - kine
1
请阅读教程国际化Flutter应用程序initializeMessages是生成代码的一部分。 - kine
@kine 谢谢。我已经生成了包含消息[en, pl]的.arb和.dart文件,将Platform.locale传递给Locale构造函数并尝试了您的解决方案,但不幸的是没有成功 - 调用Strings.current.title仍然返回在return Intl.message("Hello wordl"...)中设置的“Hello world”文本。我尝试了几次更改语言,但结果都一样。这只是我的问题还是这个方法已经不再有效了? - Matt
1
@Matt,你说你将 Platform.locale 传递给了语言环境构造函数。我没有测试过这个,我的示例代码使用的是 window.locale。请尝试使用它再次测试,并从设备设置中更改语言。 - kine
显示剩余2条评论

7

AppLocalitzations 需要上下文。

你可以创建一个类(例如 Localization)来封装 AppLocalizations 的初始化,并使用它的上下文从主页widget中进行初始化。之后,可以使用 mixin 进行操作:

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

class Localization {
  static AppLocalizations _loc;

  AppLocalizations get loc => Localization._loc;

  static void init(BuildContext context) => _loc = AppLocalizations.of(context);
}

在首页小部件中:

...
    @override
    Widget build(BuildContext context) {
       Localization.init(context);
       return Scaffold(
...

使用mixins在某个类中(不一定是Widget)访问loc:

class XXXWidget extends StatelessWidget with Localization {
    ...
    Text(loc.xxxx)
    ...
}

class _XXXXWidgetState extends State<XXXWidget> with Localization {
    ...
    Text(loc.xxxx)
    ...
}

class XXXXController with Localization {
    ...
    cardNumberValidator = RequiredValidator(errorText: loc.commons_Required);
    ...
}

空安全版本:

class Localization {
  static AppLocalizations? _l;    
  AppLocalizations get loc => Localization._l!;

  static void init(BuildContext context) => _l = AppLocalizations.of(context)!;
}

它不再工作了。 - Paulo Pedroso
为什么不行呢?是因为空安全性吗?我正在使用适应空安全性的版本,它可以正常工作。 - mabg
很抱歉,我正在学习Flutter,尝试了11天了,我已经不记得场景该怎么解释了。但是我成功让本地化工作了。 - Paulo Pedroso
1
我编辑了答案并放置了空安全版本。 - mabg

6

我知道这个问题已经很久了。但是在实现我的应用程序时,我遇到了这个问题,我没有看到任何“好”的方式来处理它。 所以这里是我的方法。

class LanguageService {
  static String defaultLanguage = 'en';

  static Map<String, Map<String, String>> _localizedValues = {
    'en': {
      'title': 'Storefront',
      'language': 'Language',
      'googleLogin': 'Login with Google'
    },
    'vn': {
      'title': 'Cửa hàng',
      'language': 'Ngôn ngữ',
      'googleLogin': 'Đăng Nhập với Google'
    }
  };

  static set language(String lang) {
    defaultLanguage = lang;
  }

  static String get title {
    return _localizedValues[defaultLanguage]['title'];
  }

  static String get language {
    return _localizedValues[defaultLanguage]['language'];
  }

  static String get googleLogin {
    return _localizedValues[defaultLanguage]['googleLogin'];
  }

}

现在你可以按如下方式引用字符串:

String title = LanguageService.title;

你可以在这里找到详细的教程:这里

5
不,没有其他办法,因为它是使用InheritedWidget存储的,它是构建树的一部分,因此只能通过对它(BuildContext)的引用来访问。
您需要将您的context传递到模型的深处。

0

我不确定我是否从性能角度做得正确,也许有人可以对此发表评论,但是我在我的AppLocalization中使用了rx BehaviorSubject,并在加载新语言环境时触发事件。我在main.dart中监听它,并在接收到事件时进行setState操作。 我检查了性能选项卡,但是与通过上下文(继承小部件)访问翻译的方法相比,没有注意到任何大的变化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接