使用fastapi时,发现接口报错的结果是英文的,自己的英语水平不太行,就想能不能翻译成中文,发现果然有办法。
先看结果:
实现方法:
参考链接pydantic-i18n · PyPI
首先执行如下代码获取原有的英文翻译字典
from pydantic_i18n import PydanticI18nprint(PydanticI18n.get_pydantic_messages())
之后找个大模型帮忙翻译一下:
pydantic的版本不一样所以这个不能直接用我的代码,必须自己翻译一遍
首先新建一个tr.py文件
# @file : tr
# @time : 2025/5/30
# @author : yongpeng.yao
# @desc :import re
from typing import Dict, Patternfrom 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 localeasync 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 Optionalfrom 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 SLHTTPExceptionimport trapp = 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: inttoken: strtimestamp: strarticle_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 uvicornimport osapp_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状态码翻译