From 46efd5dcac7086b5fe1361e5ddc9bebdacdbb1de Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 15 Jul 2024 17:42:43 +0000
Subject: [PATCH 01/33] [pre-commit.ci] pre-commit autoupdate
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
updates:
- [github.com/pre-commit/mirrors-eslint: v9.6.0 → v9.7.0](https://github.com/pre-commit/mirrors-eslint/compare/v9.6.0...v9.7.0)
- [github.com/astral-sh/ruff-pre-commit: v0.5.1 → v0.5.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.5.1...v0.5.2)
---
.pre-commit-config.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 291fc94e9..a12619911 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -32,7 +32,7 @@ repos:
args:
- --trailing-comma=es5
- repo: https://github.com/pre-commit/mirrors-eslint
- rev: v9.6.0
+ rev: v9.7.0
hooks:
- id: eslint
additional_dependencies:
@@ -44,7 +44,7 @@ repos:
args:
- --fix
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: 'v0.5.1'
+ rev: 'v0.5.2'
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
From 25656eeff69937c4271bc38cf599af62189e1144 Mon Sep 17 00:00:00 2001
From: Aman Pandey
Date: Mon, 24 Jun 2024 19:24:26 +0530
Subject: [PATCH 02/33] Support an async middleware for the toolbar.
extract redudant code in _postprocess
disable non async capable panels
add middleware sync and async compatible test case
rename file
add panel async compatibility tests/
added panel async compatibility tests/
marked erreneous panels as non async
refactor panel test
Add function docstrings
update async panel compatibility tests
revert middleware back to __call__ and __acall__ approach
update architecture.rst documentation
fix typo in docs
remove ASGI keyword from docs
---
debug_toolbar/middleware.py | 45 ++++++++++++++++++-
debug_toolbar/panels/__init__.py | 7 +++
debug_toolbar/panels/profiling.py | 1 +
debug_toolbar/panels/redirects.py | 1 +
debug_toolbar/panels/request.py | 2 +
debug_toolbar/panels/sql/panel.py | 2 +
debug_toolbar/panels/staticfiles.py | 1 +
debug_toolbar/panels/timer.py | 2 +
docs/architecture.rst | 10 +++--
.../panels/test_async_panel_compatibility.py | 39 ++++++++++++++++
tests/test_middleware_compatibility.py | 44 ++++++++++++++++++
11 files changed, 150 insertions(+), 4 deletions(-)
create mode 100644 tests/panels/test_async_panel_compatibility.py
create mode 100644 tests/test_middleware_compatibility.py
diff --git a/debug_toolbar/middleware.py b/debug_toolbar/middleware.py
index b089d1484..03044f3a4 100644
--- a/debug_toolbar/middleware.py
+++ b/debug_toolbar/middleware.py
@@ -6,6 +6,7 @@
import socket
from functools import lru_cache
+from asgiref.sync import iscoroutinefunction, markcoroutinefunction
from django.conf import settings
from django.utils.module_loading import import_string
@@ -62,14 +63,50 @@ class DebugToolbarMiddleware:
on outgoing response.
"""
+ sync_capable = True
+ async_capable = True
+
def __init__(self, get_response):
self.get_response = get_response
+ # If get_response is a coroutine function, turns us into async mode so
+ # a thread is not consumed during a whole request.
+ self.async_mode = iscoroutinefunction(self.get_response)
+
+ if self.async_mode:
+ # Mark the class as async-capable, but do the actual switch inside
+ # __call__ to avoid swapping out dunder methods.
+ markcoroutinefunction(self)
def __call__(self, request):
# Decide whether the toolbar is active for this request.
+ if self.async_mode:
+ return self.__acall__(request)
+ # Decide whether the toolbar is active for this request.
show_toolbar = get_show_toolbar()
if not show_toolbar(request) or DebugToolbar.is_toolbar_request(request):
return self.get_response(request)
+ toolbar = DebugToolbar(request, self.get_response)
+ # Activate instrumentation ie. monkey-patch.
+ for panel in toolbar.enabled_panels:
+ panel.enable_instrumentation()
+ try:
+ # Run panels like Django middleware.
+ response = toolbar.process_request(request)
+ finally:
+ clear_stack_trace_caches()
+ # Deactivate instrumentation ie. monkey-unpatch. This must run
+ # regardless of the response. Keep 'return' clauses below.
+ for panel in reversed(toolbar.enabled_panels):
+ panel.disable_instrumentation()
+
+ return self._postprocess(request, response, toolbar)
+
+ async def __acall__(self, request):
+ # Decide whether the toolbar is active for this request.
+ show_toolbar = get_show_toolbar()
+ if not show_toolbar(request) or DebugToolbar.is_toolbar_request(request):
+ response = await self.get_response(request)
+ return response
toolbar = DebugToolbar(request, self.get_response)
@@ -78,7 +115,7 @@ def __call__(self, request):
panel.enable_instrumentation()
try:
# Run panels like Django middleware.
- response = toolbar.process_request(request)
+ response = await toolbar.process_request(request)
finally:
clear_stack_trace_caches()
# Deactivate instrumentation ie. monkey-unpatch. This must run
@@ -86,6 +123,12 @@ def __call__(self, request):
for panel in reversed(toolbar.enabled_panels):
panel.disable_instrumentation()
+ return self._postprocess(request, response, toolbar)
+
+ def _postprocess(self, request, response, toolbar):
+ """
+ Post-process the response.
+ """
# Generate the stats for all requests when the toolbar is being shown,
# but not necessarily inserted.
for panel in reversed(toolbar.enabled_panels):
diff --git a/debug_toolbar/panels/__init__.py b/debug_toolbar/panels/__init__.py
index 57f385a5e..fd3312bc3 100644
--- a/debug_toolbar/panels/__init__.py
+++ b/debug_toolbar/panels/__init__.py
@@ -1,3 +1,4 @@
+from django.core.handlers.asgi import ASGIRequest
from django.template.loader import render_to_string
from debug_toolbar import settings as dt_settings
@@ -9,6 +10,8 @@ class Panel:
Base class for panels.
"""
+ is_async = True
+
def __init__(self, toolbar, get_response):
self.toolbar = toolbar
self.get_response = get_response
@@ -21,6 +24,10 @@ def panel_id(self):
@property
def enabled(self) -> bool:
+ # check if the panel is async compatible
+ if not self.is_async and isinstance(self.toolbar.request, ASGIRequest):
+ return False
+
# The user's cookies should override the default value
cookie_value = self.toolbar.request.COOKIES.get("djdt" + self.panel_id)
if cookie_value is not None:
diff --git a/debug_toolbar/panels/profiling.py b/debug_toolbar/panels/profiling.py
index 64224a2db..ffe9b7e37 100644
--- a/debug_toolbar/panels/profiling.py
+++ b/debug_toolbar/panels/profiling.py
@@ -136,6 +136,7 @@ class ProfilingPanel(Panel):
Panel that displays profiling information.
"""
+ is_async = False
title = _("Profiling")
template = "debug_toolbar/panels/profiling.html"
diff --git a/debug_toolbar/panels/redirects.py b/debug_toolbar/panels/redirects.py
index 195d0cf11..8894d1a18 100644
--- a/debug_toolbar/panels/redirects.py
+++ b/debug_toolbar/panels/redirects.py
@@ -9,6 +9,7 @@ class RedirectsPanel(Panel):
Panel that intercepts redirects and displays a page with debug info.
"""
+ is_async = False
has_content = False
nav_title = _("Intercept redirects")
diff --git a/debug_toolbar/panels/request.py b/debug_toolbar/panels/request.py
index a936eba6b..8df382fb3 100644
--- a/debug_toolbar/panels/request.py
+++ b/debug_toolbar/panels/request.py
@@ -15,6 +15,8 @@ class RequestPanel(Panel):
title = _("Request")
+ is_async = False
+
@property
def nav_subtitle(self):
"""
diff --git a/debug_toolbar/panels/sql/panel.py b/debug_toolbar/panels/sql/panel.py
index 58c1c2738..879be38b0 100644
--- a/debug_toolbar/panels/sql/panel.py
+++ b/debug_toolbar/panels/sql/panel.py
@@ -109,6 +109,8 @@ class SQLPanel(Panel):
the request.
"""
+ is_async = False
+
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._sql_time = 0
diff --git a/debug_toolbar/panels/staticfiles.py b/debug_toolbar/panels/staticfiles.py
index 2eed2efa0..061068a30 100644
--- a/debug_toolbar/panels/staticfiles.py
+++ b/debug_toolbar/panels/staticfiles.py
@@ -73,6 +73,7 @@ class StaticFilesPanel(panels.Panel):
A panel to display the found staticfiles.
"""
+ is_async = False
name = "Static files"
template = "debug_toolbar/panels/staticfiles.html"
diff --git a/debug_toolbar/panels/timer.py b/debug_toolbar/panels/timer.py
index 554798e7d..962702f7e 100644
--- a/debug_toolbar/panels/timer.py
+++ b/debug_toolbar/panels/timer.py
@@ -17,6 +17,8 @@ class TimerPanel(Panel):
Panel that displays the time a response took in milliseconds.
"""
+ is_async = False
+
def nav_subtitle(self):
stats = self.get_stats()
if hasattr(self, "_start_rusage"):
diff --git a/docs/architecture.rst b/docs/architecture.rst
index 7be5ac78d..145676459 100644
--- a/docs/architecture.rst
+++ b/docs/architecture.rst
@@ -79,6 +79,10 @@ Problematic Parts
when the panel module is loaded
- ``debug.panels.sql``: This package is particularly complex, but provides
the main benefit of the toolbar
-- Support for async and multi-threading: This is currently unsupported, but
- is being implemented as per the
- `Async compatible toolbar project `_.
+- Support for async and multi-threading: ``debug_toolbar.middleware.DebugToolbarMiddleware``
+ is now async compatible and can process async requests. However certain
+ panels such as ``SQLPanel``, ``TimerPanel``, ``StaticFilesPanel``,
+ ``RequestPanel``, ``RedirectsPanel`` and ``ProfilingPanel`` aren't fully
+ compatible and currently being worked on. For now, these panels
+ are disabled by default when running in async environment.
+ follow the progress of this issue in `Async compatible toolbar project `_.
diff --git a/tests/panels/test_async_panel_compatibility.py b/tests/panels/test_async_panel_compatibility.py
new file mode 100644
index 000000000..d5a85ffbb
--- /dev/null
+++ b/tests/panels/test_async_panel_compatibility.py
@@ -0,0 +1,39 @@
+from django.http import HttpResponse
+from django.test import AsyncRequestFactory, RequestFactory, TestCase
+
+from debug_toolbar.panels import Panel
+from debug_toolbar.toolbar import DebugToolbar
+
+
+class MockAsyncPanel(Panel):
+ is_async = True
+
+
+class MockSyncPanel(Panel):
+ is_async = False
+
+
+class PanelAsyncCompatibilityTestCase(TestCase):
+ def setUp(self):
+ self.async_factory = AsyncRequestFactory()
+ self.wsgi_factory = RequestFactory()
+
+ def test_panels_with_asgi(self):
+ async_request = self.async_factory.get("/")
+ toolbar = DebugToolbar(async_request, lambda request: HttpResponse())
+
+ async_panel = MockAsyncPanel(toolbar, async_request)
+ sync_panel = MockSyncPanel(toolbar, async_request)
+
+ self.assertTrue(async_panel.enabled)
+ self.assertFalse(sync_panel.enabled)
+
+ def test_panels_with_wsgi(self):
+ wsgi_request = self.wsgi_factory.get("/")
+ toolbar = DebugToolbar(wsgi_request, lambda request: HttpResponse())
+
+ async_panel = MockAsyncPanel(toolbar, wsgi_request)
+ sync_panel = MockSyncPanel(toolbar, wsgi_request)
+
+ self.assertTrue(async_panel.enabled)
+ self.assertTrue(sync_panel.enabled)
diff --git a/tests/test_middleware_compatibility.py b/tests/test_middleware_compatibility.py
new file mode 100644
index 000000000..d3025c1ea
--- /dev/null
+++ b/tests/test_middleware_compatibility.py
@@ -0,0 +1,44 @@
+import asyncio
+
+from django.http import HttpResponse
+from django.test import AsyncRequestFactory, RequestFactory, TestCase
+
+from debug_toolbar.middleware import DebugToolbarMiddleware
+
+
+class MiddlewareSyncAsyncCompatibilityTestCase(TestCase):
+ def setUp(self):
+ self.factory = RequestFactory()
+ self.async_factory = AsyncRequestFactory()
+
+ def test_sync_mode(self):
+ """
+ test middlware switches to sync (__call__) based on get_response type
+ """
+
+ request = self.factory.get("/")
+ middleware = DebugToolbarMiddleware(
+ lambda x: HttpResponse("Django debug toolbar")
+ )
+
+ self.assertFalse(asyncio.iscoroutinefunction(middleware))
+
+ response = middleware(request)
+ self.assertEqual(response.status_code, 200)
+
+ async def test_async_mode(self):
+ """
+ test middlware switches to async (__acall__) based on get_response type
+ and returns a coroutine
+ """
+
+ async def get_response(request):
+ return HttpResponse("Django debug toolbar")
+
+ middleware = DebugToolbarMiddleware(get_response)
+ request = self.async_factory.get("/")
+
+ self.assertTrue(asyncio.iscoroutinefunction(middleware))
+
+ response = await middleware(request)
+ self.assertEqual(response.status_code, 200)
From a9a66a99d0899acaf904bf2a4a2021b78e5f962f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?M=C3=A1rton=20Salomv=C3=A1ry?=
Date: Tue, 16 Jul 2024 15:58:59 +0200
Subject: [PATCH 03/33] Add async tests (#1835)
* Add asynchronous examples (#1819)
* Add tests for async usage (#1819)
* Include daphne is requirements_dev
---
example/README.rst | 10 +++++++
example/asgi.py | 9 +++++++
example/settings.py | 3 ++-
example/templates/async_db.html | 14 ++++++++++
example/urls.py | 11 +++++++-
example/views.py | 27 +++++++++++++++++++
requirements_dev.txt | 4 +++
tests/panels/test_sql.py | 46 +++++++++++++++++++++++++++++++++
tests/test_integration.py | 44 +++++++++++++++++++++++++++++++
tests/urls.py | 2 ++
tests/views.py | 13 ++++++++++
11 files changed, 181 insertions(+), 2 deletions(-)
create mode 100644 example/asgi.py
create mode 100644 example/templates/async_db.html
diff --git a/example/README.rst b/example/README.rst
index 94c09f8e5..1c34e4893 100644
--- a/example/README.rst
+++ b/example/README.rst
@@ -46,3 +46,13 @@ environment variable::
$ DB_BACKEND=postgresql python example/manage.py migrate
$ DB_BACKEND=postgresql python example/manage.py runserver
+
+Using an asynchronous (ASGI) server:
+
+Install [Daphne](https://pypi.org/project/daphne/) first:
+
+ $ python -m pip install daphne
+
+Then run the Django development server:
+
+ $ ASYNC_SERVER=true python example/manage.py runserver
diff --git a/example/asgi.py b/example/asgi.py
new file mode 100644
index 000000000..9d7c78703
--- /dev/null
+++ b/example/asgi.py
@@ -0,0 +1,9 @@
+"""ASGI config for example project."""
+
+import os
+
+from django.core.asgi import get_asgi_application
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "example.settings")
+
+application = get_asgi_application()
diff --git a/example/settings.py b/example/settings.py
index 26b75fa5c..06b70f7fa 100644
--- a/example/settings.py
+++ b/example/settings.py
@@ -18,6 +18,7 @@
# Application definition
INSTALLED_APPS = [
+ *(["daphne"] if os.getenv("ASYNC_SERVER", False) else []), # noqa: FBT003
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
@@ -66,6 +67,7 @@
USE_TZ = True
WSGI_APPLICATION = "example.wsgi.application"
+ASGI_APPLICATION = "example.asgi.application"
# Cache and database
@@ -103,7 +105,6 @@
STATICFILES_DIRS = [os.path.join(BASE_DIR, "example", "static")]
-
# Only enable the toolbar when we're in debug mode and we're
# not running tests. Django will change DEBUG to be False for
# tests, so we can't rely on DEBUG alone.
diff --git a/example/templates/async_db.html b/example/templates/async_db.html
new file mode 100644
index 000000000..771c039e3
--- /dev/null
+++ b/example/templates/async_db.html
@@ -0,0 +1,14 @@
+
+
+
+
+ Async DB
+
+
+ Async DB
+
+ Value
+ {{ user_count }}
+
+
+
diff --git a/example/urls.py b/example/urls.py
index c5e60c309..86e6827fc 100644
--- a/example/urls.py
+++ b/example/urls.py
@@ -3,7 +3,13 @@
from django.views.generic import TemplateView
from debug_toolbar.toolbar import debug_toolbar_urls
-from example.views import increment, jinja2_view
+from example.views import (
+ async_db,
+ async_db_concurrent,
+ async_home,
+ increment,
+ jinja2_view,
+)
urlpatterns = [
path("", TemplateView.as_view(template_name="index.html"), name="home"),
@@ -13,6 +19,9 @@
name="bad_form",
),
path("jinja/", jinja2_view, name="jinja"),
+ path("async/", async_home, name="async_home"),
+ path("async/db/", async_db, name="async_db"),
+ path("async/db-concurrent/", async_db_concurrent, name="async_db_concurrent"),
path("jquery/", TemplateView.as_view(template_name="jquery/index.html")),
path("mootools/", TemplateView.as_view(template_name="mootools/index.html")),
path("prototype/", TemplateView.as_view(template_name="prototype/index.html")),
diff --git a/example/views.py b/example/views.py
index e7e4c1253..3e1cb04a6 100644
--- a/example/views.py
+++ b/example/views.py
@@ -1,3 +1,7 @@
+import asyncio
+
+from asgiref.sync import sync_to_async
+from django.contrib.auth.models import User
from django.http import JsonResponse
from django.shortcuts import render
@@ -13,3 +17,26 @@ def increment(request):
def jinja2_view(request):
return render(request, "index.jinja", {"foo": "bar"}, using="jinja2")
+
+
+async def async_home(request):
+ return await sync_to_async(render)(request, "index.html")
+
+
+async def async_db(request):
+ user_count = await User.objects.acount()
+
+ return await sync_to_async(render)(
+ request, "async_db.html", {"user_count": user_count}
+ )
+
+
+async def async_db_concurrent(request):
+ # Do database queries concurrently
+ (user_count, _) = await asyncio.gather(
+ User.objects.acount(), User.objects.filter(username="test").acount()
+ )
+
+ return await sync_to_async(render)(
+ request, "async_db.html", {"user_count": user_count}
+ )
diff --git a/requirements_dev.txt b/requirements_dev.txt
index 8b24a8fbb..03e436622 100644
--- a/requirements_dev.txt
+++ b/requirements_dev.txt
@@ -12,6 +12,10 @@ selenium
tox
black
+# Integration support
+
+daphne # async in Example app
+
# Documentation
Sphinx
diff --git a/tests/panels/test_sql.py b/tests/panels/test_sql.py
index 48c9e3845..332e9b1e8 100644
--- a/tests/panels/test_sql.py
+++ b/tests/panels/test_sql.py
@@ -32,6 +32,20 @@ def sql_call(*, use_iterator=False):
return list(qs)
+async def async_sql_call(*, use_iterator=False):
+ qs = User.objects.all()
+ if use_iterator:
+ qs = qs.iterator()
+ return await sync_to_async(list)(qs)
+
+
+async def concurrent_async_sql_call(*, use_iterator=False):
+ qs = User.objects.all()
+ if use_iterator:
+ qs = qs.iterator()
+ return await asyncio.gather(sync_to_async(list)(qs), User.objects.acount())
+
+
class SQLPanelTestCase(BaseTestCase):
panel_id = "SQLPanel"
@@ -57,6 +71,38 @@ def test_recording(self):
# ensure the stacktrace is populated
self.assertTrue(len(query["stacktrace"]) > 0)
+ async def test_recording_async(self):
+ self.assertEqual(len(self.panel._queries), 0)
+
+ await async_sql_call()
+
+ # ensure query was logged
+ self.assertEqual(len(self.panel._queries), 1)
+ query = self.panel._queries[0]
+ self.assertEqual(query["alias"], "default")
+ self.assertTrue("sql" in query)
+ self.assertTrue("duration" in query)
+ self.assertTrue("stacktrace" in query)
+
+ # ensure the stacktrace is populated
+ self.assertTrue(len(query["stacktrace"]) > 0)
+
+ async def test_recording_concurrent_async(self):
+ self.assertEqual(len(self.panel._queries), 0)
+
+ await concurrent_async_sql_call()
+
+ # ensure query was logged
+ self.assertEqual(len(self.panel._queries), 2)
+ query = self.panel._queries[0]
+ self.assertEqual(query["alias"], "default")
+ self.assertTrue("sql" in query)
+ self.assertTrue("duration" in query)
+ self.assertTrue("stacktrace" in query)
+
+ # ensure the stacktrace is populated
+ self.assertTrue(len(query["stacktrace"]) > 0)
+
@unittest.skipUnless(
connection.vendor == "postgresql", "Test valid only on PostgreSQL"
)
diff --git a/tests/test_integration.py b/tests/test_integration.py
index 95207c21b..e6863e7a9 100644
--- a/tests/test_integration.py
+++ b/tests/test_integration.py
@@ -250,6 +250,24 @@ def test_data_gone(self):
)
self.assertIn("Please reload the page and retry.", response.json()["content"])
+ def test_sql_page(self):
+ response = self.client.get("/execute_sql/")
+ self.assertEqual(
+ len(response.toolbar.get_panel_by_id("SQLPanel").get_stats()["queries"]), 1
+ )
+
+ def test_async_sql_page(self):
+ response = self.client.get("/async_execute_sql/")
+ self.assertEqual(
+ len(response.toolbar.get_panel_by_id("SQLPanel").get_stats()["queries"]), 1
+ )
+
+ def test_concurrent_async_sql_page(self):
+ response = self.client.get("/async_execute_sql_concurrently/")
+ self.assertEqual(
+ len(response.toolbar.get_panel_by_id("SQLPanel").get_stats()["queries"]), 2
+ )
+
@override_settings(DEBUG=True)
class DebugToolbarIntegrationTestCase(IntegrationTestCase):
@@ -843,3 +861,29 @@ def test_theme_toggle(self):
self.get("/regular/basic/")
toolbar = self.selenium.find_element(By.ID, "djDebug")
self.assertEqual(toolbar.get_attribute("data-theme"), "light")
+
+ def test_async_sql_action(self):
+ self.get("/async_execute_sql/")
+ self.selenium.find_element(By.ID, "SQLPanel")
+ self.selenium.find_element(By.ID, "djDebugWindow")
+
+ # Click to show the SQL panel
+ self.selenium.find_element(By.CLASS_NAME, "SQLPanel").click()
+
+ # SQL panel loads
+ self.wait.until(
+ EC.visibility_of_element_located((By.CSS_SELECTOR, ".remoteCall"))
+ )
+
+ def test_concurrent_async_sql_action(self):
+ self.get("/async_execute_sql_concurrently/")
+ self.selenium.find_element(By.ID, "SQLPanel")
+ self.selenium.find_element(By.ID, "djDebugWindow")
+
+ # Click to show the SQL panel
+ self.selenium.find_element(By.CLASS_NAME, "SQLPanel").click()
+
+ # SQL panel loads
+ self.wait.until(
+ EC.visibility_of_element_located((By.CSS_SELECTOR, ".remoteCall"))
+ )
diff --git a/tests/urls.py b/tests/urls.py
index f8929f1e8..68c6e0354 100644
--- a/tests/urls.py
+++ b/tests/urls.py
@@ -17,6 +17,8 @@
path("non_ascii_request/", views.regular_view, {"title": NonAsciiRepr()}),
path("new_user/", views.new_user),
path("execute_sql/", views.execute_sql),
+ path("async_execute_sql/", views.async_execute_sql),
+ path("async_execute_sql_concurrently/", views.async_execute_sql_concurrently),
path("cached_view/", views.cached_view),
path("cached_low_level_view/", views.cached_low_level_view),
path("json_view/", views.json_view),
diff --git a/tests/views.py b/tests/views.py
index 8ae4631fe..8b8b75ef6 100644
--- a/tests/views.py
+++ b/tests/views.py
@@ -1,3 +1,6 @@
+import asyncio
+
+from asgiref.sync import sync_to_async
from django.contrib.auth.models import User
from django.core.cache import cache
from django.http import HttpResponseRedirect, JsonResponse
@@ -11,6 +14,16 @@ def execute_sql(request):
return render(request, "base.html")
+async def async_execute_sql(request):
+ await sync_to_async(list)(User.objects.all())
+ return render(request, "base.html")
+
+
+async def async_execute_sql_concurrently(request):
+ await asyncio.gather(sync_to_async(list)(User.objects.all()), User.objects.acount())
+ return render(request, "base.html")
+
+
def regular_view(request, title):
return render(request, "basic.html", {"title": title})
From f2e389cdbef0a214f51f3c49a35b32e4295dd9c9 Mon Sep 17 00:00:00 2001
From: BERNARD NWABUEZE SUNDAY
Date: Fri, 19 Jul 2024 14:14:04 +0100
Subject: [PATCH 04/33] Update installation.rst (#1967)
---
docs/installation.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/installation.rst b/docs/installation.rst
index 9200504b7..6e301cb8b 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -245,8 +245,8 @@ Django Channels & Async
^^^^^^^^^^^^^^^^^^^^^^^
The Debug Toolbar currently doesn't support Django Channels or async projects.
-If you are using Django channels are having issues getting panels to load,
-please review the documentation for the configuration option
+If you are using Django channels and you are having issues getting panels to
+load, please review the documentation for the configuration option
:ref:`RENDER_PANELS `.
From 5d4e97f86193e3e80ef3fc85ed2583ed031002c2 Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 22 Jul 2024 17:43:04 +0000
Subject: [PATCH 05/33] [pre-commit.ci] pre-commit autoupdate
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
updates:
- [github.com/adamchainz/django-upgrade: 1.19.0 → 1.20.0](https://github.com/adamchainz/django-upgrade/compare/1.19.0...1.20.0)
- [github.com/astral-sh/ruff-pre-commit: v0.5.2 → v0.5.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.5.2...v0.5.4)
---
.pre-commit-config.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index a12619911..b8f58290d 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -14,7 +14,7 @@ repos:
hooks:
- id: doc8
- repo: https://github.com/adamchainz/django-upgrade
- rev: 1.19.0
+ rev: 1.20.0
hooks:
- id: django-upgrade
args: [--target-version, "4.2"]
@@ -44,7 +44,7 @@ repos:
args:
- --fix
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: 'v0.5.2'
+ rev: 'v0.5.4'
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
From 23bb473b3bde36fa107048e3cd8be6c7292808a6 Mon Sep 17 00:00:00 2001
From: Dustin Martin
Date: Mon, 22 Jul 2024 12:50:40 -0400
Subject: [PATCH 06/33] Make toolbar compatible with `FORCE_SCRIPT_NAME`
Previously, if a project used the `FORCE_SCRIPT_NAME` setting (common when
hosting a Django application on a subdirectory path via a reverse proxy),
the `django.urls.resolve()` call would always raise `Resolver404` in the
middleware. As a result, `is_toolbar_request()` always returned False.
This caused internal toolbar URLs to be inspected, and also indirectly
led to a request loop when refreshing the history panel.
In most cases (if `FORCE_SCRIPT_NAME` is unset), `get_script_prefix()` will
return "/" and the `replace()` will be a no-op.
---
debug_toolbar/toolbar.py | 5 +++--
docs/changes.rst | 3 +++
tests/test_integration.py | 17 +++++++++++++++++
3 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/debug_toolbar/toolbar.py b/debug_toolbar/toolbar.py
index 04502ab09..7858558f5 100644
--- a/debug_toolbar/toolbar.py
+++ b/debug_toolbar/toolbar.py
@@ -13,7 +13,7 @@
from django.dispatch import Signal
from django.template import TemplateSyntaxError
from django.template.loader import render_to_string
-from django.urls import include, path, re_path, resolve
+from django.urls import get_script_prefix, include, path, re_path, resolve
from django.urls.exceptions import Resolver404
from django.utils.module_loading import import_string
from django.utils.translation import get_language, override as lang_override
@@ -165,7 +165,8 @@ def is_toolbar_request(cls, request):
# not have resolver_match set.
try:
resolver_match = request.resolver_match or resolve(
- request.path, getattr(request, "urlconf", None)
+ request.path.replace(get_script_prefix(), "/", 1),
+ getattr(request, "urlconf", None),
)
except Resolver404:
return False
diff --git a/docs/changes.rst b/docs/changes.rst
index e82c598c2..ddbbdb319 100644
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -4,6 +4,9 @@ Change log
Pending
-------
+* Fixed internal toolbar requests being instrumented if the Django setting
+ ``FORCE_SCRIPT_NAME`` was set.
+
4.4.6 (2024-07-10)
------------------
diff --git a/tests/test_integration.py b/tests/test_integration.py
index e6863e7a9..eeba37694 100644
--- a/tests/test_integration.py
+++ b/tests/test_integration.py
@@ -244,6 +244,23 @@ def test_is_toolbar_request_override_request_urlconf(self):
self.request.path = "/__debug__/render_panel/"
self.assertTrue(self.toolbar.is_toolbar_request(self.request))
+ @patch("debug_toolbar.toolbar.get_script_prefix", return_value="/path/")
+ def test_is_toolbar_request_with_script_prefix(self, mocked_get_script_prefix):
+ """
+ Test cases when Django is running under a path prefix, such as via the
+ FORCE_SCRIPT_NAME setting.
+ """
+ self.request.path = "/path/__debug__/render_panel/"
+ self.assertTrue(self.toolbar.is_toolbar_request(self.request))
+
+ self.request.path = "/path/invalid/__debug__/render_panel/"
+ self.assertFalse(self.toolbar.is_toolbar_request(self.request))
+
+ self.request.path = "/path/render_panel/"
+ self.assertFalse(self.toolbar.is_toolbar_request(self.request))
+
+ self.assertEqual(mocked_get_script_prefix.call_count, 3)
+
def test_data_gone(self):
response = self.client.get(
"/__debug__/render_panel/?store_id=GONE&panel_id=RequestPanel"
From ee258fc15f8fa5133fab2063de4650d9f4afa90a Mon Sep 17 00:00:00 2001
From: Dustin Martin
Date: Mon, 22 Jul 2024 15:25:12 -0400
Subject: [PATCH 07/33] Use `path_info` when resolving requests
Maintains support for `SCRIPT_NAME` without manually calling
`get_script_prefix()`.
Tests that involved manually setting the `path` attribute of a request
have been reworked to use a `RequestFactory` so that the `path` and
`path_info` attributes are both set appropriately.
---
debug_toolbar/panels/request.py | 2 +-
debug_toolbar/toolbar.py | 5 ++--
tests/panels/test_request.py | 21 ++++++++------
tests/test_integration.py | 50 +++++++++++++++------------------
4 files changed, 38 insertions(+), 40 deletions(-)
diff --git a/debug_toolbar/panels/request.py b/debug_toolbar/panels/request.py
index 8df382fb3..f9375b381 100644
--- a/debug_toolbar/panels/request.py
+++ b/debug_toolbar/panels/request.py
@@ -41,7 +41,7 @@ def generate_stats(self, request, response):
"view_urlname": "None",
}
try:
- match = resolve(request.path)
+ match = resolve(request.path_info)
func, args, kwargs = match
view_info["view_func"] = get_name_from_obj(func)
view_info["view_args"] = args
diff --git a/debug_toolbar/toolbar.py b/debug_toolbar/toolbar.py
index 7858558f5..e1b5474de 100644
--- a/debug_toolbar/toolbar.py
+++ b/debug_toolbar/toolbar.py
@@ -13,7 +13,7 @@
from django.dispatch import Signal
from django.template import TemplateSyntaxError
from django.template.loader import render_to_string
-from django.urls import get_script_prefix, include, path, re_path, resolve
+from django.urls import include, path, re_path, resolve
from django.urls.exceptions import Resolver404
from django.utils.module_loading import import_string
from django.utils.translation import get_language, override as lang_override
@@ -165,8 +165,7 @@ def is_toolbar_request(cls, request):
# not have resolver_match set.
try:
resolver_match = request.resolver_match or resolve(
- request.path.replace(get_script_prefix(), "/", 1),
- getattr(request, "urlconf", None),
+ request.path_info, getattr(request, "urlconf", None)
)
except Resolver404:
return False
diff --git a/tests/panels/test_request.py b/tests/panels/test_request.py
index ea7f1681a..316e09ed4 100644
--- a/tests/panels/test_request.py
+++ b/tests/panels/test_request.py
@@ -1,7 +1,10 @@
from django.http import QueryDict
+from django.test import RequestFactory
from ..base import BaseTestCase
+rf = RequestFactory()
+
class RequestPanelTestCase(BaseTestCase):
panel_id = "RequestPanel"
@@ -13,9 +16,9 @@ def test_non_ascii_session(self):
self.assertIn("où", self.panel.content)
def test_object_with_non_ascii_repr_in_request_params(self):
- self.request.path = "/non_ascii_request/"
- response = self.panel.process_request(self.request)
- self.panel.generate_stats(self.request, response)
+ request = rf.get("/non_ascii_request/")
+ response = self.panel.process_request(request)
+ self.panel.generate_stats(request, response)
self.assertIn("nôt åscíì", self.panel.content)
def test_insert_content(self):
@@ -23,11 +26,11 @@ def test_insert_content(self):
Test that the panel only inserts content after generate_stats and
not the process_request.
"""
- self.request.path = "/non_ascii_request/"
- response = self.panel.process_request(self.request)
+ request = rf.get("/non_ascii_request/")
+ response = self.panel.process_request(request)
# ensure the panel does not have content yet.
self.assertNotIn("nôt åscíì", self.panel.content)
- self.panel.generate_stats(self.request, response)
+ self.panel.generate_stats(request, response)
# ensure the panel renders correctly.
content = self.panel.content
self.assertIn("nôt åscíì", content)
@@ -99,9 +102,9 @@ def test_list_for_request_in_method_post(self):
self.assertIn("[{'a': 1}, {'b': 2}]", content)
def test_namespaced_url(self):
- self.request.path = "/admin/login/"
- response = self.panel.process_request(self.request)
- self.panel.generate_stats(self.request, response)
+ request = rf.get("/admin/login/")
+ response = self.panel.process_request(request)
+ self.panel.generate_stats(request, response)
panel_stats = self.panel.get_stats()
self.assertEqual(panel_stats["view_urlname"], "admin:login")
diff --git a/tests/test_integration.py b/tests/test_integration.py
index eeba37694..9571fcaca 100644
--- a/tests/test_integration.py
+++ b/tests/test_integration.py
@@ -128,10 +128,10 @@ def test_should_render_panels_multiprocess(self):
def _resolve_stats(self, path):
# takes stats from Request panel
- self.request.path = path
+ request = rf.get(path)
panel = self.toolbar.get_panel_by_id("RequestPanel")
- response = panel.process_request(self.request)
- panel.generate_stats(self.request, response)
+ response = panel.process_request(request)
+ panel.generate_stats(request, response)
return panel.get_stats()
def test_url_resolving_positional(self):
@@ -215,52 +215,48 @@ def test_cache_disable_instrumentation(self):
self.assertEqual(len(response.toolbar.get_panel_by_id("CachePanel").calls), 0)
def test_is_toolbar_request(self):
- self.request.path = "/__debug__/render_panel/"
- self.assertTrue(self.toolbar.is_toolbar_request(self.request))
+ request = rf.get("/__debug__/render_panel/")
+ self.assertTrue(self.toolbar.is_toolbar_request(request))
- self.request.path = "/invalid/__debug__/render_panel/"
- self.assertFalse(self.toolbar.is_toolbar_request(self.request))
+ request = rf.get("/invalid/__debug__/render_panel/")
+ self.assertFalse(self.toolbar.is_toolbar_request(request))
- self.request.path = "/render_panel/"
- self.assertFalse(self.toolbar.is_toolbar_request(self.request))
+ request = rf.get("/render_panel/")
+ self.assertFalse(self.toolbar.is_toolbar_request(request))
@override_settings(ROOT_URLCONF="tests.urls_invalid")
def test_is_toolbar_request_without_djdt_urls(self):
"""Test cases when the toolbar urls aren't configured."""
- self.request.path = "/__debug__/render_panel/"
- self.assertFalse(self.toolbar.is_toolbar_request(self.request))
+ request = rf.get("/__debug__/render_panel/")
+ self.assertFalse(self.toolbar.is_toolbar_request(request))
- self.request.path = "/render_panel/"
- self.assertFalse(self.toolbar.is_toolbar_request(self.request))
+ request = rf.get("/render_panel/")
+ self.assertFalse(self.toolbar.is_toolbar_request(request))
@override_settings(ROOT_URLCONF="tests.urls_invalid")
def test_is_toolbar_request_override_request_urlconf(self):
"""Test cases when the toolbar URL is configured on the request."""
- self.request.path = "/__debug__/render_panel/"
- self.assertFalse(self.toolbar.is_toolbar_request(self.request))
+ request = rf.get("/__debug__/render_panel/")
+ self.assertFalse(self.toolbar.is_toolbar_request(request))
# Verify overriding the urlconf on the request is valid.
- self.request.urlconf = "tests.urls"
- self.request.path = "/__debug__/render_panel/"
- self.assertTrue(self.toolbar.is_toolbar_request(self.request))
+ request.urlconf = "tests.urls"
+ self.assertTrue(self.toolbar.is_toolbar_request(request))
- @patch("debug_toolbar.toolbar.get_script_prefix", return_value="/path/")
- def test_is_toolbar_request_with_script_prefix(self, mocked_get_script_prefix):
+ def test_is_toolbar_request_with_script_prefix(self):
"""
Test cases when Django is running under a path prefix, such as via the
FORCE_SCRIPT_NAME setting.
"""
- self.request.path = "/path/__debug__/render_panel/"
- self.assertTrue(self.toolbar.is_toolbar_request(self.request))
+ request = rf.get("/__debug__/render_panel/", SCRIPT_NAME="/path/")
+ self.assertTrue(self.toolbar.is_toolbar_request(request))
- self.request.path = "/path/invalid/__debug__/render_panel/"
- self.assertFalse(self.toolbar.is_toolbar_request(self.request))
+ request = rf.get("/invalid/__debug__/render_panel/", SCRIPT_NAME="/path/")
+ self.assertFalse(self.toolbar.is_toolbar_request(request))
- self.request.path = "/path/render_panel/"
+ request = rf.get("/render_panel/", SCRIPT_NAME="/path/")
self.assertFalse(self.toolbar.is_toolbar_request(self.request))
- self.assertEqual(mocked_get_script_prefix.call_count, 3)
-
def test_data_gone(self):
response = self.client.get(
"/__debug__/render_panel/?store_id=GONE&panel_id=RequestPanel"
From 969f0a7e0ea49c61da70a96fef1685fcd9236227 Mon Sep 17 00:00:00 2001
From: friedelwolff
Date: Fri, 26 Jul 2024 13:32:34 +0200
Subject: [PATCH 08/33] Support select and explain for UNION queries (#1972)
* Support select and explain for UNION queries
Some UNION queries can start with "(", causing it to not be
classified as a SELECT query, and consequently the select and
explain buttons are missing on the SQL panel.
* Remove unit test limitation to postgresql
* Document integration test for postgres union select explain test.
---
debug_toolbar/panels/sql/forms.py | 4 ++--
debug_toolbar/panels/sql/panel.py | 10 ++++++----
debug_toolbar/panels/sql/utils.py | 5 +++++
docs/changes.rst | 1 +
tests/panels/test_sql.py | 7 +++++++
tests/test_integration.py | 23 +++++++++++++++++++++++
6 files changed, 44 insertions(+), 6 deletions(-)
diff --git a/debug_toolbar/panels/sql/forms.py b/debug_toolbar/panels/sql/forms.py
index 0515c5c8e..bb83155f4 100644
--- a/debug_toolbar/panels/sql/forms.py
+++ b/debug_toolbar/panels/sql/forms.py
@@ -5,7 +5,7 @@
from django.db import connections
from django.utils.functional import cached_property
-from debug_toolbar.panels.sql.utils import reformat_sql
+from debug_toolbar.panels.sql.utils import is_select_query, reformat_sql
class SQLSelectForm(forms.Form):
@@ -27,7 +27,7 @@ class SQLSelectForm(forms.Form):
def clean_raw_sql(self):
value = self.cleaned_data["raw_sql"]
- if not value.lower().strip().startswith("select"):
+ if not is_select_query(value):
raise ValidationError("Only 'select' queries are allowed.")
return value
diff --git a/debug_toolbar/panels/sql/panel.py b/debug_toolbar/panels/sql/panel.py
index 879be38b0..7be5c4da6 100644
--- a/debug_toolbar/panels/sql/panel.py
+++ b/debug_toolbar/panels/sql/panel.py
@@ -12,7 +12,11 @@
from debug_toolbar.panels.sql import views
from debug_toolbar.panels.sql.forms import SQLSelectForm
from debug_toolbar.panels.sql.tracking import wrap_cursor
-from debug_toolbar.panels.sql.utils import contrasting_color_generator, reformat_sql
+from debug_toolbar.panels.sql.utils import (
+ contrasting_color_generator,
+ is_select_query,
+ reformat_sql,
+)
from debug_toolbar.utils import render_stacktrace
@@ -266,9 +270,7 @@ def generate_stats(self, request, response):
query["sql"] = reformat_sql(query["sql"], with_toggle=True)
query["is_slow"] = query["duration"] > sql_warning_threshold
- query["is_select"] = (
- query["raw_sql"].lower().lstrip().startswith("select")
- )
+ query["is_select"] = is_select_query(query["raw_sql"])
query["rgb_color"] = self._databases[alias]["rgb_color"]
try:
diff --git a/debug_toolbar/panels/sql/utils.py b/debug_toolbar/panels/sql/utils.py
index cb4eda348..b8fd34afe 100644
--- a/debug_toolbar/panels/sql/utils.py
+++ b/debug_toolbar/panels/sql/utils.py
@@ -86,6 +86,11 @@ def process(stmt):
return "".join(escaped_value(token) for token in stmt.flatten())
+def is_select_query(sql):
+ # UNION queries can start with "(".
+ return sql.lower().lstrip(" (").startswith("select")
+
+
def reformat_sql(sql, *, with_toggle=False):
formatted = parse_sql(sql)
if not with_toggle:
diff --git a/docs/changes.rst b/docs/changes.rst
index ddbbdb319..72dd9d2bc 100644
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -3,6 +3,7 @@ Change log
Pending
-------
+* Support select and explain buttons for ``UNION`` queries on PostgreSQL.
* Fixed internal toolbar requests being instrumented if the Django setting
``FORCE_SCRIPT_NAME`` was set.
diff --git a/tests/panels/test_sql.py b/tests/panels/test_sql.py
index 332e9b1e8..8e105657b 100644
--- a/tests/panels/test_sql.py
+++ b/tests/panels/test_sql.py
@@ -729,6 +729,13 @@ def test_similar_and_duplicate_grouping(self):
self.assertNotEqual(queries[0]["similar_color"], queries[3]["similar_color"])
self.assertNotEqual(queries[0]["duplicate_color"], queries[3]["similar_color"])
+ def test_explain_with_union(self):
+ list(User.objects.filter(id__lt=20).union(User.objects.filter(id__gt=10)))
+ response = self.panel.process_request(self.request)
+ self.panel.generate_stats(self.request, response)
+ query = self.panel._queries[0]
+ self.assertTrue(query["is_select"])
+
class SQLPanelMultiDBTestCase(BaseMultiDBTestCase):
panel_id = "SQLPanel"
diff --git a/tests/test_integration.py b/tests/test_integration.py
index 9571fcaca..df276d90c 100644
--- a/tests/test_integration.py
+++ b/tests/test_integration.py
@@ -445,6 +445,29 @@ def test_sql_explain_checks_show_toolbar(self):
)
self.assertEqual(response.status_code, 404)
+ @unittest.skipUnless(
+ connection.vendor == "postgresql", "Test valid only on PostgreSQL"
+ )
+ def test_sql_explain_postgres_union_query(self):
+ """
+ Confirm select queries that start with a parenthesis can be explained.
+ """
+ url = "/__debug__/sql_explain/"
+ data = {
+ "signed": SignedDataForm.sign(
+ {
+ "sql": "(SELECT * FROM auth_user) UNION (SELECT * from auth_user)",
+ "raw_sql": "(SELECT * FROM auth_user) UNION (SELECT * from auth_user)",
+ "params": "{}",
+ "alias": "default",
+ "duration": "0",
+ }
+ )
+ }
+
+ response = self.client.post(url, data)
+ self.assertEqual(response.status_code, 200)
+
@unittest.skipUnless(
connection.vendor == "postgresql", "Test valid only on PostgreSQL"
)
From c5cdd70d8f143a1e6c526896fcba808a75a6dcce Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 29 Jul 2024 17:46:27 +0000
Subject: [PATCH 09/33] [pre-commit.ci] pre-commit autoupdate
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
updates:
- [github.com/pre-commit/mirrors-eslint: v9.7.0 → v9.8.0](https://github.com/pre-commit/mirrors-eslint/compare/v9.7.0...v9.8.0)
- [github.com/astral-sh/ruff-pre-commit: v0.5.4 → v0.5.5](https://github.com/astral-sh/ruff-pre-commit/compare/v0.5.4...v0.5.5)
---
.pre-commit-config.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index b8f58290d..5ce696998 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -32,7 +32,7 @@ repos:
args:
- --trailing-comma=es5
- repo: https://github.com/pre-commit/mirrors-eslint
- rev: v9.7.0
+ rev: v9.8.0
hooks:
- id: eslint
additional_dependencies:
@@ -44,7 +44,7 @@ repos:
args:
- --fix
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: 'v0.5.4'
+ rev: 'v0.5.5'
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
From 573a87baa9e72b66ae90834b316efea10f76c0fb Mon Sep 17 00:00:00 2001
From: Aman Pandey
Date: Fri, 2 Aug 2024 18:58:13 +0530
Subject: [PATCH 10/33] toggle debug to true so that debug middleware make a
complete run
---
tests/test_middleware_compatibility.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tests/test_middleware_compatibility.py b/tests/test_middleware_compatibility.py
index d3025c1ea..99ed7db82 100644
--- a/tests/test_middleware_compatibility.py
+++ b/tests/test_middleware_compatibility.py
@@ -1,7 +1,7 @@
import asyncio
from django.http import HttpResponse
-from django.test import AsyncRequestFactory, RequestFactory, TestCase
+from django.test import AsyncRequestFactory, RequestFactory, TestCase, override_settings
from debug_toolbar.middleware import DebugToolbarMiddleware
@@ -11,6 +11,7 @@ def setUp(self):
self.factory = RequestFactory()
self.async_factory = AsyncRequestFactory()
+ @override_settings(DEBUG=True)
def test_sync_mode(self):
"""
test middlware switches to sync (__call__) based on get_response type
@@ -26,6 +27,7 @@ def test_sync_mode(self):
response = middleware(request)
self.assertEqual(response.status_code, 200)
+ @override_settings(DEBUG=True)
async def test_async_mode(self):
"""
test middlware switches to async (__acall__) based on get_response type
From 173b38758e8f455ad8aa9dbebb24ef99b671e1e9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?L=C3=A1szl=C3=B3=20K=C3=A1rolyi?=
<987055+karolyi@users.noreply.github.com>
Date: Mon, 5 Aug 2024 07:15:11 +0000
Subject: [PATCH 11/33] Quick hack for including csp_nonces from requests into
script tags (#1975)
Co-authored-by: tschilling
---
.gitignore | 1 +
debug_toolbar/panels/redirects.py | 6 +-
.../templates/debug_toolbar/base.html | 6 +-
.../debug_toolbar/includes/panel_content.html | 2 +-
.../templates/debug_toolbar/redirect.html | 2 +-
debug_toolbar/toolbar.py | 7 +-
requirements_dev.txt | 1 +
tests/base.py | 4 +
tests/test_csp_rendering.py | 140 ++++++++++++++++++
tox.ini | 1 +
10 files changed, 162 insertions(+), 8 deletions(-)
create mode 100644 tests/test_csp_rendering.py
diff --git a/.gitignore b/.gitignore
index 988922d50..c89013a11 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,3 +14,4 @@ geckodriver.log
coverage.xml
.direnv/
.envrc
+venv
diff --git a/debug_toolbar/panels/redirects.py b/debug_toolbar/panels/redirects.py
index 8894d1a18..349564edb 100644
--- a/debug_toolbar/panels/redirects.py
+++ b/debug_toolbar/panels/redirects.py
@@ -21,7 +21,11 @@ def process_request(self, request):
if redirect_to:
status_line = f"{response.status_code} {response.reason_phrase}"
cookies = response.cookies
- context = {"redirect_to": redirect_to, "status_line": status_line}
+ context = {
+ "redirect_to": redirect_to,
+ "status_line": status_line,
+ "toolbar": self.toolbar,
+ }
# Using SimpleTemplateResponse avoids running global context processors.
response = SimpleTemplateResponse(
"debug_toolbar/redirect.html", context
diff --git a/debug_toolbar/templates/debug_toolbar/base.html b/debug_toolbar/templates/debug_toolbar/base.html
index 4867a834e..b0308be55 100644
--- a/debug_toolbar/templates/debug_toolbar/base.html
+++ b/debug_toolbar/templates/debug_toolbar/base.html
@@ -1,10 +1,10 @@
{% load i18n static %}
{% block css %}
-
-
+
+
{% endblock %}
{% block js %}
-
+
{% endblock %}
{{ panel.title }}
{% if toolbar.should_render_panels %}
- {% for script in panel.scripts %}{% endfor %}
+ {% for script in panel.scripts %}{% endfor %}
{{ panel.content }}
{% else %}
diff --git a/debug_toolbar/templates/debug_toolbar/redirect.html b/debug_toolbar/templates/debug_toolbar/redirect.html
index 96b97de2d..cb6b4a6ea 100644
--- a/debug_toolbar/templates/debug_toolbar/redirect.html
+++ b/debug_toolbar/templates/debug_toolbar/redirect.html
@@ -3,7 +3,7 @@
Django Debug Toolbar Redirects Panel: {{ status_line }}
-
+
{{ status_line }}
diff --git a/debug_toolbar/toolbar.py b/debug_toolbar/toolbar.py
index e1b5474de..35d789a53 100644
--- a/debug_toolbar/toolbar.py
+++ b/debug_toolbar/toolbar.py
@@ -4,9 +4,11 @@
import re
import uuid
-from collections import OrderedDict
from functools import lru_cache
+# Can be removed when python3.8 is dropped
+from typing import OrderedDict
+
from django.apps import apps
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
@@ -19,6 +21,7 @@
from django.utils.translation import get_language, override as lang_override
from debug_toolbar import APP_NAME, settings as dt_settings
+from debug_toolbar.panels import Panel
class DebugToolbar:
@@ -38,7 +41,7 @@ def __init__(self, request, get_response):
# Use OrderedDict for the _panels attribute so that items can be efficiently
# removed using FIFO order in the DebugToolbar.store() method. The .popitem()
# method of Python's built-in dict only supports LIFO removal.
- self._panels = OrderedDict()
+ self._panels = OrderedDict[str, Panel]()
while panels:
panel = panels.pop()
self._panels[panel.panel_id] = panel
diff --git a/requirements_dev.txt b/requirements_dev.txt
index 03e436622..e66eba5c6 100644
--- a/requirements_dev.txt
+++ b/requirements_dev.txt
@@ -11,6 +11,7 @@ html5lib
selenium
tox
black
+django-csp # Used in tests/test_csp_rendering
# Integration support
diff --git a/tests/base.py b/tests/base.py
index 5cc432add..9d12c5219 100644
--- a/tests/base.py
+++ b/tests/base.py
@@ -1,8 +1,11 @@
+from typing import Optional
+
import html5lib
from asgiref.local import Local
from django.http import HttpResponse
from django.test import Client, RequestFactory, TestCase, TransactionTestCase
+from debug_toolbar.panels import Panel
from debug_toolbar.toolbar import DebugToolbar
@@ -32,6 +35,7 @@ def handle_toolbar_created(sender, toolbar=None, **kwargs):
class BaseMixin:
client_class = ToolbarTestClient
+ panel: Optional[Panel] = None
panel_id = None
def setUp(self):
diff --git a/tests/test_csp_rendering.py b/tests/test_csp_rendering.py
new file mode 100644
index 000000000..5e355b15a
--- /dev/null
+++ b/tests/test_csp_rendering.py
@@ -0,0 +1,140 @@
+from typing import Dict, cast
+from xml.etree.ElementTree import Element
+
+from django.conf import settings
+from django.http.response import HttpResponse
+from django.test.utils import ContextList, override_settings
+from html5lib.constants import E
+from html5lib.html5parser import HTMLParser
+
+from debug_toolbar.toolbar import DebugToolbar
+
+from .base import IntegrationTestCase
+
+
+def get_namespaces(element: Element) -> Dict[str, str]:
+ """
+ Return the default `xmlns`. See
+ https://docs.python.org/3/library/xml.etree.elementtree.html#parsing-xml-with-namespaces
+ """
+ if not element.tag.startswith("{"):
+ return {}
+ return {"": element.tag[1:].split("}", maxsplit=1)[0]}
+
+
+@override_settings(DEBUG=True)
+class CspRenderingTestCase(IntegrationTestCase):
+ """Testing if `csp-nonce` renders."""
+
+ def setUp(self):
+ super().setUp()
+ self.parser = HTMLParser()
+
+ def _fail_if_missing(
+ self, root: Element, path: str, namespaces: Dict[str, str], nonce: str
+ ):
+ """
+ Search elements, fail if a `nonce` attribute is missing on them.
+ """
+ elements = root.findall(path=path, namespaces=namespaces)
+ for item in elements:
+ if item.attrib.get("nonce") != nonce:
+ raise self.failureException(f"{item} has no nonce attribute.")
+
+ def _fail_if_found(self, root: Element, path: str, namespaces: Dict[str, str]):
+ """
+ Search elements, fail if a `nonce` attribute is found on them.
+ """
+ elements = root.findall(path=path, namespaces=namespaces)
+ for item in elements:
+ if "nonce" in item.attrib:
+ raise self.failureException(f"{item} has a nonce attribute.")
+
+ def _fail_on_invalid_html(self, content: bytes, parser: HTMLParser):
+ """Fail if the passed HTML is invalid."""
+ if parser.errors:
+ default_msg = ["Content is invalid HTML:"]
+ lines = content.split(b"\n")
+ for position, error_code, data_vars in parser.errors:
+ default_msg.append(" %s" % E[error_code] % data_vars)
+ default_msg.append(" %r" % lines[position[0] - 1])
+ msg = self._formatMessage(None, "\n".join(default_msg))
+ raise self.failureException(msg)
+
+ @override_settings(
+ MIDDLEWARE=settings.MIDDLEWARE + ["csp.middleware.CSPMiddleware"]
+ )
+ def test_exists(self):
+ """A `nonce` should exist when using the `CSPMiddleware`."""
+ response = cast(HttpResponse, self.client.get(path="/regular/basic/"))
+ self.assertEqual(response.status_code, 200)
+
+ html_root: Element = self.parser.parse(stream=response.content)
+ self._fail_on_invalid_html(content=response.content, parser=self.parser)
+ self.assertContains(response, "djDebug")
+
+ namespaces = get_namespaces(element=html_root)
+ toolbar = list(DebugToolbar._store.values())[0]
+ nonce = str(toolbar.request.csp_nonce)
+ self._fail_if_missing(
+ root=html_root, path=".//link", namespaces=namespaces, nonce=nonce
+ )
+ self._fail_if_missing(
+ root=html_root, path=".//script", namespaces=namespaces, nonce=nonce
+ )
+
+ @override_settings(
+ DEBUG_TOOLBAR_CONFIG={"DISABLE_PANELS": set()},
+ MIDDLEWARE=settings.MIDDLEWARE + ["csp.middleware.CSPMiddleware"],
+ )
+ def test_redirects_exists(self):
+ response = cast(HttpResponse, self.client.get(path="/regular/basic/"))
+ self.assertEqual(response.status_code, 200)
+
+ html_root: Element = self.parser.parse(stream=response.content)
+ self._fail_on_invalid_html(content=response.content, parser=self.parser)
+ self.assertContains(response, "djDebug")
+
+ namespaces = get_namespaces(element=html_root)
+ context: ContextList = response.context # pyright: ignore[reportAttributeAccessIssue]
+ nonce = str(context["toolbar"].request.csp_nonce)
+ self._fail_if_missing(
+ root=html_root, path=".//link", namespaces=namespaces, nonce=nonce
+ )
+ self._fail_if_missing(
+ root=html_root, path=".//script", namespaces=namespaces, nonce=nonce
+ )
+
+ @override_settings(
+ MIDDLEWARE=settings.MIDDLEWARE + ["csp.middleware.CSPMiddleware"]
+ )
+ def test_panel_content_nonce_exists(self):
+ response = cast(HttpResponse, self.client.get(path="/regular/basic/"))
+ self.assertEqual(response.status_code, 200)
+
+ toolbar = list(DebugToolbar._store.values())[0]
+ panels_to_check = ["HistoryPanel", "TimerPanel"]
+ for panel in panels_to_check:
+ content = toolbar.get_panel_by_id(panel).content
+ html_root: Element = self.parser.parse(stream=content)
+ namespaces = get_namespaces(element=html_root)
+ nonce = str(toolbar.request.csp_nonce)
+ self._fail_if_missing(
+ root=html_root, path=".//link", namespaces=namespaces, nonce=nonce
+ )
+ self._fail_if_missing(
+ root=html_root, path=".//script", namespaces=namespaces, nonce=nonce
+ )
+
+ def test_missing(self):
+ """A `nonce` should not exist when not using the `CSPMiddleware`."""
+ response = cast(HttpResponse, self.client.get(path="/regular/basic/"))
+ self.assertEqual(response.status_code, 200)
+
+ html_root: Element = self.parser.parse(stream=response.content)
+ self._fail_on_invalid_html(content=response.content, parser=self.parser)
+ self.assertContains(response, "djDebug")
+
+ namespaces = get_namespaces(element=html_root)
+ self._fail_if_found(root=html_root, path=".//link", namespaces=namespaces)
+ self._fail_if_found(root=html_root, path=".//script", namespaces=namespaces)
diff --git a/tox.ini b/tox.ini
index a0e72827a..160b33db7 100644
--- a/tox.ini
+++ b/tox.ini
@@ -21,6 +21,7 @@ deps =
pygments
selenium>=4.8.0
sqlparse
+ django-csp
passenv=
CI
COVERAGE_ARGS
From aea6cc6a72c75aa7206ebd08889ff3c0b12eb9af Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
<66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Mon, 5 Aug 2024 21:31:11 +0200
Subject: [PATCH 12/33] [pre-commit.ci] pre-commit autoupdate (#1980)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.5.5 → v0.5.6](https://github.com/astral-sh/ruff-pre-commit/compare/v0.5.5...v0.5.6)
- [github.com/tox-dev/pyproject-fmt: 2.1.4 → 2.2.1](https://github.com/tox-dev/pyproject-fmt/compare/2.1.4...2.2.1)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
---
.pre-commit-config.yaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 5ce696998..5db940f33 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -44,13 +44,13 @@ repos:
args:
- --fix
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: 'v0.5.5'
+ rev: 'v0.5.6'
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
- repo: https://github.com/tox-dev/pyproject-fmt
- rev: 2.1.4
+ rev: 2.2.1
hooks:
- id: pyproject-fmt
- repo: https://github.com/abravalheri/validate-pyproject
From 89568d52b97a97e9e6f8c5c99fd7439c29f1f61a Mon Sep 17 00:00:00 2001
From: Jon Ribbens
Date: Tue, 6 Aug 2024 13:00:22 +0100
Subject: [PATCH 13/33] Slightly increase opacity of debug toolbar button
(#1982)
* Slightly increase opacity of debug toolbar button
Avoids an accessibility issue (low-contrast text) when the page behind the button is white.
Fixes #1981
* Add line to changelog.
---------
Co-authored-by: Tim Schilling
---
debug_toolbar/static/debug_toolbar/css/toolbar.css | 2 +-
docs/changes.rst | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/debug_toolbar/static/debug_toolbar/css/toolbar.css b/debug_toolbar/static/debug_toolbar/css/toolbar.css
index e495eeb0c..79f42ae56 100644
--- a/debug_toolbar/static/debug_toolbar/css/toolbar.css
+++ b/debug_toolbar/static/debug_toolbar/css/toolbar.css
@@ -301,7 +301,7 @@
font-size: 22px;
font-weight: bold;
background: #000;
- opacity: 0.5;
+ opacity: 0.6;
}
#djDebug #djShowToolBarButton:hover {
diff --git a/docs/changes.rst b/docs/changes.rst
index 72dd9d2bc..d867b7d80 100644
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -3,10 +3,11 @@ Change log
Pending
-------
-* Support select and explain buttons for ``UNION`` queries on PostgreSQL.
+* Support select and explain buttons for ``UNION`` queries on PostgreSQL.
* Fixed internal toolbar requests being instrumented if the Django setting
``FORCE_SCRIPT_NAME`` was set.
+* Increase opacity of show Debug Toolbar handle to improve accessibility.
4.4.6 (2024-07-10)
------------------
From 405f9f23d3e233fabb88d2012b28b37c2d89f29e Mon Sep 17 00:00:00 2001
From: Aman Pandey
Date: Tue, 6 Aug 2024 17:36:38 +0530
Subject: [PATCH 14/33] Async compatible redirect panel (#1976)
* make redirect panel async capable by using aprocess_request patterm
* added async compability test for redirect panel
* remove redundant call for super process_request
---
debug_toolbar/panels/redirects.py | 25 ++++++++++++++++++++++---
docs/architecture.rst | 2 +-
docs/changes.rst | 1 +
tests/panels/test_redirects.py | 15 +++++++++++++++
4 files changed, 39 insertions(+), 4 deletions(-)
diff --git a/debug_toolbar/panels/redirects.py b/debug_toolbar/panels/redirects.py
index 349564edb..71c008f1b 100644
--- a/debug_toolbar/panels/redirects.py
+++ b/debug_toolbar/panels/redirects.py
@@ -1,3 +1,5 @@
+from inspect import iscoroutine
+
from django.template.response import SimpleTemplateResponse
from django.utils.translation import gettext_lazy as _
@@ -9,13 +11,15 @@ class RedirectsPanel(Panel):
Panel that intercepts redirects and displays a page with debug info.
"""
- is_async = False
+ is_async = True
has_content = False
nav_title = _("Intercept redirects")
- def process_request(self, request):
- response = super().process_request(request)
+ def _process_response(self, response):
+ """
+ Common response processing logic.
+ """
if 300 <= response.status_code < 400:
redirect_to = response.get("Location")
if redirect_to:
@@ -33,3 +37,18 @@ def process_request(self, request):
response.cookies = cookies
response.render()
return response
+
+ async def aprocess_request(self, request, response_coroutine):
+ """
+ Async version of process_request. used for accessing the response
+ by awaiting it when running in ASGI.
+ """
+
+ response = await response_coroutine
+ return self._process_response(response)
+
+ def process_request(self, request):
+ response = super().process_request(request)
+ if iscoroutine(response):
+ return self.aprocess_request(request, response)
+ return self._process_response(response)
diff --git a/docs/architecture.rst b/docs/architecture.rst
index 145676459..c49bfef0f 100644
--- a/docs/architecture.rst
+++ b/docs/architecture.rst
@@ -82,7 +82,7 @@ Problematic Parts
- Support for async and multi-threading: ``debug_toolbar.middleware.DebugToolbarMiddleware``
is now async compatible and can process async requests. However certain
panels such as ``SQLPanel``, ``TimerPanel``, ``StaticFilesPanel``,
- ``RequestPanel``, ``RedirectsPanel`` and ``ProfilingPanel`` aren't fully
+ ``RequestPanel`` and ``ProfilingPanel`` aren't fully
compatible and currently being worked on. For now, these panels
are disabled by default when running in async environment.
follow the progress of this issue in `Async compatible toolbar project `_.
diff --git a/docs/changes.rst b/docs/changes.rst
index d867b7d80..d4a81ffca 100644
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -8,6 +8,7 @@ Pending
* Fixed internal toolbar requests being instrumented if the Django setting
``FORCE_SCRIPT_NAME`` was set.
* Increase opacity of show Debug Toolbar handle to improve accessibility.
+* Changed the ``RedirectsPanel`` to be async compatible.
4.4.6 (2024-07-10)
------------------
diff --git a/tests/panels/test_redirects.py b/tests/panels/test_redirects.py
index 6b67e6f1d..2abed9fd0 100644
--- a/tests/panels/test_redirects.py
+++ b/tests/panels/test_redirects.py
@@ -2,6 +2,7 @@
from django.conf import settings
from django.http import HttpResponse
+from django.test import AsyncRequestFactory
from ..base import BaseTestCase
@@ -70,3 +71,17 @@ def test_insert_content(self):
self.assertIsNotNone(response)
response = self.panel.generate_stats(self.request, redirect)
self.assertIsNone(response)
+
+ async def test_async_compatibility(self):
+ redirect = HttpResponse(status=302)
+
+ async def get_response(request):
+ return redirect
+
+ await_response = await get_response(self.request)
+ self._get_response = get_response
+
+ self.request = AsyncRequestFactory().get("/")
+ response = await self.panel.process_request(self.request)
+ self.assertIsInstance(response, HttpResponse)
+ self.assertTrue(response is await_response)
From 45cbf41d56bda52e8a346e6f9b6cd8bd12d88ab2 Mon Sep 17 00:00:00 2001
From: Elyas Ebrahimpour
Date: Thu, 25 Jan 2024 00:55:50 +0330
Subject: [PATCH 15/33] :wrench: update translation for Persian language
---
debug_toolbar/locale/fa/LC_MESSAGES/django.po | 81 ++++++++++---------
1 file changed, 42 insertions(+), 39 deletions(-)
diff --git a/debug_toolbar/locale/fa/LC_MESSAGES/django.po b/debug_toolbar/locale/fa/LC_MESSAGES/django.po
index 1c9c1b32f..fe2c6317a 100644
--- a/debug_toolbar/locale/fa/LC_MESSAGES/django.po
+++ b/debug_toolbar/locale/fa/LC_MESSAGES/django.po
@@ -4,6 +4,7 @@
#
# Translators:
# Ali Soltani , 2021
+# Elyas Ebrahimpour , 2024
msgid ""
msgstr ""
"Project-Id-Version: Django Debug Toolbar\n"
@@ -31,15 +32,15 @@ msgstr "Cache"
#, python-format
msgid "%(cache_calls)d call in %(time).2fms"
msgid_plural "%(cache_calls)d calls in %(time).2fms"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%(cache_calls)d فراخوان در %(time).2f میلیثانیه"
+msgstr[1] "%(cache_calls)d فراخوان در %(time).2f میلیثانیه"
#: panels/cache.py:195
#, python-format
msgid "Cache calls from %(count)d backend"
msgid_plural "Cache calls from %(count)d backends"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "فراخوانهای کش از %(count)d بکاند"
+msgstr[1] "فراخوانهای کش از %(count)d بکاندها"
#: panels/headers.py:31
msgid "Headers"
@@ -55,7 +56,7 @@ msgstr "نمایه سازی"
#: panels/redirects.py:14
msgid "Intercept redirects"
-msgstr ""
+msgstr "رهگیری تغییر مسیرها"
#: panels/request.py:16
msgid "Request"
@@ -63,11 +64,11 @@ msgstr "ریکوئست"
#: panels/request.py:36
msgid ""
-msgstr ""
+msgstr "<بدون نمایش>"
#: panels/request.py:53
msgid ""
-msgstr ""
+msgstr "<در دسترس نیست>"
#: panels/settings.py:17
msgid "Settings"
@@ -82,19 +83,19 @@ msgstr "تنظیمات از %s"
#, python-format
msgid "%(num_receivers)d receiver of 1 signal"
msgid_plural "%(num_receivers)d receivers of 1 signal"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%(num_receivers)d گیرنده از 1 سیگنال"
+msgstr[1] "%(num_receivers)d گیرنده از 1 سیگنال"
#: panels/signals.py:62
#, python-format
msgid "%(num_receivers)d receiver of %(num_signals)d signals"
msgid_plural "%(num_receivers)d receivers of %(num_signals)d signals"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%(num_receivers)d گیرنده از %(num_signals)d سیگنال"
+msgstr[1] "%(num_receivers)d گیرنده از %(num_signals)d سیگنال"
#: panels/signals.py:67
msgid "Signals"
-msgstr "signal ها"
+msgstr "سیگنالها"
#: panels/sql/panel.py:23
msgid "Autocommit"
@@ -102,15 +103,15 @@ msgstr "کامیت خودکار"
#: panels/sql/panel.py:24
msgid "Read uncommitted"
-msgstr ""
+msgstr "خواندن بدون تاثیر"
#: panels/sql/panel.py:25
msgid "Read committed"
-msgstr ""
+msgstr "خواندن با تاثیر"
#: panels/sql/panel.py:26
msgid "Repeatable read"
-msgstr ""
+msgstr "خواندن تکرارپذیر"
#: panels/sql/panel.py:27
msgid "Serializable"
@@ -144,20 +145,21 @@ msgstr "اس کیو ال"
#, python-format
msgid "%(query_count)d query in %(sql_time).2fms"
msgid_plural "%(query_count)d queries in %(sql_time).2fms"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%(query_count)d کوئری در %(sql_time).2f میلیثانیه"
+msgstr[1] "%(query_count)d کوئری در %(sql_time).2f میلیثانیه"
#: panels/sql/panel.py:147
#, python-format
msgid "SQL queries from %(count)d connection"
msgid_plural "SQL queries from %(count)d connections"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "کوئریهای SQL از %(count)d اتصال"
+msgstr[1] "کوئریهای SQL از %(count)d اتصال"
#: panels/staticfiles.py:84
#, python-format
msgid "Static files (%(num_found)s found, %(num_used)s used)"
-msgstr ""
+msgstr "فایلهای استاتیک (%(num_found)s یافته شده، %(num_used)s استفاده شده)"
+
#: panels/staticfiles.py:105
msgid "Static files"
@@ -167,8 +169,8 @@ msgstr "فایل های استاتیک"
#, python-format
msgid "%(num_used)s file used"
msgid_plural "%(num_used)s files used"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%(num_used)s فایل استفاده شده"
+msgstr[1] "%(num_used)s فایل استفاده شده"
#: panels/templates/panel.py:143
msgid "Templates"
@@ -186,12 +188,12 @@ msgstr "بدون origin"
#: panels/timer.py:25
#, python-format
msgid "CPU: %(cum)0.2fms (%(total)0.2fms)"
-msgstr ""
+msgstr "پردازنده: %(cum)0.2f میلیثانیه (%(total)0.2f میلیثانیه)"
#: panels/timer.py:30
#, python-format
msgid "Total: %0.2fms"
-msgstr ""
+msgstr "مجموع: %0.2f میلیثانیه"
#: panels/timer.py:36 templates/debug_toolbar/panels/history.html:9
#: templates/debug_toolbar/panels/sql_explain.html:11
@@ -207,7 +209,7 @@ msgstr "زمان سی پی یو کاربر"
#: panels/timer.py:44
#, python-format
msgid "%(utime)0.3f msec"
-msgstr ""
+msgstr "%(utime)0.3f میلیثانیه"
#: panels/timer.py:45
msgid "System CPU time"
@@ -216,7 +218,7 @@ msgstr "زمان CPU سیستم"
#: panels/timer.py:45
#, python-format
msgid "%(stime)0.3f msec"
-msgstr ""
+msgstr "%(stime)0.3f میلیثانیه"
#: panels/timer.py:46
msgid "Total CPU time"
@@ -234,16 +236,16 @@ msgstr "زمان سپری شده"
#: panels/timer.py:47
#, python-format
msgid "%(total_time)0.3f msec"
-msgstr ""
+msgstr "%(total_time)0.3f میلیثانیه"
#: panels/timer.py:49
msgid "Context switches"
-msgstr ""
+msgstr "تغییرات زمینه"
#: panels/timer.py:50
#, python-format
msgid "%(vcsw)d voluntary, %(ivcsw)d involuntary"
-msgstr ""
+msgstr "%(vcsw)d اختیاری، %(ivcsw)d غیراختیاری"
#: panels/versions.py:19
msgid "Versions"
@@ -287,9 +289,7 @@ msgstr "Cache hits"
#: templates/debug_toolbar/panels/cache.html:9
msgid "Cache misses"
-msgstr ""
-"Cache misses\n"
-" "
+msgstr "عدم دسترسی به کش"
#: templates/debug_toolbar/panels/cache.html:21
msgid "Commands"
@@ -297,7 +297,7 @@ msgstr "دستورات"
#: templates/debug_toolbar/panels/cache.html:39
msgid "Calls"
-msgstr "call ها"
+msgstr "فراخوانی ها"
#: templates/debug_toolbar/panels/cache.html:43
#: templates/debug_toolbar/panels/sql.html:36
@@ -524,7 +524,7 @@ msgstr "کوئری SQL ای در این ریکوئست ثبت نشده است"
#: templates/debug_toolbar/panels/sql_explain.html:4
msgid "SQL explained"
-msgstr ""
+msgstr "توضیح SQL"
#: templates/debug_toolbar/panels/sql_explain.html:9
#: templates/debug_toolbar/panels/sql_profile.html:10
@@ -548,7 +548,7 @@ msgstr "خطا"
#: templates/debug_toolbar/panels/sql_select.html:4
msgid "SQL selected"
-msgstr ""
+msgstr "انتخاب شده SQL"
#: templates/debug_toolbar/panels/sql_select.html:36
msgid "Empty set"
@@ -616,13 +616,13 @@ msgstr[1] ""
#: templates/debug_toolbar/panels/templates.html:22
#: templates/debug_toolbar/panels/templates.html:40
msgid "Toggle context"
-msgstr ""
+msgstr "تغییر متن"
#: templates/debug_toolbar/panels/templates.html:33
msgid "Context processor"
msgid_plural "Context processors"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "پردازشگر محیط"
+msgstr[1] "پردازشگرهای محیط"
#: templates/debug_toolbar/panels/timer.html:2
msgid "Resource usage"
@@ -642,7 +642,7 @@ msgstr "ویژگی زمان بندی"
#: templates/debug_toolbar/panels/timer.html:37
msgid "Milliseconds since navigation start (+length)"
-msgstr ""
+msgstr "میلیثانیه از آغاز ناوبری (+length)"
#: templates/debug_toolbar/panels/versions.html:10
msgid "Package"
@@ -666,6 +666,9 @@ msgid ""
"debug viewing purposes. You can click the above link to continue with the "
"redirect as normal."
msgstr ""
+"نوار ابزار اشکالزدای Django یک هدایت به URL بالا را به منظور مشاهده اشکال "
+"توسط ابزار اشکالزدای افزونه کرده است. میتوانید بر روی پیوند بالا کلیک "
+"کنید تا با هدایت به صورت عادی ادامه دهید."
#: views.py:16
msgid ""
From 9e30a06e418ecdd4eeb837530b86be40bb1e3d2d Mon Sep 17 00:00:00 2001
From: Matthias Kestenholz
Date: Tue, 6 Aug 2024 14:28:30 +0200
Subject: [PATCH 16/33] Add a paragraph describing our stance on Python typing
(#1979)
---
docs/contributing.rst | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/docs/contributing.rst b/docs/contributing.rst
index 0021a88fa..c94d9e74c 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -112,10 +112,10 @@ For MySQL/MariaDB in a ``mysql`` shell::
Style
-----
-The Django Debug Toolbar uses `black `__ to
-format code and additionally uses ruff. The toolbar uses
-`pre-commit `__ to automatically apply our style
-guidelines when a commit is made. Set up pre-commit before committing with::
+The Django Debug Toolbar uses `ruff `__ to
+format and lint Python code. The toolbar uses `pre-commit
+`__ to automatically apply our style guidelines when a
+commit is made. Set up pre-commit before committing with::
$ pre-commit install
@@ -129,6 +129,18 @@ To reformat the code manually use::
$ pre-commit run --all-files
+
+Typing
+------
+
+The Debug Toolbar has been accepting patches which add type hints to the code
+base, as long as the types themselves do not cause any problems or obfuscate
+the intent.
+
+The maintainers are not committed to adding type hints and are not requiring
+new code to have type hints at this time. This may change in the future.
+
+
Patches
-------
From f6699300a81cbedaddef15a15cea227db9cfb9f3 Mon Sep 17 00:00:00 2001
From: myou1985
Date: Tue, 13 Aug 2024 21:52:11 +0900
Subject: [PATCH 17/33] Use higher contrast when dark mode is enabled (#1987)
* Added table background color setting when dark theme
---
debug_toolbar/static/debug_toolbar/css/toolbar.css | 1 +
docs/changes.rst | 1 +
2 files changed, 2 insertions(+)
diff --git a/debug_toolbar/static/debug_toolbar/css/toolbar.css b/debug_toolbar/static/debug_toolbar/css/toolbar.css
index 79f42ae56..8a19ab646 100644
--- a/debug_toolbar/static/debug_toolbar/css/toolbar.css
+++ b/debug_toolbar/static/debug_toolbar/css/toolbar.css
@@ -61,6 +61,7 @@
--djdt-font-color: #8393a7;
--djdt-background-color: #1e293bff;
--djdt-panel-content-background-color: #0f1729ff;
+ --djdt-panel-content-table-background-color: var(--djdt-background-color);
--djdt-panel-title-background-color: #242432;
--djdt-djdt-panel-content-table-strip-background-color: #324154ff;
--djdt--highlighted-background-color: #2c2a7dff;
diff --git a/docs/changes.rst b/docs/changes.rst
index d4a81ffca..b233dadc6 100644
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -9,6 +9,7 @@ Pending
``FORCE_SCRIPT_NAME`` was set.
* Increase opacity of show Debug Toolbar handle to improve accessibility.
* Changed the ``RedirectsPanel`` to be async compatible.
+* Increased the contrast of text with dark mode enabled.
4.4.6 (2024-07-10)
------------------
From d3ea31b648879ecff595d928b54f82a438b1192e Mon Sep 17 00:00:00 2001
From: Tim Schilling
Date: Fri, 2 Aug 2024 10:51:01 -0500
Subject: [PATCH 18/33] Switch to Django Commons code of conduct
---
CODE_OF_CONDUCT.md | 47 ++--------------------------------------------
1 file changed, 2 insertions(+), 45 deletions(-)
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index e0d5efab5..5fedea529 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -1,46 +1,3 @@
-# Code of Conduct
+# Django Debug Toolbar Code of Conduct
-As contributors and maintainers of the Jazzband projects, and in the interest of
-fostering an open and welcoming community, we pledge to respect all people who
-contribute through reporting issues, posting feature requests, updating documentation,
-submitting pull requests or patches, and other activities.
-
-We are committed to making participation in the Jazzband a harassment-free experience
-for everyone, regardless of the level of experience, gender, gender identity and
-expression, sexual orientation, disability, personal appearance, body size, race,
-ethnicity, age, religion, or nationality.
-
-Examples of unacceptable behavior by participants include:
-
-- The use of sexualized language or imagery
-- Personal attacks
-- Trolling or insulting/derogatory comments
-- Public or private harassment
-- Publishing other's private information, such as physical or electronic addresses,
- without explicit permission
-- Other unethical or unprofessional conduct
-
-The Jazzband roadies have the right and responsibility to remove, edit, or reject
-comments, commits, code, wiki edits, issues, and other contributions that are not
-aligned to this Code of Conduct, or to ban temporarily or permanently any contributor
-for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
-
-By adopting this Code of Conduct, the roadies commit themselves to fairly and
-consistently applying these principles to every aspect of managing the jazzband
-projects. Roadies who do not follow or enforce the Code of Conduct may be permanently
-removed from the Jazzband roadies.
-
-This code of conduct applies both within project spaces and in public spaces when an
-individual is representing the project or its community.
-
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by
-contacting the roadies at `roadies@jazzband.co`. All complaints will be reviewed and
-investigated and will result in a response that is deemed necessary and appropriate to
-the circumstances. Roadies are obligated to maintain confidentiality with regard to the
-reporter of an incident.
-
-This Code of Conduct is adapted from the [Contributor Covenant][homepage], version
-1.3.0, available at [https://contributor-covenant.org/version/1/3/0/][version]
-
-[homepage]: https://contributor-covenant.org
-[version]: https://contributor-covenant.org/version/1/3/0/
+The django-debug-toolbar project utilizes the [Django Commons Code of Conduct](https://github.com/django-commons/membership/blob/main/CODE_OF_CONDUCT.md).
From 2cad608dd9ec7d2cc11c5e379e13bed4df28f730 Mon Sep 17 00:00:00 2001
From: Tim Schilling
Date: Tue, 6 Aug 2024 07:14:56 -0500
Subject: [PATCH 19/33] Create new translatable strings.
---
debug_toolbar/locale/en/LC_MESSAGES/django.po | 128 +++++++++++-------
1 file changed, 82 insertions(+), 46 deletions(-)
diff --git a/debug_toolbar/locale/en/LC_MESSAGES/django.po b/debug_toolbar/locale/en/LC_MESSAGES/django.po
index 8fafee164..9dc155bef 100644
--- a/debug_toolbar/locale/en/LC_MESSAGES/django.po
+++ b/debug_toolbar/locale/en/LC_MESSAGES/django.po
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Django Debug Toolbar\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-20 17:23+0100\n"
+"POT-Creation-Date: 2024-08-06 07:12-0500\n"
"PO-Revision-Date: 2012-03-31 20:10+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
@@ -16,22 +16,46 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
-#: apps.py:15
+#: apps.py:18
msgid "Debug Toolbar"
msgstr ""
-#: panels/cache.py:180
+#: panels/alerts.py:67
+#, python-brace-format
+msgid ""
+"Form with id \"{form_id}\" contains file input, but does not have the "
+"attribute enctype=\"multipart/form-data\"."
+msgstr ""
+
+#: panels/alerts.py:70
+msgid ""
+"Form contains file input, but does not have the attribute "
+"enctype=\"multipart/form-data\"."
+msgstr ""
+
+#: panels/alerts.py:73
+#, python-brace-format
+msgid ""
+"Input element references form with id \"{form_id}\", but the form does not "
+"have the attribute enctype=\"multipart/form-data\"."
+msgstr ""
+
+#: panels/alerts.py:77
+msgid "Alerts"
+msgstr ""
+
+#: panels/cache.py:168
msgid "Cache"
msgstr ""
-#: panels/cache.py:186
+#: panels/cache.py:174
#, python-format
msgid "%(cache_calls)d call in %(time).2fms"
msgid_plural "%(cache_calls)d calls in %(time).2fms"
msgstr[0] ""
msgstr[1] ""
-#: panels/cache.py:195
+#: panels/cache.py:183
#, python-format
msgid "Cache calls from %(count)d backend"
msgid_plural "Cache calls from %(count)d backends"
@@ -42,7 +66,7 @@ msgstr[1] ""
msgid "Headers"
msgstr ""
-#: panels/history/panel.py:18 panels/history/panel.py:19
+#: panels/history/panel.py:19 panels/history/panel.py:20
msgid "History"
msgstr ""
@@ -50,7 +74,7 @@ msgstr ""
msgid "Profiling"
msgstr ""
-#: panels/redirects.py:14
+#: panels/redirects.py:17
msgid "Intercept redirects"
msgstr ""
@@ -58,11 +82,11 @@ msgstr ""
msgid "Request"
msgstr ""
-#: panels/request.py:36
+#: panels/request.py:38
msgid ""
msgstr ""
-#: panels/request.py:53
+#: panels/request.py:55
msgid ""
msgstr ""
@@ -93,151 +117,151 @@ msgstr[1] ""
msgid "Signals"
msgstr ""
-#: panels/sql/panel.py:23
-msgid "Autocommit"
-msgstr ""
-
-#: panels/sql/panel.py:24
+#: panels/sql/panel.py:30 panels/sql/panel.py:41
msgid "Read uncommitted"
msgstr ""
-#: panels/sql/panel.py:25
+#: panels/sql/panel.py:31 panels/sql/panel.py:43
msgid "Read committed"
msgstr ""
-#: panels/sql/panel.py:26
+#: panels/sql/panel.py:32 panels/sql/panel.py:45
msgid "Repeatable read"
msgstr ""
-#: panels/sql/panel.py:27
+#: panels/sql/panel.py:33 panels/sql/panel.py:47
msgid "Serializable"
msgstr ""
#: panels/sql/panel.py:39
+msgid "Autocommit"
+msgstr ""
+
+#: panels/sql/panel.py:61 panels/sql/panel.py:71
msgid "Idle"
msgstr ""
-#: panels/sql/panel.py:40
+#: panels/sql/panel.py:62 panels/sql/panel.py:72
msgid "Active"
msgstr ""
-#: panels/sql/panel.py:41
+#: panels/sql/panel.py:63 panels/sql/panel.py:73
msgid "In transaction"
msgstr ""
-#: panels/sql/panel.py:42
+#: panels/sql/panel.py:64 panels/sql/panel.py:74
msgid "In error"
msgstr ""
-#: panels/sql/panel.py:43
+#: panels/sql/panel.py:65 panels/sql/panel.py:75
msgid "Unknown"
msgstr ""
-#: panels/sql/panel.py:130
+#: panels/sql/panel.py:162
msgid "SQL"
msgstr ""
-#: panels/sql/panel.py:135
+#: panels/sql/panel.py:168
#, python-format
msgid "%(query_count)d query in %(sql_time).2fms"
msgid_plural "%(query_count)d queries in %(sql_time).2fms"
msgstr[0] ""
msgstr[1] ""
-#: panels/sql/panel.py:147
+#: panels/sql/panel.py:180
#, python-format
msgid "SQL queries from %(count)d connection"
msgid_plural "SQL queries from %(count)d connections"
msgstr[0] ""
msgstr[1] ""
-#: panels/staticfiles.py:84
+#: panels/staticfiles.py:82
#, python-format
msgid "Static files (%(num_found)s found, %(num_used)s used)"
msgstr ""
-#: panels/staticfiles.py:105
+#: panels/staticfiles.py:103
msgid "Static files"
msgstr ""
-#: panels/staticfiles.py:111
+#: panels/staticfiles.py:109
#, python-format
msgid "%(num_used)s file used"
msgid_plural "%(num_used)s files used"
msgstr[0] ""
msgstr[1] ""
-#: panels/templates/panel.py:143
+#: panels/templates/panel.py:101
msgid "Templates"
msgstr ""
-#: panels/templates/panel.py:148
+#: panels/templates/panel.py:106
#, python-format
msgid "Templates (%(num_templates)s rendered)"
msgstr ""
-#: panels/templates/panel.py:180
+#: panels/templates/panel.py:195
msgid "No origin"
msgstr ""
-#: panels/timer.py:25
+#: panels/timer.py:27
#, python-format
msgid "CPU: %(cum)0.2fms (%(total)0.2fms)"
msgstr ""
-#: panels/timer.py:30
+#: panels/timer.py:32
#, python-format
msgid "Total: %0.2fms"
msgstr ""
-#: panels/timer.py:36 templates/debug_toolbar/panels/history.html:9
+#: panels/timer.py:38 templates/debug_toolbar/panels/history.html:9
#: templates/debug_toolbar/panels/sql_explain.html:11
#: templates/debug_toolbar/panels/sql_profile.html:12
#: templates/debug_toolbar/panels/sql_select.html:11
msgid "Time"
msgstr ""
-#: panels/timer.py:44
+#: panels/timer.py:46
msgid "User CPU time"
msgstr ""
-#: panels/timer.py:44
+#: panels/timer.py:46
#, python-format
msgid "%(utime)0.3f msec"
msgstr ""
-#: panels/timer.py:45
+#: panels/timer.py:47
msgid "System CPU time"
msgstr ""
-#: panels/timer.py:45
+#: panels/timer.py:47
#, python-format
msgid "%(stime)0.3f msec"
msgstr ""
-#: panels/timer.py:46
+#: panels/timer.py:48
msgid "Total CPU time"
msgstr ""
-#: panels/timer.py:46
+#: panels/timer.py:48
#, python-format
msgid "%(total)0.3f msec"
msgstr ""
-#: panels/timer.py:47
+#: panels/timer.py:49
msgid "Elapsed time"
msgstr ""
-#: panels/timer.py:47
+#: panels/timer.py:49
#, python-format
msgid "%(total_time)0.3f msec"
msgstr ""
-#: panels/timer.py:49
+#: panels/timer.py:51
msgid "Context switches"
msgstr ""
-#: panels/timer.py:50
+#: panels/timer.py:52
#, python-format
msgid "%(vcsw)d voluntary, %(ivcsw)d involuntary"
msgstr ""
@@ -246,15 +270,19 @@ msgstr ""
msgid "Versions"
msgstr ""
-#: templates/debug_toolbar/base.html:22
+#: templates/debug_toolbar/base.html:23
msgid "Hide toolbar"
msgstr ""
-#: templates/debug_toolbar/base.html:22
+#: templates/debug_toolbar/base.html:23
msgid "Hide"
msgstr ""
-#: templates/debug_toolbar/base.html:29
+#: templates/debug_toolbar/base.html:25 templates/debug_toolbar/base.html:26
+msgid "Toggle Theme"
+msgstr ""
+
+#: templates/debug_toolbar/base.html:35
msgid "Show toolbar"
msgstr ""
@@ -266,6 +294,14 @@ msgstr ""
msgid "Enable for next and successive requests"
msgstr ""
+#: templates/debug_toolbar/panels/alerts.html:4
+msgid "Alerts found"
+msgstr ""
+
+#: templates/debug_toolbar/panels/alerts.html:11
+msgid "No alerts found"
+msgstr ""
+
#: templates/debug_toolbar/panels/cache.html:2
msgid "Summary"
msgstr ""
From c44e6683312ede444215bc149d5b846eebd15a90 Mon Sep 17 00:00:00 2001
From: Tim Schilling
Date: Tue, 6 Aug 2024 07:20:07 -0500
Subject: [PATCH 20/33] Update the transifex contributing docs and client
version.
---
.tx/config | 14 ++++++++------
docs/contributing.rst | 3 +++
requirements_dev.txt | 1 -
3 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/.tx/config b/.tx/config
index 5c9ecc129..15e624db3 100644
--- a/.tx/config
+++ b/.tx/config
@@ -1,8 +1,10 @@
[main]
-host = https://www.transifex.com
-lang_map = sr@latin:sr_Latn
+host = https://www.transifex.com
+lang_map = sr@latin: sr_Latn
-[django-debug-toolbar.main]
-file_filter = debug_toolbar/locale//LC_MESSAGES/django.po
-source_file = debug_toolbar/locale/en/LC_MESSAGES/django.po
-source_lang = en
+[o:django-debug-toolbar:p:django-debug-toolbar:r:main]
+file_filter = debug_toolbar/locale//LC_MESSAGES/django.po
+source_file = debug_toolbar/locale/en/LC_MESSAGES/django.po
+source_lang = en
+replace_edited_strings = false
+keep_translations = false
diff --git a/docs/contributing.rst b/docs/contributing.rst
index c94d9e74c..832ef4679 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -172,6 +172,9 @@ Prior to a release, the English ``.po`` file must be updated with ``make
translatable_strings`` and pushed to Transifex. Once translators have done
their job, ``.po`` files must be downloaded with ``make update_translations``.
+You will need to
+`install the Transifex CLI `_.
+
To publish a release you have to be a `django-debug-toolbar project lead at
Jazzband `__.
diff --git a/requirements_dev.txt b/requirements_dev.txt
index e66eba5c6..d28391b7c 100644
--- a/requirements_dev.txt
+++ b/requirements_dev.txt
@@ -26,4 +26,3 @@ sphinx-rtd-theme>1
# Other tools
pre-commit
-transifex-client
From 1bbdf387cf278ae158a8553a7c356b31ca62302e Mon Sep 17 00:00:00 2001
From: Tim Schilling
Date: Tue, 6 Aug 2024 07:21:45 -0500
Subject: [PATCH 21/33] Update translatable strings
---
debug_toolbar/locale/bg/LC_MESSAGES/django.mo | Bin 0 -> 11903 bytes
debug_toolbar/locale/bg/LC_MESSAGES/django.po | 705 ++++++++++++++++++
debug_toolbar/locale/ca/LC_MESSAGES/django.mo | Bin 2875 -> 2620 bytes
debug_toolbar/locale/ca/LC_MESSAGES/django.po | 148 ++--
debug_toolbar/locale/cs/LC_MESSAGES/django.mo | Bin 9526 -> 10854 bytes
debug_toolbar/locale/cs/LC_MESSAGES/django.po | 221 +++---
debug_toolbar/locale/de/LC_MESSAGES/django.mo | Bin 10180 -> 9839 bytes
debug_toolbar/locale/de/LC_MESSAGES/django.po | 159 ++--
debug_toolbar/locale/es/LC_MESSAGES/django.mo | Bin 9967 -> 10073 bytes
debug_toolbar/locale/es/LC_MESSAGES/django.po | 172 +++--
debug_toolbar/locale/fa/LC_MESSAGES/django.mo | Bin 6597 -> 10013 bytes
debug_toolbar/locale/fa/LC_MESSAGES/django.po | 147 ++--
debug_toolbar/locale/fi/LC_MESSAGES/django.mo | Bin 4659 -> 4200 bytes
debug_toolbar/locale/fi/LC_MESSAGES/django.po | 162 ++--
debug_toolbar/locale/fr/LC_MESSAGES/django.mo | Bin 10291 -> 10446 bytes
debug_toolbar/locale/fr/LC_MESSAGES/django.po | 178 +++--
debug_toolbar/locale/he/LC_MESSAGES/django.mo | Bin 1562 -> 1354 bytes
debug_toolbar/locale/he/LC_MESSAGES/django.po | 158 ++--
debug_toolbar/locale/id/LC_MESSAGES/django.mo | Bin 2948 -> 2549 bytes
debug_toolbar/locale/id/LC_MESSAGES/django.po | 152 ++--
debug_toolbar/locale/it/LC_MESSAGES/django.mo | Bin 8532 -> 8545 bytes
debug_toolbar/locale/it/LC_MESSAGES/django.po | 167 +++--
debug_toolbar/locale/ja/LC_MESSAGES/django.mo | Bin 3365 -> 3035 bytes
debug_toolbar/locale/ja/LC_MESSAGES/django.po | 137 ++--
debug_toolbar/locale/ko/LC_MESSAGES/django.mo | Bin 0 -> 8483 bytes
debug_toolbar/locale/ko/LC_MESSAGES/django.po | 690 +++++++++++++++++
debug_toolbar/locale/nl/LC_MESSAGES/django.mo | Bin 4274 -> 3956 bytes
debug_toolbar/locale/nl/LC_MESSAGES/django.po | 156 ++--
debug_toolbar/locale/pl/LC_MESSAGES/django.mo | Bin 4810 -> 5609 bytes
debug_toolbar/locale/pl/LC_MESSAGES/django.po | 212 +++---
debug_toolbar/locale/pt/LC_MESSAGES/django.mo | Bin 3030 -> 2935 bytes
debug_toolbar/locale/pt/LC_MESSAGES/django.po | 169 +++--
.../locale/pt_BR/LC_MESSAGES/django.mo | Bin 9018 -> 9026 bytes
.../locale/pt_BR/LC_MESSAGES/django.po | 200 +++--
debug_toolbar/locale/ru/LC_MESSAGES/django.mo | Bin 11888 -> 11468 bytes
debug_toolbar/locale/ru/LC_MESSAGES/django.po | 156 ++--
debug_toolbar/locale/sk/LC_MESSAGES/django.mo | Bin 9984 -> 9176 bytes
debug_toolbar/locale/sk/LC_MESSAGES/django.po | 240 +++---
.../locale/sv_SE/LC_MESSAGES/django.mo | Bin 2362 -> 2132 bytes
.../locale/sv_SE/LC_MESSAGES/django.po | 152 ++--
debug_toolbar/locale/uk/LC_MESSAGES/django.mo | Bin 2001 -> 11278 bytes
debug_toolbar/locale/uk/LC_MESSAGES/django.po | 387 +++++-----
.../locale/zh_CN/LC_MESSAGES/django.mo | Bin 8538 -> 8067 bytes
.../locale/zh_CN/LC_MESSAGES/django.po | 162 ++--
44 files changed, 3558 insertions(+), 1472 deletions(-)
create mode 100644 debug_toolbar/locale/bg/LC_MESSAGES/django.mo
create mode 100644 debug_toolbar/locale/bg/LC_MESSAGES/django.po
create mode 100644 debug_toolbar/locale/ko/LC_MESSAGES/django.mo
create mode 100644 debug_toolbar/locale/ko/LC_MESSAGES/django.po
diff --git a/debug_toolbar/locale/bg/LC_MESSAGES/django.mo b/debug_toolbar/locale/bg/LC_MESSAGES/django.mo
new file mode 100644
index 0000000000000000000000000000000000000000..ae59298d58f18aee1a3c23718f3020139818a32e
GIT binary patch
literal 11903
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
Q&-<&j<*NBrvcb{+0uvOc0ssI2
literal 0
HcmV?d00001
diff --git a/debug_toolbar/locale/bg/LC_MESSAGES/django.po b/debug_toolbar/locale/bg/LC_MESSAGES/django.po
new file mode 100644
index 000000000..d9fd766fe
--- /dev/null
+++ b/debug_toolbar/locale/bg/LC_MESSAGES/django.po
@@ -0,0 +1,705 @@
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+#
+# Translators:
+# arneatec , 2022
+msgid ""
+msgstr ""
+"Project-Id-Version: Django Debug Toolbar\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2024-08-06 07:12-0500\n"
+"PO-Revision-Date: 2010-11-30 00:00+0000\n"
+"Last-Translator: arneatec , 2022\n"
+"Language-Team: Bulgarian (http://app.transifex.com/django-debug-toolbar/django-debug-toolbar/language/bg/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: bg\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: apps.py:18
+msgid "Debug Toolbar"
+msgstr "Debug Toolbar"
+
+#: panels/alerts.py:67
+#, python-brace-format
+msgid ""
+"Form with id \"{form_id}\" contains file input, but does not have the "
+"attribute enctype=\"multipart/form-data\"."
+msgstr ""
+
+#: panels/alerts.py:70
+msgid ""
+"Form contains file input, but does not have the attribute "
+"enctype=\"multipart/form-data\"."
+msgstr ""
+
+#: panels/alerts.py:73
+#, python-brace-format
+msgid ""
+"Input element references form with id \"{form_id}\", but the form does not "
+"have the attribute enctype=\"multipart/form-data\"."
+msgstr ""
+
+#: panels/alerts.py:77
+msgid "Alerts"
+msgstr ""
+
+#: panels/cache.py:168
+msgid "Cache"
+msgstr "Кеш"
+
+#: panels/cache.py:174
+#, python-format
+msgid "%(cache_calls)d call in %(time).2fms"
+msgid_plural "%(cache_calls)d calls in %(time).2fms"
+msgstr[0] "%(cache_calls)d извикване за %(time).2fms"
+msgstr[1] "%(cache_calls)d извиквания за %(time).2fms"
+
+#: panels/cache.py:183
+#, python-format
+msgid "Cache calls from %(count)d backend"
+msgid_plural "Cache calls from %(count)d backends"
+msgstr[0] "Извиквания на кеша от %(count)d бекенд"
+msgstr[1] "Извиквания на кеша от %(count)d бекенда"
+
+#: panels/headers.py:31
+msgid "Headers"
+msgstr "Хедъри"
+
+#: panels/history/panel.py:19 panels/history/panel.py:20
+msgid "History"
+msgstr "История"
+
+#: panels/profiling.py:140
+msgid "Profiling"
+msgstr "Профилиране"
+
+#: panels/redirects.py:17
+msgid "Intercept redirects"
+msgstr "Прехвани пренасочвания"
+
+#: panels/request.py:16
+msgid "Request"
+msgstr "Заявка"
+
+#: panels/request.py:38
+msgid ""
+msgstr ""
+
+#: panels/request.py:55
+msgid ""
+msgstr ""
+
+#: panels/settings.py:17
+msgid "Settings"
+msgstr "Настройки"
+
+#: panels/settings.py:20
+#, python-format
+msgid "Settings from %s"
+msgstr "Настройки от %s"
+
+#: panels/signals.py:57
+#, python-format
+msgid "%(num_receivers)d receiver of 1 signal"
+msgid_plural "%(num_receivers)d receivers of 1 signal"
+msgstr[0] "%(num_receivers)d получател на 1 сигнал"
+msgstr[1] "%(num_receivers)d получатели на 1 сигнал"
+
+#: panels/signals.py:62
+#, python-format
+msgid "%(num_receivers)d receiver of %(num_signals)d signals"
+msgid_plural "%(num_receivers)d receivers of %(num_signals)d signals"
+msgstr[0] "%(num_receivers)d приемник на %(num_signals)d сигнала"
+msgstr[1] "%(num_receivers)d приемника на %(num_signals)d сигнала"
+
+#: panels/signals.py:67
+msgid "Signals"
+msgstr "Сигнали"
+
+#: panels/sql/panel.py:30 panels/sql/panel.py:41
+msgid "Read uncommitted"
+msgstr "Read uncommitted"
+
+#: panels/sql/panel.py:31 panels/sql/panel.py:43
+msgid "Read committed"
+msgstr "Read committed"
+
+#: panels/sql/panel.py:32 panels/sql/panel.py:45
+msgid "Repeatable read"
+msgstr "Repeatable read"
+
+#: panels/sql/panel.py:33 panels/sql/panel.py:47
+msgid "Serializable"
+msgstr "Serializable"
+
+#: panels/sql/panel.py:39
+msgid "Autocommit"
+msgstr "Autocommit"
+
+#: panels/sql/panel.py:61 panels/sql/panel.py:71
+msgid "Idle"
+msgstr "Незает"
+
+#: panels/sql/panel.py:62 panels/sql/panel.py:72
+msgid "Active"
+msgstr "Активен"
+
+#: panels/sql/panel.py:63 panels/sql/panel.py:73
+msgid "In transaction"
+msgstr "В транзакция"
+
+#: panels/sql/panel.py:64 panels/sql/panel.py:74
+msgid "In error"
+msgstr "В грешка"
+
+#: panels/sql/panel.py:65 panels/sql/panel.py:75
+msgid "Unknown"
+msgstr "Непознато"
+
+#: panels/sql/panel.py:162
+msgid "SQL"
+msgstr "SQL"
+
+#: panels/sql/panel.py:168
+#, python-format
+msgid "%(query_count)d query in %(sql_time).2fms"
+msgid_plural "%(query_count)d queries in %(sql_time).2fms"
+msgstr[0] "%(query_count)d заявка за %(sql_time).2fms"
+msgstr[1] "%(query_count)d заявки за %(sql_time).2fms"
+
+#: panels/sql/panel.py:180
+#, python-format
+msgid "SQL queries from %(count)d connection"
+msgid_plural "SQL queries from %(count)d connections"
+msgstr[0] "SQL заявки от %(count)d връзка"
+msgstr[1] "SQL заявки от %(count)d връзки"
+
+#: panels/staticfiles.py:82
+#, python-format
+msgid "Static files (%(num_found)s found, %(num_used)s used)"
+msgstr "Статични файлове (%(num_found)s открити, %(num_used)s използвани)"
+
+#: panels/staticfiles.py:103
+msgid "Static files"
+msgstr "Статични файлове"
+
+#: panels/staticfiles.py:109
+#, python-format
+msgid "%(num_used)s file used"
+msgid_plural "%(num_used)s files used"
+msgstr[0] "%(num_used)s файл използван"
+msgstr[1] "%(num_used)s файла са използвани"
+
+#: panels/templates/panel.py:101
+msgid "Templates"
+msgstr "Шаблони"
+
+#: panels/templates/panel.py:106
+#, python-format
+msgid "Templates (%(num_templates)s rendered)"
+msgstr "Шаблони (%(num_templates)s рендерирани)"
+
+#: panels/templates/panel.py:195
+msgid "No origin"
+msgstr "Няма произход"
+
+#: panels/timer.py:27
+#, python-format
+msgid "CPU: %(cum)0.2fms (%(total)0.2fms)"
+msgstr "Процесор: %(cum)0.2fms (%(total)0.2fms)"
+
+#: panels/timer.py:32
+#, python-format
+msgid "Total: %0.2fms"
+msgstr "Общо: %0.2fms"
+
+#: panels/timer.py:38 templates/debug_toolbar/panels/history.html:9
+#: templates/debug_toolbar/panels/sql_explain.html:11
+#: templates/debug_toolbar/panels/sql_profile.html:12
+#: templates/debug_toolbar/panels/sql_select.html:11
+msgid "Time"
+msgstr "Време"
+
+#: panels/timer.py:46
+msgid "User CPU time"
+msgstr "Потребителско процесорно време "
+
+#: panels/timer.py:46
+#, python-format
+msgid "%(utime)0.3f msec"
+msgstr "%(utime)0.3f msec"
+
+#: panels/timer.py:47
+msgid "System CPU time"
+msgstr "Системно процесорно време"
+
+#: panels/timer.py:47
+#, python-format
+msgid "%(stime)0.3f msec"
+msgstr "%(stime)0.3f msec"
+
+#: panels/timer.py:48
+msgid "Total CPU time"
+msgstr "Общо процесорно време"
+
+#: panels/timer.py:48
+#, python-format
+msgid "%(total)0.3f msec"
+msgstr "%(total)0.3f msec"
+
+#: panels/timer.py:49
+msgid "Elapsed time"
+msgstr "Изминало време"
+
+#: panels/timer.py:49
+#, python-format
+msgid "%(total_time)0.3f msec"
+msgstr "%(total_time)0.3f msec"
+
+#: panels/timer.py:51
+msgid "Context switches"
+msgstr "Контекстни превключвания"
+
+#: panels/timer.py:52
+#, python-format
+msgid "%(vcsw)d voluntary, %(ivcsw)d involuntary"
+msgstr "%(vcsw)d волеви, %(ivcsw)d неволеви"
+
+#: panels/versions.py:19
+msgid "Versions"
+msgstr "Версии"
+
+#: templates/debug_toolbar/base.html:23
+msgid "Hide toolbar"
+msgstr "Скрий лента с инструменти "
+
+#: templates/debug_toolbar/base.html:23
+msgid "Hide"
+msgstr "Скрий"
+
+#: templates/debug_toolbar/base.html:25 templates/debug_toolbar/base.html:26
+msgid "Toggle Theme"
+msgstr ""
+
+#: templates/debug_toolbar/base.html:35
+msgid "Show toolbar"
+msgstr "Покажи лента с инструменти"
+
+#: templates/debug_toolbar/includes/panel_button.html:4
+msgid "Disable for next and successive requests"
+msgstr "Деактивирай за следващо и всички последващи заявки"
+
+#: templates/debug_toolbar/includes/panel_button.html:4
+msgid "Enable for next and successive requests"
+msgstr "Активирай за следващо и всички последващи заявки"
+
+#: templates/debug_toolbar/panels/alerts.html:4
+msgid "Alerts found"
+msgstr ""
+
+#: templates/debug_toolbar/panels/alerts.html:11
+msgid "No alerts found"
+msgstr ""
+
+#: templates/debug_toolbar/panels/cache.html:2
+msgid "Summary"
+msgstr "Обобщение"
+
+#: templates/debug_toolbar/panels/cache.html:6
+msgid "Total calls"
+msgstr "Общо извиквания"
+
+#: templates/debug_toolbar/panels/cache.html:7
+msgid "Total time"
+msgstr "Общо време"
+
+#: templates/debug_toolbar/panels/cache.html:8
+msgid "Cache hits"
+msgstr "Кеш успехи"
+
+#: templates/debug_toolbar/panels/cache.html:9
+msgid "Cache misses"
+msgstr "Кеш неуспехи"
+
+#: templates/debug_toolbar/panels/cache.html:21
+msgid "Commands"
+msgstr "Команди"
+
+#: templates/debug_toolbar/panels/cache.html:39
+msgid "Calls"
+msgstr "Извиквания"
+
+#: templates/debug_toolbar/panels/cache.html:43
+#: templates/debug_toolbar/panels/sql.html:36
+msgid "Time (ms)"
+msgstr "Време (ms)"
+
+#: templates/debug_toolbar/panels/cache.html:44
+msgid "Type"
+msgstr "Вид"
+
+#: templates/debug_toolbar/panels/cache.html:45
+#: templates/debug_toolbar/panels/request.html:8
+msgid "Arguments"
+msgstr "Аргументи"
+
+#: templates/debug_toolbar/panels/cache.html:46
+#: templates/debug_toolbar/panels/request.html:9
+msgid "Keyword arguments"
+msgstr "Аргументи с ключови думи"
+
+#: templates/debug_toolbar/panels/cache.html:47
+msgid "Backend"
+msgstr "Бекенд"
+
+#: templates/debug_toolbar/panels/headers.html:3
+msgid "Request headers"
+msgstr "Хедъри на заявката"
+
+#: templates/debug_toolbar/panels/headers.html:8
+#: templates/debug_toolbar/panels/headers.html:27
+#: templates/debug_toolbar/panels/headers.html:48
+msgid "Key"
+msgstr "Ключ"
+
+#: templates/debug_toolbar/panels/headers.html:9
+#: templates/debug_toolbar/panels/headers.html:28
+#: templates/debug_toolbar/panels/headers.html:49
+#: templates/debug_toolbar/panels/history_tr.html:23
+#: templates/debug_toolbar/panels/request_variables.html:12
+#: templates/debug_toolbar/panels/settings.html:6
+#: templates/debug_toolbar/panels/timer.html:11
+msgid "Value"
+msgstr "Стойност"
+
+#: templates/debug_toolbar/panels/headers.html:22
+msgid "Response headers"
+msgstr "Хедъри на отговора"
+
+#: templates/debug_toolbar/panels/headers.html:41
+msgid "WSGI environ"
+msgstr "WSGI environ"
+
+#: templates/debug_toolbar/panels/headers.html:43
+msgid ""
+"Since the WSGI environ inherits the environment of the server, only a "
+"significant subset is shown below."
+msgstr "Понеже WSGI environ наследява средата на сървъра, е показана само важната част от него по-долу."
+
+#: templates/debug_toolbar/panels/history.html:10
+msgid "Method"
+msgstr "Метод"
+
+#: templates/debug_toolbar/panels/history.html:11
+#: templates/debug_toolbar/panels/staticfiles.html:43
+msgid "Path"
+msgstr "Път"
+
+#: templates/debug_toolbar/panels/history.html:12
+msgid "Request Variables"
+msgstr "Променливи на зявката"
+
+#: templates/debug_toolbar/panels/history.html:13
+msgid "Status"
+msgstr "Състояние"
+
+#: templates/debug_toolbar/panels/history.html:14
+#: templates/debug_toolbar/panels/sql.html:37
+msgid "Action"
+msgstr "Действие"
+
+#: templates/debug_toolbar/panels/history_tr.html:22
+#: templates/debug_toolbar/panels/request_variables.html:11
+msgid "Variable"
+msgstr "Променлива"
+
+#: templates/debug_toolbar/panels/profiling.html:5
+msgid "Call"
+msgstr "Извикване"
+
+#: templates/debug_toolbar/panels/profiling.html:6
+msgid "CumTime"
+msgstr "КумулативноВреме"
+
+#: templates/debug_toolbar/panels/profiling.html:7
+#: templates/debug_toolbar/panels/profiling.html:9
+msgid "Per"
+msgstr "За"
+
+#: templates/debug_toolbar/panels/profiling.html:8
+msgid "TotTime"
+msgstr "ОбщоВреме"
+
+#: templates/debug_toolbar/panels/profiling.html:10
+msgid "Count"
+msgstr "Брой"
+
+#: templates/debug_toolbar/panels/request.html:3
+msgid "View information"
+msgstr "Информация за изгледа"
+
+#: templates/debug_toolbar/panels/request.html:7
+msgid "View function"
+msgstr "Функция на изгледа"
+
+#: templates/debug_toolbar/panels/request.html:10
+msgid "URL name"
+msgstr "Име на URL"
+
+#: templates/debug_toolbar/panels/request.html:24
+msgid "Cookies"
+msgstr "Бисквитки"
+
+#: templates/debug_toolbar/panels/request.html:27
+msgid "No cookies"
+msgstr "Няма бисквитки"
+
+#: templates/debug_toolbar/panels/request.html:31
+msgid "Session data"
+msgstr "Данни на сесията"
+
+#: templates/debug_toolbar/panels/request.html:34
+msgid "No session data"
+msgstr "Няма данни от сесията"
+
+#: templates/debug_toolbar/panels/request.html:38
+msgid "GET data"
+msgstr "GET данни"
+
+#: templates/debug_toolbar/panels/request.html:41
+msgid "No GET data"
+msgstr "Няма GET данни"
+
+#: templates/debug_toolbar/panels/request.html:45
+msgid "POST data"
+msgstr "POST данни"
+
+#: templates/debug_toolbar/panels/request.html:48
+msgid "No POST data"
+msgstr "Няма POST данни"
+
+#: templates/debug_toolbar/panels/settings.html:5
+msgid "Setting"
+msgstr "Настройка"
+
+#: templates/debug_toolbar/panels/signals.html:5
+msgid "Signal"
+msgstr "Сигнал"
+
+#: templates/debug_toolbar/panels/signals.html:6
+msgid "Receivers"
+msgstr "Получатели"
+
+#: templates/debug_toolbar/panels/sql.html:6
+#, python-format
+msgid "%(num)s query"
+msgid_plural "%(num)s queries"
+msgstr[0] "%(num)s заявка"
+msgstr[1] "%(num)s заявки"
+
+#: templates/debug_toolbar/panels/sql.html:8
+#, python-format
+msgid ""
+"including %(count)s similar"
+msgstr "Включва %(count)s подобни"
+
+#: templates/debug_toolbar/panels/sql.html:12
+#, python-format
+msgid ""
+"and %(dupes)s duplicates"
+msgstr "и %(dupes)s повторени"
+
+#: templates/debug_toolbar/panels/sql.html:34
+msgid "Query"
+msgstr "Заявка"
+
+#: templates/debug_toolbar/panels/sql.html:35
+#: templates/debug_toolbar/panels/timer.html:36
+msgid "Timeline"
+msgstr "Във времето"
+
+#: templates/debug_toolbar/panels/sql.html:52
+#, python-format
+msgid "%(count)s similar queries."
+msgstr "%(count)s подобни заявки."
+
+#: templates/debug_toolbar/panels/sql.html:58
+#, python-format
+msgid "Duplicated %(dupes)s times."
+msgstr "Повторени %(dupes)s пъти."
+
+#: templates/debug_toolbar/panels/sql.html:95
+msgid "Connection:"
+msgstr "Връзка:"
+
+#: templates/debug_toolbar/panels/sql.html:97
+msgid "Isolation level:"
+msgstr "Изолационно ниво:"
+
+#: templates/debug_toolbar/panels/sql.html:100
+msgid "Transaction status:"
+msgstr "Статус на транзакцията:"
+
+#: templates/debug_toolbar/panels/sql.html:114
+msgid "(unknown)"
+msgstr "(неясен)"
+
+#: templates/debug_toolbar/panels/sql.html:123
+msgid "No SQL queries were recorded during this request."
+msgstr "Не са записани никакви SQL заявки по време на тази заявка."
+
+#: templates/debug_toolbar/panels/sql_explain.html:4
+msgid "SQL explained"
+msgstr "SQL разяснен"
+
+#: templates/debug_toolbar/panels/sql_explain.html:9
+#: templates/debug_toolbar/panels/sql_profile.html:10
+#: templates/debug_toolbar/panels/sql_select.html:9
+msgid "Executed SQL"
+msgstr "Изпълнен SQL"
+
+#: templates/debug_toolbar/panels/sql_explain.html:13
+#: templates/debug_toolbar/panels/sql_profile.html:14
+#: templates/debug_toolbar/panels/sql_select.html:13
+msgid "Database"
+msgstr "База данни"
+
+#: templates/debug_toolbar/panels/sql_profile.html:4
+msgid "SQL profiled"
+msgstr "SQL профилиран"
+
+#: templates/debug_toolbar/panels/sql_profile.html:37
+msgid "Error"
+msgstr "Грешка"
+
+#: templates/debug_toolbar/panels/sql_select.html:4
+msgid "SQL selected"
+msgstr "Избран SQL"
+
+#: templates/debug_toolbar/panels/sql_select.html:36
+msgid "Empty set"
+msgstr "Празно множество"
+
+#: templates/debug_toolbar/panels/staticfiles.html:3
+msgid "Static file path"
+msgid_plural "Static file paths"
+msgstr[0] "Път към статичен файл"
+msgstr[1] "Пътища към статични файлове"
+
+#: templates/debug_toolbar/panels/staticfiles.html:7
+#, python-format
+msgid "(prefix %(prefix)s)"
+msgstr "(префикс %(prefix)s)"
+
+#: templates/debug_toolbar/panels/staticfiles.html:11
+#: templates/debug_toolbar/panels/staticfiles.html:22
+#: templates/debug_toolbar/panels/staticfiles.html:34
+#: templates/debug_toolbar/panels/templates.html:10
+#: templates/debug_toolbar/panels/templates.html:30
+#: templates/debug_toolbar/panels/templates.html:47
+msgid "None"
+msgstr "None"
+
+#: templates/debug_toolbar/panels/staticfiles.html:14
+msgid "Static file app"
+msgid_plural "Static file apps"
+msgstr[0] "Приложение статичен файл"
+msgstr[1] "Приложения статично файлове"
+
+#: templates/debug_toolbar/panels/staticfiles.html:25
+msgid "Static file"
+msgid_plural "Static files"
+msgstr[0] "Статичен файл"
+msgstr[1] "Статични файлове"
+
+#: templates/debug_toolbar/panels/staticfiles.html:39
+#, python-format
+msgid "%(payload_count)s file"
+msgid_plural "%(payload_count)s files"
+msgstr[0] "%(payload_count)s файл"
+msgstr[1] "%(payload_count)s файла"
+
+#: templates/debug_toolbar/panels/staticfiles.html:44
+msgid "Location"
+msgstr "Местоположение"
+
+#: templates/debug_toolbar/panels/template_source.html:4
+msgid "Template source:"
+msgstr "Произход на шаблона:"
+
+#: templates/debug_toolbar/panels/templates.html:2
+msgid "Template path"
+msgid_plural "Template paths"
+msgstr[0] "Път към шаблон"
+msgstr[1] "Пътища към шаблони"
+
+#: templates/debug_toolbar/panels/templates.html:13
+msgid "Template"
+msgid_plural "Templates"
+msgstr[0] "Шаблон"
+msgstr[1] "Шаблони"
+
+#: templates/debug_toolbar/panels/templates.html:22
+#: templates/debug_toolbar/panels/templates.html:40
+msgid "Toggle context"
+msgstr "Превключи контекста"
+
+#: templates/debug_toolbar/panels/templates.html:33
+msgid "Context processor"
+msgid_plural "Context processors"
+msgstr[0] "Контекстен процесор"
+msgstr[1] "Контекстни процесори"
+
+#: templates/debug_toolbar/panels/timer.html:2
+msgid "Resource usage"
+msgstr "Използване на ресурси"
+
+#: templates/debug_toolbar/panels/timer.html:10
+msgid "Resource"
+msgstr "Ресурс"
+
+#: templates/debug_toolbar/panels/timer.html:26
+msgid "Browser timing"
+msgstr "Време в браузъра"
+
+#: templates/debug_toolbar/panels/timer.html:35
+msgid "Timing attribute"
+msgstr "Атрибут на измерването"
+
+#: templates/debug_toolbar/panels/timer.html:37
+msgid "Milliseconds since navigation start (+length)"
+msgstr "Милисекунди от началото на навигацията (+дължината)"
+
+#: templates/debug_toolbar/panels/versions.html:10
+msgid "Package"
+msgstr "Пакет"
+
+#: templates/debug_toolbar/panels/versions.html:11
+msgid "Name"
+msgstr "Име"
+
+#: templates/debug_toolbar/panels/versions.html:12
+msgid "Version"
+msgstr "Версия"
+
+#: templates/debug_toolbar/redirect.html:10
+msgid "Location:"
+msgstr "Местоположение:"
+
+#: templates/debug_toolbar/redirect.html:12
+msgid ""
+"The Django Debug Toolbar has intercepted a redirect to the above URL for "
+"debug viewing purposes. You can click the above link to continue with the "
+"redirect as normal."
+msgstr "Django Debug Toolbar прехвана пренасочване към горния URL с цел преглед за отстраняване на грешки /дебъг/. Можете да кликнете върху връзката по-горе, за да продължите с пренасочването по нормалния начин."
+
+#: views.py:16
+msgid ""
+"Data for this panel isn't available anymore. Please reload the page and "
+"retry."
+msgstr "Данните за този панел вече не са налични. Моля, презаредете страницата и опитайте отново. "
diff --git a/debug_toolbar/locale/ca/LC_MESSAGES/django.mo b/debug_toolbar/locale/ca/LC_MESSAGES/django.mo
index fb52f10ea7ece01aa633d924692c04ede2a188fa..c7e63dbe45af833d8f6cf425d775c0bf9fc1bcbd 100644
GIT binary patch
delta 1398
zcmX|>OGuPa6vwamn$a>fvoy2MeC1=N&sWe8y@W(^;leCvQJ>SKL!%?(6a|J0p+yh`
zgKdK70kv=uBosXsMNk`yiguNY5Q3;S(Tj-s{bz1ozW@E5bMC$8o_p^w_sbuYO)Zq>
z%oy4hRE6fVjOm4w*>tqaImY<25RCZs03H-_)R;0$HpH*-N-XL{@U^_R6&bS1%0vpSE&4dp!UmS
zaUuJgB8&o933bAHsD+(S6SqRvm|ai_dThMk`UhY!aSz_$`4UitS27vXG(xQpLgnwY
zem9)bgkB7>AM%;~bSmgD)JcxP74SGz;%TUa=dFJMuEf6vm1hpFg7=^{d=7P>cToA>
zL*@VEWYxe;K;29TD)DZp`8`nc_CggrU^xU=0qTSwq4NBK%JbLy1vo0G7;3``
z>({^%{N^bPo@}YD$6ANFkSf;V2GoJnv{^0EW}DDvq#Nr*q%w8LMQW89qz}}Jy%Fg!
zYAr|w==W#p)zNe{dbbLs>(fb_k^UQMP$T-^sxiuuZb2tg)Bi^kT8r9|S}+5%!LrP<
zEyD)mU~pTeG!sa_qcu$cV;NeL>dJM>B4bBPw-+9X(8prwZXz|AJ5dr3d&y{g%=B3!
zG*_FK$QpD5ZEb-L*KysD>$bSGf<`BPTVOa(v~f8sCf5PhVZC
Z$$z$N-%vE{g`%#szF`{v)1^$#Z)kH`Q3
literal 2875
zcmZ9MTWB6d6vxL}js3J%Ypd1Pc4}{l?dD6;M3XO#G}qpeHkYq?5roO^WV7w=?B`x`
z5&C9*QG5^;(FaiwrC=YdzKAa+`XGY(Ao$?rNx?gaB1KUA|92;8>#%2jd(O%K{dbzl#8GdO5@99#>10&D`OK|JCyYxk@kfE{FjXYDV6x556JwO_RQyCB!O407L(t^HH*cIaP$bonO`kN6E8_xTf~
z|Nnqow+TUTolTb8K(4nNq(3bn=XF{80LXQZfL!+k$n_>buJb6!eO!?9LXh7#?D#o5
ze%{)j1@VYi(DD1%EiZsv_Z^V_d|>sUjp%n_t9~m
z55djgXCOin--GnySCHrP7s&Ph1{r?^AJM+matFxyyFmJP0OUG7AouMDIe!G?yyGC_
znX*(M_m4sPe;(xb&wz~cc@U3y86DSq!|E46`t_dGKLWY`=OEAf8<6q;2y&e(ARh6r
z)z@JX{n-F=zb#gm;GNK0KpgXGgIYAsW!nqk{#zj(kev|5(E_PL_CuN>E3F+b5^@iO
z{|@@{|JG#<%nxH>I|Okc2O({c-H-<%{P(aiXPb(*GS5AD?}Y4t;MXJ`fUq$KY#SlF
zAls>+-4D4J!d$Q&fZPqiaToap#6Adf*-8bC_uyej4YCEo_7J2OvIoNZ#~gM;*zRN3
zoSU;IUN9}9-_3&96qwgyK)Gj&P8&}QDtAt!55uBM#o(MWMnenZ6a#S-DdWK$!&)p;
z!+UNrF{CmzqcCSURE<=7G7BOoNfIYwcu~7~2HVucs5q*Xr;}714Ln_RGK=GIMkV5y
zky)Zls!IP(=p`|#=dt-{?5e`$m6sY!zKnF5Dqp8m{J{8PtTc#|3R|Cy<&ojK^xzlY
z$4^bIDn^TOorsBCCre^dyE>SsN0a*TT&EeB#(CmuL3gKg5~whELd}FQ=q%$#mZ_MU
zix*b?p9*}VLQw)^Ig*79>N;wKDubVOri7hrj?$LmEezmHJPke862CoVl*aj<)tr
zr>)cJ=#uR{wXTEv+t4bbD$Sfaj}x)SNlo@IMM$M9`*S}}kwtk(m6ldzEr+Ad#nw3S
zAHm1Q&vCR)U8|@j2XTg>GO~Ft%Nn(6bzxzlwYVw4tX^z&t+{`#O4M`P$cP|$(CEiS($29vclbvmmX@i&UP9@kk=>^_8QhEoVQNX3vwLg4iXj{0h4vuKc^*}%tH
zl`dbWjm1oPa&3_C53Ve+(hKm%k>-&Y$0f^xFvR%LI8ipMMWv4}zik4AdljLkct%Wk
tQP#H3-SPx&(Q~vMxTflZM$RBsZV4+Nzt-z3fBDiim9KN8)s}t{*?;qwWiJ2#
diff --git a/debug_toolbar/locale/ca/LC_MESSAGES/django.po b/debug_toolbar/locale/ca/LC_MESSAGES/django.po
index bdeaffd7e..393b74bc1 100644
--- a/debug_toolbar/locale/ca/LC_MESSAGES/django.po
+++ b/debug_toolbar/locale/ca/LC_MESSAGES/django.po
@@ -3,38 +3,61 @@
#
#
# Translators:
-# Libre El Chaval , 2013
+# el_libre como el chaval , 2013
msgid ""
msgstr ""
"Project-Id-Version: Django Debug Toolbar\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-20 17:23+0100\n"
-"PO-Revision-Date: 2014-04-25 19:53+0000\n"
-"Last-Translator: Aymeric Augustin \n"
-"Language-Team: Catalan (http://www.transifex.com/projects/p/django-debug-"
-"toolbar/language/ca/)\n"
-"Language: ca\n"
+"POT-Creation-Date: 2024-08-06 07:12-0500\n"
+"PO-Revision-Date: 2010-11-30 00:00+0000\n"
+"Last-Translator: el_libre como el chaval , 2013\n"
+"Language-Team: Catalan (http://app.transifex.com/django-debug-toolbar/django-debug-toolbar/language/ca/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+"Language: ca\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: apps.py:15
+#: apps.py:18
msgid "Debug Toolbar"
msgstr ""
-#: panels/cache.py:180
+#: panels/alerts.py:67
+#, python-brace-format
+msgid ""
+"Form with id \"{form_id}\" contains file input, but does not have the "
+"attribute enctype=\"multipart/form-data\"."
+msgstr ""
+
+#: panels/alerts.py:70
+msgid ""
+"Form contains file input, but does not have the attribute "
+"enctype=\"multipart/form-data\"."
+msgstr ""
+
+#: panels/alerts.py:73
+#, python-brace-format
+msgid ""
+"Input element references form with id \"{form_id}\", but the form does not "
+"have the attribute enctype=\"multipart/form-data\"."
+msgstr ""
+
+#: panels/alerts.py:77
+msgid "Alerts"
+msgstr ""
+
+#: panels/cache.py:168
msgid "Cache"
msgstr "Caxè"
-#: panels/cache.py:186
+#: panels/cache.py:174
#, python-format
msgid "%(cache_calls)d call in %(time).2fms"
msgid_plural "%(cache_calls)d calls in %(time).2fms"
msgstr[0] ""
msgstr[1] ""
-#: panels/cache.py:195
+#: panels/cache.py:183
#, python-format
msgid "Cache calls from %(count)d backend"
msgid_plural "Cache calls from %(count)d backends"
@@ -45,7 +68,7 @@ msgstr[1] ""
msgid "Headers"
msgstr "Encapçalaments"
-#: panels/history/panel.py:18 panels/history/panel.py:19
+#: panels/history/panel.py:19 panels/history/panel.py:20
msgid "History"
msgstr ""
@@ -53,7 +76,7 @@ msgstr ""
msgid "Profiling"
msgstr ""
-#: panels/redirects.py:14
+#: panels/redirects.py:17
msgid "Intercept redirects"
msgstr ""
@@ -61,11 +84,11 @@ msgstr ""
msgid "Request"
msgstr "Demanar"
-#: panels/request.py:36
+#: panels/request.py:38
msgid ""
msgstr ""
-#: panels/request.py:53
+#: panels/request.py:55
msgid ""
msgstr ""
@@ -74,10 +97,9 @@ msgid "Settings"
msgstr "Configuració"
#: panels/settings.py:20
-#, fuzzy, python-format
-#| msgid "Settings"
+#, python-format
msgid "Settings from %s"
-msgstr "Configuració"
+msgstr ""
#: panels/signals.py:57
#, python-format
@@ -97,151 +119,151 @@ msgstr[1] ""
msgid "Signals"
msgstr "Senyals"
-#: panels/sql/panel.py:23
-msgid "Autocommit"
-msgstr ""
-
-#: panels/sql/panel.py:24
+#: panels/sql/panel.py:30 panels/sql/panel.py:41
msgid "Read uncommitted"
msgstr ""
-#: panels/sql/panel.py:25
+#: panels/sql/panel.py:31 panels/sql/panel.py:43
msgid "Read committed"
msgstr ""
-#: panels/sql/panel.py:26
+#: panels/sql/panel.py:32 panels/sql/panel.py:45
msgid "Repeatable read"
msgstr ""
-#: panels/sql/panel.py:27
+#: panels/sql/panel.py:33 panels/sql/panel.py:47
msgid "Serializable"
msgstr "Seriable"
#: panels/sql/panel.py:39
+msgid "Autocommit"
+msgstr ""
+
+#: panels/sql/panel.py:61 panels/sql/panel.py:71
msgid "Idle"
msgstr ""
-#: panels/sql/panel.py:40
+#: panels/sql/panel.py:62 panels/sql/panel.py:72
msgid "Active"
msgstr "Actiu"
-#: panels/sql/panel.py:41
+#: panels/sql/panel.py:63 panels/sql/panel.py:73
msgid "In transaction"
msgstr "En transacció"
-#: panels/sql/panel.py:42
+#: panels/sql/panel.py:64 panels/sql/panel.py:74
msgid "In error"
msgstr ""
-#: panels/sql/panel.py:43
+#: panels/sql/panel.py:65 panels/sql/panel.py:75
msgid "Unknown"
msgstr "Desconegut"
-#: panels/sql/panel.py:130
+#: panels/sql/panel.py:162
msgid "SQL"
msgstr "SQL"
-#: panels/sql/panel.py:135
+#: panels/sql/panel.py:168
#, python-format
msgid "%(query_count)d query in %(sql_time).2fms"
msgid_plural "%(query_count)d queries in %(sql_time).2fms"
msgstr[0] ""
msgstr[1] ""
-#: panels/sql/panel.py:147
+#: panels/sql/panel.py:180
#, python-format
msgid "SQL queries from %(count)d connection"
msgid_plural "SQL queries from %(count)d connections"
msgstr[0] ""
msgstr[1] ""
-#: panels/staticfiles.py:84
+#: panels/staticfiles.py:82
#, python-format
msgid "Static files (%(num_found)s found, %(num_used)s used)"
msgstr ""
-#: panels/staticfiles.py:105
+#: panels/staticfiles.py:103
msgid "Static files"
msgstr ""
-#: panels/staticfiles.py:111
+#: panels/staticfiles.py:109
#, python-format
msgid "%(num_used)s file used"
msgid_plural "%(num_used)s files used"
msgstr[0] ""
msgstr[1] ""
-#: panels/templates/panel.py:143
+#: panels/templates/panel.py:101
msgid "Templates"
msgstr "Plantilles"
-#: panels/templates/panel.py:148
+#: panels/templates/panel.py:106
#, python-format
msgid "Templates (%(num_templates)s rendered)"
msgstr ""
-#: panels/templates/panel.py:180
+#: panels/templates/panel.py:195
msgid "No origin"
msgstr ""
-#: panels/timer.py:25
+#: panels/timer.py:27
#, python-format
msgid "CPU: %(cum)0.2fms (%(total)0.2fms)"
msgstr ""
-#: panels/timer.py:30
+#: panels/timer.py:32
#, python-format
msgid "Total: %0.2fms"
msgstr "Total: %0.2fms"
-#: panels/timer.py:36 templates/debug_toolbar/panels/history.html:9
+#: panels/timer.py:38 templates/debug_toolbar/panels/history.html:9
#: templates/debug_toolbar/panels/sql_explain.html:11
#: templates/debug_toolbar/panels/sql_profile.html:12
#: templates/debug_toolbar/panels/sql_select.html:11
msgid "Time"
msgstr "Hora"
-#: panels/timer.py:44
+#: panels/timer.py:46
msgid "User CPU time"
msgstr ""
-#: panels/timer.py:44
+#: panels/timer.py:46
#, python-format
msgid "%(utime)0.3f msec"
msgstr ""
-#: panels/timer.py:45
+#: panels/timer.py:47
msgid "System CPU time"
msgstr ""
-#: panels/timer.py:45
+#: panels/timer.py:47
#, python-format
msgid "%(stime)0.3f msec"
msgstr ""
-#: panels/timer.py:46
+#: panels/timer.py:48
msgid "Total CPU time"
msgstr ""
-#: panels/timer.py:46
+#: panels/timer.py:48
#, python-format
msgid "%(total)0.3f msec"
msgstr ""
-#: panels/timer.py:47
+#: panels/timer.py:49
msgid "Elapsed time"
msgstr "Temps emprat"
-#: panels/timer.py:47
+#: panels/timer.py:49
#, python-format
msgid "%(total_time)0.3f msec"
msgstr ""
-#: panels/timer.py:49
+#: panels/timer.py:51
msgid "Context switches"
msgstr ""
-#: panels/timer.py:50
+#: panels/timer.py:52
#, python-format
msgid "%(vcsw)d voluntary, %(ivcsw)d involuntary"
msgstr ""
@@ -250,15 +272,19 @@ msgstr ""
msgid "Versions"
msgstr "Versions"
-#: templates/debug_toolbar/base.html:22
+#: templates/debug_toolbar/base.html:23
msgid "Hide toolbar"
msgstr "Amagar barra d'eina"
-#: templates/debug_toolbar/base.html:22
+#: templates/debug_toolbar/base.html:23
msgid "Hide"
msgstr "Amagar"
-#: templates/debug_toolbar/base.html:29
+#: templates/debug_toolbar/base.html:25 templates/debug_toolbar/base.html:26
+msgid "Toggle Theme"
+msgstr ""
+
+#: templates/debug_toolbar/base.html:35
msgid "Show toolbar"
msgstr "Mostrar barra d'eines"
@@ -270,6 +296,14 @@ msgstr ""
msgid "Enable for next and successive requests"
msgstr ""
+#: templates/debug_toolbar/panels/alerts.html:4
+msgid "Alerts found"
+msgstr ""
+
+#: templates/debug_toolbar/panels/alerts.html:11
+msgid "No alerts found"
+msgstr ""
+
#: templates/debug_toolbar/panels/cache.html:2
msgid "Summary"
msgstr "Resum"
@@ -365,10 +399,8 @@ msgid "Path"
msgstr ""
#: templates/debug_toolbar/panels/history.html:12
-#, fuzzy
-#| msgid "Variable"
msgid "Request Variables"
-msgstr "Variable"
+msgstr ""
#: templates/debug_toolbar/panels/history.html:13
msgid "Status"
diff --git a/debug_toolbar/locale/cs/LC_MESSAGES/django.mo b/debug_toolbar/locale/cs/LC_MESSAGES/django.mo
index 0545db3b575c8f02879e51b70f99ef2789cbde25..a0daa392e6891cbef86e7bd0faa4273521573642 100644
GIT binary patch
literal 10854
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
E0ZIe?YXATM
diff --git a/debug_toolbar/locale/cs/LC_MESSAGES/django.po b/debug_toolbar/locale/cs/LC_MESSAGES/django.po
index 18070ee8e..395b6feca 100644
--- a/debug_toolbar/locale/cs/LC_MESSAGES/django.po
+++ b/debug_toolbar/locale/cs/LC_MESSAGES/django.po
@@ -3,59 +3,87 @@
#
#
# Translators:
-# Vlada Macek , 2013
+# Josef Kolář , 2020
+# kuboja, 2024
+# Vláďa Macek , 2013-2014
+# Vláďa Macek , 2015,2021
msgid ""
msgstr ""
"Project-Id-Version: Django Debug Toolbar\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-20 17:23+0100\n"
-"PO-Revision-Date: 2014-04-25 19:53+0000\n"
-"Last-Translator: Aymeric Augustin \n"
-"Language-Team: Czech (http://www.transifex.com/projects/p/django-debug-"
-"toolbar/language/cs/)\n"
-"Language: cs\n"
+"POT-Creation-Date: 2024-08-06 07:12-0500\n"
+"PO-Revision-Date: 2010-11-30 00:00+0000\n"
+"Last-Translator: kuboja, 2024\n"
+"Language-Team: Czech (http://app.transifex.com/django-debug-toolbar/django-debug-toolbar/language/cs/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
+"Language: cs\n"
+"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n"
-#: apps.py:15
+#: apps.py:18
msgid "Debug Toolbar"
+msgstr "Debug Toolbar"
+
+#: panels/alerts.py:67
+#, python-brace-format
+msgid ""
+"Form with id \"{form_id}\" contains file input, but does not have the "
+"attribute enctype=\"multipart/form-data\"."
+msgstr ""
+
+#: panels/alerts.py:70
+msgid ""
+"Form contains file input, but does not have the attribute "
+"enctype=\"multipart/form-data\"."
msgstr ""
-#: panels/cache.py:180
+#: panels/alerts.py:73
+#, python-brace-format
+msgid ""
+"Input element references form with id \"{form_id}\", but the form does not "
+"have the attribute enctype=\"multipart/form-data\"."
+msgstr ""
+
+#: panels/alerts.py:77
+msgid "Alerts"
+msgstr ""
+
+#: panels/cache.py:168
msgid "Cache"
msgstr "Mezipaměť"
-#: panels/cache.py:186
+#: panels/cache.py:174
#, python-format
msgid "%(cache_calls)d call in %(time).2fms"
msgid_plural "%(cache_calls)d calls in %(time).2fms"
msgstr[0] "%(cache_calls)d volání během %(time).2fms"
msgstr[1] "%(cache_calls)d volání během %(time).2fms"
msgstr[2] "%(cache_calls)d volání během %(time).2fms"
+msgstr[3] "%(cache_calls)d volání během %(time).2fms"
-#: panels/cache.py:195
+#: panels/cache.py:183
#, python-format
msgid "Cache calls from %(count)d backend"
msgid_plural "Cache calls from %(count)d backends"
msgstr[0] "Volání mezipaměti z %(count)d backendu"
msgstr[1] "Volání mezipaměti z %(count)d backendů"
msgstr[2] "Volání mezipaměti z %(count)d backendů"
+msgstr[3] "Volání mezipaměti z %(count)d backendů"
#: panels/headers.py:31
msgid "Headers"
-msgstr "Záhlaví"
+msgstr "Hlavičky"
-#: panels/history/panel.py:18 panels/history/panel.py:19
+#: panels/history/panel.py:19 panels/history/panel.py:20
msgid "History"
-msgstr ""
+msgstr "Historie"
#: panels/profiling.py:140
msgid "Profiling"
msgstr "Profilování"
-#: panels/redirects.py:14
+#: panels/redirects.py:17
msgid "Intercept redirects"
msgstr "Zachycení přesměrování"
@@ -63,23 +91,22 @@ msgstr "Zachycení přesměrování"
msgid "Request"
msgstr "Požadavek"
-#: panels/request.py:36
+#: panels/request.py:38
msgid ""
msgstr "<žádný pohled>"
-#: panels/request.py:53
+#: panels/request.py:55
msgid ""
msgstr ""
#: panels/settings.py:17
msgid "Settings"
-msgstr "Settings"
+msgstr "Nastavení"
#: panels/settings.py:20
-#, fuzzy, python-format
-#| msgid "Settings from %s
"
+#, python-format
msgid "Settings from %s"
-msgstr "Nastavení z modulu %s
"
+msgstr ""
#: panels/signals.py:57
#, python-format
@@ -88,6 +115,7 @@ msgid_plural "%(num_receivers)d receivers of 1 signal"
msgstr[0] "%(num_receivers)d příjemce 1 signálu"
msgstr[1] "%(num_receivers)d příjemci 1 signálu"
msgstr[2] "%(num_receivers)d příjemců 1 signálu"
+msgstr[3] "%(num_receivers)d příjemců 1 signálu"
#: panels/signals.py:62
#, python-format
@@ -96,161 +124,163 @@ msgid_plural "%(num_receivers)d receivers of %(num_signals)d signals"
msgstr[0] "%(num_receivers)d příjemce %(num_signals)d signálů"
msgstr[1] "%(num_receivers)d příjemci %(num_signals)d signálů"
msgstr[2] "%(num_receivers)d příjemců %(num_signals)d signálů"
+msgstr[3] "%(num_receivers)d příjemců %(num_signals)d signálů"
#: panels/signals.py:67
msgid "Signals"
msgstr "Signály"
-#: panels/sql/panel.py:23
-msgid "Autocommit"
-msgstr "Autocommit"
-
-#: panels/sql/panel.py:24
+#: panels/sql/panel.py:30 panels/sql/panel.py:41
msgid "Read uncommitted"
msgstr "Read uncommitted"
-#: panels/sql/panel.py:25
+#: panels/sql/panel.py:31 panels/sql/panel.py:43
msgid "Read committed"
msgstr "Read committed"
-#: panels/sql/panel.py:26
+#: panels/sql/panel.py:32 panels/sql/panel.py:45
msgid "Repeatable read"
msgstr "Repeatable read"
-#: panels/sql/panel.py:27
+#: panels/sql/panel.py:33 panels/sql/panel.py:47
msgid "Serializable"
msgstr "Serializable"
#: panels/sql/panel.py:39
+msgid "Autocommit"
+msgstr "Autocommit"
+
+#: panels/sql/panel.py:61 panels/sql/panel.py:71
msgid "Idle"
msgstr "V klidu (idle)"
-#: panels/sql/panel.py:40
+#: panels/sql/panel.py:62 panels/sql/panel.py:72
msgid "Active"
msgstr "Aktivní"
-#: panels/sql/panel.py:41
+#: panels/sql/panel.py:63 panels/sql/panel.py:73
msgid "In transaction"
msgstr "Uvnitř transakce"
-#: panels/sql/panel.py:42
+#: panels/sql/panel.py:64 panels/sql/panel.py:74
msgid "In error"
msgstr "V chybovém stavu"
-#: panels/sql/panel.py:43
+#: panels/sql/panel.py:65 panels/sql/panel.py:75
msgid "Unknown"
msgstr "Neznámé"
-#: panels/sql/panel.py:130
+#: panels/sql/panel.py:162
msgid "SQL"
msgstr "SQL"
-#: panels/sql/panel.py:135
-#, fuzzy, python-format
-#| msgid "%(cache_calls)d call in %(time).2fms"
-#| msgid_plural "%(cache_calls)d calls in %(time).2fms"
+#: panels/sql/panel.py:168
+#, python-format
msgid "%(query_count)d query in %(sql_time).2fms"
msgid_plural "%(query_count)d queries in %(sql_time).2fms"
-msgstr[0] "%(cache_calls)d volání během %(time).2fms"
-msgstr[1] "%(cache_calls)d volání během %(time).2fms"
-msgstr[2] "%(cache_calls)d volání během %(time).2fms"
+msgstr[0] "%(query_count)ddotaz během %(sql_time).2f ms"
+msgstr[1] "%(query_count)d dotazy během %(sql_time).2f ms"
+msgstr[2] "%(query_count)d dotazů během %(sql_time).2f ms"
+msgstr[3] "%(query_count)d dotazů během %(sql_time).2f ms"
-#: panels/sql/panel.py:147
+#: panels/sql/panel.py:180
#, python-format
msgid "SQL queries from %(count)d connection"
msgid_plural "SQL queries from %(count)d connections"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "SQL dotazy z %(count)d spojení"
+msgstr[1] "SQL dotazy ze %(count)d spojení"
+msgstr[2] "SQL dotazy z %(count)d spojení"
+msgstr[3] "SQL dotazy z %(count)d spojení"
-#: panels/staticfiles.py:84
+#: panels/staticfiles.py:82
#, python-format
msgid "Static files (%(num_found)s found, %(num_used)s used)"
msgstr "Statické soubory (nalezeno: %(num_found)s, použito: %(num_used)s)"
-#: panels/staticfiles.py:105
+#: panels/staticfiles.py:103
msgid "Static files"
msgstr "Statické soubory"
-#: panels/staticfiles.py:111
+#: panels/staticfiles.py:109
#, python-format
msgid "%(num_used)s file used"
msgid_plural "%(num_used)s files used"
msgstr[0] "%(num_used)s soubor použit"
msgstr[1] "%(num_used)s soubory použity"
msgstr[2] "%(num_used)s souborů použito"
+msgstr[3] "%(num_used)s souborů použito"
-#: panels/templates/panel.py:143
+#: panels/templates/panel.py:101
msgid "Templates"
msgstr "Šablony"
-#: panels/templates/panel.py:148
+#: panels/templates/panel.py:106
#, python-format
msgid "Templates (%(num_templates)s rendered)"
msgstr "Šablony (renderovaných: %(num_templates)s)"
-#: panels/templates/panel.py:180
+#: panels/templates/panel.py:195
msgid "No origin"
-msgstr ""
+msgstr "Zdroj chybí"
-#: panels/timer.py:25
+#: panels/timer.py:27
#, python-format
msgid "CPU: %(cum)0.2fms (%(total)0.2fms)"
msgstr "CPU: %(cum)0.2fms (%(total)0.2fms)"
-#: panels/timer.py:30
+#: panels/timer.py:32
#, python-format
msgid "Total: %0.2fms"
msgstr "Celkem: %0.2fms"
-#: panels/timer.py:36 templates/debug_toolbar/panels/history.html:9
+#: panels/timer.py:38 templates/debug_toolbar/panels/history.html:9
#: templates/debug_toolbar/panels/sql_explain.html:11
#: templates/debug_toolbar/panels/sql_profile.html:12
#: templates/debug_toolbar/panels/sql_select.html:11
msgid "Time"
msgstr "Čas"
-#: panels/timer.py:44
+#: panels/timer.py:46
msgid "User CPU time"
msgstr "Uživatelský čas CPU"
-#: panels/timer.py:44
+#: panels/timer.py:46
#, python-format
msgid "%(utime)0.3f msec"
msgstr "%(utime)0.3f msec"
-#: panels/timer.py:45
+#: panels/timer.py:47
msgid "System CPU time"
msgstr "Systémový čas CPU"
-#: panels/timer.py:45
+#: panels/timer.py:47
#, python-format
msgid "%(stime)0.3f msec"
msgstr "%(stime)0.3f msec"
-#: panels/timer.py:46
+#: panels/timer.py:48
msgid "Total CPU time"
msgstr "Celkový čas CPU"
-#: panels/timer.py:46
+#: panels/timer.py:48
#, python-format
msgid "%(total)0.3f msec"
msgstr "%(total)0.3f msec"
-#: panels/timer.py:47
+#: panels/timer.py:49
msgid "Elapsed time"
msgstr "Uplynulý čas"
-#: panels/timer.py:47
+#: panels/timer.py:49
#, python-format
msgid "%(total_time)0.3f msec"
msgstr "%(total_time)0.3f msec"
-#: panels/timer.py:49
+#: panels/timer.py:51
msgid "Context switches"
msgstr "Přepnutí kontextu"
-#: panels/timer.py:50
+#: panels/timer.py:52
#, python-format
msgid "%(vcsw)d voluntary, %(ivcsw)d involuntary"
msgstr "%(vcsw)d dobrovolně, %(ivcsw)d nedobrovolně"
@@ -259,15 +289,19 @@ msgstr "%(vcsw)d dobrovolně, %(ivcsw)d nedobrovolně"
msgid "Versions"
msgstr "Verze"
-#: templates/debug_toolbar/base.html:22
+#: templates/debug_toolbar/base.html:23
msgid "Hide toolbar"
msgstr "Skrýt lištu"
-#: templates/debug_toolbar/base.html:22
+#: templates/debug_toolbar/base.html:23
msgid "Hide"
msgstr "Skrýt"
-#: templates/debug_toolbar/base.html:29
+#: templates/debug_toolbar/base.html:25 templates/debug_toolbar/base.html:26
+msgid "Toggle Theme"
+msgstr ""
+
+#: templates/debug_toolbar/base.html:35
msgid "Show toolbar"
msgstr "Zobrazit lištu"
@@ -279,6 +313,14 @@ msgstr "Vypnout pro následné požadavky"
msgid "Enable for next and successive requests"
msgstr "Zapnout pro následné požadavky"
+#: templates/debug_toolbar/panels/alerts.html:4
+msgid "Alerts found"
+msgstr ""
+
+#: templates/debug_toolbar/panels/alerts.html:11
+msgid "No alerts found"
+msgstr ""
+
#: templates/debug_toolbar/panels/cache.html:2
msgid "Summary"
msgstr "Souhrn"
@@ -362,13 +404,11 @@ msgstr "Prostředí WSGI"
msgid ""
"Since the WSGI environ inherits the environment of the server, only a "
"significant subset is shown below."
-msgstr ""
-"Níže je zobrazena pouze podstatná část proměnných prostředí, protože WSGI je "
-"dědí od serveru."
+msgstr "Níže je zobrazena pouze podstatná část proměnných prostředí, protože WSGI je dědí od serveru."
#: templates/debug_toolbar/panels/history.html:10
msgid "Method"
-msgstr ""
+msgstr "Metoda"
#: templates/debug_toolbar/panels/history.html:11
#: templates/debug_toolbar/panels/staticfiles.html:43
@@ -376,14 +416,12 @@ msgid "Path"
msgstr "Cesta"
#: templates/debug_toolbar/panels/history.html:12
-#, fuzzy
-#| msgid "Request headers"
msgid "Request Variables"
-msgstr "Záhlaví požadavku"
+msgstr "Proměnné požadavku"
#: templates/debug_toolbar/panels/history.html:13
msgid "Status"
-msgstr ""
+msgstr "Stav"
#: templates/debug_toolbar/panels/history.html:14
#: templates/debug_toolbar/panels/sql.html:37
@@ -479,20 +517,21 @@ msgid_plural "%(num)s queries"
msgstr[0] "%(num)s dotaz"
msgstr[1] "%(num)s dotazy"
msgstr[2] "%(num)s dotazů"
+msgstr[3] "%(num)s dotazů"
#: templates/debug_toolbar/panels/sql.html:8
#, python-format
msgid ""
"including %(count)s similar"
-msgstr ""
+msgstr "včetně %(count)s podobných"
#: templates/debug_toolbar/panels/sql.html:12
#, python-format
msgid ""
"and %(dupes)s duplicates"
-msgstr ""
+msgstr "a %(dupes)s duplicitních"
#: templates/debug_toolbar/panels/sql.html:34
msgid "Query"
@@ -504,11 +543,9 @@ msgid "Timeline"
msgstr "Časová osa"
#: templates/debug_toolbar/panels/sql.html:52
-#, fuzzy, python-format
-#| msgid "%(count)s message"
-#| msgid_plural "%(count)s messages"
+#, python-format
msgid "%(count)s similar queries."
-msgstr "%(count)s zpráva"
+msgstr "%(count)s podobných dotazů."
#: templates/debug_toolbar/panels/sql.html:58
#, python-format
@@ -573,6 +610,7 @@ msgid_plural "Static file paths"
msgstr[0] "Cesta ke statickým souborům"
msgstr[1] "Cesty ke statickým souborům"
msgstr[2] "Cesty ke statickým souborům"
+msgstr[3] "Cesty ke statickým souborům"
#: templates/debug_toolbar/panels/staticfiles.html:7
#, python-format
@@ -594,6 +632,7 @@ msgid_plural "Static file apps"
msgstr[0] "Aplikace se statickými soubory"
msgstr[1] "Aplikace se statickými soubory"
msgstr[2] "Aplikace se statickými soubory"
+msgstr[3] "Aplikace se statickými soubory"
#: templates/debug_toolbar/panels/staticfiles.html:25
msgid "Static file"
@@ -601,6 +640,7 @@ msgid_plural "Static files"
msgstr[0] "Statický soubor"
msgstr[1] "Statické soubory"
msgstr[2] "Statické soubory"
+msgstr[3] "Statické soubory"
#: templates/debug_toolbar/panels/staticfiles.html:39
#, python-format
@@ -609,6 +649,7 @@ msgid_plural "%(payload_count)s files"
msgstr[0] "%(payload_count)s soubor"
msgstr[1] "%(payload_count)s soubory"
msgstr[2] "%(payload_count)s souborů"
+msgstr[3] "%(payload_count)s souborů"
#: templates/debug_toolbar/panels/staticfiles.html:44
msgid "Location"
@@ -624,6 +665,7 @@ msgid_plural "Template paths"
msgstr[0] "Cesta k šabloně"
msgstr[1] "Cesty k šablonám"
msgstr[2] "Cesty k šablonám"
+msgstr[3] "Cesty k šablonám"
#: templates/debug_toolbar/panels/templates.html:13
msgid "Template"
@@ -631,6 +673,7 @@ msgid_plural "Templates"
msgstr[0] "Šablona"
msgstr[1] "Šablony"
msgstr[2] "Šablony"
+msgstr[3] "Šablony"
#: templates/debug_toolbar/panels/templates.html:22
#: templates/debug_toolbar/panels/templates.html:40
@@ -643,6 +686,7 @@ msgid_plural "Context processors"
msgstr[0] "Procesor kontextu"
msgstr[1] "Procesory kontextu"
msgstr[2] "Procesory kontextu"
+msgstr[3] "Procesory kontextu"
#: templates/debug_toolbar/panels/timer.html:2
msgid "Resource usage"
@@ -666,7 +710,7 @@ msgstr "Milisekund od začátku navigace (+délka)"
#: templates/debug_toolbar/panels/versions.html:10
msgid "Package"
-msgstr ""
+msgstr "Balíček"
#: templates/debug_toolbar/panels/versions.html:11
msgid "Name"
@@ -685,15 +729,10 @@ msgid ""
"The Django Debug Toolbar has intercepted a redirect to the above URL for "
"debug viewing purposes. You can click the above link to continue with the "
"redirect as normal."
-msgstr ""
-"Aplikace Django Debug Toolbar zachytila přesměrování na výše uvedenou adresu "
-"URL za účelem ladicího zobrazení. Chcete-li přesměrování dokončit, klepněte "
-"na odkaz výše."
+msgstr "Aplikace Django Debug Toolbar zachytila přesměrování na výše uvedenou adresu URL za účelem ladicího zobrazení. Chcete-li přesměrování dokončit, klepněte na odkaz výše."
#: views.py:16
msgid ""
"Data for this panel isn't available anymore. Please reload the page and "
"retry."
-msgstr ""
-"Data pro tento panel již nejsou k dispozici. Obnovte stránku a zkuste to "
-"znova."
+msgstr "Data pro tento panel již nejsou k dispozici. Obnovte stránku a zkuste to znova."
diff --git a/debug_toolbar/locale/de/LC_MESSAGES/django.mo b/debug_toolbar/locale/de/LC_MESSAGES/django.mo
index 001276ee58238e21158e6a2afb96fc6f8bac80c4..f62a4baf6d30a58c3732525e206da8f094debd5b 100644
GIT binary patch
delta 3211
zcmXxme@vBC9LMp4pb7FLZ%Tls*8~9-xfde@A(a#n5GYi{AL$iti1OnG_%rGXW?C{_
zP|oGtoJ+GdoetJ?*7`Z;GFE@&Dn-jSTeh;=boxiN-kgBzy!HVkEA#Za}UzjW`N-T08CeeHcZ1FFu4vkbmYl
zKab-8j>PY<2(P2APmVJt+60Zsq{5_4KI*~+sL3xzCT%J)8Q0*$*ok^jFY5ZY?eS48
z=lCS*{`;tb>!vh_#R-^$B+FD`B+obNsifj2RENFxfWDk8}FZ#cYm?Q1^EPsi=e9s2T1@24@bVUdPj@2VX{IVhE?<
zFL(lD#yhDVK%GC28t~_+`@TYD<4_kSA%iyQs5LA=by$e%
zpcIwLD%586+4J@Ge83)WM_t#68pr`uhL2(op29sm-{e1P%-%3#KEp~*lq5PIn8WDi
z_&m1ZRa}kbe1&rGee~kbxC+PdZYhH;)*zB3bHE<
zP;28x%`g>}+6+{ta!{ElM5V9z)WBz9F6N^8Yr~*MxRZ)H
z>b55iqHZ{X%E(E3e8HZ-XdOhQ_*?63)LQ?Cp*=O(c^i^Yui2
zgEm_$Y7MucI@*hccnCGaYu4MSO?n^MI%bU9d0-6c0ST!7CZQfY6*a+B)PudK4ClIo
z&V!0+(1>eL1E@n?*pA9j2kM3%R7XcpGk+J={vql?mr=X?Yt(&1xD@Z8`puu>oG(L7
zs3u57YhQ00+E5*LqEdelwN~$;26P4kcnBp(c9P
zwts{yVbBax3FpL3)Q9F4Y5;doGkJg!7?t9jk3&5;0d<`lmCEU;8O^cBrP#x94Ze!M
zVi>AC0c|Bl5Ss{9CT}`j-*L(W@zZHr;<21qK?O3c
zONnk`9Z^f{BUBoc|2n50`t!Nj*7cRrH$9(t-nNM>Vm|R4v5Zi8h0w;*m#>RhLNpVT
z36(VBX<|R24XTnz%qBwr|8rAO*-h}agvwLa8JJ0ICtkO0YtcizXpgs8pTJ~WkFdUk
zEw)~Q?L;dPMZ89Y_8))vOcn7g!Jp+&(T-M`MU)Z=gpb%m6cYMIG!i3;dLo<9`@fh_
z8QxcZ>P^IYVjE#n(rSIR8~y8QeT|K6>2-a9=%W5>(MjR`|Hj=68{1OrYj0?2Hf6Sw
z*XMG**?-1~=?etkGKg_7_g+8udRR
CZ6GB8
delta 3488
zcmZA3X>6259LMn~J%DnQwxBJCUCPoHN`d9Ja#>ExwnYS#BFEA$+roAWZJ|(s1udZE
zP+U!r1VJVEf}X6O`p}IBu{*Y4FT8<4OzdP#G1lWi{LK10
z&Z6z^Y)mpXShwN>#)Qr5w&Mu)S1+
z5M~Buq7UP-5hr64CUSq%LWM<`Z;-{CA5kaXL=AKc+u>d8fbm_NOe7!bxurRZ;aDoCsqkmc@uM4li@NX%YC<p<9Y1y0#wFIQ0L7KQ>mabAJgzOy6`*HQybIG8Q6`(X?suu
z1W*HnP%B)CB*AP#y~eL$bdOP)IE`7@g8T7LRHnmwcnNjFKGcj4qb~dam60>38(p;R
z%c#A*iQ3CMwm<$s=i%y#8aM|vULNZD5vWX#MQxeaIUY7M>M9YJk5{=f^(ewA-U5l8nkkFVuAt?C}|>>r1UZ49}*cf{JE%
z0+sr+_y}IabWF`~CX$EIPb@x6e<5nXMtghN@<1rI;eHm&3ORNp3
z@tcqr$LvNj5jMxEXocr68!zA?{0HOk0FSbczl)mCan!({pfdC^d+4|C;T;jaq3!
zmUDgzY6~+l7Dr$^z5n@Cbb|?~l@y_FydZi4|2Cj*T!lJs1uB(c)QYy*_Fmjh`!H_8
zF{~yAM-wXf4$j`a#QmpaR5lQg
z5_JS0LsLbltR%eA8s7rs({EPU_TxB>Xdp79Q>2nkJVR*ztBLzd8I3_i1)(RGe>qJJ
z!N>7l(SsIGWD$LcCx{FpK&U)REGLE$0|}KpqPJ2MAs!=&iAls(qL64UFH>1Tv?az8
zJBT*Klf*VcWv+uMv2MZVi7B>SiVKNy+t%m3k_b<<9bK&dXFeTM@9S)&uBSZC_C1FM
zL=mCa@+o2-;U+o}FA^all}IF1#_6YTPMNQ)B67JyNqUvPw$>N$tE+lNsIFhF%l0&9
zcFc-RsPKhC{$TUuq$@GQ{44!I<|9)m2u9?p5-s1zInvRU=Rt3Ya2i+(>@%D@k_5
zT33*R{_^I}lf4O@hj{WlL-Ga>b9qMQ4;>Y8r@14=X&JHg_4Uom(uT+Mm{b|6tMLWy
zn^?5x*U9&0WCx6l&Umk<
c-^Dx^tthLwcbaQubq$Lx_lKH)$k?3lAJ$T7i~s-t
diff --git a/debug_toolbar/locale/de/LC_MESSAGES/django.po b/debug_toolbar/locale/de/LC_MESSAGES/django.po
index 7cd10febe..18a6be6a8 100644
--- a/debug_toolbar/locale/de/LC_MESSAGES/django.po
+++ b/debug_toolbar/locale/de/LC_MESSAGES/django.po
@@ -5,37 +5,61 @@
# Translators:
# Jannis Leidel , 2012-2014,2021
# Matthias Kestenholz , 2021
+# Tim Schilling, 2021
msgid ""
msgstr ""
"Project-Id-Version: Django Debug Toolbar\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-20 17:23+0100\n"
-"PO-Revision-Date: 2021-12-04 17:38+0000\n"
-"Last-Translator: Tim Schilling\n"
-"Language-Team: German (http://www.transifex.com/django-debug-toolbar/django-"
-"debug-toolbar/language/de/)\n"
-"Language: de\n"
+"POT-Creation-Date: 2024-08-06 07:12-0500\n"
+"PO-Revision-Date: 2010-11-30 00:00+0000\n"
+"Last-Translator: Tim Schilling, 2021\n"
+"Language-Team: German (http://app.transifex.com/django-debug-toolbar/django-debug-toolbar/language/de/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+"Language: de\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: apps.py:15
+#: apps.py:18
msgid "Debug Toolbar"
msgstr "Debug Toolbar"
-#: panels/cache.py:180
+#: panels/alerts.py:67
+#, python-brace-format
+msgid ""
+"Form with id \"{form_id}\" contains file input, but does not have the "
+"attribute enctype=\"multipart/form-data\"."
+msgstr ""
+
+#: panels/alerts.py:70
+msgid ""
+"Form contains file input, but does not have the attribute "
+"enctype=\"multipart/form-data\"."
+msgstr ""
+
+#: panels/alerts.py:73
+#, python-brace-format
+msgid ""
+"Input element references form with id \"{form_id}\", but the form does not "
+"have the attribute enctype=\"multipart/form-data\"."
+msgstr ""
+
+#: panels/alerts.py:77
+msgid "Alerts"
+msgstr ""
+
+#: panels/cache.py:168
msgid "Cache"
msgstr "Cache"
-#: panels/cache.py:186
+#: panels/cache.py:174
#, python-format
msgid "%(cache_calls)d call in %(time).2fms"
msgid_plural "%(cache_calls)d calls in %(time).2fms"
msgstr[0] "%(cache_calls)d Abfrage in %(time).2fms"
msgstr[1] "%(cache_calls)d Abfragen in %(time).2fms"
-#: panels/cache.py:195
+#: panels/cache.py:183
#, python-format
msgid "Cache calls from %(count)d backend"
msgid_plural "Cache calls from %(count)d backends"
@@ -46,7 +70,7 @@ msgstr[1] "Cache-Aufrufe von %(count)d Backends"
msgid "Headers"
msgstr "Header"
-#: panels/history/panel.py:18 panels/history/panel.py:19
+#: panels/history/panel.py:19 panels/history/panel.py:20
msgid "History"
msgstr "Geschichte"
@@ -54,7 +78,7 @@ msgstr "Geschichte"
msgid "Profiling"
msgstr "Profiling"
-#: panels/redirects.py:14
+#: panels/redirects.py:17
msgid "Intercept redirects"
msgstr "Umleitungen abfangen"
@@ -62,11 +86,11 @@ msgstr "Umleitungen abfangen"
msgid "Request"
msgstr "Anfrage"
-#: panels/request.py:36
+#: panels/request.py:38
msgid ""
msgstr ""
-#: panels/request.py:53
+#: panels/request.py:55
msgid ""
msgstr ""
@@ -97,151 +121,151 @@ msgstr[1] "%(num_receivers)d Empfänger von %(num_signals)d Signalen"
msgid "Signals"
msgstr "Signale"
-#: panels/sql/panel.py:23
-msgid "Autocommit"
-msgstr "Autocommit"
-
-#: panels/sql/panel.py:24
+#: panels/sql/panel.py:30 panels/sql/panel.py:41
msgid "Read uncommitted"
msgstr "Read uncommitted"
-#: panels/sql/panel.py:25
+#: panels/sql/panel.py:31 panels/sql/panel.py:43
msgid "Read committed"
msgstr "Read committed"
-#: panels/sql/panel.py:26
+#: panels/sql/panel.py:32 panels/sql/panel.py:45
msgid "Repeatable read"
msgstr "Repeatable read"
-#: panels/sql/panel.py:27
+#: panels/sql/panel.py:33 panels/sql/panel.py:47
msgid "Serializable"
msgstr "Serializable"
#: panels/sql/panel.py:39
+msgid "Autocommit"
+msgstr "Autocommit"
+
+#: panels/sql/panel.py:61 panels/sql/panel.py:71
msgid "Idle"
msgstr "Wartet"
-#: panels/sql/panel.py:40
+#: panels/sql/panel.py:62 panels/sql/panel.py:72
msgid "Active"
msgstr "Aktiv"
-#: panels/sql/panel.py:41
+#: panels/sql/panel.py:63 panels/sql/panel.py:73
msgid "In transaction"
msgstr "In einer Transaktion"
-#: panels/sql/panel.py:42
+#: panels/sql/panel.py:64 panels/sql/panel.py:74
msgid "In error"
msgstr "Fehler"
-#: panels/sql/panel.py:43
+#: panels/sql/panel.py:65 panels/sql/panel.py:75
msgid "Unknown"
msgstr "Unbekannt"
-#: panels/sql/panel.py:130
+#: panels/sql/panel.py:162
msgid "SQL"
msgstr "SQL"
-#: panels/sql/panel.py:135
+#: panels/sql/panel.py:168
#, python-format
msgid "%(query_count)d query in %(sql_time).2fms"
msgid_plural "%(query_count)d queries in %(sql_time).2fms"
msgstr[0] "%(query_count)d Abfrage in %(sql_time).2f ms"
msgstr[1] "%(query_count)d Abfragen in %(sql_time).2f ms"
-#: panels/sql/panel.py:147
+#: panels/sql/panel.py:180
#, python-format
msgid "SQL queries from %(count)d connection"
msgid_plural "SQL queries from %(count)d connections"
msgstr[0] "SQL-Abfragen von %(count)d Verbindung"
msgstr[1] "SQL-Abfragen von %(count)d Verbindungen"
-#: panels/staticfiles.py:84
+#: panels/staticfiles.py:82
#, python-format
msgid "Static files (%(num_found)s found, %(num_used)s used)"
msgstr "Statische Dateien (%(num_found)s gefunden, %(num_used)s benutzt)"
-#: panels/staticfiles.py:105
+#: panels/staticfiles.py:103
msgid "Static files"
msgstr "Statische Dateien"
-#: panels/staticfiles.py:111
+#: panels/staticfiles.py:109
#, python-format
msgid "%(num_used)s file used"
msgid_plural "%(num_used)s files used"
msgstr[0] "%(num_used)s Datei benutzt"
msgstr[1] "%(num_used)s Dateien benutzt"
-#: panels/templates/panel.py:143
+#: panels/templates/panel.py:101
msgid "Templates"
msgstr "Templates"
-#: panels/templates/panel.py:148
+#: panels/templates/panel.py:106
#, python-format
msgid "Templates (%(num_templates)s rendered)"
msgstr "Templates (%(num_templates)s gerendert)"
-#: panels/templates/panel.py:180
+#: panels/templates/panel.py:195
msgid "No origin"
msgstr "Kein Ursprung"
-#: panels/timer.py:25
+#: panels/timer.py:27
#, python-format
msgid "CPU: %(cum)0.2fms (%(total)0.2fms)"
msgstr "CPU: %(cum)0.2fms (%(total)0.2fms)"
-#: panels/timer.py:30
+#: panels/timer.py:32
#, python-format
msgid "Total: %0.2fms"
msgstr "Gesamt: %0.2fms"
-#: panels/timer.py:36 templates/debug_toolbar/panels/history.html:9
+#: panels/timer.py:38 templates/debug_toolbar/panels/history.html:9
#: templates/debug_toolbar/panels/sql_explain.html:11
#: templates/debug_toolbar/panels/sql_profile.html:12
#: templates/debug_toolbar/panels/sql_select.html:11
msgid "Time"
msgstr "Zeit"
-#: panels/timer.py:44
+#: panels/timer.py:46
msgid "User CPU time"
msgstr "CPU-Zeit Benutzer"
-#: panels/timer.py:44
+#: panels/timer.py:46
#, python-format
msgid "%(utime)0.3f msec"
msgstr "%(utime)0.3f ms"
-#: panels/timer.py:45
+#: panels/timer.py:47
msgid "System CPU time"
msgstr "CPU-Zeit System"
-#: panels/timer.py:45
+#: panels/timer.py:47
#, python-format
msgid "%(stime)0.3f msec"
msgstr "%(stime)0.3f ms"
-#: panels/timer.py:46
+#: panels/timer.py:48
msgid "Total CPU time"
msgstr "CPU-Zeit gesamt"
-#: panels/timer.py:46
+#: panels/timer.py:48
#, python-format
msgid "%(total)0.3f msec"
msgstr "%(total)0.3f ms"
-#: panels/timer.py:47
+#: panels/timer.py:49
msgid "Elapsed time"
msgstr "Verstrichene Zeit"
-#: panels/timer.py:47
+#: panels/timer.py:49
#, python-format
msgid "%(total_time)0.3f msec"
msgstr "%(total_time)0.3f ms"
-#: panels/timer.py:49
+#: panels/timer.py:51
msgid "Context switches"
msgstr "Kontextwechsel"
-#: panels/timer.py:50
+#: panels/timer.py:52
#, python-format
msgid "%(vcsw)d voluntary, %(ivcsw)d involuntary"
msgstr "%(vcsw)d freiwillig, %(ivcsw)d unfreiwillig"
@@ -250,15 +274,19 @@ msgstr "%(vcsw)d freiwillig, %(ivcsw)d unfreiwillig"
msgid "Versions"
msgstr "Versionen"
-#: templates/debug_toolbar/base.html:22
+#: templates/debug_toolbar/base.html:23
msgid "Hide toolbar"
msgstr "Toolbar ausblenden"
-#: templates/debug_toolbar/base.html:22
+#: templates/debug_toolbar/base.html:23
msgid "Hide"
msgstr "Ausblenden"
-#: templates/debug_toolbar/base.html:29
+#: templates/debug_toolbar/base.html:25 templates/debug_toolbar/base.html:26
+msgid "Toggle Theme"
+msgstr ""
+
+#: templates/debug_toolbar/base.html:35
msgid "Show toolbar"
msgstr "Toolbar einblenden"
@@ -270,6 +298,14 @@ msgstr "Für nächste und die darauffolgenden Anfragen deaktivieren"
msgid "Enable for next and successive requests"
msgstr "Für nächste und die darauffolgenden Anfragen aktivieren"
+#: templates/debug_toolbar/panels/alerts.html:4
+msgid "Alerts found"
+msgstr ""
+
+#: templates/debug_toolbar/panels/alerts.html:11
+msgid "No alerts found"
+msgstr ""
+
#: templates/debug_toolbar/panels/cache.html:2
msgid "Summary"
msgstr "Zusammenfassung"
@@ -353,9 +389,7 @@ msgstr "WSGI-Umgebung"
msgid ""
"Since the WSGI environ inherits the environment of the server, only a "
"significant subset is shown below."
-msgstr ""
-"Da sich die WSGI-Umgebung von der Umgebung des Servers ableitet, wird nur "
-"eine notwendige Teilmenge dargestellt."
+msgstr "Da sich die WSGI-Umgebung von der Umgebung des Servers ableitet, wird nur eine notwendige Teilmenge dargestellt."
#: templates/debug_toolbar/panels/history.html:10
msgid "Method"
@@ -473,18 +507,14 @@ msgstr[1] "%(num)s Abfragen"
msgid ""
"including %(count)s similar"
-msgstr ""
-"inklusive %(count)s ähnlich"
+msgstr "inklusive %(count)s ähnlich"
#: templates/debug_toolbar/panels/sql.html:12
#, python-format
msgid ""
"and %(dupes)s duplicates"
-msgstr ""
-"und %(dupes)s dupliziert"
+msgstr "und %(dupes)s dupliziert"
#: templates/debug_toolbar/panels/sql.html:34
msgid "Query"
@@ -668,15 +698,10 @@ msgid ""
"The Django Debug Toolbar has intercepted a redirect to the above URL for "
"debug viewing purposes. You can click the above link to continue with the "
"redirect as normal."
-msgstr ""
-"Die Django Debug Toolbar hat eine Weiterleitung an die obenstehende URL zur "
-"weiteren Überprüfung abgefangen. Klicken Sie den Link, um wie gewohnt "
-"weitergeleitet zu werden."
+msgstr "Die Django Debug Toolbar hat eine Weiterleitung an die obenstehende URL zur weiteren Überprüfung abgefangen. Klicken Sie den Link, um wie gewohnt weitergeleitet zu werden."
#: views.py:16
msgid ""
"Data for this panel isn't available anymore. Please reload the page and "
"retry."
-msgstr ""
-"Die Daten für dieses Panel sind nicht mehr verfügbar. Bitte laden Sie die "
-"Seite neu."
+msgstr "Die Daten für dieses Panel sind nicht mehr verfügbar. Bitte laden Sie die Seite neu."
diff --git a/debug_toolbar/locale/es/LC_MESSAGES/django.mo b/debug_toolbar/locale/es/LC_MESSAGES/django.mo
index e2a8c6cfd29d8d98a14788e542e9c23d44ca2a98..583f88ef926e3ff3844eacfe0d532360df3f356f 100644
GIT binary patch
delta 3287
zcmYM$32;qU9LMpKND!i$P+3HCvmi?3y`Xr6iY1{zts$yB5lM(7mLRl!_R6%D&W+L5
z)KsT-gEp-$6fIiX(a~khpbMiltxl^mbhKlcet+*BdM5w(IrqME&+7N#-LJyJ94c
z!Xa3QYQF`UquGTKjBgH7QNu&1MSp@U(tLsGcn%-N+o*w}TZY=VMqMZ32uwviKL<7O
z#h8I>ur0og8u$!q0T-|%teMNRlG)N}u$GSTdj&_D^O>lD;hdQe-}*WM50QDH1I9@X(oREJflnJz-5a4Bl5
z*4gjt?f0+S>usoZ`%n`(jLN_nT!$C%RG2a4{0P)?olV*tz5jcubXP;%iQx$hihFP@
zrt_;a5^Is|HK(l?Q9meu*y{-1vCdq#L6Tr{Q4=aet-J)4@;Ru5EyKoo|LdqIB^#`p
zZG-LDp8NYyd-@$J1GjJ`-bHQQa`sIV+lboZ9jFZMv%Zh&{}|@um#B=l=4Z5t-v10L
zdeDPv*b}QT7qxPJ`XkV>8Js!Py;N%p11m61OKRFv|+u^R7TZ>-|PmE$fPg{{&;dtHKqxUNNYa0K=INz?#eA;~nq
zqWWpd!3n+%s0<@V?xQldgKf@#wkm`{WgWrPX~eNYD4no_Pez(YJw
zOeIu05p#&Xx}YozVe+hEkv#A4!pS!gRo=-j`FgNS~F
z`czTYh7(T^+R843N(M0^ShH=F{s{y>Xrcexp?-ikd%>SzFyjfOy%AABs7xmO#A;pG
zGR-;zb%0fR5fh0%#B}0*@oN13Ts=*Uv3HlFPO6VsO5_t2gnocjIuf}=9idlIMF%XK
z&;d&(?w1r>$+13$U5N$6n&3ThHHk_VQ5(F$ztz@m$XgUF5!NL*+t!ETT%wwYB3>X=
z^pDbLLa(h}Jrx~Xl}ut7p&z9w#0njd0fb(unM5Q}LUbp35<>`;=R%lboJBlC)VS@U
zCpK)3J`vtf+VXN(OjWUeetA`;DX<<@3s%jI#Ojt9@Bn{_1MCas0{N-TFAy6*Y7H
z6*-koPLAVs`a2%S=Ttf=IaE4ypw`~;dV)m_JT&mqAlv;RzR+!+;BluW^mo@LY;u23
zsBwEHPIeb2j&|!4;~GvTt`Bo>w@q|&lk(jSNdp@`N-7U;Gj3XWvA?+dctfT6zv^>K
plXo{{I&;I_th8A7Xlj(ZJ++^EEVanJm-?=|BhA}zBCT_y{{RH+P`m&D
delta 3504
zcmY+`drZ}39LMnoP$b10Dj*^J1T@f4kKrY}R-$D>DuK6Bk8lF)cn)wtM5|+JnOa`@
z*}C7BHETAfq^@O|E9WNFoYso|XsxWaZnkFGrnTOm-|u0oXMBIJ=XZN9-{<)q?W(v~
z9{(z>#}kIKo5&`f>tW1E)vw_|aZ-($i^H)1!<-y#!IN@r}Q@_)x^0-g-M%A)Psvr4K2qMya)SW6qSJuH~?QlJ$DH8-rM&41Xgf<
z8uflU4{HLsSct`VEmmVH{hMYgnsFSj!)>Sr59t9shHB_TREHm<2K<@5|E0bDgS~zc
z_53AdvgU78W>Z-Qs>Z=23}9SqGl7FToP&C?95tY7)BskZI$mRKMJ>hsSd3dx13HY#
z)G^e1A7B8_qEeoiW(+EJWJYm84V2m&Gf*AgX0I#rTgRa~
zn1*Vw4AoABy}tsLsW9rf7}nzk%)|?EDh`#uQM)x~u;0;5IDzvDR0CU34eUV8%tgj#
zUO|1fM^PQ0N2T@xj>KQ_H5@X;&+u{7{gbEx$2+O$#ZOV0_zu<4C3}7qwWfXeXtjnJ
zsOR#KF`EEt>B>+I&PBaniOS$I)KWFr`%!y;oqrxT8>#5QZK#1fiAwc;+=)l<*#u)|
zWf(J`^RLNU0S1QpnX5)+t_`F34Bmmg`IVZ4OR)qWN9}>r)-Fuf_y3c<3W
zSu-Ea2_?FA5iaKL_PN>DkBN}PHQ4fsLaJt8QF(%CU3f^
zsG&=!fu!X4-)$CZ0P|1{EVQmfWh8>?cs$^A^KSH(F)A4_T
z2Rd=Tqhc;-%_pN8E=RpsWzTC-yF85geP}{`zpbbN@3iN8k$r03L`~onDx+sn1OEou
zpXO(4a(uYop@T|MA*$iYsE!t(W>RIXL474nsIO#`J>P{I@Jpz64x&0bfvl?OLS^PM
zYH9w#MvV7jYmT6@4$JTboPZZldm<~JPY=hS8i=79SdZ#pGb(e>quM!a&%Z!r;1?W?
zf8k{;DDd0K=3$m1Zt|&UMq^RGXfsh6s6?eKj2g&V)N|WWGk+E}@MsH0+3gOgC3Z8oZ-yYL}wzyxd}x{I!FBzD^iOK=r&
z4{;kYhgeFeOeV$>B*HvMOeJ#Y-`q>6Xq{Dxi5XtaKWP0lK&5l7f64m+xr6#LB0^}O
z+PF;8D>07zaC$S=g;ruN!K&(G^NPbUzKDZ%=uATEzJ@3xx{Fd-O{^!B6_xvl5TSjs
znYfjhLZ}q_c%P%H)9m^6SVh#^^XqVz)?ejz@96(p*{Vk+#{fa*z5i0(k2exG6WfRd
zgqBSEW&@#8=i}{}QMNwLD&`Xp6E#G+`kzhZQDP_2Mm#{Y6DtUn@x(%63o(Y!CMzYn
z%Q`Bn34H}y34QJ
zSNkj(x+WBh1?xg)L}5*|HPTWPbL^Fl-}{_ROs)?`BB5}{`~AL6=n+~Q3cD{47@R#X
zTG#zl%y3fI5UDfeenakC1NQc}O~jlqH$$}@vj(>J>^nYC92i$TF5mPNj{X;xvX^n}gwLg%M}?G$&Bxj?G-;9?a~;5F@eR>i-YXyW+l)dAnPm
zI?&A=+TxxXI@KMORpM^Qn$XdiwIjjZls&OWFcJ*AN3+X11`nH`IIE(88JMb74K=}<
zh7UR-|EZQTey`1#QyU69&7r!6SW9!%EVPwa_kDML?i*PZQKvrGP7drV_VHkCv?I@H
jNpye9>*XHGo9+(EpXj#d4|3P#KjfwqjO@6%AS3Bt&|HBA
diff --git a/debug_toolbar/locale/es/LC_MESSAGES/django.po b/debug_toolbar/locale/es/LC_MESSAGES/django.po
index 7babef326..d757cce1f 100644
--- a/debug_toolbar/locale/es/LC_MESSAGES/django.po
+++ b/debug_toolbar/locale/es/LC_MESSAGES/django.po
@@ -12,44 +12,69 @@ msgid ""
msgstr ""
"Project-Id-Version: Django Debug Toolbar\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-20 17:23+0100\n"
-"PO-Revision-Date: 2021-10-01 11:10+0000\n"
-"Last-Translator: Daniel Iglesias \n"
-"Language-Team: Spanish (http://www.transifex.com/django-debug-toolbar/django-"
-"debug-toolbar/language/es/)\n"
-"Language: es\n"
+"POT-Creation-Date: 2024-08-06 07:12-0500\n"
+"PO-Revision-Date: 2010-11-30 00:00+0000\n"
+"Last-Translator: Daniel Iglesias , 2021\n"
+"Language-Team: Spanish (http://app.transifex.com/django-debug-toolbar/django-debug-toolbar/language/es/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"Language: es\n"
+"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
-#: apps.py:15
+#: apps.py:18
msgid "Debug Toolbar"
msgstr "Barra de herramientas de Depuración"
-#: panels/cache.py:180
+#: panels/alerts.py:67
+#, python-brace-format
+msgid ""
+"Form with id \"{form_id}\" contains file input, but does not have the "
+"attribute enctype=\"multipart/form-data\"."
+msgstr ""
+
+#: panels/alerts.py:70
+msgid ""
+"Form contains file input, but does not have the attribute "
+"enctype=\"multipart/form-data\"."
+msgstr ""
+
+#: panels/alerts.py:73
+#, python-brace-format
+msgid ""
+"Input element references form with id \"{form_id}\", but the form does not "
+"have the attribute enctype=\"multipart/form-data\"."
+msgstr ""
+
+#: panels/alerts.py:77
+msgid "Alerts"
+msgstr ""
+
+#: panels/cache.py:168
msgid "Cache"
msgstr "Cache"
-#: panels/cache.py:186
+#: panels/cache.py:174
#, python-format
msgid "%(cache_calls)d call in %(time).2fms"
msgid_plural "%(cache_calls)d calls in %(time).2fms"
msgstr[0] "%(cache_calls)d llamada en %(time).2fms"
msgstr[1] "%(cache_calls)d llamadas en %(time).2fms"
+msgstr[2] "%(cache_calls)d llamadas en %(time).2fms"
-#: panels/cache.py:195
+#: panels/cache.py:183
#, python-format
msgid "Cache calls from %(count)d backend"
msgid_plural "Cache calls from %(count)d backends"
msgstr[0] "%(count)d llamadas al Cache desde el backend"
msgstr[1] "%(count)d llamadas al Caché desde backends"
+msgstr[2] "%(count)d llamadas al Caché desde backends"
#: panels/headers.py:31
msgid "Headers"
msgstr "Encabezados"
-#: panels/history/panel.py:18 panels/history/panel.py:19
+#: panels/history/panel.py:19 panels/history/panel.py:20
msgid "History"
msgstr "Historial"
@@ -57,7 +82,7 @@ msgstr "Historial"
msgid "Profiling"
msgstr "Análisis de rendimiento"
-#: panels/redirects.py:14
+#: panels/redirects.py:17
msgid "Intercept redirects"
msgstr "Interceptar re-direcionamiento"
@@ -65,11 +90,11 @@ msgstr "Interceptar re-direcionamiento"
msgid "Request"
msgstr "Petición"
-#: panels/request.py:36
+#: panels/request.py:38
msgid ""
msgstr ""
-#: panels/request.py:53
+#: panels/request.py:55
msgid ""
msgstr ""
@@ -88,6 +113,7 @@ msgid "%(num_receivers)d receiver of 1 signal"
msgid_plural "%(num_receivers)d receivers of 1 signal"
msgstr[0] "%(num_receivers)d receptor de 1 señal"
msgstr[1] "%(num_receivers)d receptores de 1 señal"
+msgstr[2] "%(num_receivers)d receptores de 1 señal"
#: panels/signals.py:62
#, python-format
@@ -95,156 +121,160 @@ msgid "%(num_receivers)d receiver of %(num_signals)d signals"
msgid_plural "%(num_receivers)d receivers of %(num_signals)d signals"
msgstr[0] "%(num_receivers)d receptor de %(num_signals)d señales"
msgstr[1] "%(num_receivers)d receptores de %(num_signals)d señales"
+msgstr[2] "%(num_receivers)d receptores de %(num_signals)d señales"
#: panels/signals.py:67
msgid "Signals"
msgstr "Señales"
-#: panels/sql/panel.py:23
-msgid "Autocommit"
-msgstr "Autocommit"
-
-#: panels/sql/panel.py:24
+#: panels/sql/panel.py:30 panels/sql/panel.py:41
msgid "Read uncommitted"
msgstr "Leer cambios tentativos"
-#: panels/sql/panel.py:25
+#: panels/sql/panel.py:31 panels/sql/panel.py:43
msgid "Read committed"
msgstr "Leer cambios permanentes"
-#: panels/sql/panel.py:26
+#: panels/sql/panel.py:32 panels/sql/panel.py:45
msgid "Repeatable read"
msgstr "Lectura repetible"
-#: panels/sql/panel.py:27
+#: panels/sql/panel.py:33 panels/sql/panel.py:47
msgid "Serializable"
msgstr "Serializable"
#: panels/sql/panel.py:39
+msgid "Autocommit"
+msgstr "Autocommit"
+
+#: panels/sql/panel.py:61 panels/sql/panel.py:71
msgid "Idle"
msgstr "Inactivo"
-#: panels/sql/panel.py:40
+#: panels/sql/panel.py:62 panels/sql/panel.py:72
msgid "Active"
msgstr "Activo"
-#: panels/sql/panel.py:41
+#: panels/sql/panel.py:63 panels/sql/panel.py:73
msgid "In transaction"
msgstr "En transacción"
-#: panels/sql/panel.py:42
+#: panels/sql/panel.py:64 panels/sql/panel.py:74
msgid "In error"
msgstr "En error"
-#: panels/sql/panel.py:43
+#: panels/sql/panel.py:65 panels/sql/panel.py:75
msgid "Unknown"
msgstr "Desconocido"
-#: panels/sql/panel.py:130
+#: panels/sql/panel.py:162
msgid "SQL"
msgstr "SQL"
-#: panels/sql/panel.py:135
+#: panels/sql/panel.py:168
#, python-format
msgid "%(query_count)d query in %(sql_time).2fms"
msgid_plural "%(query_count)d queries in %(sql_time).2fms"
msgstr[0] ""
msgstr[1] ""
+msgstr[2] ""
-#: panels/sql/panel.py:147
+#: panels/sql/panel.py:180
#, python-format
msgid "SQL queries from %(count)d connection"
msgid_plural "SQL queries from %(count)d connections"
msgstr[0] ""
msgstr[1] ""
+msgstr[2] ""
-#: panels/staticfiles.py:84
+#: panels/staticfiles.py:82
#, python-format
msgid "Static files (%(num_found)s found, %(num_used)s used)"
msgstr "Archivos estáticos (%(num_found)s encontrados, %(num_used)s en uso)"
-#: panels/staticfiles.py:105
+#: panels/staticfiles.py:103
msgid "Static files"
msgstr "Archivos estáticos"
-#: panels/staticfiles.py:111
+#: panels/staticfiles.py:109
#, python-format
msgid "%(num_used)s file used"
msgid_plural "%(num_used)s files used"
msgstr[0] "%(num_used)s archivo usado"
msgstr[1] "%(num_used)s archivos usados"
+msgstr[2] "%(num_used)s archivos usados"
-#: panels/templates/panel.py:143
+#: panels/templates/panel.py:101
msgid "Templates"
msgstr "Plantillas"
-#: panels/templates/panel.py:148
+#: panels/templates/panel.py:106
#, python-format
msgid "Templates (%(num_templates)s rendered)"
msgstr "Plantillas (%(num_templates)s renderizadas)"
-#: panels/templates/panel.py:180
+#: panels/templates/panel.py:195
msgid "No origin"
msgstr "Sin origen"
-#: panels/timer.py:25
+#: panels/timer.py:27
#, python-format
msgid "CPU: %(cum)0.2fms (%(total)0.2fms)"
msgstr "CPU: %(cum)0.2fms (%(total)0.2fms)"
-#: panels/timer.py:30
+#: panels/timer.py:32
#, python-format
msgid "Total: %0.2fms"
msgstr "Total: %0.2fms"
-#: panels/timer.py:36 templates/debug_toolbar/panels/history.html:9
+#: panels/timer.py:38 templates/debug_toolbar/panels/history.html:9
#: templates/debug_toolbar/panels/sql_explain.html:11
#: templates/debug_toolbar/panels/sql_profile.html:12
#: templates/debug_toolbar/panels/sql_select.html:11
msgid "Time"
msgstr "Tiempo"
-#: panels/timer.py:44
+#: panels/timer.py:46
msgid "User CPU time"
msgstr "Tiempo en CPU de usuario"
-#: panels/timer.py:44
+#: panels/timer.py:46
#, python-format
msgid "%(utime)0.3f msec"
msgstr "%(utime)0.3f mseg"
-#: panels/timer.py:45
+#: panels/timer.py:47
msgid "System CPU time"
msgstr "Tiempo en CPU del sistema"
-#: panels/timer.py:45
+#: panels/timer.py:47
#, python-format
msgid "%(stime)0.3f msec"
msgstr "%(stime)0.3f mseg"
-#: panels/timer.py:46
+#: panels/timer.py:48
msgid "Total CPU time"
msgstr "Tiempo total de CPU"
-#: panels/timer.py:46
+#: panels/timer.py:48
#, python-format
msgid "%(total)0.3f msec"
msgstr "%(total)0.3f mseg"
-#: panels/timer.py:47
+#: panels/timer.py:49
msgid "Elapsed time"
msgstr "Tiempo transcurrido"
-#: panels/timer.py:47
+#: panels/timer.py:49
#, python-format
msgid "%(total_time)0.3f msec"
msgstr "%(total_time)0.3f mseg"
-#: panels/timer.py:49
+#: panels/timer.py:51
msgid "Context switches"
msgstr "Cambios de contexto"
-#: panels/timer.py:50
+#: panels/timer.py:52
#, python-format
msgid "%(vcsw)d voluntary, %(ivcsw)d involuntary"
msgstr "%(vcsw)d voluntario, %(ivcsw)d involuntario"
@@ -253,15 +283,19 @@ msgstr "%(vcsw)d voluntario, %(ivcsw)d involuntario"
msgid "Versions"
msgstr "Versiones"
-#: templates/debug_toolbar/base.html:22
+#: templates/debug_toolbar/base.html:23
msgid "Hide toolbar"
msgstr "Ocutar barra de herramientas"
-#: templates/debug_toolbar/base.html:22
+#: templates/debug_toolbar/base.html:23
msgid "Hide"
msgstr "Ocultar"
-#: templates/debug_toolbar/base.html:29
+#: templates/debug_toolbar/base.html:25 templates/debug_toolbar/base.html:26
+msgid "Toggle Theme"
+msgstr ""
+
+#: templates/debug_toolbar/base.html:35
msgid "Show toolbar"
msgstr "Mostrar barra de herramientas"
@@ -273,6 +307,14 @@ msgstr "Deshabilitar para el próximo y sucesivos peticiones"
msgid "Enable for next and successive requests"
msgstr "Habilitar para el próximo y sucesivos peticiones"
+#: templates/debug_toolbar/panels/alerts.html:4
+msgid "Alerts found"
+msgstr ""
+
+#: templates/debug_toolbar/panels/alerts.html:11
+msgid "No alerts found"
+msgstr ""
+
#: templates/debug_toolbar/panels/cache.html:2
msgid "Summary"
msgstr "Resúmen"
@@ -356,9 +398,7 @@ msgstr "Entorno WSGI"
msgid ""
"Since the WSGI environ inherits the environment of the server, only a "
"significant subset is shown below."
-msgstr ""
-"Ya que el entorno WSGI hereda el entorno del servidor, solo un subconjunto "
-"significativo es mostrado más abajo."
+msgstr "Ya que el entorno WSGI hereda el entorno del servidor, solo un subconjunto significativo es mostrado más abajo."
#: templates/debug_toolbar/panels/history.html:10
msgid "Method"
@@ -470,6 +510,7 @@ msgid "%(num)s query"
msgid_plural "%(num)s queries"
msgstr[0] "%(num)s consulta"
msgstr[1] "%(num)s consultas"
+msgstr[2] "%(num)s consultas"
#: templates/debug_toolbar/panels/sql.html:8
#, python-format
@@ -483,9 +524,7 @@ msgstr ""
msgid ""
"and %(dupes)s duplicates"
-msgstr ""
-"y %(dupes)s repetidos"
+msgstr "y %(dupes)s repetidos"
#: templates/debug_toolbar/panels/sql.html:34
msgid "Query"
@@ -563,6 +602,7 @@ msgid "Static file path"
msgid_plural "Static file paths"
msgstr[0] "Ruta a archivos estático"
msgstr[1] "Rutas a archivos estáticos"
+msgstr[2] "Rutas a archivos estáticos"
#: templates/debug_toolbar/panels/staticfiles.html:7
#, python-format
@@ -583,12 +623,14 @@ msgid "Static file app"
msgid_plural "Static file apps"
msgstr[0] "Aplicación a archivos estáticos"
msgstr[1] "Aplicaciones de archivos estáticos"
+msgstr[2] "Aplicaciones de archivos estáticos"
#: templates/debug_toolbar/panels/staticfiles.html:25
msgid "Static file"
msgid_plural "Static files"
msgstr[0] "Archivo estático"
msgstr[1] "Archivos estáticos"
+msgstr[2] "Archivos estáticos"
#: templates/debug_toolbar/panels/staticfiles.html:39
#, python-format
@@ -596,6 +638,7 @@ msgid "%(payload_count)s file"
msgid_plural "%(payload_count)s files"
msgstr[0] "%(payload_count)s archivo"
msgstr[1] "%(payload_count)s archivos"
+msgstr[2] "%(payload_count)s archivos"
#: templates/debug_toolbar/panels/staticfiles.html:44
msgid "Location"
@@ -610,12 +653,14 @@ msgid "Template path"
msgid_plural "Template paths"
msgstr[0] "Ruta de plantilla"
msgstr[1] "Rutas de plantillas"
+msgstr[2] "Rutas de plantillas"
#: templates/debug_toolbar/panels/templates.html:13
msgid "Template"
msgid_plural "Templates"
msgstr[0] "Plantilla"
msgstr[1] "Plantillas"
+msgstr[2] "Plantillas"
#: templates/debug_toolbar/panels/templates.html:22
#: templates/debug_toolbar/panels/templates.html:40
@@ -627,6 +672,7 @@ msgid "Context processor"
msgid_plural "Context processors"
msgstr[0] "Procesador de contexto"
msgstr[1] "Procesadores de contexto"
+msgstr[2] "Procesadores de contexto"
#: templates/debug_toolbar/panels/timer.html:2
msgid "Resource usage"
@@ -669,16 +715,10 @@ msgid ""
"The Django Debug Toolbar has intercepted a redirect to the above URL for "
"debug viewing purposes. You can click the above link to continue with the "
"redirect as normal."
-msgstr ""
-"El Django Debug Toolbar ha interceptado un re-direccionamiento a la "
-"dirección de Internet mostrada arriba, con el propósito de inspeccionarla. "
-"Usted puede hacer clic en el vínculo de arriba para continuar con el re-"
-"direccionamiento normalmente."
+msgstr "El Django Debug Toolbar ha interceptado un re-direccionamiento a la dirección de Internet mostrada arriba, con el propósito de inspeccionarla. Usted puede hacer clic en el vínculo de arriba para continuar con el re-direccionamiento normalmente."
#: views.py:16
msgid ""
"Data for this panel isn't available anymore. Please reload the page and "
"retry."
-msgstr ""
-"La información de este panel ya no se encuentra disponible. Por favor "
-"recargue la página y pruebe nuevamente."
+msgstr "La información de este panel ya no se encuentra disponible. Por favor recargue la página y pruebe nuevamente."
diff --git a/debug_toolbar/locale/fa/LC_MESSAGES/django.mo b/debug_toolbar/locale/fa/LC_MESSAGES/django.mo
index 403810b2c994d292726d5deded8106311bf7c082..fa30fd402f9ba6ae1e196f1f93805de3f9468fee 100644
GIT binary patch
literal 10013
zcmchbdyE}deaBBijEkE#t&^rDrgV~!c$fID*A5NI#y0q|P7JoQvDZ#1P0Z}Qv%6#8
zJ99HLch?Iokl@Eg7+Qg5Bx|SN63Ap5-RqpEjlnJ_2qBUj+NW8?QHJ7q|iZdGM&iIq+usUv&Mig1z*=1>OkW@H57|3B285
z3FObblb<(&gATWXnzs`~6!R#!7#s(G7OaD}fgb@Efu936gR`LKzYMaac?Cp8vzSGi
zcReUomx8EbmVs{rmxDhCZUwc^qoC#o;C65ysC6%Zurz-K_JCgjmw~T<+VAEYoPOYP
z`Xx|&c7b~Teo%bILGAN6DEX$``wzSEkGt_tgPMO7WDD~&C_8=ul)Nv3Zvg)ulpmU)
z=D!5We%}LS*Z&1e;35`jzq>){e=jJxHi4_ahe6rzW1!Z55@e}43ToY~8$SU`{_}49
z&p^rXqI>@(P<@fD!-SOaSPAgJ}jp!Nws
z`5^=)|0K8-JmC6YarkwIFM-3Q0uO}snGLAP<(H5{kMbi
z(|w@)GUKK$e<4p!lYs`0WR^{s~a_c?y&te$T!CL-+m}*FOnr-g!`R{52?h`~x_9
zjWPcMK1KfsN&PF}&A$k5@E$M#p9dcS-}+0%ya`ZwY2Iv%2iy)W2RDHluY&i2zYR+M
zFM*iO{3G}a;LD)u&LV!KkLR!#)cn;TTbj+F?D81+R&XyUIi3Qg?>~c+;I~29Z4XKM
z%ivy6_L>H@-zPxD*XKdm;S6{m_~#&^m{;8RO%zMM4ygS<3vLE4g3@yl
zn_&vm1InK3!S{mOLB-E!KtwZ7gW~f=Q2Klsl%8J$+1kA1-Y;eo$$c}ZdCNdT*(?X&
z2HxlTkAbpV9rVB{*Z&Ntxcoe*{ZD`c;5pZS8I;`r3EmFA8D|fIYr$K=kAaHwKLPIm
zp98heWjFq>uKztya{j>KwO*mmVo>&524W&}C&-`K$dBw^0a;=aQ1<+u
zQ0u<|$}ismHGUn!DQ<5CwQen(!0p!)IKp!O|;Zv;OCO0FkC@%;pd=;n{y
z_+L2uTTpU*4U`}L36%Z*9n`-6?Z$5)i4oh{UUBdaXfY(8?SW9sWRPUgL)h9!F{XG>
zjPAE1#m@%Ueh92U?|1!fc#O_(LCQzjdJ!a74h-ukuA5
zdN-6piV;0K3NSkz3gidX0OjqwpiPh-TyK4>_HRH{NU^1-1gWk~Lh`p_Naxo5(1)R6
zNO7?i+6I-OhoRL_2(5x1fb_hf0J9RDaP3FI-O!WJAhZV3^J|dm+g(rsDV9{H-UGFs
zeXj8YScBr$3-Eo=uS0i3d!b!WKlD!MgV42*9>uDjN1*M{I%otUJk5hp1JW}JjjM4-
zPuVYz2YbqXwVL);JfRmx-W@$zSPOdlR*%-w1t+Bo&59dQ)|+~1SPQFu;yvC7k}yd7
zU=THGdy=3WgcCuceOhfV9%V1RO~bLsw=%faYphCtyk%Oo3hA`b595Btyha*S&}=lU
z2A<@p6>Ed3!dB_y)jjj9di6}K^(u2yyRyIU?oqFn24(io;>@r1
zUNur|(LLO_YUxBdox}+faTSO8$_(VlHU%S%F>g4It0R75HifC2VmFE;vX-Qcvcx7ASxpe8=)b8^uZCqm
z3o6*M(x?Y1;jX|TeFv+4otU>>Ggzx