信息发布→ 登录 注册 退出

在Lar*el中实现多语言验证错误消息的并行展示

发布时间:2025-11-23

点击量:

在Laravel中实现多语言验证错误消息的并行展示

本教程详细讲解如何在lar*el应用中实现多语言验证错误消息的并行展示。通过重写formrequest的`messages`方法,为每个验证规则和字段定制多语言错误信息,并结合`failedvalidation`方法进行响应格式化,从而在单个api响应中同时返回不同语言的验证结果,满足复杂的国际化需求。

Lar*el多语言验证错误消息的并行展示

在构建国际化(i18n)API时,一个常见的需求是能够在单个API响应中,为同一个字段的验证错误同时提供多种语言的提示。Lar*el的FormRequest默认行为是根据当前的应用程序语言环境(Locale)返回验证错误信息。然而,当我们需要一个统一的响应结构,例如,某个字段的错误信息同时包含英文和法文版本时,默认机制就显得不足了。

核心挑战与目标响应结构

传统的Lar*el验证流程中,当验证失败时,FormRequest会调用failedValidation方法,并传入一个已经根据当前Locale生成好消息的MessageBag实例。这意味着在failedValidation阶段,我们已经无法轻易地为同一个错误动态地生成其他语言的消息。

我们的目标是实现以下类似的多语言错误响应结构:

{
  "detail": {
      "email": {
        "en-CA" : [
          "The email has already been taken."
        ],
        "fr-CA" : [
          "The french text."
        ]
      },
      "first_name": {
        "en-CA" : [
          "The first name must be at least 5.",
          "The first name must be an integer."
        ],
        "fr-CA" : [
          "The french text",
          "The french text."
        ]
      }
  }
}

要实现这种结构,我们需要在验证器生成错误消息的阶段就介入,而不是在消息生成完毕后尝试转换。

解决方案:重写FormRequest的messages()方法

Lar*el的FormRequest提供了一个messages()方法,允许开发者为每个验证规则和字段定制错误消息。这是在验证器生成MessageBag之前介入的关键点。通过在此方法中明确指定每种语言的错误消息,我们可以确保MessageBag在构建时就包含了所有必要的多语言信息。

1. 定义验证规则

首先,像往常一样在FormRequest中定义你的验证规则。例如:

PictoGraphic PictoGraphic

AI驱动的矢量插图库和插图生成平台

PictoGraphic 133 查看详情 PictoGraphic
// app/Http/Requests/SysUserStoreRequest.php
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class SysUserStoreRequest extends ApiRequest // 假设ApiRequest是你的基类FormRequest
{
    public function rules()
    {
        return [
            'email' => 'required|email|unique:users,email,' . $this->id,
            'first_name' => 'required|string|min:5',
            // ... 其他字段规则
        ];
    }

    // ... 其他方法
}

2. 实现多语言消息生成

在SysUserStoreRequest中重写messages()方法,为每个字段和规则定义多语言错误信息。

// app/Http/Requests/SysUserStoreRequest.php
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;

class SysUserStoreRequest extends ApiRequest
{
    public function rules()
    {
        return [
            'email' => 'required|email|unique:users,email,' . ($this->id ?? 'NULL'), // 确保unique规则在更新时能排除自身
            'first_name' => 'required|string|min:5',
            // ...
        ];
    }

    public function messages()
    {
        return [
            'email.required' => [
               'en-CA' => __('validation.required', ['attribute' => __('portal.email', [], 'en-CA')], 'en-CA'),
               'fr-CA' => __('validation.required', ['attribute' => __('portal.email', [], 'fr-CA')], 'fr-CA'),
            ],
            'email.email' => [
               'en-CA' => __('validation.email', ['attribute' => __('portal.email', [], 'en-CA')], 'en-CA'),
               'fr-CA' => __('validation.email', ['attribute' => __('portal.email', [], 'fr-CA')], 'fr-CA'),
            ],
            'email.unique' => [
               'en-CA' => __('validation.unique', ['attribute' => __('portal.email', [], 'en-CA')], 'en-CA'),
               'fr-CA' => __('validation.unique', ['attribute' => __('portal.email', [], 'fr-CA')], 'fr-CA'),
            ],
            'first_name.required' => [
               'en-CA' => __('validation.required', ['attribute' => __('portal.first_name', [], 'en-CA')], 'en-CA'),
               'fr-CA' => __('validation.required', ['attribute' => __('portal.first_name', [], 'fr-CA')], 'fr-CA'),
            ],
            'first_name.min' => [
               'en-CA' => __('validation.min.string', ['attribute' => __('portal.first_name', [], 'en-CA'), 'min' => 5], 'en-CA'),
               'fr-CA' => __('validation.min.string', ['attribute' => __('portal.first_name', [], 'fr-CA'), 'min' => 5], 'fr-CA'),
            ],
            // ... 为其他字段和规则添加类似的多语言消息
        ];
    }
}

代码解释:

  • 'email.required':这是消息键,由字段名和验证规则名组成。
  • [ 'en-CA' => ..., 'fr-CA' => ... ]:值是一个关联数组,键是目标语言环境代码(例如en-CA, fr-CA),值是该语言环境下的具体错误消息。
  • __('validation.required', ['attribute' => __('portal.email', [], 'en-CA')], 'en-CA'):
    • __('validation.required', ..., 'en-CA'):这是Lar*el的翻译辅助函数,用于从lang/en-CA/validation.php文件中获取required规则的原始消息。第三个参数'en-CA'明确指定了要使用的语言文件。
    • ['attribute' => __('portal.email', [], 'en-CA')]:这是用于替换验证消息中占位符(如:attribute)的参数。这里我们再次使用__函数来翻译字段名本身(例如,从lang/en-CA/portal.php获取email的翻译),确保整个错误消息是完全本地化的。
    • 对于带有min、max等参数的规则,需要传递相应的参数,例如'min' => 5。

通过这种方式,当验证失败时,Validator的MessageBag中,每个错误消息项将不再是简单的字符串,而是一个包含所有指定语言消息的数组。例如,$validator->getMessageBag()->toArray()可能会返回类似: ['email' => [['en-CA' => '...', 'fr-CA' => '...']]]

格式化最终API响应:重写failedValidation()

尽管messages()方法帮助我们生成了多语言数据,但MessageBag的默认结构可能不完全符合我们期望的最终JSON格式。我们需要在ApiRequest(或你的基础FormRequest类)中重写failedValidation方法,将MessageBag的内容转换为目标结构。

// app/Http/Requests/ApiRequest.php
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;

abstract class ApiRequest extends FormRequest
{
    /**
     * Handle a failed validation attempt.
     *
     * @param  \Illuminate\Contracts\Validation\Validator  $validator
     * @return void
     *
     * @throws \Illuminate\Http\Exceptions\HttpResponseException
     */
    protected function failedValidation(Validator $validator)
    {
        $errors = $validator->getMessageBag()->toArray();
        $formattedErrors = [];

        foreach ($errors as $field => $fieldErrors) {
            $formattedErrors[$field] = [];
            foreach ($fieldErrors as $errorItem) {
                // errorItem 此时是一个形如 ['en-CA' => '...', 'fr-CA' => '...'] 的数组
                foreach ($errorItem as $locale => $message) {
                    if (!isset($formattedErrors[$field][$locale])) {
                        $formattedErrors[$field][$locale] = [];
                    }
                    $formattedErrors[$field][$locale][] = $message;
                }
            }
        }

        // 抛出包含自定义错误结构的HTTP响应异常
        throw new HttpResponseException(response()->json([
            'detail' => $formattedErrors
        ], 422)); // 422 Unprocessable Entity 是常见的验证错误状态码
    }
}

代码解释:

  1. $validator->getMessageBag()->toArray():获取原始的错误消息数组。
  2. $formattedErrors = []:初始化一个空数组,用于存储最终格式化的错误。
  3. 外层foreach ($errors as $field => $fieldErrors):遍历每个发生错误的字段(例如email, first_name)。$fieldErrors是一个数组,其中包含该字段的所有错误消息项。
  4. 内层foreach ($fieldErrors as $errorItem):遍历某个字段的每个具体错误。由于我们在messages()方法中定义了多语言结构,$errorItem现在是一个关联数组,键是语言代码,值是该语言的错误消息。
  5. 最内层foreach ($errorItem as $locale => $message):遍历$errorItem中的每个语言及其对应的消息。
  6. $formattedErrors[$field][$locale][] = $message;:将消息添加到$formattedErrors中,按照字段 -> 语言 -> 消息数组的层级结构组织。
  7. throw new HttpResponseException(...):构建并抛出一个HttpResponseException,其中包含我们自定义的JSON响应结构。

完整示例代码

为了更清晰地展示,以下是整合后的ApiRequest和SysUserStoreRequest示例:

// app/Http/Requests/ApiRequest.php
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;

abstract class ApiRequest extends FormRequest
{
    /**
     * Handle a failed validation attempt.
     *
     * @param  \Illuminate\Contracts\Validation\Validator  $validator
     * @return void
     *
     * @throws \Illuminate\Http\Exceptions\HttpResponseException
     */
    protected function failedValidation(Validator $validator)
    {
        $errors = $validator->getMessageBag()->toArray();
        $formattedErrors = [];

        foreach ($errors as $field => $fieldErrors) {
            $formattedErrors[$field] = [];
            foreach ($fieldErrors as $errorItem) {
                foreach ($errorItem as $locale => $message) {
                    if (!isset($formattedErrors[$field][$locale])) {
                        $formattedErrors[$field][$locale] = [];
                    }
                    $formattedErrors[$field][$locale][] = $message;
                }
            }
        }

        throw new HttpResponseException(response()->json([
            'detail' => $formattedErrors
        ], 422));
    }
}

// app/Http/Requests/SysUserStoreRequest.php
namespace App\Http\Requests;

use App\Http\Requests\ApiRequest; // 确保引入你的基类
use Illuminate\Support\Facades\Lang; // 引入Lang门面

class SysUserStoreRequest extends ApiRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true; // 根据你的授权逻辑设置
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'email' => 'required|email|unique:users,email,' . ($this->id ?? 'NULL'),
            'first_name' => 'required|string|min:5',
            // ... 其他字段规则
        ];
    }

    /**
     * Get the error messages for the defined validation rules.
     *
     * @return array
     */
    public function messages()
    {
        return [
            'email.required' => [
               'en-CA' => Lang::get('validation.required', ['attribute' => Lang::get('portal.email', [], 'en-CA')],

以上就是在Lar*el中实现多语言验证错误消息的并行展示的详细内容,更多请关注php中文网其它相关文章!


相关文章: 在J*a中如何开发简易仓库管理与库存统计_仓库管理库存统计项目实战解析  如何将HTML表格多行数据保存到Google Sheet  漫蛙网页登录入口 漫蛙漫画官方授权网址  QQ邮箱网页版入口 QQ邮箱官方邮箱登录通道  Lar*el的路由模型绑定怎么用_Lar*el Route Model Binding简化控制器逻辑  lar*el怎么安全地存储和获取配置文件中的敏感信息_lar*el敏感信息安全存储方法  如何在复杂的电商平台中优雅地管理共享资源并确保正确重定向,使用spryker-shop/resource-share-page模块助你一臂之力  支付宝碰一碰设备是REDMI手机吗 博主拆机辟谣:处理器、内存都不一样  微信网页版扫码登录入口 微信网页版二维码登录入口  Sublime怎么配置Nim语言环境_Sublime Nim代码高亮与补全  《GTA6》开发画面疑似泄露!这次可不是AI了  C++如何实现线程池_C++11手动实现一个简单的固定大小线程池  J*aScript数组对象转换:按指定键分组与值收集  AO3网页版最新入口合集 Archive of Our Own在线访问指南  J*a初级项目如何接入API数据_第三方接口请求与响应解析  漫画星球免费下拉式入口 漫画星球免费漫画在线阅读网站  创客贴用户入口官网登录 创客贴网页版电脑版系统  c++中为什么推荐使用using替代typedef_c++现代化类型别名  怎么在html里运行vbs脚本_html中运行vbs脚本方法【教程】  蛙漫漫画官网在线入口 蛙漫全本漫画免费阅读平台  1688商家版怎样分析买家画像精准供货_1688商家版分析买家画像精准供货【供货策略】  J*aScript map 迭代中检测空数组元素的有效方法  163邮箱官方主页登录 直达网易邮箱登录核心页面  Mac怎么查看崩溃日志_Mac控制台错误报告分析  《明末:渊虚之羽》设计师谈设计角色:那会刚毕业 充满激情  J*aScript中向JSON对象添加新属性的正确姿势  Win11如何使用Windows Sandbox Win11沙盒功能开启与使用教程【详解】  Win11怎么设置鼠标主按键_Win11鼠标左右键功能互换  Basecamp怎样用留言钉固定重点_Basecamp用留言钉固定重点【重点标记】  字由网在线版登录地址 字由网网页版安全入口  解决Flask中Quill编辑器内容提交失败及TypeError的指南  漫蛙漫画官方首页 漫蛙2漫画在线阅读入口  动漫共和国防屏蔽稳定域名-动漫共和国官方正版直达通道  解决Bootstrap卡片顶部边距导致背景图下移的问题  Selenium Python中处理点击后新窗口加载冻结问题的策略与实践  如何让 composer 信任自签名的 HTTPS 证书源?  c++如何使用std::memory_order控制原子操作顺序_c++ C++11内存模型详解  Excel如何用迷你图显趋势_Excel用迷你图显趋势【趋势小图】  基于多条件高效更新SQL表:利用CASE表达式优化业务逻辑  处理嵌套交互式控件:前端可访问性指南  漫蛙漫画网页端入口 漫蛙2官方正版漫画站点  php源码怎么在电脑上测试_电脑测试php源码方法步骤【教程】  2026年CSGO开箱网站推荐 CSGO开箱平台精选  拼多多视频播放卡顿如何处理 拼多多视频播放优化技巧  树莓派传感器触发:通过Twilio API发送WhatsApp消息教程  Tailwind CSS line-clamp 布局问题解析与修复指南  ExcelARRAYTOTEXT函数怎么自定义分隔符输出数组文本_ARRAYTOTEXT实现动态生成SQL语句  抖音创作助手登录入口_抖音创作辅助工具官网直达  Go语言中Map存储的结构体如何调用指针方法:深入解析与实践  微信网页版官方入口直达 微信网页版网页版登录使用方法 

在线客服
服务热线

服务热线

4008988990

微信咨询
二维码
返回顶部
×二维码

截屏,微信识别二维码

打开微信

微信号已复制,请打开微信添加咨询详情!