You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在NestJS+Next.js中实现后端错误(含校验信息)多语言前端展示?

前端本地化处理后端错误信息方案(基于next-i18next)

核心思路

由于后端不改动错误逻辑,前端需将后端返回的标准化错误(尤其是class-validator生成的校验错误)映射到前端翻译key,通过next-i18next的翻译能力渲染多语言文本,同时覆盖自定义后端错误。

具体实现步骤

1. 明确后端错误结构

先梳理后端返回的错误格式,class-validator的校验错误通常为数组结构,示例如下:

{
  "statusCode": 400,
  "message": [
    {
      "property": "username",
      "constraints": {
        "isString": "username must be a string",
        "isEmpty": "username should not be empty",
        "minLength": "username must be longer than or equal to 10 characters"
      }
    }
  ],
  "error": "Bad Request"
}

2. 配置前端翻译文件

在public/locales下的多语言文件夹(如zh、en)中创建errors.json,存放错误翻译内容:

英文(en/errors.json)

{
  "validation": {
    "username": {
      "isString": "Username must be a string",
      "isEmpty": "Username cannot be empty",
      "minLength": "Username must be at least 10 characters long"
    },
    "common": {
      "badRequest": "Invalid request",
      "serverError": "Server error occurred"
    }
  },
  "customErrors": {
    "userNotFound": "User not found"
  }
}

中文(zh/errors.json)

{
  "validation": {
    "username": {
      "isString": "用户名必须为字符串",
      "isEmpty": "用户名不能为空",
      "minLength": "用户名长度不能少于10个字符"
    },
    "common": {
      "badRequest": "请求无效",
      "serverError": "服务器发生错误"
    }
  },
  "customErrors": {
    "userNotFound": "用户不存在"
  }
}

3. 编写错误映射与翻译工具

创建utils/errorTranslator.ts,实现后端错误到前端翻译key的映射:

import { useTranslation } from 'next-i18next';

// 映射class-validator错误文本到翻译key
const validatorErrorMap: Record<string, string> = {
  'username must be a string': 'validation.username.isString',
  'username should not be empty': 'validation.username.isEmpty',
  'username must be longer than or equal to 10 characters': 'validation.username.minLength',
  // 新增其他校验错误映射
};

// 通用错误文本映射
const commonErrorMap: Record<string, string> = {
  'Bad Request': 'validation.common.badRequest',
};

export const translateError = (error: any) => {
  const { t } = useTranslation('errors');
  
  // 处理class-validator的数组型校验错误
  if (Array.isArray(error.message)) {
    return error.message.map(err => {
      return Object.values(err.constraints).map(msg => {
        return validatorErrorMap[msg] ? t(validatorErrorMap[msg]) : msg;
      }).join(', ');
    }).join('; ');
  }
  
  // 处理单个错误文本
  if (typeof error.message === 'string') {
    if (validatorErrorMap[error.message]) return t(validatorErrorMap[error.message]);
    if (commonErrorMap[error.message]) return t(commonErrorMap[error.message]);
    // 自定义错误匹配
    if (error.message.includes('User not found')) return t('customErrors.userNotFound');
    // 兜底返回原文本
    return error.message;
  }
  
  // 未知错误兜底
  return t('validation.common.serverError');
};

4. 组件中使用翻译工具

在表单或API请求的错误处理逻辑中调用翻译函数:

import { useState, FormEvent } from 'react';
import { useTranslation } from 'next-i18next';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import { translateError } from '../utils/errorTranslator';

export default function LoginPage() {
  const { t } = useTranslation('errors');
  const [errorMsg, setErrorMsg] = useState('');

  const handleSubmit = async (e: FormEvent) => {
    e.preventDefault();
    try {
      const res = await fetch('/api/login', {
        method: 'POST',
        body: JSON.stringify({ username: 'test' })
      });
      if (!res.ok) {
        const error = await res.json();
        setErrorMsg(translateError(error));
      }
    } catch (err) {
      setErrorMsg(t('validation.common.serverError'));
    }
  };

  return (
    <div className="p-4">
      {errorMsg && <p className="text-red-500 mb-4">{errorMsg}</p>}
      <form onSubmit={handleSubmit}>
        <input type="text" placeholder={t('validation.fields.username')} className="border p-2 mb-2" />
        <button type="submit" className="bg-blue-500 text-white p-2">Login</button>
      </form>
    </div>
  );
}

export async function getStaticProps({ locale }: { locale: string }) {
  return {
    props: {
      ...await serverSideTranslations(locale, ['errors']),
    },
  };
}

优化建议

  • 动态字段映射:将字段名也加入翻译(如validation.fields.username对应“用户名”),通过正则匹配后端错误中的字段名,动态生成翻译key,减少硬编码。
  • 全局错误拦截:在axios等请求库的拦截器中统一处理错误翻译,避免每个组件重复编写错误逻辑。
  • 批量生成映射表:根据class-validator的默认错误模板(如{{property}} must be a string),批量生成错误文本与翻译key的映射关系,提升扩展性。

内容的提问来源于stack exchange,提问作者lCode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 06:03:37