Skip to content

Commit da88665

Browse files
amurekipre-commit-ci[bot]tim-schillingmatthiask
authored
Use correct language in panels (#1717)
* Use correct language in panels PR #1703 introduced a bug where SQLPanel (and probably others) is rendered in `LANGUAGE_CODE` language, while it should use `TOOLBAR_LANGUAGE` if provided. This PR fixes panel's content language. * Add missing changelog entries * Use code formatting and include more details on the recent change. * Create decorator to use TOOLBAR_LANGUAGE in toolbar specific views. This reviews the third-party panel documentation to reference these two decorators and explain them. They aren't necessary but should be used. Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Tim Schilling <schillingt@better-simple.com> Co-authored-by: Matthias Kestenholz <mk@feinheit.ch>
1 parent 145b112 commit da88665

File tree

10 files changed

+115
-10
lines changed

10 files changed

+115
-10
lines changed

debug_toolbar/decorators.py

+16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import functools
22

33
from django.http import Http404
4+
from django.utils.translation import get_language, override as language_override
5+
6+
from debug_toolbar import settings as dt_settings
47

58

69
def require_show_toolbar(view):
@@ -15,3 +18,16 @@ def inner(request, *args, **kwargs):
1518
return view(request, *args, **kwargs)
1619

1720
return inner
21+
22+
23+
def render_with_toolbar_language(view):
24+
"""Force any rendering within the view to use the toolbar's language."""
25+
26+
@functools.wraps(view)
27+
def inner(request, *args, **kwargs):
28+
29+
lang = dt_settings.get_config()["TOOLBAR_LANGUAGE"] or get_language()
30+
with language_override(lang):
31+
return view(request, *args, **kwargs)
32+
33+
return inner

debug_toolbar/panels/history/views.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
from django.http import HttpResponseBadRequest, JsonResponse
22
from django.template.loader import render_to_string
33

4-
from debug_toolbar.decorators import require_show_toolbar
4+
from debug_toolbar.decorators import render_with_toolbar_language, require_show_toolbar
55
from debug_toolbar.panels.history.forms import HistoryStoreForm
66
from debug_toolbar.toolbar import DebugToolbar
77

88

99
@require_show_toolbar
10+
@render_with_toolbar_language
1011
def history_sidebar(request):
1112
"""Returns the selected debug toolbar history snapshot."""
1213
form = HistoryStoreForm(request.GET)
@@ -37,6 +38,7 @@ def history_sidebar(request):
3738

3839

3940
@require_show_toolbar
41+
@render_with_toolbar_language
4042
def history_refresh(request):
4143
"""Returns the refreshed list of table rows for the History Panel."""
4244
form = HistoryStoreForm(request.GET)

debug_toolbar/panels/sql/views.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from django.template.loader import render_to_string
33
from django.views.decorators.csrf import csrf_exempt
44

5-
from debug_toolbar.decorators import require_show_toolbar
5+
from debug_toolbar.decorators import render_with_toolbar_language, require_show_toolbar
66
from debug_toolbar.forms import SignedDataForm
77
from debug_toolbar.panels.sql.forms import SQLSelectForm
88

@@ -18,6 +18,7 @@ def get_signed_data(request):
1818

1919
@csrf_exempt
2020
@require_show_toolbar
21+
@render_with_toolbar_language
2122
def sql_select(request):
2223
"""Returns the output of the SQL SELECT statement"""
2324
verified_data = get_signed_data(request)
@@ -47,6 +48,7 @@ def sql_select(request):
4748

4849
@csrf_exempt
4950
@require_show_toolbar
51+
@render_with_toolbar_language
5052
def sql_explain(request):
5153
"""Returns the output of the SQL EXPLAIN on the given query"""
5254
verified_data = get_signed_data(request)
@@ -85,6 +87,7 @@ def sql_explain(request):
8587

8688
@csrf_exempt
8789
@require_show_toolbar
90+
@render_with_toolbar_language
8891
def sql_profile(request):
8992
"""Returns the output of running the SQL and getting the profiling statistics"""
9093
verified_data = get_signed_data(request)

debug_toolbar/panels/templates/views.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
from django.template.loader import render_to_string
66
from django.utils.html import format_html, mark_safe
77

8-
from debug_toolbar.decorators import require_show_toolbar
8+
from debug_toolbar.decorators import render_with_toolbar_language, require_show_toolbar
99

1010

1111
@require_show_toolbar
12+
@render_with_toolbar_language
1213
def template_source(request):
1314
"""
1415
Return the source of a template, syntax-highlighted by Pygments if

debug_toolbar/views.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
from django.utils.html import escape
33
from django.utils.translation import gettext as _
44

5-
from debug_toolbar.decorators import require_show_toolbar
5+
from debug_toolbar.decorators import render_with_toolbar_language, require_show_toolbar
66
from debug_toolbar.toolbar import DebugToolbar
77

88

99
@require_show_toolbar
10+
@render_with_toolbar_language
1011
def render_panel(request):
1112
"""Render the contents of a panel"""
1213
toolbar = DebugToolbar.fetch(request.GET["store_id"])

docs/changes.rst

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ Pending
55
-------
66

77
* Fixed PostgreSQL raw query with a tuple parameter during on explain.
8+
* Use ``TOOLBAR_LANGUAGE`` setting when rendering individual panels
9+
that are loaded via AJAX.
10+
* Add decorator for rendering toolbar views with ``TOOLBAR_LANGUAGE``.
811

912
3.8.1 (2022-12-03)
1013
------------------
@@ -27,6 +30,7 @@ Pending
2730
* Fix highlighting on history panel so odd rows are highlighted when
2831
selected.
2932
* Formalize support for Python 3.11.
33+
* Added ``TOOLBAR_LANGUAGE`` setting.
3034

3135
3.7.0 (2022-09-25)
3236
------------------

docs/configuration.rst

+3-3
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ Toolbar options
151151
the request doesn't originate from the toolbar itself, EG that
152152
``is_toolbar_request`` is false for a given request.
153153

154+
.. _TOOLBAR_LANGUAGE:
155+
154156
* ``TOOLBAR_LANGUAGE``
155157

156158
Default: ``None``
@@ -160,9 +162,7 @@ Toolbar options
160162
render the toolbar in a different language than what the application is
161163
rendered in. For example, if you wish to use English for development,
162164
but want to render your application in French, you would set this to
163-
``"en-us"`` and `settings.LANGUAGE_CODE`_ to ``"fr"``.
164-
165-
.. _settings.LANGUAGE_CODE: https://docs.djangoproject.com/en/stable/ref/settings/#std-setting-LANGUAGE_CODE
165+
``"en-us"`` and :setting:`LANGUAGE_CODE` to ``"fr"``.
166166

167167
Panel options
168168
~~~~~~~~~~~~~

docs/panels.rst

+12-3
Original file line numberDiff line numberDiff line change
@@ -350,9 +350,18 @@ Third-party panels must subclass :class:`~debug_toolbar.panels.Panel`,
350350
according to the public API described below. Unless noted otherwise, all
351351
methods are optional.
352352

353-
Panels can ship their own templates, static files and views. All views should
354-
be decorated with ``debug_toolbar.decorators.require_show_toolbar`` to prevent
355-
unauthorized access. There is no public CSS API at this time.
353+
Panels can ship their own templates, static files and views.
354+
355+
Any views defined for the third-party panel use the following decorators:
356+
357+
- ``debug_toolbar.decorators.require_show_toolbar`` - Prevents unauthorized
358+
access to the view.
359+
- ``debug_toolbar.decorators.render_with_toolbar_language`` - Supports
360+
internationalization for any content rendered by the view. This will render
361+
the response with the :ref:`TOOLBAR_LANGUAGE <TOOLBAR_LANGUAGE>` rather than
362+
:setting:`LANGUAGE_CODE`.
363+
364+
There is no public CSS API at this time.
356365

357366
.. autoclass:: debug_toolbar.panels.Panel
358367

tests/test_decorators.py

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from unittest.mock import patch
2+
3+
from django.http import HttpResponse
4+
from django.test import RequestFactory, TestCase
5+
from django.test.utils import override_settings
6+
7+
from debug_toolbar.decorators import render_with_toolbar_language
8+
9+
10+
@render_with_toolbar_language
11+
def stub_view(request):
12+
return HttpResponse(200)
13+
14+
15+
@override_settings(DEBUG=True, LANGUAGE_CODE="fr")
16+
class RenderWithToolbarLanguageTestCase(TestCase):
17+
@override_settings(DEBUG_TOOLBAR_CONFIG={"TOOLBAR_LANGUAGE": "de"})
18+
@patch("debug_toolbar.decorators.language_override")
19+
def test_uses_toolbar_language(self, mock_language_override):
20+
stub_view(RequestFactory().get("/"))
21+
mock_language_override.assert_called_once_with("de")
22+
23+
@patch("debug_toolbar.decorators.language_override")
24+
def test_defaults_to_django_language_code(self, mock_language_override):
25+
stub_view(RequestFactory().get("/"))
26+
mock_language_override.assert_called_once_with("fr")

tests/test_integration.py

+43
Original file line numberDiff line numberDiff line change
@@ -671,8 +671,51 @@ def test_toolbar_language_will_render_to_default_language_when_not_set(self):
671671
hide_button = self.selenium.find_element(By.ID, "djHideToolBarButton")
672672
assert hide_button.text == "Hide »"
673673

674+
self.get("/execute_sql/")
675+
sql_panel = self.selenium.find_element(By.ID, "SQLPanel")
676+
677+
# Click to show the SQL panel
678+
self.selenium.find_element(By.CLASS_NAME, "SQLPanel").click()
679+
680+
table = self.wait.until(
681+
lambda selenium: sql_panel.find_element(By.TAG_NAME, "table")
682+
)
683+
self.assertIn("Query", table.text)
684+
self.assertIn("Action", table.text)
685+
674686
@override_settings(DEBUG_TOOLBAR_CONFIG={"TOOLBAR_LANGUAGE": "pt-br"})
675687
def test_toolbar_language_will_render_to_locale_when_set(self):
676688
self.get("/regular/basic/")
677689
hide_button = self.selenium.find_element(By.ID, "djHideToolBarButton")
678690
assert hide_button.text == "Esconder »"
691+
692+
self.get("/execute_sql/")
693+
sql_panel = self.selenium.find_element(By.ID, "SQLPanel")
694+
695+
# Click to show the SQL panel
696+
self.selenium.find_element(By.CLASS_NAME, "SQLPanel").click()
697+
698+
table = self.wait.until(
699+
lambda selenium: sql_panel.find_element(By.TAG_NAME, "table")
700+
)
701+
self.assertIn("Query", table.text)
702+
self.assertIn("Linha", table.text)
703+
704+
@override_settings(DEBUG_TOOLBAR_CONFIG={"TOOLBAR_LANGUAGE": "en-us"})
705+
@override_settings(LANGUAGE_CODE="de")
706+
def test_toolbar_language_will_render_to_locale_when_set_both(self):
707+
self.get("/regular/basic/")
708+
hide_button = self.selenium.find_element(By.ID, "djHideToolBarButton")
709+
assert hide_button.text == "Hide »"
710+
711+
self.get("/execute_sql/")
712+
sql_panel = self.selenium.find_element(By.ID, "SQLPanel")
713+
714+
# Click to show the SQL panel
715+
self.selenium.find_element(By.CLASS_NAME, "SQLPanel").click()
716+
717+
table = self.wait.until(
718+
lambda selenium: sql_panel.find_element(By.TAG_NAME, "table")
719+
)
720+
self.assertIn("Query", table.text)
721+
self.assertIn("Action", table.text)

0 commit comments

Comments
 (0)