summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2021-09-08 08:37:27 +0200
committerGitHub <noreply@github.com>2021-09-08 08:37:27 +0200
commit4a43335d300da942602fbf216cd0a53b60827ab4 (patch)
tree0fa559e6c92066934e0c79cada2293b986e56e29
parent301a85a12f3c2c9427c7ff581fd4683bab1f29f6 (diff)
downloaddjango-4a43335d300da942602fbf216cd0a53b60827ab4.tar.gz
Fixed #30086, Refs #32873 -- Made floatformat template filter independent of USE_L10N.
-rw-r--r--django/template/defaultfilters.py40
-rw-r--r--docs/ref/templates/builtins.txt19
-rw-r--r--docs/releases/4.0.txt7
-rw-r--r--tests/i18n/tests.py18
-rw-r--r--tests/template_tests/filter_tests/test_floatformat.py16
5 files changed, 79 insertions, 21 deletions
diff --git a/django/template/defaultfilters.py b/django/template/defaultfilters.py
index 1c844580c6..5ccef38048 100644
--- a/django/template/defaultfilters.py
+++ b/django/template/defaultfilters.py
@@ -126,13 +126,29 @@ def floatformat(text, arg=-1):
* {{ 6666.6666|floatformat:"2g" }} displays "6,666.67"
* {{ 10000|floatformat:"g" }} displays "10,000"
+ If arg has the 'u' suffix, force the result to be unlocalized. When the
+ active locale is pl (Polish):
+
+ * {{ 66666.6666|floatformat:"2" }} displays "66666,67"
+ * {{ 66666.6666|floatformat:"2u" }} displays "66666.67"
+
If the input float is infinity or NaN, display the string representation
of that value.
"""
force_grouping = False
- if isinstance(arg, str) and arg.endswith('g'):
- force_grouping = True
- arg = arg[:-1] or -1
+ use_l10n = True
+ if isinstance(arg, str):
+ last_char = arg[-1]
+ if arg[-2:] in {'gu', 'ug'}:
+ force_grouping = True
+ use_l10n = False
+ arg = arg[:-2] or -1
+ elif last_char == 'g':
+ force_grouping = True
+ arg = arg[:-1] or -1
+ elif last_char == 'u':
+ use_l10n = False
+ arg = arg[:-1] or -1
try:
input_val = repr(text)
d = Decimal(input_val)
@@ -152,9 +168,12 @@ def floatformat(text, arg=-1):
return input_val
if not m and p < 0:
- return mark_safe(
- formats.number_format('%d' % (int(d)), 0, force_grouping=force_grouping),
- )
+ return mark_safe(formats.number_format(
+ '%d' % (int(d)),
+ 0,
+ use_l10n=use_l10n,
+ force_grouping=force_grouping,
+ ))
exp = Decimal(1).scaleb(-abs(p))
# Set the precision high enough to avoid an exception (#15789).
@@ -174,9 +193,12 @@ def floatformat(text, arg=-1):
if sign and rounded_d:
digits.append('-')
number = ''.join(reversed(digits))
- return mark_safe(
- formats.number_format(number, abs(p), force_grouping=force_grouping),
- )
+ return mark_safe(formats.number_format(
+ number,
+ abs(p),
+ use_l10n=use_l10n,
+ force_grouping=force_grouping,
+ ))
@register.filter(is_safe=True)
diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt
index 936c80cdb5..baf0608a40 100644
--- a/docs/ref/templates/builtins.txt
+++ b/docs/ref/templates/builtins.txt
@@ -1736,6 +1736,18 @@ example, when the active locale is ``en`` (English):
``34232.00`` ``{{ value|floatformat:"-3g" }}`` ``34,232``
============ ================================= =============
+Output is always localized (independently of the :ttag:`{% localize off %}
+<localize>` tag) unless the argument passed to ``floatformat`` has the ``u``
+suffix, which will force disabling localization. For example, when the active
+locale is ``pl`` (Polish):
+
+============ ================================= =============
+``value`` Template Output
+============ ================================= =============
+``34.23234`` ``{{ value|floatformat:"3" }}`` ``34,232``
+``34.23234`` ``{{ value|floatformat:"3u" }}`` ``34.232``
+============ ================================= =============
+
Using ``floatformat`` with no argument is equivalent to using ``floatformat``
with an argument of ``-1``.
@@ -1743,6 +1755,13 @@ with an argument of ``-1``.
The ``g`` suffix to force grouping by thousand separators was added.
+.. versionchanged:: 4.0
+
+ ``floatformat`` template filter no longer depends on the
+ :setting:`USE_L10N` setting and always returns localized output.
+
+ The ``u`` suffix to force disabling localization was added.
+
.. templatefilter:: force_escape
``force_escape``
diff --git a/docs/releases/4.0.txt b/docs/releases/4.0.txt
index 88b3c8ac37..7ae566d43a 100644
--- a/docs/releases/4.0.txt
+++ b/docs/releases/4.0.txt
@@ -355,7 +355,8 @@ Signals
Templates
~~~~~~~~~
-* ...
+* :tfilter:`floatformat` template filter now allows using the ``u`` suffix to
+ force disabling localization.
Tests
~~~~~
@@ -574,6 +575,10 @@ Miscellaneous
<overriding-built-in-widget-templates>` with the appropriate template from
Django 3.2.
+* The :tfilter:`floatformat` template filter no longer depends on the
+ :setting:`USE_L10N` setting and always returns localized output. Use the
+ ``u`` suffix to disable localization.
+
.. _deprecated-features-4.0:
Features deprecated in 4.0
diff --git a/tests/i18n/tests.py b/tests/i18n/tests.py
index eba4a8595c..104d986a2c 100644
--- a/tests/i18n/tests.py
+++ b/tests/i18n/tests.py
@@ -523,15 +523,15 @@ class FormattingTests(SimpleTestCase):
self.assertEqual('99999.999', Template('{{ f }}').render(self.ctxt))
self.assertEqual('Des. 31, 2009', Template('{{ d }}').render(self.ctxt))
self.assertEqual('Des. 31, 2009, 8:50 p.m.', Template('{{ dt }}').render(self.ctxt))
- self.assertEqual('66666.67', Template('{{ n|floatformat:2 }}').render(self.ctxt))
- self.assertEqual('100000.0', Template('{{ f|floatformat }}').render(self.ctxt))
+ self.assertEqual('66666.67', Template('{{ n|floatformat:"2u" }}').render(self.ctxt))
+ self.assertEqual('100000.0', Template('{{ f|floatformat:"u" }}').render(self.ctxt))
self.assertEqual(
'66666.67',
- Template('{{ n|floatformat:"2g" }}').render(self.ctxt),
+ Template('{{ n|floatformat:"2gu" }}').render(self.ctxt),
)
self.assertEqual(
'100000.0',
- Template('{{ f|floatformat:"g" }}').render(self.ctxt),
+ Template('{{ f|floatformat:"ug" }}').render(self.ctxt),
)
self.assertEqual('10:15 a.m.', Template('{{ t|time:"TIME_FORMAT" }}').render(self.ctxt))
self.assertEqual('12/31/2009', Template('{{ d|date:"SHORT_DATE_FORMAT" }}').render(self.ctxt))
@@ -628,12 +628,12 @@ class FormattingTests(SimpleTestCase):
)
# We shouldn't change the behavior of the floatformat filter re:
- # thousand separator and grouping when USE_L10N is False even
- # if the USE_THOUSAND_SEPARATOR, NUMBER_GROUPING and
- # THOUSAND_SEPARATOR settings are specified
+ # thousand separator and grouping when localization is disabled
+ # even if the USE_THOUSAND_SEPARATOR, NUMBER_GROUPING and
+ # THOUSAND_SEPARATOR settings are specified.
with self.settings(USE_THOUSAND_SEPARATOR=True, NUMBER_GROUPING=1, THOUSAND_SEPARATOR='!'):
- self.assertEqual('66666.67', Template('{{ n|floatformat:2 }}').render(self.ctxt))
- self.assertEqual('100000.0', Template('{{ f|floatformat }}').render(self.ctxt))
+ self.assertEqual('66666.67', Template('{{ n|floatformat:"2u" }}').render(self.ctxt))
+ self.assertEqual('100000.0', Template('{{ f|floatformat:"u" }}').render(self.ctxt))
def test_false_like_locale_formats(self):
"""
diff --git a/tests/template_tests/filter_tests/test_floatformat.py b/tests/template_tests/filter_tests/test_floatformat.py
index 64d65f7dc4..1035fb96da 100644
--- a/tests/template_tests/filter_tests/test_floatformat.py
+++ b/tests/template_tests/filter_tests/test_floatformat.py
@@ -2,7 +2,6 @@ from decimal import Decimal, localcontext
from django.template.defaultfilters import floatformat
from django.test import SimpleTestCase
-from django.test.utils import override_settings
from django.utils import translation
from django.utils.safestring import mark_safe
@@ -60,7 +59,6 @@ class FunctionTests(SimpleTestCase):
self.assertEqual(floatformat(1.5e-15, -20), '0.00000000000000150000')
self.assertEqual(floatformat(1.00000000000000015, 16), '1.0000000000000002')
- @override_settings(USE_L10N=True)
def test_force_grouping(self):
with translation.override('en'):
self.assertEqual(floatformat(10000, 'g'), '10,000')
@@ -73,6 +71,20 @@ class FunctionTests(SimpleTestCase):
# Invalid suffix.
self.assertEqual(floatformat(10000, 'g2'), '10000')
+ def test_unlocalize(self):
+ with translation.override('de', deactivate=True):
+ self.assertEqual(floatformat(66666.666, '2'), '66666,67')
+ self.assertEqual(floatformat(66666.666, '2u'), '66666.67')
+ with self.settings(
+ USE_THOUSAND_SEPARATOR=True,
+ NUMBER_GROUPING=3,
+ THOUSAND_SEPARATOR='!',
+ ):
+ self.assertEqual(floatformat(66666.666, '2gu'), '66!666.67')
+ self.assertEqual(floatformat(66666.666, '2ug'), '66!666.67')
+ # Invalid suffix.
+ self.assertEqual(floatformat(66666.666, 'u2'), '66666.666')
+
def test_zero_values(self):
self.assertEqual(floatformat(0, 6), '0.000000')
self.assertEqual(floatformat(0, 7), '0.0000000')