[FastAPI] ニッチなところを突く！Pydantic-i18nでPydanticのバリデーションメッセージを英語から日本語へ変換！！

# この記事を読んでできること
Pydanticのバリデーションメッセージを英語から日本語に変換して返すことができる
# 概要
- i18nとは
- Pydantic-i18nとは
- 実装
# 記述しないこと
- FastAPIについて
- Pydanticとは
- Pydanticの実装

# 使用技術
fastapi==0.78.0
pydantic==1.9.1
pydantic-i18n==0.2.3

# i18nとは
**i18n**（Internationalization（国際化対応）の略称）とは、文化や地域、言語によって異なるターゲットオーディエンスに合わせて容易にローカライズできる製品、アプリケーション、または文書内容の設計と開発のこと 
今回の実装ではPydanticのデフォルト設定の言語が英語であるため、それを日本語に変換するという国際化対応を行う
# Pydantic-i18nとは
[Pydantic-i18n](https://github.com/boardpack/pydantic-i18n)とはPydantic専用のi18nライブラリである
これを使用すればPydanticだけでは変更できないバリデーションメッセージもあらゆる言語に変換することができる
# 実装
基本的にはGitHubのREADMEに沿って実装を行えば良いが、記載されていないところもあるので実例を出して説明する
こんな感じでサクッと！


appオブジェクトが存在するmain.py
READMEに沿ってコピペ実装可能

```main.py
import os
import translation

from fastapi import FastAPI, Depends
from fastapi.exceptions import RequestValidationError

from routers import router

app = FastAPI(dependencies=[Depends(translation.get_locale)])
app.add_exception_handler(
    RequestValidationError, translation.validation_exception_handler
)


app.include_router(router.router)
```


こちらも基本的にはREADME通りで問題ないが、必ず`DEFAULT_LOCALE="ja_JP"`にするように！
```translation.py
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

from pydantic_messages import translations


__all__ = ["get_locale", "validation_exception_handler"]

DEFAULT_LOCALE = "ja_JP"

tr = PydanticI18n(translations)


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)},
    )
```

ここでは、Pydanticのデフォルトの英文のリデーションメッセージと新たに変換させたい文章をJSON形式で記述する
`PydanticI18n.get_pydantic_messages()`を実行することによってPydanticの全てのバリデーションメッセージを取得することができる
### pydantic_messages.pyにおける注意点
1. en_USのJSONのkeyとja_JPのkeyは必ず同じ値でなければならない（Pydantic-18nはそれぞれのkeyを照らしあわせて、valueを返しているため）
1. en_USのvalueは任意
1. 変数を必要とする場合（4文字以上、5文字以下など）、`{}`で対応することが可能（この記法はREADMEにも記載がなく、調査に苦労した）
```pydantic_messages.py
translations = {
    "en_US": {
        "field required": "",
        "value is not a valid integer": "",
        "ensure this value has at least {} characters": "",
        "ensure this value has at most {} characters": "",
        "ensure this value is less than or equal to {}": "",
        "ensure this value is less than {}": "",
        "ensure this value is greater than or equal to {}": "",
    },
    "ja_JP": {
        "field required": "必須入力です。",
        "value is not a valid integer": "半角数字で入力してください。",
        "ensure this value has at least {} characters": "{}文字以上で入力してください。",
        "ensure this value has at most {} characters": "{}文字以下で入力してください。",
        "ensure this value is less than {}": "{}未満で入力してください。",
        "ensure this value is less than or equal to {}": "{}以下で入力してください。",
        "ensure this value is greater than or equal to {}": "{}以上で入力してください。",
    },
}
```
# 挙動確認
### では、OpenAPI（Swagger）で挙動を確認してみよう！


パスワード（pin_number）が4文字以下を期待しているのに、5文字以上だった場合

<img width="442" alt="スクリーンショット 2023-01-06 17.03.50.png (86.5 kB)" src="https://img.esa.io/uploads/production/attachments/14274/2023/01/06/126296/74232eb8-fb2a-4967-bf1c-55aea68ade99.png">


ちゃんと動いてますね！！

# 所感
READMEをみれば実装できると思いますが、このライブラリは情報量が限りなく少なく、初心者さんには大変だと思い、書かせていただきました。
どんなシステムもユーザフレンドリーでいきましょう！！
# 参考
- [Pydantic-18n](https://github.com/boardpack/pydantic-i18n)
- https://github.com/boardpack/pydantic-i18n/issues/13
- https://github.com/tiangolo/fastapi/issues/1153