12

I learn from Currency formatting in Python, use the locale module to format numbers as currency. For instance,

#! /usr/bin/env python
# -*- coding: utf-8 -*-

import locale

value = 123456789

l = locale.setlocale(locale.LC_ALL, '')     # LC_CTYPE=en_US.UTF-8;LC_NUMERIC=fr_FR.UTF-8;LC_TIME=fr_FR.UTF-8;LC_COLLATE=en_US.UTF-8;LC_MONETARY=fr_FR.UTF-8;LC_MESSAGES=en_US.UTF-8;LC_PAPER=fr_FR.UTF-8;LC_NAME=fr_FR.UTF-8;LC_ADDRESS=fr_FR.UTF-8;LC_TELEPHONE=fr_FR.UTF-8;LC_MEASUREMENT=fr_FR.UTF-8;LC_IDENTIFICATION=fr_FR.UTF-8
s = locale.currency(value, grouping=True)   # 123 456 789,00 €

locale.setlocale(locale.LC_ALL, 'en_US.utf-8') 
s = locale.currency(value, grouping=True)   # $123,456,789.00

locale.setlocale(locale.LC_ALL, 'en_US')    # WHY? locale.Error: unsupported locale setting
s = locale.currency(value, grouping=True)

I'd like to format numbers to other currency, say de_DE. I encounter the issue locale.Error: unsupported locale setting since the locale de_DE is not in the list of locale -a.

locale.setlocale(locale.LC_ALL, 'de_DE')        # locale.Error: unsupported locale setting
s = locale.currency(value, grouping=True)

One solution is to add this locale to my machine. Is there a better way?

Community
  • 1
  • 1
SparkAndShine
  • 17,001
  • 22
  • 90
  • 134

3 Answers3

10

babel.numbers

In [22]: from babel.numbers import format_decimal
In [23]:  format_decimal(12345, locale='de_DE')
Out[23]: u'12.345'

In [24]: format_decimal(1.2345, locale='sv_SE')
Out[24]: u'1,234'

Or in your case format_currency:

In [7]: from babel.numbers import format_currency

In [8]: print format_currency(1099.98, 'USD', locale='en_US')
$1,099.98

In [9]: print format_currency(1099.98, 'USD', locale='es_CO')
1.099,98 US$

In [10]: print format_currency(1099.98, 'EUR', locale='de_DE')
1.099,98 €
Michael Davidson
  • 1,391
  • 1
  • 14
  • 31
Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
  • Thx. I just found [`babel.numbers.format_currency`](http://babel.pocoo.org/en/latest/api/numbers.html) under your guide. – SparkAndShine Jun 01 '16 at 22:33
  • No worries, it is a pretty neat lib, it does a multitude of things. I added the link to format_currency and the doc example. – Padraic Cunningham Jun 01 '16 at 22:35
  • 1
    I know you can parse without the dollar sign if you pass the locale but with `$123,456,789.00` I am not sure how or if you can handle that. http://babel.pocoo.org/en/latest/numbers.html#parsing-numbers – Padraic Cunningham Jun 01 '16 at 22:44
  • Thx. It is not fair to ask a new question. So, I start a new question, [Format currency as numbers in Python](http://stackoverflow.com/questions/37580151/format-currency-as-numbers-in-python). – SparkAndShine Jun 01 '16 at 23:04
  • 1
    No prob, I actually have an idea for a parser that can work for any currency, I will give you a ping when I get something working but hopefully there is a nice lib already – Padraic Cunningham Jun 01 '16 at 23:12
  • Many thanks. Sadly, [Format local currency as numbers in Python](http://stackoverflow.com/questions/37580151/format-local-currency-as-numbers-in-python) is labeled as duplicate. I don't think it is duplicate. – SparkAndShine Jun 01 '16 at 23:21
  • 1
    I reopened the question as it is certainly not a dupe, there is a lot more to going from a formatted currency string back to a decimal – Padraic Cunningham Jun 01 '16 at 23:25
4

For reference (for those that are looking to format numbers similar to how you would format currency), you can use locale.format_string to format numbers

value = 123456789

import locale
locale.setlocale(locale.LC_ALL, 'de_DE') 
print(locale.format_string('%.2f', value, True))

Would return

123.456.789,00
vrieswerk
  • 41
  • 3
  • This doesn't seem to work on python 3.7.6. I used the package babel and format_number instead. – squarism Mar 18 '20 at 18:33
  • It works with python 3.9 and 3.10, but you might need to add the locale to your OS. One can use `sudo dpkg-reconfigure locales` on Debian-based systems (from https://stackoverflow.com/a/43203667/6281925). – ksyrium Jul 12 '23 at 10:53
1

I know of two solutions to this:

Babel

Babel is the best solution because you can choose any currency, regardless of the locale.

The down side is that it's poorly documented. To know all the options, you'll have to read the Babel source code for the function you want to use

Install Babel:

$ pip install Babel

How to use:

import babel.numbers

amount = 123456789.123

print(babel.numbers.format_currency(amount, 'EUR', locale='fr_CA'))
# 123 456 789,12 €

print(babel.numbers.format_currency(amount, 'EUR', locale='en_CA'))
# €123,456,789.12

print(babel.numbers.format_currency(amount, '', locale='en_CA'))
# 123,456,789.12

localize.currency()

One limitation of locale.currency() is that it presumes the currency that matches the locale. For example en_US => $/USD and fr_FR => €/EUR So you may want to use the String.replace() method to replace the currency symbol after if the displayed currency doesn't match the locale.

Based on the locale setting, for example en_US or en_GB, fr_FR or fr_CA, it will know:

  • Which decimal separator to use (eg 100.00 vs 100,00)
  • Which thousands separator to use (eg 1,000 vs 1.000)
  • Which currency symbol to use (eg $100 vs €100 or USD 100 vs EUR 100)
  • Where to place the currency symbol (eg $100 vs 100 $)
import locale

locale.setlocale(locale.LC_ALL, 'fr_FR')

amount = 123456789.123
grouping = True  # thousands separator

# '123.456.789,12 Eu'
locale.currency(amount, symbol=True, grouping=True, international=False)

# '123.456.789,12 EUR'
locale.currency(amount, symbol=True, grouping=True, international=False)

# '123.456,789'
locale.currency(amount, symbol=False, grouping=True)

# '123456,789'
locale.currency(amount, symbol=False, grouping=True)

The optional arguments are as follows

# which currency symbol to use, and where to place it
symbol=True and international=True # => 'USD 100.00'
symbol=True and international=False # => '$100.00'
symbol=False # => '100.00'

# thousands separator
grouping = True # => '1000.00'
grouping = False # => '1,000.00'
Adonis Gaitatzis
  • 3,189
  • 26
  • 24