store/translate 表单字段模型中的静态错误字符串是不好的做法吗?
Is it bad practice to store/translate static error strings in a form field model?
我正在构建一个 Flutter 应用,其中有一个注册表单,如果用户输入无效的电子邮件,该表单会抛出错误。
我有以下电子邮件表单字段模型(使用 formz 包):
enum EmailFieldValidationError { empty, invalid }
class EmailField extends FormzInput<String, EmailFieldValidationError> {
const EmailField.pure() : super.pure('');
const EmailField.dirty([String value = '']) : super.dirty(value);
static final RegExp _emailRegExp = RegExp(
r'^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$',
);
@override
EmailFieldValidationError? validator(String? value) {
}
String? get errorText {
if (error != null && !pure && value.isNotEmpty) {
switch (error) {
case EmailFieldValidationError.invalid:
return 'Invalid email.';
default:
return null;
}
}
return null;
}
}
当我想在 TextFormField()
下有条件地显示错误消息时,这使我的小部件中的事情变得非常简单,但在考虑如何本地化(我想添加到应用程序)在 flutter 中需要我使用 BuildContext
来 build 错误字符串。像这样:
String? buildErrorText(BuildContext context) {
if (error != null && !pure && value.isNotEmpty) {
switch (error) {
case EmailFieldValidationError.invalid:
return AppLocalizations.of(context)!.emailFieldInvalidValueError;
default:
return null;
}
}
return null;
}
考虑到我需要实例化一个 BuildContext
并使用我的本地化 class 对其进行配置,以便能够测试此表单字段模型,我认为关注点分离很差这里。
我认为首先在 class 本身内为我的表单字段模型生成错误文本是个好主意。这主要是为了避免重复代码。但是在本地化成为我的应用程序的一个不错的选择之后,这成为了一个问题,我 运行 陷入分析瘫痪 reading/considering 从模型中分离静态字符串生成的不同选项 class同时避免了我原来的重复代码问题。
如有任何想法,我们将不胜感激。
显示基于区块状态的错误文本。
我最终找到了一个简单的解决方案,但由于我没有得到任何可行的答案,所以这是我的解决方案。如果有人可以验证或提供反馈以进一步改进它,那就太好了。
我基本上创建了一个新的“通用”小部件,以根据给定的 EmailField
值简单地呈现 TextFormField
。如果当前值有任何错误,它将根据错误类型呈现适当的错误字符串:
class CommonEmailFormField extends StatelessWidget {
const CommonEmailFormField({
Key? key,
required this.email,
this.onChanged,
}) : super(key: key);
final EmailField email;
final Function(String)? onChanged;
String? get _errorText {
if (email.error != null && !email.pure && email.value.isNotEmpty) {
switch (email.error) {
case EmailFieldValidationError.invalid:
return 'Invalid email.';
default:
return null;
}
}
return null;
}
@override
Widget build(BuildContext context) {
return TextFormField(
initialValue: email.value,
onChanged: onChanged,
decoration: InputDecoration(
labelText: 'Email *',
errorText: _errorText,
),
);
}
}
我已将代码段简化为简明扼要。你可以看看实际实现here.
一旦我开始添加本地化,它将要求我更改 _errorText
getter 从 BuildContext
读取静态本地化字符串,但这仍然是驱动 [=38] 的代码=] 行为和我保持关注点分离。
无论如何,这个解决方案解决了我的主要问题:
- 测试中不必要的复杂性。现在我不需要设置 UI
BuildContext
就可以在添加本地化后测试现场模型。
- 重复代码。我可以在任何需要的地方重复使用这个通用小部件。
- 关注点分离。专门驱动 UI/View 行为的代码与驱动模型行为的代码很好地分开。这 in-turn 简化了测试。
我正在构建一个 Flutter 应用,其中有一个注册表单,如果用户输入无效的电子邮件,该表单会抛出错误。
我有以下电子邮件表单字段模型(使用 formz 包):
enum EmailFieldValidationError { empty, invalid }
class EmailField extends FormzInput<String, EmailFieldValidationError> {
const EmailField.pure() : super.pure('');
const EmailField.dirty([String value = '']) : super.dirty(value);
static final RegExp _emailRegExp = RegExp(
r'^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$',
);
@override
EmailFieldValidationError? validator(String? value) {
}
String? get errorText {
if (error != null && !pure && value.isNotEmpty) {
switch (error) {
case EmailFieldValidationError.invalid:
return 'Invalid email.';
default:
return null;
}
}
return null;
}
}
当我想在 TextFormField()
下有条件地显示错误消息时,这使我的小部件中的事情变得非常简单,但在考虑如何本地化(我想添加到应用程序)在 flutter 中需要我使用 BuildContext
来 build 错误字符串。像这样:
String? buildErrorText(BuildContext context) {
if (error != null && !pure && value.isNotEmpty) {
switch (error) {
case EmailFieldValidationError.invalid:
return AppLocalizations.of(context)!.emailFieldInvalidValueError;
default:
return null;
}
}
return null;
}
考虑到我需要实例化一个 BuildContext
并使用我的本地化 class 对其进行配置,以便能够测试此表单字段模型,我认为关注点分离很差这里。
我认为首先在 class 本身内为我的表单字段模型生成错误文本是个好主意。这主要是为了避免重复代码。但是在本地化成为我的应用程序的一个不错的选择之后,这成为了一个问题,我 运行 陷入分析瘫痪 reading/considering 从模型中分离静态字符串生成的不同选项 class同时避免了我原来的重复代码问题。
如有任何想法,我们将不胜感激。
显示基于区块状态的错误文本。
我最终找到了一个简单的解决方案,但由于我没有得到任何可行的答案,所以这是我的解决方案。如果有人可以验证或提供反馈以进一步改进它,那就太好了。
我基本上创建了一个新的“通用”小部件,以根据给定的 EmailField
值简单地呈现 TextFormField
。如果当前值有任何错误,它将根据错误类型呈现适当的错误字符串:
class CommonEmailFormField extends StatelessWidget {
const CommonEmailFormField({
Key? key,
required this.email,
this.onChanged,
}) : super(key: key);
final EmailField email;
final Function(String)? onChanged;
String? get _errorText {
if (email.error != null && !email.pure && email.value.isNotEmpty) {
switch (email.error) {
case EmailFieldValidationError.invalid:
return 'Invalid email.';
default:
return null;
}
}
return null;
}
@override
Widget build(BuildContext context) {
return TextFormField(
initialValue: email.value,
onChanged: onChanged,
decoration: InputDecoration(
labelText: 'Email *',
errorText: _errorText,
),
);
}
}
我已将代码段简化为简明扼要。你可以看看实际实现here.
一旦我开始添加本地化,它将要求我更改 _errorText
getter 从 BuildContext
读取静态本地化字符串,但这仍然是驱动 [=38] 的代码=] 行为和我保持关注点分离。
无论如何,这个解决方案解决了我的主要问题:
- 测试中不必要的复杂性。现在我不需要设置 UI
BuildContext
就可以在添加本地化后测试现场模型。 - 重复代码。我可以在任何需要的地方重复使用这个通用小部件。
- 关注点分离。专门驱动 UI/View 行为的代码与驱动模型行为的代码很好地分开。这 in-turn 简化了测试。