Opened 2 years ago

Last modified 2 years ago

#20601 new New feature

intcomma and floatformat internationalization error

Reported by: c.schmitt@… Owned by:
Component: Template system Version: 1.5
Severity: Normal Keywords: internationalization, humanize, contrib, float, floatcomma
Cc: merb Triage Stage: Accepted
Has patch: no 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 (10)

comment:1 Changed 2 years ago by merb

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

comment:2 Changed 2 years ago by merb

  • Cc merb added

comment:3 Changed 2 years ago by merb

  • Owner changed from nobody to merb
  • Status changed from new to assigned

comment:4 Changed 2 years ago by merb

  • Summary changed from intcomma and floatvalue internationalization error to intcomma and floatformat internationalization error

comment:5 in reply to: ↑ description Changed 2 years ago by merb

Replying to c.schmitt@…:

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.

i meant floatformat not floatvalue.

comment:6 Changed 2 years ago by merb

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.

Last edited 2 years ago by merb (previous) (diff)

comment:7 Changed 2 years ago by merb

  • Type changed from Cleanup/optimization to Bug

comment:8 Changed 2 years ago by merb

  • Owner merb deleted
  • Status changed from assigned to new

comment:9 Changed 2 years ago by claudep

  • Component changed from Python 2 to Template system
  • Triage Stage changed from Unreviewed to Accepted
  • Type changed from Bug to 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 Changed 2 years ago by merb

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'?

Note: See TracTickets for help on using tickets.
Back to Top