自定义错误消息¶
可以更改消息的内容以适应自定义用例;它可以包含将被有用信息替换的占位符。
下面的占位符始终可用;根据原始消息,甚至可以使用更多。
| 占位符 | 描述 |
|---|---|
{message_code} |
消息代码 |
{node_name} |
消息绑定的节点名称 |
{node_path} |
消息绑定的节点路径 |
{node_type} |
消息绑定的节点类型 |
{expected_signature} |
预期类型的字符串表示形式 |
{source_value} |
赋予节点的源值 |
{original_message} |
定制之前的原始消息 |
用法:
try {
(new \CuyZ\Valinor\MapperBuilder())
->mapper()
->map(SomeClass::class, [/* … */]);
} catch (\CuyZ\Valinor\Mapper\MappingError $error) {
foreach ($error->messages() as $message) {
if ($message->code() === 'some_code') {
$message = $message
->withParameter('some_parameter', 'some custom value')
->withBody('new message / {message_code} / {some_parameter}');
}
// new message / some_code / some custom value
echo $message;
}
}
这些消息使用 [ICU 库] 进行格式化,使占位符能够使用高级语法来执行正确的翻译,例如货币支持。
try {
(new \CuyZ\Valinor\MapperBuilder())->mapper()->map('int<0, 100>', 1337);
} catch (\CuyZ\Valinor\Mapper\MappingError $error) {
$message = $error->messages()->toArray()[0];
if (is_numeric($message->sourceValue())) {
$message = $message->withBody(
'Invalid amount {source_value, number, currency}'
);
}
// Invalid amount: $1,337.00
echo $message->withLocale('en_US');
// Invalid amount: £1,337.00
echo $message->withLocale('en_GB');
// Invalid amount: 1 337,00 €
echo $message->withLocale('fr_FR');
}
有关可用语法的更多信息,请参阅 [ICU 文档]。
警告
如果未安装intl扩展,则可以使用填充程序来替换占位符,但它不会处理如上所述的高级语法。
更深入的消息定制/翻译¶
对于更深入的消息更改,可以使用格式化程序来自定义正文和参数。
注意
可以将格式化程序添加到消息中
翻译¶
格式化程序TranslationMessageFormatter可用于翻译消息的内容。
该库提供了所有可以返回的消息的列表;可以使用自定义翻译来填充或修改此列表。
\CuyZ\Valinor\Mapper\Tree\Message\Formatter\TranslationMessageFormatter::default()
// Create/override a single entry…
->withTranslation('fr', 'some custom message', 'un message personnalisé')
// …or several entries.
->withTranslations([
'some custom message' => [
'en' => 'Some custom message',
'fr' => 'Un message personnalisé',
'es' => 'Un mensaje personalizado',
],
'some other message' => [
// …
],
])
->format($message);
替换映射表¶
格式化程序MessageMapFormatter可用于提供消息替换列表。它可以用一个数组实例化,其中每个键代表:
- 要替换的消息的代码
- 要替换的消息正文
- 要替换的消息的类名
如果没有找到这些内容,消息的内容将保持不变,除非为类提供了默认内容。
如果找到这些键之一,则将使用数组条目来替换消息的内容。该条目可以是纯文本,也可以是可调用的,将消息作为参数并返回字符串;例如,建议在使用自定义翻译服务的情况下使用可调用函数,以避免无用的贪婪操作。
在任何情况下,内容都可以包含如上所述的占位符。
(new \CuyZ\Valinor\Mapper\Tree\Message\Formatter\MessageMapFormatter([
// Will match if the given message has this exact code
'some_code' => 'New content / code: {message_code}',
// Will match if the given message has this exact content
'Some message content' => 'New content / previous: {original_message}',
// Will match if the given message is an instance of `SomeError`
SomeError::class => 'New content / value: {source_value}',
// A callback can be used to get access to the message instance
OtherError::class => function (NodeMessage $message): string {
if ($message->path() === 'foo.bar') {
return 'Some custom message';
}
return $message->body();
},
// For greedy operation, it is advised to use a lazy-callback
'foo' => fn () => $this->customTranslator->translate('foo.bar'),
]))
->defaultsTo('some default message')
// …or…
->defaultsTo(fn () => $this->customTranslator->translate('default_message'))
->format($message);
多个格式化器¶
可以使用AggregateMessageFormatter将多个格式化程序连接到一个格式化程序中。然后可以轻松地将这个实例注入到处理消息的服务中。
格式化程序将以与聚合相同的顺序被调用。
(new \CuyZ\Valinor\Mapper\Tree\Message\Formatter\AggregateMessageFormatter(
new \CuyZ\Valinor\Mapper\Tree\Message\Formatter\LocaleMessageFormatter('fr'),
new \CuyZ\Valinor\Mapper\Tree\Message\Formatter\MessageMapFormatter([
// …
],
\CuyZ\Valinor\Mapper\Tree\Message\Formatter\TranslationMessageFormatter::default(),
))->format($message)