{"id":14979069,"url":"https://github.com/boardpack/pydantic-i18n","last_synced_at":"2025-04-12T22:34:31.762Z","repository":{"id":38982456,"uuid":"392117825","full_name":"boardpack/pydantic-i18n","owner":"boardpack","description":"pydantic-i18n is an extension to support an i18n for the pydantic error messages.","archived":false,"fork":false,"pushed_at":"2024-11-25T23:07:04.000Z","size":359,"stargazers_count":83,"open_issues_count":7,"forks_count":11,"subscribers_count":0,"default_branch":"master","last_synced_at":"2024-11-26T09:13:12.436Z","etag":null,"topics":["fastapi","i18n","internationalization","pydantic","python","translation"],"latest_commit_sha":null,"homepage":"https://pydantic-i18n.boardpack.org","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/boardpack.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-08-02T22:58:53.000Z","updated_at":"2024-11-04T16:59:42.000Z","dependencies_parsed_at":"2024-04-16T05:27:45.144Z","dependency_job_id":"39409833-b3ad-42cd-9cd1-734c7ebf6e57","html_url":"https://github.com/boardpack/pydantic-i18n","commit_stats":{"total_commits":323,"total_committers":5,"mean_commits":64.6,"dds":0.5325077399380804,"last_synced_commit":"65426e6aca94ea2fa7f812b38f9bf6957b92dfa4"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boardpack%2Fpydantic-i18n","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boardpack%2Fpydantic-i18n/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boardpack%2Fpydantic-i18n/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/boardpack%2Fpydantic-i18n/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/boardpack","download_url":"https://codeload.github.com/boardpack/pydantic-i18n/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248641918,"owners_count":21138299,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fastapi","i18n","internationalization","pydantic","python","translation"],"created_at":"2024-09-24T13:59:10.766Z","updated_at":"2025-04-12T22:34:31.730Z","avatar_url":"https://github.com/boardpack.png","language":"Python","funding_links":[],"categories":["Utilities"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://pydantic-i18n.boardpack.org/\"\u003e\u003cimg src=\"https://pydantic-i18n.boardpack.org/img/logo-white.png\" alt=\"pydantic-i18n\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    \u003cem\u003epydantic-i18n is an extension to support an i18n for the pydantic error messages.\u003c/em\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://github.com/boardpack/pydantic-i18n/actions?query=workflow%3ATest\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://github.com/boardpack/pydantic-i18n/workflows/Test/badge.svg\" alt=\"Test\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://codecov.io/gh/boardpack/pydantic-i18n\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://img.shields.io/codecov/c/github/boardpack/pydantic-i18n?color=%2334D058\" alt=\"Coverage\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://pypi.org/project/pydantic-i18n\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://img.shields.io/pypi/v/pydantic-i18n?color=%2334D058\u0026label=pypi%20package\" alt=\"Package version\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/psf/black\"\u003e\u003cimg alt=\"Code style: black\" src=\"https://camo.githubusercontent.com/d91ed7ac7abbd5a6102cbe988dd8e9ac21bde0a73d97be7603b891ad08ce3479/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f64652532307374796c652d626c61636b2d3030303030302e737667\" data-canonical-src=\"https://img.shields.io/badge/code%20style-black-000000.svg\" style=\"max-width:100%;\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://pycqa.github.io/isort/\" rel=\"nofollow\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/fe4a658dd745f746410f961ae45d44355db1cc0e4c09c7877d265c1380248943/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f253230696d706f7274732d69736f72742d2532333136373462313f7374796c653d666c6174266c6162656c436f6c6f723d656638333336\" alt=\"Imports: isort\" data-canonical-src=\"https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat\u0026amp;labelColor=ef8336\" style=\"max-width:100%;\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n**Documentation**: \u003ca href=\"https://pydantic-i18n.boardpack.org\" target=\"_blank\"\u003ehttps://pydantic-i18n.boardpack.org\u003c/a\u003e\n\n**Source Code**: \u003ca href=\"https://github.com/boardpack/pydantic-i18n\" target=\"_blank\"\u003ehttps://github.com/boardpack/pydantic-i18n\u003c/a\u003e\n\n---\n\n## Requirements\n\nPython 3.8+\n\npydantic-i18n has the next dependencies:\n\n* \u003ca href=\"https://pydantic-docs.helpmanual.io/\" class=\"external-link\" target=\"_blank\"\u003ePydantic\u003c/a\u003e\n* \u003ca href=\"http://babel.pocoo.org/en/latest/index.html\" class=\"external-link\" target=\"_blank\"\u003eBabel\u003c/a\u003e\n\n\n## Installation\n\n\u003cdiv class=\"termy\"\u003e\n\n```console\n$ pip install pydantic-i18n\n\n---\u003e 100%\n```\n\n\u003c/div\u003e\n\n## First steps\n\nTo start to work with pydantic-i18n, you can just create a dictionary (or\ncreate any needed translations storage and then convert it into dictionary)\nand pass to the main `PydanticI18n` class.\n\nTo translate messages, you need to pass result of `exception.errors()` call to\nthe `translate` method:\n\n```Python  hl_lines=\"14 24\"\nfrom pydantic import BaseModel, ValidationError\nfrom pydantic_i18n import PydanticI18n\n\n\ntranslations = {\n    \"en_US\": {\n        \"Field required\": \"field required\",\n    },\n    \"de_DE\": {\n        \"Field required\": \"Feld erforderlich\",\n    },\n}\n\ntr = PydanticI18n(translations)\n\n\nclass User(BaseModel):\n    name: str\n\n\ntry:\n    User()\nexcept ValidationError as e:\n    translated_errors = tr.translate(e.errors(), locale=\"de_DE\")\n\nprint(translated_errors)\n# [\n#     {\n#         'type': 'missing',\n#         'loc': ('name',),\n#         'msg': 'Feld erforderlich',\n#         'input': {\n#\n#         },\n#         'url': 'https://errors.pydantic.dev/2.6/v/missing'\n#     }\n# ]\n```\n_(This script is complete, it should run \"as is\" for Pydantic 2+, an example for Pydantic 1 is\n[here](https://github.com/boardpack/pydantic-i18n/blob/master/docs_src/pydantic_v1/dict-loader/tutorial001.py))_\n\nIn the next chapters, you will see current available loaders and how to\nimplement your own loader.\n\n## Usage with FastAPI\n\nHere is a simple example usage with FastAPI.\n\n### Create it\n\nLet's create a `tr.py` file:\n\n```Python linenums=\"1\" hl_lines=\"13-22 25-26 32 35\"\nfrom fastapi import Request\nfrom fastapi.exceptions import RequestValidationError\nfrom starlette.responses import JSONResponse\nfrom starlette.status import HTTP_422_UNPROCESSABLE_ENTITY\n\nfrom pydantic_i18n import PydanticI18n\n\n__all__ = [\"get_locale\", \"validation_exception_handler\"]\n\n\nDEFAULT_LOCALE = \"en_US\"\n\ntranslations = {\n    \"en_US\": {\n        \"Field required\": \"field required\",\n    },\n    \"de_DE\": {\n        \"Field required\": \"Feld erforderlich\",\n    },\n}\n\ntr = PydanticI18n(translations)\n\n\ndef get_locale(locale: str = DEFAULT_LOCALE) -\u003e str:\n    return locale\n\n\nasync def validation_exception_handler(\n    request: Request, exc: RequestValidationError\n) -\u003e JSONResponse:\n    current_locale = request.query_params.get(\"locale\", DEFAULT_LOCALE)\n    return JSONResponse(\n        status_code=HTTP_422_UNPROCESSABLE_ENTITY,\n        content={\"detail\": tr.translate(exc.errors(), current_locale)},\n    )\n```\n\n`11-20`: As you see, we selected the simplest variant to store translations,\nyou can use any that you need.\n\n`23-24`: To not include `locale` query parameter into every handler, we\ncreated a simple function `get_locale`, which we will include as a global\ndependency with `Depends`.\n\n`29-36`: An example of overridden function to return translated messages of the\nvalidation exception.\n\nNow we are ready to create a FastAPI application:\n\n```Python linenums=\"1\" hl_lines=\"8 10\"\nfrom fastapi import Depends, FastAPI, Request\nfrom fastapi.exceptions import RequestValidationError\n\nfrom pydantic import BaseModel\n\nimport tr\n\napp = FastAPI(dependencies=[Depends(tr.get_locale)])\n\napp.add_exception_handler(RequestValidationError, tr.validation_exception_handler)\n\n\nclass User(BaseModel):\n    name: str\n\n\n@app.post(\"/user\", response_model=User)\ndef create_user(request: Request, user: User):\n    pass\n```\n\n`8`: Add `get_locale` function as a global dependency.\n\n!!! note\n    If you need to use i18n only for specific part of your\n    application, you can add this `get_locale` function to the specific\n    `APIRouter`. More information about `APIRouter` you can find\n    [here](https://fastapi.tiangolo.com/tutorial/bigger-applications/#apirouter).\n\n`10`: Override default request validation error handler with\n`validation_exception_handler`.\n\n### Run it\n\nRun the server with:\n\n\u003cdiv class=\"termy\"\u003e\n\n```console\n$ uvicorn main:app --reload\n\nINFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)\nINFO:     Started reloader process [28720]\nINFO:     Started server process [28722]\nINFO:     Waiting for application startup.\nINFO:     Application startup complete.\n```\n\n\u003c/div\u003e\n\n\u003cdetails markdown=\"1\"\u003e\n\u003csummary\u003eAbout the command \u003ccode\u003euvicorn main:app --reload\u003c/code\u003e...\u003c/summary\u003e\n\nThe command `uvicorn main:app` refers to:\n\n* `main`: the file `main.py` (the Python \"module\").\n* `app`: the object created inside of `main.py` with the line `app = FastAPI()`.\n* `--reload`: make the server restart after code changes. Only do this for development.\n\n\u003c/details\u003e\n\n### Send it\n\nOpen your browser at \u003ca href=\"http://127.0.0.1:8000/docs#/default/create_user_user_post\" class=\"external-link\" target=\"_blank\"\u003ehttp://127.0.0.1:8000/docs#/default/create_user_user_post\u003c/a\u003e.\n\nSend POST-request with empty body and `de_DE` locale query param via swagger UI\n or `curl`:\n\n```bash\n$ curl -X 'POST' \\\n  'http://127.0.0.1:8000/user?locale=de_DE' \\\n  -H 'accept: application/json' \\\n  -H 'Content-Type: application/json' \\\n  -d '{\n}'\n```\n\n### Check it\n\nAs a result, you will get the next response body:\n\n```json hl_lines=\"8\"\n{\n  \"detail\": [\n    {\n      \"loc\": [\n        \"body\",\n        \"name\"\n      ],\n      \"msg\": \"Feld erforderlich\",\n      \"type\": \"value_error.missing\"\n    }\n  ]\n}\n```\n\nIf you don't mention the `locale` param, English locale will be used by\ndefault.\n\n## Use placeholder in error strings\n\nYou can use placeholders in error strings, but you **must mark** every placeholder with `{}`.\n\n```Python\nfrom decimal import Decimal\n\nfrom pydantic import BaseModel, ValidationError, Field\nfrom pydantic_i18n import PydanticI18n\n\n\ntranslations = {\n    \"en_US\": {\n        \"Decimal input should have no more than {} in total\":\n            \"Decimal input should have no more than {} in total\",\n    },\n    \"es_AR\": {\n        \"Decimal input should have no more than {} in total\":\n            \"La entrada decimal no debe tener más de {} en total\",\n    },\n}\n\ntr = PydanticI18n(translations)\n\n\nclass CoolSchema(BaseModel):\n    my_field: Decimal = Field(max_digits=3)\n\n\ntry:\n    CoolSchema(my_field=1111)\nexcept ValidationError as e:\n    translated_errors = tr.translate(e.errors(), locale=\"es_AR\")\n\nprint(translated_errors)\n# [\n#     {\n#         'type': 'decimal_max_digits',\n#         'loc': ('my_field',),\n#         'msg': 'La entrada decimal no debe tener más de 3 digits en total',\n#         'input': 1111,\n#         'ctx': {\n#             'max_digits': 3\n#         },\n#         'url': 'https://errors.pydantic.dev/2.6/v/decimal_max_digits'\n#     }\n# ]\n```\n_(This script is complete, it should run \"as is\" for Pydantic 2+, an example for Pydantic 1 is\n[here](https://github.com/boardpack/pydantic-i18n/blob/master/docs_src/pydantic_v1/placeholder/tutorial001.py))_\n\n## Get current error strings from Pydantic\n\npydantic-i18n doesn't provide prepared translations of all current error\nmessages from pydantic, but you can use a special class method\n`PydanticI18n.get_pydantic_messages` to load original messages in English. By\ndefault, it returns a `dict` object:\n\n```Python\nfrom pydantic_i18n import PydanticI18n\n\nprint(PydanticI18n.get_pydantic_messages())\n# {\n#     \"Object has no attribute '{}'\": \"Object has no attribute '{}'\",\n#     \"Invalid JSON: {}\": \"Invalid JSON: {}\",\n#     \"JSON input should be string, bytes or bytearray\": \"JSON input should be string, bytes or bytearray\",\n#     \"Recursion error - cyclic reference detected\": \"Recursion error - cyclic reference detected\",\n#     \"Field required\": \"Field required\",\n#     \"Field is frozen\": \"Field is frozen\",\n#     .....\n# }\n```\n_(This script is complete, it should run \"as is\" for Pydantic 2+, an example for Pydantic 1 is\n[here](https://github.com/boardpack/pydantic-i18n/blob/master/docs_src/pydantic_v1/pydantic-messages/tutorial001.py))_\n\nYou can also choose JSON string or Babel format with `output` parameter values\n`\"json\"` and `\"babel\"`:\n\n```Python\nfrom pydantic_i18n import PydanticI18n\n\nprint(PydanticI18n.get_pydantic_messages(output=\"json\"))\n# {\n#     \"Field required\": \"Field required\",\n#     \"Field is frozen\": \"Field is frozen\",\n#     \"Error extracting attribute: {}\": \"Error extracting attribute: {}\",\n#     .....\n# }\n\nprint(PydanticI18n.get_pydantic_messages(output=\"babel\"))\n# msgid \"Field required\"\n# msgstr \"Field required\"\n#\n# msgid \"Field is frozen\"\n# msgstr \"Field is frozen\"\n#\n# msgid \"Error extracting attribute: {}\"\n# msgstr \"Error extracting attribute: {}\"\n# ....\n\n```\n_(This script is complete, it should run \"as is\" for Pydantic 2+, an example for Pydantic 1 is\n[here](https://github.com/boardpack/pydantic-i18n/blob/master/docs_src/pydantic_v1/pydantic-messages/tutorial002.py))_\n\n\n## Loaders\n\npydantic-i18n provides a list of loaders to use translations.\n\n### DictLoader\n\nDictLoader is the simplest loader and default in PydanticI18n. So you can\njust pass your translations dictionary without any other preparation steps.\n\n```Python\nfrom pydantic import BaseModel, ValidationError\nfrom pydantic_i18n import PydanticI18n\n\n\ntranslations = {\n    \"en_US\": {\n        \"Field required\": \"field required\",\n    },\n    \"de_DE\": {\n        \"Field required\": \"Feld erforderlich\",\n    },\n}\n\ntr = PydanticI18n(translations)\n\n\nclass User(BaseModel):\n    name: str\n\n\ntry:\n    User()\nexcept ValidationError as e:\n    translated_errors = tr.translate(e.errors(), locale=\"de_DE\")\n\nprint(translated_errors)\n# [\n#     {\n#         'type': 'missing',\n#         'loc': ('name',),\n#         'msg': 'Feld erforderlich',\n#         'input': {\n#\n#         },\n#         'url': 'https://errors.pydantic.dev/2.6/v/missing'\n#     }\n# ]\n```\n_(This script is complete, it should run \"as is\" for Pydantic 2+, an example for Pydantic 1 is\n[here](https://github.com/boardpack/pydantic-i18n/blob/master/docs_src/pydantic_v1/dict-loader/tutorial001.py))_\n\n### JsonLoader\n\nJsonLoader needs to get the path to some directory with the next structure:\n\n```text\n\n|-- translations\n    |-- en_US.json\n    |-- de_DE.json\n    |-- ...\n```\n\nwhere e.g. `en_US.json` looks like:\n\n```json\n{\n    \"Field required\": \"Field required\"\n}\n```\n\nand `de_DE.json`:\n\n```json\n{\n    \"Field required\": \"Feld erforderlich\"\n}\n```\n\nThen we can use `JsonLoader` to load our translations:\n\n```Python\nfrom pydantic import BaseModel, ValidationError\nfrom pydantic_i18n import PydanticI18n, JsonLoader\n\nloader = JsonLoader(\"./translations\")\ntr = PydanticI18n(loader)\n\n\nclass User(BaseModel):\n    name: str\n\n\ntry:\n    User()\nexcept ValidationError as e:\n    translated_errors = tr.translate(e.errors(), locale=\"de_DE\")\n\nprint(translated_errors)\n# [\n#     {\n#         'type': 'missing',\n#         'loc': ('name',\n#                 ),\n#         'msg': 'Feld erforderlich',\n#         'input': {\n#\n#         },\n#         'url': 'https://errors.pydantic.dev/2.6/v/missing'\n#     }\n# ]\n\n```\n_(This script is complete, it should run \"as is\" for Pydantic 2+, an example for Pydantic 1 is\n[here](https://github.com/boardpack/pydantic-i18n/blob/master/docs_src/pydantic_v1/json-loader/tutorial001.py))_\n\n### BabelLoader\n\nBabelLoader works in the similar way as JsonLoader. It also needs a\ntranslations directory with the next structure:\n\n```text\n\n|-- translations\n    |-- en_US\n        |-- LC_MESSAGES\n            |-- messages.mo\n            |-- messages.po\n    |-- de_DE\n        |-- LC_MESSAGES\n            |-- messages.mo\n            |-- messages.po\n    |-- ...\n```\n\nInformation about translations preparation you can find on the\n[Babel docs pages](http://babel.pocoo.org/en/latest/cmdline.html){:target=\"_blank\"} and e.g.\nfrom [this article](https://phrase.com/blog/posts/i18n-advantages-babel-python/#Message_Extraction){:target=\"_blank\"}.\n\nHere is an example of the `BabelLoader` usage:\n\n```Python\nfrom pydantic import BaseModel, ValidationError\nfrom pydantic_i18n import PydanticI18n, BabelLoader\n\nloader = BabelLoader(\"./translations\")\ntr = PydanticI18n(loader)\n\n\nclass User(BaseModel):\n    name: str\n\n\ntry:\n    User()\nexcept ValidationError as e:\n    translated_errors = tr.translate(e.errors(), locale=\"de_DE\")\n\nprint(translated_errors)\n# [\n#     {\n#         'type': 'missing',\n#         'loc': ('name',),\n#         'msg': 'Feld erforderlich',\n#         'input': {\n#\n#         },\n#         'url': 'https://errors.pydantic.dev/2.6/v/missing'\n#     }\n# ]\n\n```\n_(This script is complete, it should run \"as is\" for Pydantic 2+, an example for Pydantic 1 is\n[here](https://github.com/boardpack/pydantic-i18n/blob/master/docs_src/pydantic_v1/babel-loader/tutorial001.py))_\n\n### Write your own loader\n\nIf current loaders aren't suitable for you, it's possible to write your own\nloader and use it with pydantic-i18n. To do it, you need to import\n`BaseLoader` and implement the next items:\n\n - property `locales` to get a list of locales;\n - method `get_translations` to get content for the specific locale.\n\nIn some cases you will also need to change implementation of the `gettext`\nmethod.\n\nHere is an example of the loader to get translations from CSV files:\n\n```text\n|-- translations\n    |-- en_US.csv\n    |-- de_DE.csv\n    |-- ...\n```\n\n`en_US.csv` content:\n\n```csv\nField required,Field required\n```\n\n`de_DE.csv` content:\n\n```csv\nField required,Feld erforderlich\n```\n\n```Python\nimport os\nfrom typing import List, Dict\n\nfrom pydantic import BaseModel, ValidationError\nfrom pydantic_i18n import PydanticI18n, BaseLoader\n\n\nclass CsvLoader(BaseLoader):\n    def __init__(self, directory: str):\n        self.directory = directory\n\n    @property\n    def locales(self) -\u003e List[str]:\n        return [\n            filename[:-4]\n            for filename in os.listdir(self.directory)\n            if filename.endswith(\".csv\")\n        ]\n\n    def get_translations(self, locale: str) -\u003e Dict[str, str]:\n        with open(os.path.join(self.directory, f\"{locale}.csv\")) as fp:\n            data = dict(line.strip().split(\",\") for line in fp)\n\n        return data\n\n\nclass User(BaseModel):\n    name: str\n\n\nif __name__ == '__main__':\n    loader = CsvLoader(\"./translations\")\n    tr = PydanticI18n(loader)\n\n    try:\n        User()\n    except ValidationError as e:\n        translated_errors = tr.translate(e.errors(), locale=\"de_DE\")\n\n    print(translated_errors)\n    # [\n    #     {\n    #         'type': 'missing',\n    #         'loc': ('name',),\n    #         'msg': 'Feld erforderlich',\n    #         'input': {\n    #\n    #         },\n    #         'url': 'https://errors.pydantic.dev/2.6/v/missing'\n    #     }\n    # ]\n\n```\n_(This script is complete, it should run \"as is\" for Pydantic 2+, an example for Pydantic 1 is\n[here](https://github.com/boardpack/pydantic-i18n/blob/master/docs_src/pydantic_v1/own-loader/tutorial001.py))_\n\n## Acknowledgments\n\nThanks to [Samuel Colvin](https://github.com/samuelcolvin) and his\n[pydantic](https://github.com/samuelcolvin/pydantic) library.\n\nAlso, thanks to [Sebastián Ramírez](https://github.com/tiangolo) and his\n[FastAPI](https://github.com/tiangolo/fastapi) project,  some scripts and\ndocumentation structure and parts were used from there.\n\n## License\n\nThis project is licensed under the terms of the MIT license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboardpack%2Fpydantic-i18n","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fboardpack%2Fpydantic-i18n","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fboardpack%2Fpydantic-i18n/lists"}