title: Using Python 2.X's locale module to format numbers and currency
body: <p>The task is to format numbers, currency amounts and dates as <code>unicode</code> strings in a locale-aware manner.</p>
  
  <p>First naive attempt with numbers gave hope:</p>
  
  <pre><code>Python 2.7 (r27:82525, Jul  4 2010, 09:01:59) [MSC v.1500 32 bit (Intel)] on win32
  Type "help", "copyright", "credits" or "license" for more information.
  &gt;&gt;&gt; import locale
  &gt;&gt;&gt; locale.setlocale(locale.LC_ALL, '')
  'English_Australia.1252'
  &gt;&gt;&gt; locale.format("%d", 12345678, grouping=True)
  '12,345,678'
  &gt;&gt;&gt; locale.format(u"%d", 12345678, grouping=True)
  u'12,345,678'
  &gt;&gt;&gt;
  </code></pre>
  
  <p>Now try French:</p>
  
  <pre><code>&gt;&gt;&gt; locale.setlocale(locale.LC_ALL, 'French_France')
  'French_France.1252'
  &gt;&gt;&gt; locale.format("%d", 12345678, grouping=True)
  '12\xa0345\xa0678'
  &gt;&gt;&gt; locale.format(u"%d", 12345678, grouping=True)
  Traceback (most recent call last):
    File "&lt;stdin&gt;", line 1, in &lt;module&gt;
    File "C:\python27\lib\locale.py", line 190, in format
      return _format(percent, value, grouping, monetary, *additional)
    File "C:\python27\lib\locale.py", line 211, in _format
      formatted, seps = _group(formatted, monetary=monetary)
    File "C:\python27\lib\locale.py", line 160, in _group
      left_spaces + thousands_sep.join(groups) + right_spaces,
  UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 0: ordinal not in range(128)
  </code></pre>
  
  <p>What is happening here?</p>
  
  <pre><code>&gt;&gt;&gt; locale.localeconv() # output edited for brevity
  {'thousands_sep': '\xa0', 'mon_thousands_sep': '\xa0', 'currency_symbol': '\x80'}
  </code></pre>
  
  <p>Wah! Looks a little legacyish. A work-around suggests itself:</p>
  
  <pre><code>&gt;&gt;&gt; locale.format("%d", 12345678, grouping=True).decode(locale.getpreferredencoding())
  u'12\xa0345\xa0678'
  &gt;&gt;&gt;
  </code></pre>
  
  <p><strong>UPDATE 1</strong> <code>locale.getpreferredencoding()</code> is <strong>NOT</strong> the way to go; use <code>locale.getlocale()[1]</code> instead:</p>
  
  <pre><code>Python 2.7 (r27:82525, Jul  4 2010, 09:01:59) [MSC v.1500 32 bit (Intel)] on win32
  Type "help", "copyright", "credits" or "license" for more information.
  &gt;&gt;&gt; import locale
  &gt;&gt;&gt; locale.getpreferredencoding(), locale.getlocale()
  ('cp1252', (None, None))
  &gt;&gt;&gt; locale.setlocale(locale.LC_ALL, '')
  'English_Australia.1252'
  &gt;&gt;&gt; locale.getpreferredencoding(), locale.getlocale()
  ('cp1252', ('English_Australia', '1252'))
  &gt;&gt;&gt; locale.setlocale(locale.LC_ALL, 'russian_russia')
  'Russian_Russia.1251'
  &gt;&gt;&gt; locale.getpreferredencoding(), locale.getlocale()
  ('cp1252', ('Russian_Russia', '1251')) #### Whoops! ####
  &gt;&gt;&gt;
  </code></pre>
  
  <p><strong>UPDATE 2</strong> There are very similar problems with the strftime() family and with str.format()</p>
  
  <pre><code>&gt;&gt;&gt; locale.setlocale(locale.LC_ALL, 'french_france')
  'French_France.1252'
  &gt;&gt;&gt; format(12345678, 'n')
  '12\xa0345\xa0678'
  &gt;&gt;&gt; format(12345678, u'n') # type triggers cast to unicode somehow
  Traceback (most recent call last):
    File "&lt;stdin&gt;", line 1, in &lt;module&gt;
  UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 2: ordinal not in range(128)
  &gt;&gt;&gt; import datetime;datetime.date(1999,12,31).strftime(u'%B') # type is ignored
  'd\xe9cembre'
  &gt;&gt;&gt;
  </code></pre>
  
  <p>In all cases, the workaround is to use only <code>str</code> objects when calling these methods, get a <code>str</code> result, and decode it using the encoding obtained by <code>locale.getlocale()[1]</code></p>
  
  <p>Other problems:</p>
  
  <p>(1) It's a considerable nuisance when testing/exploring that the Windows locale names are not only different from POSIX ("fr_FR") but also verbose, and not fully documented. For example, evidently the grouping in India is not "every 3 digits" ... I can't find the locale to use to explore this; attempts like "Hindi" and "Hindi_India" don't work.</p>
  
  <p>(2) Some of the localeconv() data is just plain wrong. E.g. for Korean the currency symbol is given as <code>'\\'</code> i.e. a single backslash. I'm aware that some 7-bit legacy charsets are not ASCII-compatible and that chr(92) was sometimes used for the local currency symbol, so I expected <code>'\\'</code>.decode('949') to produce a won symbol, not just <code>u'\\'</code></p>
  
  <p>I'm aware of modules such as <code>babel</code> but I don't particularly want to impose a big external dependency like that. Can I get correctness and convenience at the same time? Is there something about the <code>locale</code> module that I've missed?</p>