使用fastapi时,发现接口报错的结果是英文的,自己的英语水平不太行,就想能不能翻译成中文,发现果然有办法。

先看结果:

实现方法:

参考链接pydantic-i18n · PyPI

首先执行如下代码获取原有的英文翻译字典

from pydantic_i18n import PydanticI18n

print(PydanticI18n.get_pydantic_messages())

之后找个大模型帮忙翻译一下:

pydantic的版本不一样所以这个不能直接用我的代码,必须自己翻译一遍

首先新建一个tr.py文件

# @file    : tr
# @time    : 2025/5/30
# @author  : yongpeng.yao
# @desc    :

import re
from typing import Dict, Pattern

from fastapi import Request
from fastapi.exceptions import RequestValidationError
from pydantic_i18n import PydanticI18n
from starlette.responses import JSONResponse
from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY

__all__ = ["get_locale", "validation_exception_handler"]

DEFAULT_LOCALE = "zh_CN"

translations = {
    "en_US": {
        "Field required": "field required",
    },
    "zh_CN": {
        "Object has no attribute '{}'": "对象没有属性 '{}'",
        "Invalid JSON: {}": "无效的JSON数据: {}",
        "JSON input should be string, bytes or bytearray": "JSON输入应为字符串、字节或字节数组",
        "Cannot check `{}` when validating from json, use a JsonOrPython validator instead": "从json验证时无法检查`{}`,请改用JsonOrPython验证器",
        "Recursion error - cyclic reference detected": "递归错误-检测到循环引用",
        "Field required": "字段必填",
        "Field is frozen": "字段已被冻结",
        "Instance is frozen": "实例已被冻结",
        "Extra inputs are not permitted": "不允许额外的输入",
        "Keys should be strings": "键名应为字符串",
        "Error extracting attribute: {}": "提取属性时出错: {}",
        "Input should be a valid dictionary or instance of {}": "输入应为有效的字典或{}的实例",
        "Input should be a valid dictionary or object to extract fields from": "输入应为有效的字典或可提取字段的对象",
        "Input should be a dictionary or an instance of {}": "输入应为字典或{}的实例",
        "Input should be an instance of {}": "输入应为{}的实例",
        "Input should be None": "输入应为None",
        "Input should be greater than {}": "输入应大于{}",
        "Input should be greater than or equal to {}": "输入应大于等于{}",
        "Input should be less than {}": "输入应小于{}",
        "Input should be less than or equal to {}": "输入应小于等于{}",
        "Input should be a multiple of {}": "输入应为{}的倍数",
        "Input should be a finite number": "输入应为有限数字",
        "Input should be iterable": "输入应为可迭代对象",
        "Error iterating over object, error: {}": "迭代对象时出错: {}",
        "Input should be a valid string": "输入应为有效的字符串",
        "Input should be a string, not an instance of a subclass of str": "输入应为字符串,而不是str子类的实例",
        "Input should be a valid string, unable to parse raw data as a unicode string": "输入应为有效的字符串,无法将原始数据解析为unicode字符串",
        "String should have at least {}": "字符串长度至少为{}",
        "String should have at most {}": "字符串长度最多为{}",
        "String should match pattern '{}'": "字符串应匹配模式'{}'",
        "Input should be {}": "输入应为{}",
        "Input should be a valid dictionary": "输入应为有效的字典",
        "Input should be a valid mapping, error: {}": "输入应为有效的映射,错误: {}",
        "Input should be a valid list": "输入应为有效的列表",
        "Input should be a valid tuple": "输入应为有效的元组",
        "Input should be a valid set": "输入应为有效的集合",
        "Set items should be hashable": "集合元素应为可哈希对象",
        "Input should be a valid boolean": "输入应为有效的布尔值",
        "Input should be a valid boolean, unable to interpret input": "输入应为有效的布尔值,无法解析输入",
        "Input should be a valid integer": "输入应为有效的整数",
        "Input should be a valid integer, unable to parse string as an integer": "输入应为有效的整数,无法将字符串解析为整数",
        "Unable to parse input string as an integer, exceeded maximum size": "无法将输入字符串解析为整数,超过最大长度限制",
        "Input should be a valid integer, got a number with a fractional part": "输入应为有效的整数,但包含小数部分",
        "Input should be a valid number": "输入应为有效的数字",
        "Input should be a valid number, unable to parse string as a number": "输入应为有效的数字,无法将字符串解析为数字",
        "Input should be a valid bytes": "输入应为有效的字节",
        "Data should have at least {}": "数据长度至少为{}",
        "Data should have at most {}": "数据长度最多为{}",
        "Data should be valid {}": "数据应为有效的{}",
        "Value error, {}": "数值错误, {}",
        "Assertion failed, {}": "断言失败, {}",
        "Input should be a valid date": "输入应为有效的日期",
        "Input should be a valid date in the format YYYY-MM-DD, {}": "输入应为YYYY-MM-DD格式的有效日期, {}",
        "Input should be a valid date or datetime, {}": "输入应为有效的日期或时间, {}",
        "Datetimes provided to dates should have zero time - e.g. be exact dates": "提供给日期的日期时间应没有时间部分(即精确日期)",
        "Date should be in the past": "日期应为过去时间",
        "Date should be in the future": "日期应为未来时间",
        "Input should be a valid time": "输入应为有效的时间",
        "Input should be in a valid time format, {}": "输入应为有效的时间格式, {}",
        "Input should be a valid datetime": "输入应为有效的日期时间",
        "Input should be a valid datetime, {}": "输入应为有效的日期时间, {}",
        "Invalid datetime object, got {}": "无效的日期时间对象, 得到{}",
        "Input should be a valid datetime or date, {}": "输入应为有效的日期时间或日期, {}",
        "Input should be in the past": "输入应为过去时间",
        "Input should be in the future": "输入应为未来时间",
        "Input should not have timezone info": "输入不应包含时区信息",
        "Input should have timezone info": "输入应包含时区信息",
        "Timezone offset of {}": "时区偏移量为{}",
        "Input should be a valid timedelta": "输入应为有效的时间差",
        "Input should be a valid timedelta, {}": "输入应为有效的时间差, {}",
        "Input should be a valid frozenset": "输入应为有效的不可变集合",
        "Input should be a subclass of {}": "输入应为{}的子类",
        "Input should be callable": "输入应为可调用对象",
        "Input tag '{}": "输入标签'{}",
        "Unable to extract tag using discriminator {}": "无法使用鉴别器{}提取标签",
        "Arguments must be a tuple, list or a dictionary": "参数应为元组、列表或字典",
        "Missing required argument": "缺少必需参数",
        "Unexpected keyword argument": "意外的关键字参数",
        "Missing required keyword only argument": "缺少必需的关键字参数",
        "Unexpected positional argument": "意外的位置参数",
        "Missing required positional only argument": "缺少必需的位置参数",
        "Got multiple values for argument": "参数有多个值",
        "URL input should be a string or URL": "URL输入应为字符串或URL对象",
        "Input should be a valid URL, {}": "输入应为有效的URL, {}",
        "Input violated strict URL syntax rules, {}": "输入违反了严格的URL语法规则, {}",
        "URL should have at most {}": "URL长度最多为{}",
        "URL scheme should be {}": "URL协议应为{}",
        "UUID input should be a string, bytes or UUID object": "UUID输入应为字符串、字节或UUID对象",
        "Input should be a valid UUID, {}": "输入应为有效的UUID, {}",
        "UUID version {} expected": "应为版本{}的UUID",
        "Decimal input should be an integer, float, string or Decimal object": "Decimal输入应为整数、浮点数、字符串或Decimal对象",
        "Input should be a valid decimal": "输入应为有效的十进制数",
        "Decimal input should have no more than {} in total": "Decimal输入总位数不应超过{}",
        "Decimal input should have no more than {}": "Decimal输入小数位数不应超过{}",
        "Decimal input should have no more than {} before the decimal point": "Decimal输入小数点前位数不应超过{}",
        "Input should be a valid python complex object, a number, or a valid complex string following the rules at https://docs.python.org/3/library/functions.html#complex": "输入应为有效的python复数对象、数字或符合https://docs.python.org/3/library/functions.html#complex规则的复数字符串",
        "Input should be a valid complex string following the rules at https://docs.python.org/3/library/functions.html#complex": "输入应为符合https://docs.python.org/3/library/functions.html#complex规则的复数字符串"
    },
}


class MyPydanticI18n(PydanticI18n):

    def _init_pattern(self) -> Pattern[str]:
        keys = [key for key in self.source.get_translations(self.default_locale) if '{}' in key]
        keys = sorted(keys, key=len, reverse=True)
        return re.compile(
            "|".join("({})".format(re.escape(i).replace(r"\{\}", "(.+)")) for i in keys)
        )

    def _translate(self, message: str, locale: str) -> str:
        if locale not in self.locales:
            raise ValueError(f"Locale '{locale}' wasn't found.")
        if message in self.source.get_translations(locale):
            return self.source.gettext(message, locale)

        return super()._translate(message, locale)


tr = MyPydanticI18n(translations, default_locale=DEFAULT_LOCALE)


def get_locale(locale: str = DEFAULT_LOCALE) -> str:
    return locale


async def validation_exception_handler(
        request: Request, exc: RequestValidationError
) -> JSONResponse:
    current_locale = request.query_params.get("locale", DEFAULT_LOCALE)
    return JSONResponse(
        status_code=HTTP_422_UNPROCESSABLE_ENTITY,
        content={"detail": tr.translate(exc.errors(), current_locale)},
    )


http_status_codes: Dict[int, str] = {
    # 客户端错误 (4xx)
    400: "错误请求(服务器无法理解的请求)",
    401: "未授权(需要身份验证)",
    402: "需要支付(保留用于未来支付系统)",
    403: "禁止访问(服务器拒绝执行请求)",
    404: "未找到(资源不存在)",
    405: "方法不允许(禁用请求中指定的方法)",
    406: "不可接受(无法生成客户端可接受的内容)",
    407: "需要代理认证(类似401但需代理认证)",
    408: "请求超时(服务器等待请求超时)",
    409: "冲突(请求与资源当前状态冲突)",
    410: "已删除(资源已永久删除)",
    411: "需要长度(请求需要Content-Length头)",
    412: "前置条件失败(请求头中条件不满足)",
    413: "请求实体过大(请求体超过服务器限制)",
    414: "URI过长(请求URI超过服务器限制)",
    415: "不支持的媒体类型(服务器无法处理请求格式)",
    416: "范围无效(请求范围无法满足)",
    417: "预期失败(无法满足Expect请求头)",
    418: "我是茶壶(愚人节玩笑代码)",
    421: "错误定向请求(请求被定向到无法响应的服务器)",
    422: "无法处理的实体(请求格式正确但语义错误)",
    423: "已锁定(WebDAV:资源被锁定)",
    424: "依赖失败(WebDAV:因前序请求失败导致当前失败)",
    425: "过早请求(服务器不愿处理可能重播的请求)",
    426: "需要升级(客户端应切换协议)",
    428: "需要前置条件(请求必须包含条件头)",
    429: "请求过多(客户端发送过多请求)",
    431: "请求头字段过大(请求头超出服务器限制)",
    451: "因法律原因不可用(服务器因法律要求无法提供资源)",

    # 服务器错误 (5xx)
    500: "服务器内部错误(服务器遇到意外错误)",
    501: "未实现(服务器不支持请求的功能)",
    502: "错误网关(网关或代理从上游服务器收到无效响应)",
    503: "服务不可用(服务器暂时过载或维护)",
    504: "网关超时(网关或代理等待上游服务器响应超时)",
    505: "HTTP版本不支持(服务器不支持请求的HTTP版本)",
    506: "变种也可协商(服务器存在内部配置错误)",
    507: "存储空间不足(WebDAV:无法存储完成请求所需内容)",
    508: "检测到循环(WebDAV:操作导致无限循环)",
    510: "未扩展(请求需要扩展但服务器不支持)",
    511: "需要网络认证(客户端需要认证才能访问网络)"
}

之后在main.py中使用

#!/usr/bin/evn python
# -*- coding: utf-8 -*-
from typing import Optional

from fastapi import Depends, FastAPI, Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from starlette.exceptions import HTTPException as SLHTTPException

import tr

app = FastAPI(dependencies=[Depends(tr.get_locale)])

app.add_exception_handler(RequestValidationError, tr.validation_exception_handler)


@app.exception_handler(SLHTTPException)
async def http_exception_handler(request: Request, exc: SLHTTPException):
    # 翻译错误消息
    translated_detail = tr.http_status_codes.get(exc.status_code, exc.detail)

    return JSONResponse(
        status_code=exc.status_code,
        content={
            "http_code": exc.status_code,
            "message": translated_detail,
        },
    )


class Item(BaseModel):
    user_id: int
    token: str
    timestamp: str
    article_id: Optional[str] = None


@app.post("/action/")
def callback(item: Item):
    return {
        'user_id': item.user_id,
        'article_id': item.article_id,
        'token': item.token,
        'timestamp': item.timestamp
    }


if __name__ == "__main__":
    import uvicorn
    import os

    app_model_name = os.path.basename(__file__).replace(".py", "")
    print(app_model_name)
    uvicorn.run(f"{app_model_name}:app", host='127.0.0.1')

完成!

2025-05-30 14:13增加http状态码翻译

Logo

电影级数字人,免显卡端渲染SDK,十行代码即可调用,工业级demo免费开源下载!

更多推荐