From ac3999ea92682203986c7e2fcea1a9642ab14942 Mon Sep 17 00:00:00 2001 From: Zareian Date: Wed, 23 Sep 2026 01:45:37 +0330 Subject: [PATCH] render the Persian API docs right-to-left Swagger UI and Redoc lay every description out left-to-right, because they were built for English. Our text is Persian, and in an LTR block the sentence-final full stop jumps to the start of the line, table columns come out reversed, and every English word inside a Persian sentence lands in the wrong place. The screenshot of /api/docs/ showed all three. This is not fixable by rewriting the text, because the base direction of the block is what is wrong. Both views now render through a thin template of ours that extends the drf-spectacular one via {{ block.super }} and adds scoped CSS: right-to-left for the blocks that carry rendered Markdown, and an explicit left-to-right override for code and pre, so that "Authorization: Bearer " and every JSON sample stay readable. Table cells align right, list bullets move to the right margin, and the API title keeps its LTR treatment since it is English. Writing the description in English instead would have fixed only the header. The per-endpoint descriptions are Persian across the whole codebase and were broken the same way, so the shell fixes the entire page rather than one block of it, and keeps the repo's convention of Persian documentation. The upstream templates are untouched, so a drf-spectacular upgrade cannot be broken by this. Two tests cover it, because this failure is invisible to every other kind of check: nothing errors, nothing 500s, the page simply reads wrong to a human. Co-Authored-By: Claude Opus 5 --- README.md | 2 +- config/settings.py | 4 +- config/tests.py | 24 ++++++++++ config/urls.py | 9 +++- templates/tadrisino/redoc.html | 36 +++++++++++++++ templates/tadrisino/swagger_ui.html | 69 +++++++++++++++++++++++++++++ 6 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 templates/tadrisino/redoc.html create mode 100644 templates/tadrisino/swagger_ui.html diff --git a/README.md b/README.md index fcdfcd2..a0ed6b6 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ | **آدرسِ زنده** | `https://api.math.tadrisino2.ir` · [سلامت](https://api.math.tadrisino2.ir/api/health) | | **استک** | Python 3.11+ · Django 5.2 · DRF · SQLite · Qdrant (RAG) | | **API** | ۵۶ اندپوینت · مستنداتِ زنده در `/api/docs/` | -| **تست** | ۴۸۱ تست، همه سبز (`python manage.py test`) | +| **تست** | ۴۸۳ تست، همه سبز (`python manage.py test`) | | **محتوا** | ۸ پایه · ۵۸ فصل · ۲۶۳ نود · ۲٬۶۱۷ درس · ۲٬۴۶۳ سوال | --- diff --git a/config/settings.py b/config/settings.py index a9648fb..7526e61 100644 --- a/config/settings.py +++ b/config/settings.py @@ -237,7 +237,9 @@ ROOT_URLCONF = 'config.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], + # قالب‌های سطحِ پروژه (که به هیچ اپی تعلق ندارند) — فعلاً فقط + # پوسته‌ی راست‌به‌چپِ صفحه‌های مستنداتِ API. + 'DIRS': [BASE_DIR / 'templates'], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ diff --git a/config/tests.py b/config/tests.py index 083a296..4e73c87 100644 --- a/config/tests.py +++ b/config/tests.py @@ -450,3 +450,27 @@ class CorsDevPortTests(TestCase): # و پذیرشِ هر پورتِ localhost را واقعاً خطرناک می‌کرد. from django.conf import settings self.assertFalse(settings.CORS_ALLOW_CREDENTIALS) + + +class ApiDocsRtlShellTests(TestCase): + """ + صفحه‌های مستنداتِ API باید پوسته‌ی راست‌به‌چپِ خودمان را داشته باشند. + + بدونِ آن، Swagger متنِ فارسی را در یک بلوکِ چپ‌به‌راست می‌چیند و نتیجه‌اش + پریدنِ نقطه‌ی جمله به ابتدای خط و برعکس شدنِ ستون‌های جدول است. این تست + هست چون خرابی‌اش فقط با چشم دیده می‌شود: هیچ خطایی نمی‌دهد و هیچ تستِ + دیگری نمی‌گیردش. + """ + + def test_swagger_ui_carries_the_rtl_shell(self): + html = self.client.get('/api/docs/').content.decode() + self.assertIn('direction: rtl', html) + # کد باید صریحاً چپ‌به‌راست بماند، وگرنه «Authorization: Bearer ...» + # در بلوکِ RTL جابه‌جا می‌شود. + self.assertIn('direction: ltr', html) + # قالبِ اصلیِ drf-spectacular باید دست‌نخورده زیرش باشد. + self.assertIn('swagger-ui-bundle', html) + + def test_redoc_carries_the_rtl_shell(self): + html = self.client.get('/api/redoc/').content.decode() + self.assertIn('direction: rtl', html) diff --git a/config/urls.py b/config/urls.py index 5d78161..569e0b3 100644 --- a/config/urls.py +++ b/config/urls.py @@ -68,8 +68,13 @@ urlpatterns = [ # OpenAPI schema + Swagger UI + Redoc path('api/schema/', SpectacularAPIView.as_view(), name='schema'), - path('api/docs/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'), - path('api/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'), + # قالبِ خودمان فقط یک پوسته‌ی راست‌به‌چپ روی قالبِ drf-spectacular است؛ + # بدونش متنِ فارسی در یک بلوکِ LTR رندر می‌شود و نقطه‌ی جمله و ترتیبِ + # ستون‌های جدول جابه‌جا می‌شوند. توضیح در خودِ قالب. + path('api/docs/', SpectacularSwaggerView.as_view( + url_name='schema', template_name='tadrisino/swagger_ui.html'), name='swagger-ui'), + path('api/redoc/', SpectacularRedocView.as_view( + url_name='schema', template_name='tadrisino/redoc.html'), name='redoc'), # همه زیرِ /api/ جمع می‌شوند؛ هر اپ مسیرهای خودش را نگه می‌دارد، پس # ترتیبِ این فهرست اهمیتی ندارد و تداخلی بینشان نیست. diff --git a/templates/tadrisino/redoc.html b/templates/tadrisino/redoc.html new file mode 100644 index 0000000..39198ee --- /dev/null +++ b/templates/tadrisino/redoc.html @@ -0,0 +1,36 @@ +{% extends "drf_spectacular/redoc.html" %} + +{# همان مشکلِ راست‌به‌چپِ swagger_ui.html، این بار در Redoc. توضیحِ کامل آنجاست. #} + +{% block head %} +{{ block.super }} + +{% endblock head %} diff --git a/templates/tadrisino/swagger_ui.html b/templates/tadrisino/swagger_ui.html new file mode 100644 index 0000000..a392afb --- /dev/null +++ b/templates/tadrisino/swagger_ui.html @@ -0,0 +1,69 @@ +{% extends "drf_spectacular/swagger_ui.html" %} + +{# Swagger UI هر متنی را چپ‌به‌راست می‌چیند، چون برای انگلیسی نوشته شده. متنِ + ما فارسی است، و در یک بلوکِ LTR نتیجه‌اش این می‌شود که نقطه‌ی پایانِ جمله + به ابتدای خط می‌پرد، ترتیبِ ستون‌های جدول برعکس می‌شود، و هر کلمه‌ی + انگلیسیِ وسطِ جمله جای خودش را گم می‌کند. + + راهِ حل، تغییرِ *متن* نیست — جهتِ خودِ بلوک باید راست‌به‌چپ شود. اینجا فقط + بخش‌هایی که Markdown فارسی رندر می‌کنند RTL می‌شوند؛ ساختارِ خودِ Swagger + (مسیرها، متدها، نامِ فیلدها) دست‌نخورده می‌ماند چون همه انگلیسی‌اند. + + قالبِ اصلی دست نمی‌خورد: این فایل با {{ block.super }} رویش سوار می‌شود، + پس به‌روزرسانیِ drf-spectacular چیزی را خراب نمی‌کند. #} + +{% block head %} +{{ block.super }} + +{% endblock head %}