diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 4a1305ba..c7116d06 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -2,30 +2,24 @@ name: deploy on: push: branches: - - 'dev' + - "dev" jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Build and Publish - uses: VaultVulp/gp-docker-action@1.1.8 + uses: VaultVulp/gp-docker-action@1.6.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} image-name: fastapi-admin - examples: + deploy: runs-on: ubuntu-latest needs: - build steps: - - name: Deploy - uses: appleboy/ssh-action@master + - name: Deploy fastapi-admin + uses: steebchen/kubectl@v2.0.0 with: - host: ${{ secrets.HOST }} - username: ${{ secrets.USERNAME }} - key: ${{ secrets.KEY }} - port: ${{ secrets.PORT }} - script: | - cd /root/fastapi-admin/ - docker-compose pull - docker-compose up -d + config: ${{ secrets.KUBE_CONFIG }} + command: rollout restart deployment fastapi-admin diff --git a/.gitignore b/.gitignore index 8730e8ac..ff50ff8f 100644 --- a/.gitignore +++ b/.gitignore @@ -54,7 +54,6 @@ coverage.xml .pytest_cache/ # Translations -*.mo *.pot # Django stuff: diff --git a/CHANGELOG.md b/CHANGELOG.md index 47d8090c..6fe4b8fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,16 @@ ## 1.0 +### 1.0.5 + +- Fix translations build. +- Improve datetime and date input + ### 1.0.4 - Add `widgets.filters.Boolean` class - Fix multiple json field input. (#98) +- Fix `jinja2.ext.autoescape` error. ### 1.0.3 diff --git a/Dockerfile b/Dockerfile index d8116c38..e930563b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,15 @@ -FROM jfloff/alpine-python +FROM python:3.9 as builder ENV CRYPTOGRAPHY_DONT_BUILD_RUST=1 RUN mkdir -p /fastapi-admin WORKDIR /fastapi-admin COPY pyproject.toml poetry.lock /fastapi-admin/ -RUN pip install --upgrade pip -RUN pip3 install poetry ENV POETRY_VIRTUALENVS_CREATE false -RUN poetry install --no-root +RUN pip install --upgrade pip && pip3 install poetry && poetry install --no-root COPY . /fastapi-admin -RUN poetry install -RUN make compile +RUN poetry install && make compile + +FROM python:3.9-slim +WORKDIR /fastapi-admin +COPY --from=builder /usr/local/lib/python3.9/site-packages /usr/local/lib/python3.9/site-packages +COPY --from=builder /usr/local/bin/ /usr/local/bin/ +COPY --from=builder /fastapi-admin /fastapi-admin diff --git a/README-es.md b/README-es.md new file mode 100644 index 00000000..4ae40a3f --- /dev/null +++ b/README-es.md @@ -0,0 +1,60 @@ +# FastAPI Admin + +[![image](https://img.shields.io/pypi/v/fastapi-admin.svg?style=flat)](https://pypi.python.org/pypi/fastapi-admin) +[![image](https://img.shields.io/github/license/fastapi-admin/fastapi-admin)](https://github.com/fastapi-admin/fastapi-admin) +[![image](https://github.com/fastapi-admin/fastapi-admin/workflows/deploy/badge.svg)](https://github.com/fastapi-admin/fastapi-admin/actions?query=workflow:deploy) +[![image](https://github.com/fastapi-admin/fastapi-admin/workflows/pypi/badge.svg)](https://github.com/fastapi-admin/fastapi-admin/actions?query=workflow:pypi) + +[中文文档](./README-zh.md) +[한국어 문서](./README-ko.md) + +## Introducción + +`fastapi-admin` es un panel de administrador basado en [FastAPI](https://github.com/tiangolo/fastapi) y [TortoiseORM](https://github.com/tortoise/tortoise-orm/) con [tabler](https://github.com/tabler/tabler) ui, inspirado en Djando Admin. + +## Instalación + +```shell +> pip install fastapi-admin +``` + +## Requisitos + +- [Redis](https://redis.io) + +## Demo Online + +Puedes checar una demo online [aquí](https://fastapi-admin.long2ice.io/admin/login). + +- Usuario: `admin` +- Contraseña: `123456` + +O una demo online versión pro [aquí](https://fastapi-admin-pro.long2ice.io/admin/login). + +- Usuario: `admin` +- Contraseña: `123456` + +## Capturas + +![](https://raw.githubusercontent.com/fastapi-admin/fastapi-admin/dev/images/login.png) + +![](https://raw.githubusercontent.com/fastapi-admin/fastapi-admin/dev/images/dashboard.png) + +## Ejecutar el ejemplo localmente + +1. Clona el repositorio. +2. Crea un archivo `.env`. + ```dotenv + DATABASE_URL=mysql://root:123456@127.0.0.1:3306/fastapi_admin + REDIS_URL=redis://localhost:6379/0 + ``` +3. Ejecuta el comando `docker-compose up -d --build`. +4. Visita para crear el primer administrador. + +## Documentación + +Mira la documentación en . + +## Licencia + +Este proyecto está licenciado bajo la [licencia Apache-2.0](https://github.com/fastapi-admin/fastapi-admin/blob/master/LICENSE). diff --git a/README-ja.md b/README-ja.md new file mode 100644 index 00000000..257422f2 --- /dev/null +++ b/README-ja.md @@ -0,0 +1,63 @@ +# FastAPI Admin + +[![image](https://img.shields.io/pypi/v/fastapi-admin.svg?style=flat)](https://pypi.python.org/pypi/fastapi-admin) +[![image](https://img.shields.io/github/license/fastapi-admin/fastapi-admin)](https://github.com/fastapi-admin/fastapi-admin) +[![image](https://github.com/fastapi-admin/fastapi-admin/workflows/deploy/badge.svg)](https://github.com/fastapi-admin/fastapi-admin/actions?query=workflow:deploy) +[![image](https://github.com/fastapi-admin/fastapi-admin/workflows/pypi/badge.svg)](https://github.com/fastapi-admin/fastapi-admin/actions?query=workflow:pypi) + +[中文文档](./README-zh.md) +[한국어 문서](./README-ko.md) +[日本語ドキュメント](./README-ja.md) + +## はじめに + +`fastapi-admin`は、[tabler](https://github.com/tabler/tabler)UIを使用して開発された[FastAPI](https://github.com/tiangolo/fastapi)と[TortoiseORM](https://github.com/tortoise/tortoise-orm/)の高速な管理ダッシュボードで、Django adminを参考にしています。 + +## インストール + +```shell +> pip install fastapi-admin +``` + +## 環境 + +- [Redis](https://redis.io) + +## オンラインデモ + +[ここ](https://fastapi-admin.long2ice.io/admin/login)でオンラインデモを確認できます。 + +- username: `admin` +- password: `123456` + +もしくは、[ここ](https://fastapi-admin-pro.long2ice.io/admin/login)でプロ版のオンラインデモを確認できます。 + +- username: `admin` +- password: `123456` + +## スクリーンショット + +![](https://raw.githubusercontent.com/fastapi-admin/fastapi-admin/dev/images/login.png) + +![](https://raw.githubusercontent.com/fastapi-admin/fastapi-admin/dev/images/dashboard.png) + +## ローカル環境での実行方法 + +1. レポジトリをクローンする。 +2. .envファイルを作成し、以下の内容を記述する。 + + ```dotenv + DATABASE_URL=mysql://root:123456@127.0.0.1:3306/fastapi-admin + REDIS_URL=redis://localhost:6379/0 + ``` + +3. `docker-compose up -d --build`を実行する。 +4. にアクセスして、管理者用アカウントを作成する。 + +## ドキュメント + +ドキュメントは[こちら](https://fastapi-admin-docs.long2ice.io)で確認できます。 + +## ライセンス + +このプロジェクトは、[Apache-2.0](https://github.com/fastapi-admin/fastapi-admin/blob/master/LICENSE)ライセンスに準拠しています。 diff --git a/README-ko.md b/README-ko.md new file mode 100644 index 00000000..a5d28f11 --- /dev/null +++ b/README-ko.md @@ -0,0 +1,63 @@ +# FastAPI Admin + +[![image](https://img.shields.io/pypi/v/fastapi-admin.svg?style=flat)](https://pypi.python.org/pypi/fastapi-admin) +[![image](https://img.shields.io/github/license/fastapi-admin/fastapi-admin)](https://github.com/fastapi-admin/fastapi-admin) +[![image](https://github.com/fastapi-admin/fastapi-admin/workflows/deploy/badge.svg)](https://github.com/fastapi-admin/fastapi-admin/actions?query=workflow:deploy) +[![image](https://github.com/fastapi-admin/fastapi-admin/workflows/pypi/badge.svg)](https://github.com/fastapi-admin/fastapi-admin/actions?query=workflow:pypi) + +[中文文档](./README-zh.md) +[한국어 문서](./README-ko.md) +[日本語ドキュメント](./README-ja.md) + +## 개요 + +`fastapi-admin`은 Django admin에 영감을 받아 만든 [FastAPI](https://github.com/tiangolo/fastapi)와 [TortoiseORM](https://github.com/tortoise/tortoise-orm/) 그리고 [tabler](https://github.com/tabler/tabler) UI를 바탕으로 한 빠른 관리자 대시보드입니다. + +## 설치 + +```shell +> pip install fastapi-admin +``` + +## 요구 사항 + +- [Redis](https://redis.io) + +## 온라인 예시 + +[이곳](https://fastapi-admin.long2ice.io/admin/login)에서 온라인 예시를 볼 수 있습니다. + +- username(유저이름): `admin` +- password(비밀번호): `123456` + +또는 [이곳](https://fastapi-admin-pro.long2ice.io/admin/login)에서 프로 버전 예시를 볼 수 있습니다. + +- username(유저이름): `admin` +- password(비밀번호): `123456` + +## 스크린샷 + +![](https://raw.githubusercontent.com/fastapi-admin/fastapi-admin/dev/images/login.png) + +![](https://raw.githubusercontent.com/fastapi-admin/fastapi-admin/dev/images/dashboard.png) + +## 로컬 환경에서 예시 돌려보기 + +1. 레포지토리를 클론합니다. +2. `.env`파일을 만듭니다. + + ```dotenv + DATABASE_URL=mysql://root:123456@127.0.0.1:3306/fastapi-admin + REDIS_URL=redis://localhost:6379/0 + ``` + +3. `docker-compose up -d --build`를 실행합니다. +4. 에 방문해 첫번째 관리자를 만듭니다. + +## 문서 + +여기 문서를 확인하세요. + +## 라이센스 + +이 프로젝트는 [Apache-2.0](https://github.com/fastapi-admin/fastapi-admin/blob/master/LICENSE)라이센스를 바탕으로 합니다. diff --git a/README-zh.md b/README-zh.md index caf87639..2d3cb822 100644 --- a/README-zh.md +++ b/README-zh.md @@ -5,6 +5,10 @@ [![image](https://github.com/fastapi-admin/fastapi-admin/workflows/gh-pages/badge.svg)](https://github.com/fastapi-admin/fastapi-admin/actions?query=workflow:gh-pages) [![image](https://github.com/fastapi-admin/fastapi-admin/workflows/pypi/badge.svg)](https://github.com/fastapi-admin/fastapi-admin/actions?query=workflow:pypi) +[中文文档](./README-zh.md) +[한국어 문서](./README-ko.md) +[日本語ドキュメント](./README-ja.md) + ## 简介 `fastapi-admin` 是一个基于 [FastAPI](https://github.com/tiangolo/fastapi) @@ -49,3 +53,9 @@ ## 许可 本项目遵循 [Apache-2.0](https://github.com/fastapi-admin/fastapi-admin/blob/master/LICENSE) 开源许可。 + +## 感谢 + +[![image](./images/yxvm.png)](https://yxvm.com/) + +[NodeSupport](https://github.com/NodeSeekDev/NodeSupport) 赞助了本项目 diff --git a/README.md b/README.md index 5ec7fba1..21d0b847 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ [![image](https://github.com/fastapi-admin/fastapi-admin/workflows/pypi/badge.svg)](https://github.com/fastapi-admin/fastapi-admin/actions?query=workflow:pypi) [中文文档](./README-zh.md) +[한국어 문서](./README-ko.md) +[日本語ドキュメント](./README-ja.md) ## Introduction @@ -63,3 +65,9 @@ See documentation at . This project is licensed under the [Apache-2.0](https://github.com/fastapi-admin/fastapi-admin/blob/master/LICENSE) License. + +## Credits + +[![image](./images/yxvm.png)](https://yxvm.com/) + +[NodeSupport](https://github.com/NodeSeekDev/NodeSupport) supports this project. diff --git a/babel.cfg b/babel.cfg index 806b6cb5..92d71b03 100644 --- a/babel.cfg +++ b/babel.cfg @@ -1,3 +1,3 @@ [python: fastapi_admin/**.py] [jinja2: fastapi_admin/templates/**.html] -extensions = jinja2.ext.i18n,jinja2.ext.autoescape +extensions = jinja2.ext.i18n diff --git a/examples/main.py b/examples/main.py index 4bc65d2a..eff816ea 100644 --- a/examples/main.py +++ b/examples/main.py @@ -1,6 +1,7 @@ import os +from contextlib import asynccontextmanager -import aioredis +import redis.asyncio as redis import uvicorn from fastapi import FastAPI from starlette.middleware.cors import CORSMiddleware @@ -27,8 +28,30 @@ ) +@asynccontextmanager +async def lifespan(app: FastAPI): + r = redis.from_url( + settings.REDIS_URL, + decode_responses=True, + encoding="utf8", + ) + await admin_app.configure( + logo_url="https://preview.tabler.io/static/logo-white.svg", + template_folders=[os.path.join(BASE_DIR, "templates")], + favicon_url="https://raw.githubusercontent.com/fastapi-admin/fastapi-admin/dev/images/favicon.png", + providers=[ + LoginProvider( + login_logo_url="https://preview.tabler.io/static/logo.svg", + admin_model=Admin, + ) + ], + redis=r, + ) + yield + + def create_app(): - app = FastAPI() + app = FastAPI(lifespan=lifespan) app.mount( "/static", StaticFiles(directory=os.path.join(BASE_DIR, "static")), @@ -44,26 +67,6 @@ async def index(): admin_app.add_exception_handler(HTTP_403_FORBIDDEN, forbidden_error_exception) admin_app.add_exception_handler(HTTP_401_UNAUTHORIZED, unauthorized_error_exception) - @app.on_event("startup") - async def startup(): - redis = aioredis.from_url( - settings.REDIS_URL, - decode_responses=True, - encoding="utf8", - ) - await admin_app.configure( - logo_url="https://preview.tabler.io/static/logo-white.svg", - template_folders=[os.path.join(BASE_DIR, "templates")], - favicon_url="https://raw.githubusercontent.com/fastapi-admin/fastapi-admin/dev/images/favicon.png", - providers=[ - LoginProvider( - login_logo_url="https://preview.tabler.io/static/logo.svg", - admin_model=Admin, - ) - ], - redis=redis, - ) - app.mount("/admin", admin_app) app.add_middleware( CORSMiddleware, @@ -92,4 +95,4 @@ async def startup(): app_ = create_app() if __name__ == "__main__": - uvicorn.run("main:app_", debug=True, reload=True) + uvicorn.run("main:app_", reload=True) diff --git a/examples/resources.py b/examples/resources.py index 9ac17062..f6b2e10f 100644 --- a/examples/resources.py +++ b/examples/resources.py @@ -152,7 +152,7 @@ class GithubLink(Link): @app.register class DocumentationLink(Link): label = "Documentation" - url = "https://fastapi-admin.github.io" + url = "https://fastapi-admin-docs.long2ice.io" icon = "fas fa-file-code" target = "_blank" diff --git a/examples/templates/base.html b/examples/templates/base.html index e90150cc..c2a8ed94 100644 --- a/examples/templates/base.html +++ b/examples/templates/base.html @@ -1,42 +1,44 @@ + - - - - - - + + + + + {% if request.app.favicon_url %} - + {% endif %} - + - {% block head %} - - + + - gtag('js', new Date()); - gtag('config', 'G-T7MFB9RV5E'); - {% endblock %} {{ title }} {% block outer_body %} - + + {% block body %} {% endblock %} - + {% endblock %} + diff --git a/fastapi_admin/__init__.py b/fastapi_admin/__init__.py index c02d8461..9d33622b 100644 --- a/fastapi_admin/__init__.py +++ b/fastapi_admin/__init__.py @@ -1 +1 @@ -VERSION = "1.0.4" +VERSION = "1.0.5" diff --git a/fastapi_admin/app.py b/fastapi_admin/app.py index 48920429..6f3655dd 100644 --- a/fastapi_admin/app.py +++ b/fastapi_admin/app.py @@ -1,6 +1,6 @@ from typing import Dict, List, Optional, Type -from aioredis import Redis +import redis.asyncio as redis from fastapi import FastAPI from pydantic import HttpUrl from starlette.middleware.base import BaseHTTPMiddleware @@ -22,13 +22,13 @@ class FastAPIAdmin(FastAPI): admin_path: str resources: List[Type[Resource]] = [] model_resources: Dict[Type[Model], Type[Resource]] = {} - redis: Redis + redis: redis.Redis language_switch: bool = True favicon_url: Optional[HttpUrl] = None async def configure( self, - redis: Redis, + redis: redis.Redis, logo_url: str = None, default_locale: str = "en_US", language_switch: bool = True, diff --git a/fastapi_admin/file_upload.py b/fastapi_admin/file_upload.py index 8d56bac2..f35435d9 100644 --- a/fastapi_admin/file_upload.py +++ b/fastapi_admin/file_upload.py @@ -12,7 +12,7 @@ def __init__( self, uploads_dir: str, allow_extensions: Optional[List[str]] = None, - max_size: int = 1024 ** 3, + max_size: int = 1024**3, filename_generator: Optional[Callable] = None, prefix: str = "/static/uploads", ): diff --git a/fastapi_admin/i18n.py b/fastapi_admin/i18n.py index 5b490b26..b8c0e5ac 100644 --- a/fastapi_admin/i18n.py +++ b/fastapi_admin/i18n.py @@ -8,7 +8,10 @@ TRANSLATIONS = { "zh_CN": Translations.load(os.path.join(BASE_DIR, "locales"), locales=["zh_CN"]), "en_US": Translations.load(os.path.join(BASE_DIR, "locales"), locales=["en_US"]), + "es_PY": Translations.load(os.path.join(BASE_DIR, "locales"), locales=["es_PY"]), "fr_FR": Translations.load(os.path.join(BASE_DIR, "locales"), locales=["fr_FR"]), + "fa_IR": Translations.load(os.path.join(BASE_DIR, "locales"), locales=["fa_IR"]), + "tr_TR": Translations.load(os.path.join(BASE_DIR, "locales"), locales=["tr_TR"]), } translations = TRANSLATIONS.get("en_US") diff --git a/fastapi_admin/locales/en_US/LC_MESSAGES/messages.mo b/fastapi_admin/locales/en_US/LC_MESSAGES/messages.mo new file mode 100644 index 00000000..6299020e Binary files /dev/null and b/fastapi_admin/locales/en_US/LC_MESSAGES/messages.mo differ diff --git a/fastapi_admin/locales/en_US/LC_MESSAGES/messages.po b/fastapi_admin/locales/en_US/LC_MESSAGES/messages.po index c62de86a..74409398 100644 --- a/fastapi_admin/locales/en_US/LC_MESSAGES/messages.po +++ b/fastapi_admin/locales/en_US/LC_MESSAGES/messages.po @@ -7,16 +7,16 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2021-08-06 23:07+0800\n" +"POT-Creation-Date: 2024-08-28 10:24+0100\n" "PO-Revision-Date: 2021-04-16 22:46+0800\n" "Last-Translator: FULL NAME \n" "Language: en_US\n" "Language-Team: en_US \n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.14.0\n" #: fastapi_admin/resources.py:91 msgid "create" @@ -115,27 +115,32 @@ msgstr "Search" msgid "bulk_actions" msgstr "Bulk Actions" -#: fastapi_admin/templates/list.html:125 +#: fastapi_admin/templates/list.html:139 msgid "actions" msgstr "Actions" -#: fastapi_admin/templates/list.html:156 +#: fastapi_admin/templates/list.html:170 #, python-format msgid "Showing %(from)s to %(to)s of %(total)s entries" msgstr "" -#: fastapi_admin/templates/list.html:167 +#: fastapi_admin/templates/list.html:181 msgid "prev_page" msgstr "Prev" -#: fastapi_admin/templates/list.html:188 +#: fastapi_admin/templates/list.html:202 msgid "next_page" msgstr "Next" +#: fastapi_admin/templates/list.html:214 +msgid "delete_confirmation" +msgstr "Are you sure want to delete this item?" + #: fastapi_admin/templates/update.html:23 msgid "save_and_return" msgstr "Save and return" +#: fastapi_admin/templates/errors/401.html:21 #: fastapi_admin/templates/errors/403.html:21 #: fastapi_admin/templates/errors/404.html:21 #: fastapi_admin/templates/errors/500.html:21 diff --git a/fastapi_admin/locales/es_PY/LC_MESSAGES/messages.mo b/fastapi_admin/locales/es_PY/LC_MESSAGES/messages.mo new file mode 100644 index 00000000..a909f510 Binary files /dev/null and b/fastapi_admin/locales/es_PY/LC_MESSAGES/messages.mo differ diff --git a/fastapi_admin/locales/es_PY/LC_MESSAGES/messages.po b/fastapi_admin/locales/es_PY/LC_MESSAGES/messages.po new file mode 100644 index 00000000..a13b6663 --- /dev/null +++ b/fastapi_admin/locales/es_PY/LC_MESSAGES/messages.po @@ -0,0 +1,242 @@ +# Spanish (Paraguay) translations for PROJECT. +# Copyright (C) 2024 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2024. +# +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2024-08-28 10:24+0100\n" +"PO-Revision-Date: 2024-02-21 12:22-0300\n" +"Last-Translator: FULL NAME \n" +"Language: es_PY\n" +"Language-Team: es_PY \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.14.0\n" + +#: fastapi_admin/resources.py:91 +msgid "create" +msgstr "Agregar nuevo" + +#: fastapi_admin/resources.py:112 +msgid "update" +msgstr "Editar" + +#: fastapi_admin/resources.py:114 +msgid "delete" +msgstr "Borrar" + +#: fastapi_admin/resources.py:120 +msgid "delete_selected" +msgstr "Eliminar seleccionados" + +#: fastapi_admin/providers/login.py:90 +msgid "login_failed" +msgstr "Fallo en el inicio de sesión" + +#: fastapi_admin/providers/login.py:161 +msgid "confirm_password_different" +msgstr "Las contraseñas no coinciden" + +#: fastapi_admin/providers/login.py:196 +msgid "old_password_error" +msgstr "Error en la contraseña antigua" + +#: fastapi_admin/providers/login.py:198 +msgid "new_password_different" +msgstr "La nueva contraseña no coincide" + +#: fastapi_admin/templates/create.html:14 +#: fastapi_admin/templates/update.html:16 +msgid "save" +msgstr "Guardar" + +#: fastapi_admin/templates/create.html:16 +msgid "save_and_add_another" +msgstr "Guardar y agregar otro" + +#: fastapi_admin/templates/create.html:18 +#: fastapi_admin/templates/update.html:29 +msgid "return" +msgstr "Volver" + +#: fastapi_admin/templates/init.html:10 +msgid "Create first admin" +msgstr "Crear primer administrador" + +#: fastapi_admin/templates/init.html:12 +#: fastapi_admin/templates/providers/login/login.html:44 +msgid "username" +msgstr "Nombre de usuario" + +#: fastapi_admin/templates/init.html:14 +msgid "username_placeholder" +msgstr "Ingrese el nombre de usuario" + +#: fastapi_admin/templates/init.html:18 +#: fastapi_admin/templates/providers/login/login.html:54 +msgid "password" +msgstr "Contraseña" + +#: fastapi_admin/templates/init.html:23 +msgid "password_placeholder" +msgstr "Ingrese la contraseña" + +#: fastapi_admin/templates/init.html:31 +msgid "confirm_password" +msgstr "Confirmar contraseña" + +#: fastapi_admin/templates/init.html:36 +msgid "confirm_password_placeholder" +msgstr "Ingrese la contraseña nuevamente" + +#: fastapi_admin/templates/init.html:43 +#: fastapi_admin/templates/providers/login/password.html:32 +msgid "submit" +msgstr "Enviar" + +#: fastapi_admin/templates/list.html:13 +msgid "show" +msgstr "Mostrar" + +#: fastapi_admin/templates/list.html:24 +msgid "entries" +msgstr "entradas" + +#: fastapi_admin/templates/list.html:33 +msgid "search" +msgstr "Buscar" + +#: fastapi_admin/templates/list.html:46 +msgid "bulk_actions" +msgstr "Acciones masivas" + +#: fastapi_admin/templates/list.html:139 +msgid "actions" +msgstr "Acciones" + +#: fastapi_admin/templates/list.html:170 +#, python-format +msgid "Showing %(from)s to %(to)s of %(total)s entries" +msgstr "Mostrando %(from)s a %(to)s de %(total)s entradas" + +#: fastapi_admin/templates/list.html:181 +msgid "prev_page" +msgstr "Pág. Anterior" + +#: fastapi_admin/templates/list.html:202 +msgid "next_page" +msgstr "Pág. Siguiente" + +#: fastapi_admin/templates/list.html:214 +msgid "delete_confirmation" +msgstr "¿Estás seguro de que quieres eliminar este artículo?" + +#: fastapi_admin/templates/update.html:23 +msgid "save_and_return" +msgstr "Guardar y volver" + +#: fastapi_admin/templates/errors/401.html:21 +#: fastapi_admin/templates/errors/403.html:21 +#: fastapi_admin/templates/errors/404.html:21 +#: fastapi_admin/templates/errors/500.html:21 +msgid "return_home" +msgstr "Volver a inicio" + +#: fastapi_admin/templates/providers/login/avatar.html:18 +#: fastapi_admin/templates/providers/login/password.html:6 +msgid "update_password" +msgstr "Actualizar contraseña" + +#: fastapi_admin/templates/providers/login/avatar.html:24 +msgid "logout" +msgstr "Cerrar sesión" + +#: fastapi_admin/templates/providers/login/login.html:49 +#, fuzzy +msgid "login_username_placeholder" +msgstr "Ingrese el nombre de usuario" + +#: fastapi_admin/templates/providers/login/login.html:59 +#, fuzzy +msgid "login_password_placeholder" +msgstr "Ingrese la contraseña antigua" + +#: fastapi_admin/templates/providers/login/login.html:75 +msgid "remember_me" +msgstr "Recordarme" + +#: fastapi_admin/templates/providers/login/login.html:80 +msgid "sign_in" +msgstr "Iniciar sesión" + +#: fastapi_admin/templates/providers/login/password.html:12 +msgid "old_password" +msgstr "Contraseña antigua" + +#: fastapi_admin/templates/providers/login/password.html:15 +msgid "old_password_placeholder" +msgstr "Ingrese la contraseña antigua" + +#: fastapi_admin/templates/providers/login/password.html:19 +msgid "new_password" +msgstr "Nueva contraseña" + +#: fastapi_admin/templates/providers/login/password.html:22 +msgid "new_password_placeholder" +msgstr "Ingrese la nueva contraseña" + +#: fastapi_admin/templates/providers/login/password.html:26 +msgid "re_new_password" +msgstr "Repetir nueva contraseña" + +#: fastapi_admin/templates/providers/login/password.html:29 +msgid "re_new_password_placeholder" +msgstr "Ingrese la nueva contraseña nuevamente" + +#~ msgid "You can only try after %(seconds)s seconds" +#~ msgstr "Solo puedes intentarlo después de %(seconds)s segundos" + +#~ msgid "Login failed %(times)s times, you can try %(rest_times)s more times" +#~ msgstr "" +#~ "Fallo en el inicio de sesión " +#~ "%(times)s veces, puedes intentarlo " +#~ "%(rest_times)s veces más" + +#~ msgid "Import" +#~ msgstr "Importar" + +#~ msgid "Export" +#~ msgstr "Exportar" + +#~ msgid "Success create %(count)s %(label)s" +#~ msgstr "Éxito al crear %(count)s %(label)s" + +#~ msgid "captcha_error" +#~ msgstr "Error en el captcha" + +#~ msgid "Google recaptcha verify failed" +#~ msgstr "La verificación de Google reCAPTCHA falló" + +#~ msgid "Format" +#~ msgstr "Formato" + +#~ msgid "File to import" +#~ msgstr "Archivo a importar" + +#~ msgid "captcha" +#~ msgstr "Captcha" + +#~ msgid "captcha_placeholder" +#~ msgstr "Ingrese el captcha" + +#~ msgid "Search in site..." +#~ msgstr "Buscar en el sitio..." + +#~ msgid "No results found for search text" +#~ msgstr "No se encontraron resultados para el texto de búsqueda" + diff --git a/fastapi_admin/locales/fa_IR/LC_MESSAGES/messages.mo b/fastapi_admin/locales/fa_IR/LC_MESSAGES/messages.mo new file mode 100644 index 00000000..a585e97b Binary files /dev/null and b/fastapi_admin/locales/fa_IR/LC_MESSAGES/messages.mo differ diff --git a/fastapi_admin/locales/fa_IR/LC_MESSAGES/messages.po b/fastapi_admin/locales/fa_IR/LC_MESSAGES/messages.po new file mode 100644 index 00000000..d5f290f6 --- /dev/null +++ b/fastapi_admin/locales/fa_IR/LC_MESSAGES/messages.po @@ -0,0 +1,198 @@ +# English (United States) translations for PROJECT. +# Copyright (C) 2021 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2021. +# +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2024-08-28 10:24+0100\n" +"PO-Revision-Date: 2021-04-16 22:46+0800\n" +"Last-Translator: FULL NAME \n" +"Language: fa_IR\n" +"Language-Team: fa_IR \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.14.0\n" + +#: fastapi_admin/resources.py:91 +msgid "create" +msgstr "ایجاد" + +#: fastapi_admin/resources.py:112 +msgid "update" +msgstr "به‌روزرسانی" + +#: fastapi_admin/resources.py:114 +msgid "delete" +msgstr "پاک کردن" + +#: fastapi_admin/resources.py:120 +msgid "delete_selected" +msgstr "پاک کردن انتخاب‌شده‌ها" + +#: fastapi_admin/providers/login.py:90 +msgid "login_failed" +msgstr "ورود به حساب کاربری شما انجام نشد" + +#: fastapi_admin/providers/login.py:161 +msgid "confirm_password_different" +msgstr "تایید رمز عبور متفاوت است" + +#: fastapi_admin/providers/login.py:196 +msgid "old_password_error" +msgstr "خطای رمز عبور قدیمی" + +#: fastapi_admin/providers/login.py:198 +msgid "new_password_different" +msgstr "رمز عبور جدید متفاوت است" + +#: fastapi_admin/templates/create.html:14 +#: fastapi_admin/templates/update.html:16 +msgid "save" +msgstr "ذخیره" + +#: fastapi_admin/templates/create.html:16 +msgid "save_and_add_another" +msgstr "ذخیره و ایجاد یکی دیگر" + +#: fastapi_admin/templates/create.html:18 +#: fastapi_admin/templates/update.html:29 +msgid "return" +msgstr "بازگشت" + +#: fastapi_admin/templates/init.html:10 +msgid "Create first admin" +msgstr "ساخت اولین مدیر" + +#: fastapi_admin/templates/init.html:12 +#: fastapi_admin/templates/providers/login/login.html:44 +msgid "username" +msgstr "نام کاربری" + +#: fastapi_admin/templates/init.html:14 +msgid "username_placeholder" +msgstr "نام کاربری را وارد کنید" + +#: fastapi_admin/templates/init.html:18 +#: fastapi_admin/templates/providers/login/login.html:54 +msgid "password" +msgstr "رمز عبور" + +#: fastapi_admin/templates/init.html:23 +msgid "password_placeholder" +msgstr "رمز عبور را وارد کنید" + +#: fastapi_admin/templates/init.html:31 +msgid "confirm_password" +msgstr "رمز عبور را دوباره وارد کنید" + +#: fastapi_admin/templates/init.html:36 +msgid "confirm_password_placeholder" +msgstr "رمز عبور را دوباره وارد کنید" + +#: fastapi_admin/templates/init.html:43 +#: fastapi_admin/templates/providers/login/password.html:32 +msgid "submit" +msgstr "ارسال" + +#: fastapi_admin/templates/list.html:13 +msgid "show" +msgstr "نمایش" + +#: fastapi_admin/templates/list.html:24 +msgid "entries" +msgstr "مورد" + +#: fastapi_admin/templates/list.html:33 +msgid "search" +msgstr "جستجو" + +#: fastapi_admin/templates/list.html:46 +msgid "bulk_actions" +msgstr "اقدامات دسته‌ای" + +#: fastapi_admin/templates/list.html:139 +msgid "actions" +msgstr "اقدامات" + +#: fastapi_admin/templates/list.html:170 +#, python-format +msgid "Showing %(from)s to %(to)s of %(total)s entries" +msgstr "نمایش %(from)s الی %(to)s از %(total)s مورد" + +#: fastapi_admin/templates/list.html:181 +msgid "prev_page" +msgstr "قبلی" + +#: fastapi_admin/templates/list.html:202 +msgid "next_page" +msgstr "بعدی" + +#: fastapi_admin/templates/list.html:214 +msgid "delete_confirmation" +msgstr "هل أنت متأكد أنك تريد حذف هذا العنصر؟" + +#: fastapi_admin/templates/update.html:23 +msgid "save_and_return" +msgstr "ذخیره و بازگشت" + +#: fastapi_admin/templates/errors/401.html:21 +#: fastapi_admin/templates/errors/403.html:21 +#: fastapi_admin/templates/errors/404.html:21 +#: fastapi_admin/templates/errors/500.html:21 +msgid "return_home" +msgstr "بازگشت به خانه" + +#: fastapi_admin/templates/providers/login/avatar.html:18 +#: fastapi_admin/templates/providers/login/password.html:6 +msgid "update_password" +msgstr "به‌روزرسانی رمز عبور" + +#: fastapi_admin/templates/providers/login/avatar.html:24 +msgid "logout" +msgstr "خروج" + +#: fastapi_admin/templates/providers/login/login.html:49 +msgid "login_username_placeholder" +msgstr "نام کاربری را وارد کنید" + +#: fastapi_admin/templates/providers/login/login.html:59 +msgid "login_password_placeholder" +msgstr "رمز عبور را وارد کنید" + +#: fastapi_admin/templates/providers/login/login.html:75 +msgid "remember_me" +msgstr "مرا به خاطر بسپار" + +#: fastapi_admin/templates/providers/login/login.html:80 +msgid "sign_in" +msgstr "ورود" + +#: fastapi_admin/templates/providers/login/password.html:12 +msgid "old_password" +msgstr "رمز عبور قدیمی" + +#: fastapi_admin/templates/providers/login/password.html:15 +msgid "old_password_placeholder" +msgstr "رمز عبور قدیمی را وارد کنید" + +#: fastapi_admin/templates/providers/login/password.html:19 +msgid "new_password" +msgstr "رمز عبور جدید" + +#: fastapi_admin/templates/providers/login/password.html:22 +msgid "new_password_placeholder" +msgstr "رمز عبور جدید را وارد کنید" + +#: fastapi_admin/templates/providers/login/password.html:26 +msgid "re_new_password" +msgstr "رمز عبور جدید را تایید کنید" + +#: fastapi_admin/templates/providers/login/password.html:29 +msgid "re_new_password_placeholder" +msgstr "رمز عبور جدید را دوباره وارد کنید" + diff --git a/fastapi_admin/locales/fr_FR/LC_MESSAGES/messages.mo b/fastapi_admin/locales/fr_FR/LC_MESSAGES/messages.mo new file mode 100644 index 00000000..8623e87a Binary files /dev/null and b/fastapi_admin/locales/fr_FR/LC_MESSAGES/messages.mo differ diff --git a/fastapi_admin/locales/fr_FR/LC_MESSAGES/messages.po b/fastapi_admin/locales/fr_FR/LC_MESSAGES/messages.po index 1bdd8024..5e6e7f79 100644 --- a/fastapi_admin/locales/fr_FR/LC_MESSAGES/messages.po +++ b/fastapi_admin/locales/fr_FR/LC_MESSAGES/messages.po @@ -7,16 +7,16 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2021-08-06 23:07+0800\n" +"POT-Creation-Date: 2024-08-28 10:24+0100\n" "PO-Revision-Date: 2021-04-16 22:46+0800\n" "Last-Translator: FULL NAME \n" "Language: fr_FR\n" "Language-Team: fr_FR \n" -"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.14.0\n" #: fastapi_admin/resources.py:91 msgid "create" @@ -115,27 +115,32 @@ msgstr "Search" msgid "bulk_actions" msgstr "Actions groupées" -#: fastapi_admin/templates/list.html:125 +#: fastapi_admin/templates/list.html:139 msgid "actions" msgstr "Actions" -#: fastapi_admin/templates/list.html:156 +#: fastapi_admin/templates/list.html:170 #, python-format msgid "Showing %(from)s to %(to)s of %(total)s entries" msgstr "Voir %(from)s de %(to)s à %(total)s entrées" -#: fastapi_admin/templates/list.html:167 +#: fastapi_admin/templates/list.html:181 msgid "prev_page" msgstr "Prec" -#: fastapi_admin/templates/list.html:188 +#: fastapi_admin/templates/list.html:202 msgid "next_page" msgstr "Suiv" +#: fastapi_admin/templates/list.html:214 +msgid "delete_confirmation" +msgstr "Etes-vous sûr de vouloir supprimer cet élément ?" + #: fastapi_admin/templates/update.html:23 msgid "save_and_return" msgstr "Enregistrer et retourner" +#: fastapi_admin/templates/errors/401.html:21 #: fastapi_admin/templates/errors/403.html:21 #: fastapi_admin/templates/errors/404.html:21 #: fastapi_admin/templates/errors/500.html:21 diff --git a/fastapi_admin/locales/tr_TR/LC_MESSAGES/messages.po b/fastapi_admin/locales/tr_TR/LC_MESSAGES/messages.po new file mode 100644 index 00000000..9d9588f7 --- /dev/null +++ b/fastapi_admin/locales/tr_TR/LC_MESSAGES/messages.po @@ -0,0 +1,193 @@ +# Turkish translations for FastAPI Admin. +# Copyright (C) 2021 ORGANIZATION +# This file is distributed under the same license as the FastAPI Admin project. +# FIRST AUTHOR , 2021. +# +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2021-08-06 23:07+0800\n" +"PO-Revision-Date: 2024-03-01 02:39+0300\n" +"Last-Translator: Hasan Sezer Taşan \n" +"Language: tr_TR\n" +"Language-Team: tr_TR \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.12.1\n" + +#: fastapi_admin/resources.py:91 +msgid "create" +msgstr "Oluştur" + +#: fastapi_admin/resources.py:112 +msgid "update" +msgstr "Güncelle" + +#: fastapi_admin/resources.py:114 +msgid "delete" +msgstr "Sil" + +#: fastapi_admin/resources.py:120 +msgid "delete_selected" +msgstr "Seçili öğeleri sil" + +#: fastapi_admin/providers/login.py:90 +msgid "login_failed" +msgstr "Giriş başarısız" + +#: fastapi_admin/providers/login.py:161 +msgid "confirm_password_different" +msgstr "Şifreler farklı" + +#: fastapi_admin/providers/login.py:196 +msgid "old_password_error" +msgstr "Eski şifre hatalı" + +#: fastapi_admin/providers/login.py:198 +msgid "new_password_different" +msgstr "Yeni şifre farklı" + +#: fastapi_admin/templates/create.html:14 +#: fastapi_admin/templates/update.html:16 +msgid "save" +msgstr "Kaydet" + +#: fastapi_admin/templates/create.html:16 +msgid "save_and_add_another" +msgstr "Kaydet ve başka bir tane ekle" + +#: fastapi_admin/templates/create.html:18 +#: fastapi_admin/templates/update.html:29 +msgid "return" +msgstr "Geri dön" + +#: fastapi_admin/templates/init.html:10 +msgid "Create first admin" +msgstr "İlk yöneticiyi oluştur" + +#: fastapi_admin/templates/init.html:12 +#: fastapi_admin/templates/providers/login/login.html:44 +msgid "username" +msgstr "Kullanıcı adı" + +#: fastapi_admin/templates/init.html:14 +msgid "username_placeholder" +msgstr "Kullanıcı adını girin" + +#: fastapi_admin/templates/init.html:18 +#: fastapi_admin/templates/providers/login/login.html:54 +msgid "password" +msgstr "Şifre" + +#: fastapi_admin/templates/init.html:23 +msgid "password_placeholder" +msgstr "Şifreyi girin" + +#: fastapi_admin/templates/init.html:31 +msgid "confirm_password" +msgstr "Şifreyi onayla" + +#: fastapi_admin/templates/init.html:36 +msgid "confirm_password_placeholder" +msgstr "Şifreyi tekrar girin" + +#: fastapi_admin/templates/init.html:43 +#: fastapi_admin/templates/providers/login/password.html:32 +msgid "submit" +msgstr "Gönder" + +#: fastapi_admin/templates/list.html:13 +msgid "show" +msgstr "Göster" + +#: fastapi_admin/templates/list.html:24 +msgid "entries" +msgstr "Kayıtlar" + +#: fastapi_admin/templates/list.html:33 +msgid "search" +msgstr "Ara" + +#: fastapi_admin/templates/list.html:46 +msgid "bulk_actions" +msgstr "Toplu işlemler" + +#: fastapi_admin/templates/list.html:125 +msgid "actions" +msgstr "İşlemler" + +#: fastapi_admin/templates/list.html:156 +#, python-format +msgid "Showing %(from)s to %(to)s of %(total)s entries" +msgstr "Toplam %(total)s kayıttan %(from)s ile %(to)s arası kayıt gösteriliyor." + +#: fastapi_admin/templates/list.html:167 +msgid "prev_page" +msgstr "Önceki" + +#: fastapi_admin/templates/list.html:188 +msgid "next_page" +msgstr "Sonraki" + +#: fastapi_admin/templates/update.html:23 +msgid "save_and_return" +msgstr "Kaydet ve geri dön" + +#: fastapi_admin/templates/errors/403.html:21 +#: fastapi_admin/templates/errors/404.html:21 +#: fastapi_admin/templates/errors/500.html:21 +msgid "return_home" +msgstr "Beni anasayfaya götür" + +#: fastapi_admin/templates/providers/login/avatar.html:18 +#: fastapi_admin/templates/providers/login/password.html:6 +msgid "update_password" +msgstr "Şifreyi güncelle" + +#: fastapi_admin/templates/providers/login/avatar.html:24 +msgid "logout" +msgstr "Çıkış yap" + +#: fastapi_admin/templates/providers/login/login.html:49 +msgid "login_username_placeholder" +msgstr "Kullanıcı adını girin" + +#: fastapi_admin/templates/providers/login/login.html:59 +msgid "login_password_placeholder" +msgstr "Şifreyi girin" + +#: fastapi_admin/templates/providers/login/login.html:75 +msgid "remember_me" +msgstr "Beni hatırla" + +#: fastapi_admin/templates/providers/login/login.html:80 +msgid "sign_in" +msgstr "Giriş yap" + +#: fastapi_admin/templates/providers/login/password.html:12 +msgid "old_password" +msgstr "Eski şifre" + +#: fastapi_admin/templates/providers/login/password.html:15 +msgid "old_password_placeholder" +msgstr "Eski şifreyi girin" + +#: fastapi_admin/templates/providers/login/password.html:19 +msgid "new_password" +msgstr "Yeni şifre" + +#: fastapi_admin/templates/providers/login/password.html:22 +msgid "new_password_placeholder" +msgstr "Yeni şifreyi girin" + +#: fastapi_admin/templates/providers/login/password.html:26 +msgid "re_new_password" +msgstr "Yeni şifreyi onaylayın" + +#: fastapi_admin/templates/providers/login/password.html:29 +msgid "re_new_password_placeholder" +msgstr "Yeni şifreyi tekrar girin" + diff --git a/fastapi_admin/locales/zh_CN/LC_MESSAGES/messages.mo b/fastapi_admin/locales/zh_CN/LC_MESSAGES/messages.mo new file mode 100644 index 00000000..64198aff Binary files /dev/null and b/fastapi_admin/locales/zh_CN/LC_MESSAGES/messages.mo differ diff --git a/fastapi_admin/locales/zh_CN/LC_MESSAGES/messages.po b/fastapi_admin/locales/zh_CN/LC_MESSAGES/messages.po index b36eb69a..df3690f6 100644 --- a/fastapi_admin/locales/zh_CN/LC_MESSAGES/messages.po +++ b/fastapi_admin/locales/zh_CN/LC_MESSAGES/messages.po @@ -7,16 +7,16 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2021-08-06 23:07+0800\n" +"POT-Creation-Date: 2024-08-28 10:24+0100\n" "PO-Revision-Date: 2021-04-16 22:46+0800\n" "Last-Translator: FULL NAME \n" "Language: zh_Hans_CN\n" "Language-Team: zh_Hans_CN \n" -"Plural-Forms: nplurals=1; plural=0\n" +"Plural-Forms: nplurals=1; plural=0;\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.9.1\n" +"Generated-By: Babel 2.14.0\n" #: fastapi_admin/resources.py:91 msgid "create" @@ -115,27 +115,32 @@ msgstr "查询" msgid "bulk_actions" msgstr "批量操作" -#: fastapi_admin/templates/list.html:125 +#: fastapi_admin/templates/list.html:139 msgid "actions" msgstr "动作" -#: fastapi_admin/templates/list.html:156 +#: fastapi_admin/templates/list.html:170 #, python-format msgid "Showing %(from)s to %(to)s of %(total)s entries" msgstr "显示 %(from)s 到 %(to)s 共 %(total)s 项" -#: fastapi_admin/templates/list.html:167 +#: fastapi_admin/templates/list.html:181 msgid "prev_page" msgstr "上一页" -#: fastapi_admin/templates/list.html:188 +#: fastapi_admin/templates/list.html:202 msgid "next_page" msgstr "下一页" +#: fastapi_admin/templates/list.html:214 +msgid "delete_confirmation" +msgstr "您确定要删除该项目吗?" + #: fastapi_admin/templates/update.html:23 msgid "save_and_return" msgstr "保存并返回" +#: fastapi_admin/templates/errors/401.html:21 #: fastapi_admin/templates/errors/403.html:21 #: fastapi_admin/templates/errors/404.html:21 #: fastapi_admin/templates/errors/500.html:21 diff --git a/fastapi_admin/providers/login.py b/fastapi_admin/providers/login.py index 098f2ebc..ba6ff6f2 100644 --- a/fastapi_admin/providers/login.py +++ b/fastapi_admin/providers/login.py @@ -2,7 +2,7 @@ import uuid from typing import Type -from aioredis import Redis +import redis.asyncio as redis from fastapi import Depends, Form from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint from starlette.requests import Request @@ -77,7 +77,7 @@ async def pre_save_admin(self, _, instance: AbstractAdmin, using_db, update_fiel else: instance.password = hash_password(instance.password) - async def login(self, request: Request, redis: Redis = Depends(get_redis)): + async def login(self, request: Request, redis: redis.Redis = Depends(get_redis)): form = await request.form() username = form.get("username") password = form.get("password") @@ -119,7 +119,7 @@ async def authenticate( request: Request, call_next: RequestResponseEndpoint, ): - redis = request.app.redis # type:Redis + redis = request.app.redis # type:ignore token = request.cookies.get(self.access_token) path = request.scope["path"] admin = None diff --git a/fastapi_admin/resources.py b/fastapi_admin/resources.py index 6789b3d1..dcfe3496 100644 --- a/fastapi_admin/resources.py +++ b/fastapi_admin/resources.py @@ -129,11 +129,21 @@ async def get_inputs(cls, request: Request, obj: Optional[TortoiseModel] = None) ret = [] for field in cls.get_fields(is_display=False): input_ = field.input + name = input_.context.get("name") if isinstance(input_, inputs.DisplayOnly): continue if isinstance(input_, inputs.File): cls.enctype = "multipart/form-data" - name = input_.context.get("name") + if ( + isinstance(input_, inputs.ForeignKey) + and (obj is not None) + and name in obj._meta.fk_fields + ): + await obj.fetch_related(name) + # Value must be the string representation of the fk obj + value = str(getattr(obj, name, None)) + ret.append(await input_.render(request, value)) + continue ret.append(await input_.render(request, getattr(obj, name, None))) return ret @@ -159,6 +169,10 @@ async def resolve_data(cls, request: Request, data: FormData): if input_.context.get("disabled") or isinstance(input_, inputs.DisplayOnly): continue name = input_.context.get("name") + if isinstance(input_, inputs.ForeignKey): + v = data.getlist(name)[0] + ret[name] = int(v) if v else None + continue if isinstance(input_, inputs.ManyToMany): v = data.getlist(name) value = await input_.parse_value(request, v) @@ -289,6 +303,16 @@ def get_m2m_field(cls): ret.append(field) return ret + @classmethod + def get_fk_field(cls): + ret = [] + for field in cls.fields or cls.model._meta.fields: + if isinstance(field, Field): + field = field.name + if field in cls.model._meta.fk_fields: + ret.append(field) + return ret + class Dropdown(Resource): resources: List[Type[Resource]] diff --git a/fastapi_admin/routes/resources.py b/fastapi_admin/routes/resources.py index a2f9d098..ebdda047 100644 --- a/fastapi_admin/routes/resources.py +++ b/fastapi_admin/routes/resources.py @@ -1,3 +1,5 @@ +from typing import Optional + from fastapi import APIRouter, Depends, Path from jinja2 import TemplateNotFound from starlette.requests import Request @@ -25,22 +27,39 @@ async def list_view( resource: str = Path(...), page_size: int = 10, page_num: int = 1, + order_by: Optional[str] = None, ): fields_label = model_resource.get_fields_label() fields = model_resource.get_fields() + fk_fields = model_resource.get_fk_field() qs = model.all() params, qs = await model_resource.resolve_query_params(request, dict(request.query_params), qs) filters = await model_resource.get_filters(request, params) total = await qs.count() + if order_by: + qs = qs.order_by(order_by) if page_size: qs = qs.limit(page_size) else: page_size = model_resource.page_size qs = qs.offset((page_num - 1) * page_size) - values = await qs.values() - rendered_values, row_attributes, column_attributes, cell_attributes = await render_values( - request, model_resource, fields, values - ) + if fk_fields: + objects = await qs.select_related(*fk_fields) + values = [] + for obj in objects: + obj_as_dict = dict(obj) + for attr in fk_fields: + obj_as_dict[attr] = getattr(obj, attr) + values.append(obj_as_dict) + else: + values = await qs.values() + + ( + rendered_values, + row_attributes, + column_attributes, + cell_attributes, + ) = await render_values(request, model_resource, fields, values) context = { "request": request, "resources": resources, @@ -86,13 +105,14 @@ async def update( ): form = await request.form() data, m2m_data = await model_resource.resolve_data(request, form) + m2m_fields = model_resource.get_m2m_field() async with in_transaction() as conn: obj = ( await model.filter(pk=pk) .using_db(conn) .select_for_update() .get() - .prefetch_related(*model_resource.get_m2m_field()) + .prefetch_related(*m2m_fields) ) await obj.update_from_dict(data).save(using_db=conn) for k, items in m2m_data.items(): @@ -103,8 +123,9 @@ async def update( obj = ( await model.filter(pk=pk) .using_db(conn) + .select_related(*model_resource.get_fk_field()) .get() - .prefetch_related(*model_resource.get_m2m_field()) + .prefetch_related(*m2m_fields) ) inputs = await model_resource.get_inputs(request, obj) if "save" in form.keys(): diff --git a/fastapi_admin/templates/base.html b/fastapi_admin/templates/base.html index 946db4ad..25c8a379 100644 --- a/fastapi_admin/templates/base.html +++ b/fastapi_admin/templates/base.html @@ -3,17 +3,16 @@ - - - - - + + + + {% if request.app.favicon_url %} {% endif %} - + {% block head %} diff --git a/fastapi_admin/templates/components/language.html b/fastapi_admin/templates/components/language.html index b059f656..b276bcff 100644 --- a/fastapi_admin/templates/components/language.html +++ b/fastapi_admin/templates/components/language.html @@ -26,5 +26,17 @@ href="{{ {'language':'fr_FR'}|current_page_with_params }}"> 🇫🇷Français + + 🇮🇷Persian + + + 🇵🇾Español + + + 🇹🇷Türkçe + diff --git a/fastapi_admin/templates/layout.html b/fastapi_admin/templates/layout.html index 3ed58edc..f6c13302 100644 --- a/fastapi_admin/templates/layout.html +++ b/fastapi_admin/templates/layout.html @@ -15,6 +15,12 @@

{% endif %} + +{% endblock %} diff --git a/fastapi_admin/templates/widgets/inputs/datetime.html b/fastapi_admin/templates/widgets/inputs/datetime.html new file mode 100644 index 00000000..76afadac --- /dev/null +++ b/fastapi_admin/templates/widgets/inputs/datetime.html @@ -0,0 +1,27 @@ + + +
+ + + {% if help_text %} + + {{ help_text }} + + {% endif %} +
+ +{% block script %} + +{% endblock %} diff --git a/fastapi_admin/templates/widgets/inputs/select.html b/fastapi_admin/templates/widgets/inputs/select.html index cfac0dc0..fb15e5e0 100644 --- a/fastapi_admin/templates/widgets/inputs/select.html +++ b/fastapi_admin/templates/widgets/inputs/select.html @@ -1,7 +1,7 @@ {% with id = 'form-select-' + name %}
{{ label }}
- {% for option in options %}