#20601 closed New feature (fixed)
Incorrect separators when chaining floatformat to intcomma in some locales
Reported by: | Owned by: | Jacob Walls | |
---|---|---|---|
Component: | Template system | Version: | 4.0 |
Severity: | Normal | Keywords: | internationalization, humanize, contrib, float, floatcomma |
Cc: | merb, Alexey, Cassiano R. N. dos Santos | Triage Stage: | Ready for checkin |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
When u use floatvalue "2" and intcomma together in a template the output of intcomma won't be internationalized.
Since intcomma wont work with decimals in django 1.5.1 i tried to convert a decimal to a float in a template, but it wont give me the excepted output.
When i have the value of 1000.11 it should be 1000,11 in germany, with intcomma(float(1000,11)) i get 1.000,11. But when i use Decimal(1000,11)|floatvalue"2"|intcomma, i will get 1,000,11. Thats a bug or maybe an unwanted behavior.
Change History (28)
comment:1 by , 11 years ago
comment:2 by , 11 years ago
Cc: | added |
---|
comment:3 by , 11 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:4 by , 11 years ago
Summary: | intcomma and floatvalue internationalization error → intcomma and floatformat internationalization error |
---|
comment:5 by , 11 years ago
comment:6 by , 11 years ago
This is the actual humanize function:
@register.filter(is_safe=True) def intcomma(value, use_l10n=True): """ Converts an integer to a string containing commas every three digits. For example, 3000 becomes '3,000' and 45000 becomes '45,000'. """ if settings.USE_L10N and use_l10n: try: if not isinstance(value, float): value = int(value) except (TypeError, ValueError): return intcomma(value, False) else: return number_format(value, force_grouping=True) orig = force_text(value) new = re.sub("^(-?\d+)(\d{3})", '\g<1>,\g<2>', orig) if orig == new: return new else: return intcomma(new, use_l10n)
The problem is that floatformat returns a SafeText type, so it isn't a instance of float and intcomma gets recalled with use_l10n=False. So this line gets called:
new = re.sub("^(-?\d+)(\d{3})", '\g<1>,\g<2>', orig)
This line will add an , to every 3rd place on the SafeText type so a string of:
1000,11 or 1000000,11 will be
1,000,11 or 1,000,000,11 which could get converted to an integer, so the next time intcomma gets called,
it will just say that it won't get changed so it returns the SafeText String that is incorrect and won't make any sense.
So this will be an uncorrect return value it should return either the correct output of 1.000.000,11 or nothing since it isn't a valid number.
So I think it would be better to better check the value for localized format numbers or maybe better make a SafeDecimal or SafeFloat variable as a output of floatformat.
Even this won't fix it: https://github.com/django/django/pull/785/files
since floatformat will return SafeText a localized version of a Decimal value.
comment:7 by , 11 years ago
Type: | Cleanup/optimization → Bug |
---|
comment:8 by , 11 years ago
Owner: | removed |
---|---|
Status: | assigned → new |
comment:9 by , 11 years ago
Component: | Python 2 → Template system |
---|---|
Triage Stage: | Unreviewed → Accepted |
Type: | Bug → New feature |
Basically, the issue is that both intcomma
and floatformat
take numbers (or number-convertible values) to output a string representation. So chaining them is basically broken. One strategy would be to try harder to make those string representation transformed back to numbers, but then the first transformation would be lost.
I'm of the opinion that either one of these filters should be able to do all necessary transformations. For example, we could imagine that the floatformat
argument takes an optional g
suffix to indicate grouping. So the result of Decimal(1000,11)|floatvalue:"2g"
would be 1.000,11 for German (i.e. numberformat
would be passed force_grouping=True
in floatformat
filter).
comment:10 by , 11 years ago
wouldn't it be better to make them type safe? Like raise an error if intcomma or floatformat won't get 'numbers' or 'localized_numbers'?
comment:12 by , 7 years ago
Cc: | added |
---|
comment:13 by , 7 years ago
Should we try to parse value to float?
Something like try to find float separator with regex, and convert it before isinstance
check
comment:14 by , 5 years ago
For the specific German case a fix:
'|'.join(intcomma(floatformat(amount, 2)).rsplit(',', 1)).replace(',', '.').replace('|', ',')
Maybe this helps anybody...
In my opinion a currency-filter with optional thousand separators would solve this issue for most people.
comment:15 by , 5 years ago
Has patch: | set |
---|---|
Owner: | set to |
Status: | new → assigned |
Version: | 1.10 → master |
comment:16 by , 5 years ago
Patch needs improvement: | set |
---|
comment:17 by , 4 years ago
Owner: | changed from | to
---|
comment:18 by , 4 years ago
Patch needs improvement: | unset |
---|---|
Summary: | intcomma and floatformat internationalization error → Incorrect separators when chaining floatvalue to intcomma in some locales |
comment:19 by , 4 years ago
Patch needs improvement: | set |
---|
comment:21 by , 4 years ago
Triage Stage: | Accepted → Ready for checkin |
---|
comment:22 by , 4 years ago
Summary: | Incorrect separators when chaining floatvalue to intcomma in some locales → Incorrect separators when chaining floatformat to intcomma in some locales |
---|
follow-up: 25 comment:24 by , 3 years ago
Is this fixed for Django 2.2?
Doing
{{ variable | intcomma | floatformat:2 }}
or
{{ variable | floatformat:2 | intcomma }}
does not work.
In the first case results broken, and in second, gives, e.g. 1,000,00 when the correct would be 1.000,00 for pt-BR (brazilian portuguese).
comment:25 by , 3 years ago
follow-up: 27 comment:26 by , 3 years ago
Cc: | added |
---|---|
Has patch: | unset |
Type: | New feature → Bug |
Version: | dev → 4.0 |
I'm just trying the fix in Django 4.0.1 with both
{{ variable | intcomma | floatformat:2 }} {# breaks template #}
and
{{ variable | floatformat:2 | intcomma }} {# results i.e., 10,123,00 (would be 10.123,00) #}
But the bug persists.
In my settings.py:
LANGUAGE_CODE = 'pt-BR' USE_I18N = True USE_L10N = True
comment:27 by , 3 years ago
Has patch: | set |
---|---|
Type: | Bug → New feature |
Replying to Cassiano R. N. dos Santos:
But the bug persists.
I don't see the "g" suffix in your example. Also in Django 4.0 the floatformat
template filter no longer depends on the USE_L10N
setting and always returns localized output. Have you tried {{ variable | floatformat:"2g" }}
?
Replying to c.schmitt@…:
i meant floatformat not floatvalue.