fastapi国际化

fastapi国际化

tone 3096 2024-09-22

在 FastAPI 中配置多语言支持并使用 fastapi-babel 库,以下步骤为操作示例:

1. 安装依赖

首先,需要安装 fastapi-babelBabel 库:

pip install fastapi-babel Babel

2. 创建配置文件

在项目中创建一个 babel.py 文件,用于配置 Babel。配置示例:

from fastapi_babel import Babel, BabelConfigs

configs = BabelConfigs(
    ROOT_DIR=__file__,
    BABEL_DEFAULT_LOCALE="en",  # 默认语言
    BABEL_TRANSLATION_DIRECTORY="lang",  # 翻译文件存放的目录
)

babel = Babel(configs=configs)

if __name__ == "__main__":
    babel.run_cli()

3. 提取可翻译的消息

创建 babel.cfg 文件,指定要提取的 Python 文件类型:

[python: **.py]

然后使用以下命令提取可翻译的字符串并生成 messages.pot 文件:

pybabel extract -F babel.cfg -o messages.pot .

4. 初始化翻译文件

使用以下命令初始化特定语言的翻译文件(例如,法语 fa):

pybabel init -i messages.pot -d lang -l fa

执行后会在 lang/fa/LC_MESSAGES/ 目录下生成一个 messages.po 文件。

如果已经存在翻译好的文件,根目录下的messages.pot文件有产生新的数据执行下面的命令进行更新

pybabel update -i messages.pot -d lang

-i messages.pot:指定输入文件为已经生成的 .pot 文件。
-d translations:指定翻译目录,通常这个目录下包含各个语言的 .po 文件
-l zh:指定语言代码

5. 添加翻译内容

打开生成的 messages.po 文件,添加对应的翻译内容。每一条可翻译的消息都会有一个 msgid 和一个 msgstr,需要在 msgstr 中填写对应的翻译。

6. 编译翻译文件

在添加完翻译内容后,使用以下命令编译这些翻译文件:

pybabel compile -d lang -l fa

这会生成二进制的 messages.mo 文件,供应用程序在运行时使用。

7. 在 FastAPI 中使用 Babel

在 FastAPI 应用中,引入 Babel 中间件,并配置应用使用翻译:

from fastapi import FastAPI, Request
from fastapi_babel import BabelMiddleware, _

app = FastAPI()

# 加载配置
configs = BabelConfigs(
    ROOT_DIR=__file__,
    BABEL_DEFAULT_LOCALE="en",
    BABEL_TRANSLATION_DIRECTORY="lang",
)
app.add_middleware(BabelMiddleware, babel_configs=configs)

def get_locale(request: Request) -> str:
  return request.headers.get("accept-language", "en")


def get_translator(request: Request):
  locale = get_locale(request)
  log.info(f'当前语言环境为:{locale}')
  babel.locale = locale  # 临时设置当前请求的语言环境
  return babel.gettext

@app.get("/")
async def index(request: Request):
    return {"message": _("Hello, World!")}

if __name__ == "__main__":
    babel.run_cli()

8. 通过请求头控制语言

在运行时,可以通过设置 HTTP 请求的 Accept-Language 头来控制返回的语言。例如,设置 Accept-Language: fa 会返回法语的翻译内容。

注意事项

  • 不要将 fastapi-babelmain.pyrun.py 直接一起使用,因为这可能会导致 uvicorn 的运行问题。
  • 如果 BABEL_DEFAULT_LOCALE 设置为 zh,而代码中的字符串(如 "hello")也是用中文环境下的内容,FastAPI Babel 会认为这已经是翻译后的文本,因此不会再从本地的翻译文件中获取对应的翻译内容。这是因为默认语言和请求语言相同时,Babel 会直接返回代码中的原始字符串,而不再进行翻译查找。
  • 目前上下文传递有问题github有issue暂未解决!!!

将语言环境处理逻辑从中间件中分离出来,单独处理的方法是一个更优雅且避免并发问题的解决方案。通过将语言环境的处理集中在一个独立的方法中,可以确保每个请求都能正确解析和应用语言环境,而不会受到其他请求的干扰。

具体实现方法:

  1. 创建独立的语言环境解析方法

    可以创建一个独立的函数,用于解析并返回当前请求的语言环境。这样可以避免使用全局变量,并确保每次请求处理时都能正确获取语言环境。

from fastapi import FastAPI, Request
from fastapi_babel import Babel, BabelConfigs

app = FastAPI()

configs = BabelConfigs(
    ROOT_DIR=__file__,
    BABEL_DEFAULT_LOCALE="en",
    BABEL_TRANSLATION_DIRECTORY="lang"
)

babel = Babel(configs=configs)

def get_locale(request: Request) -> str:
    return request.headers.get("accept-language", "en")

def get_translator(request: Request):
    locale = get_locale(request)
    babel.locale = locale  # 临时设置当前请求的语言环境
    return babel.gettext

@app.get("/")
async def index(request: Request):
    _ = get_translator(request)
    return {"message": _("Hello, World!")}
  1. 函数的职责分离

    在这个实现中,get_locale函数负责解析请求中的语言环境,get_translator函数则负责根据当前请求的语言环境获取对应的gettext翻译函数。每个请求都会调用这些函数,因此语言环境的处理是完全独立和请求特定的,不会与其他请求产生冲突。

  2. 优势

    • 避免共享状态:这种方法避免了使用全局状态或变量,因此在高并发环境中不会出现竞争条件或数据污染。
    • 更清晰的结构:将语言处理逻辑从中间件中分离出来,使得代码结构更加清晰易懂,职责分离明确。
    • 可测试性:独立的方法更易于测试和维护,可以单独测试语言环境的解析和翻译逻辑,而不依赖于整个请求处理流程。

通过这种方法,可以在保持应用灵活性的同时,确保在任何并发条件下语言环境都能正确处理,从而避免潜在的问题。

服务器常用状态码和英文描述以及中文翻译如下:

状态码英文描述中文翻译
200OK请求成功
201Created已创建
202Accepted已接受
204No Content无内容
301Moved Permanently永久移动
302Found临时移动
304Not Modified未修改
400Bad Request错误请求
401Unauthorized未授权
403Forbidden禁止访问
404Not Found未找到
405Method Not Allowed方法不被允许
500Internal Server Error服务器内部错误
502Bad Gateway错误网关
503Service Unavailable服务不可用
504Gateway Timeout网关超时