Commits

Vinay Sajip committed e2aac98 Draft

Whitespace and misc. other tidy-ups.

  • Participants
  • Parent commits 6e30dff

Comments (0)

Files changed (23)

File babel/compat.py

 
     from itertools import izip
     from ConfigParser import RawConfigParser
-    
+
     xrange = xrange
 
     from gettext import GNUTranslations

File babel/core.py

 
 def get_global(key):
     """Return the dictionary for the given key in the global data.
-    
+
     The global data is stored in the ``babel/global.dat`` file and contains
     information independent of individual locales.
-    
+
     >>> get_global('zone_aliases')['UTC'] == 'Etc/GMT'
     True
     >>> get_global('zone_territories')['Europe/Berlin'] == 'DE'
     True
-    
+
     :param key: the data key
     :return: the dictionary found in the global data under the given key
     :rtype: `dict`
 
 
 LOCALE_ALIASES = {
-    'ar': 'ar_SY', 'bg': 'bg_BG', 'bs': 'bs_BA', 'ca': 'ca_ES', 'cs': 'cs_CZ', 
-    'da': 'da_DK', 'de': 'de_DE', 'el': 'el_GR', 'en': 'en_US', 'es': 'es_ES', 
-    'et': 'et_EE', 'fa': 'fa_IR', 'fi': 'fi_FI', 'fr': 'fr_FR', 'gl': 'gl_ES', 
-    'he': 'he_IL', 'hu': 'hu_HU', 'id': 'id_ID', 'is': 'is_IS', 'it': 'it_IT', 
-    'ja': 'ja_JP', 'km': 'km_KH', 'ko': 'ko_KR', 'lt': 'lt_LT', 'lv': 'lv_LV', 
-    'mk': 'mk_MK', 'nl': 'nl_NL', 'nn': 'nn_NO', 'no': 'nb_NO', 'pl': 'pl_PL', 
-    'pt': 'pt_PT', 'ro': 'ro_RO', 'ru': 'ru_RU', 'sk': 'sk_SK', 'sl': 'sl_SI', 
+    'ar': 'ar_SY', 'bg': 'bg_BG', 'bs': 'bs_BA', 'ca': 'ca_ES', 'cs': 'cs_CZ',
+    'da': 'da_DK', 'de': 'de_DE', 'el': 'el_GR', 'en': 'en_US', 'es': 'es_ES',
+    'et': 'et_EE', 'fa': 'fa_IR', 'fi': 'fi_FI', 'fr': 'fr_FR', 'gl': 'gl_ES',
+    'he': 'he_IL', 'hu': 'hu_HU', 'id': 'id_ID', 'is': 'is_IS', 'it': 'it_IT',
+    'ja': 'ja_JP', 'km': 'km_KH', 'ko': 'ko_KR', 'lt': 'lt_LT', 'lv': 'lv_LV',
+    'mk': 'mk_MK', 'nl': 'nl_NL', 'nn': 'nn_NO', 'no': 'nb_NO', 'pl': 'pl_PL',
+    'pt': 'pt_PT', 'ro': 'ro_RO', 'ru': 'ru_RU', 'sk': 'sk_SK', 'sl': 'sl_SI',
     'sv': 'sv_SE', 'th': 'th_TH', 'tr': 'tr_TR', 'uk': 'uk_UA'
 }
 
 
     def __init__(self, identifier):
         """Create the exception.
-        
+
         :param identifier: the identifier string of the unsupported locale
         """
         Exception.__init__(self, 'unknown locale %r' % identifier)
 
 class Locale(object):
     """Representation of a specific locale.
-    
+
     >>> locale = Locale('en', 'US')
     >>> repr(locale)
     "Locale('en', territory='US')"
     >>> locale.display_name == 'English (United States)'
     True
-    
+
     A `Locale` object can also be instantiated from a raw locale string:
-    
+
     >>> locale = Locale.parse('en-US', sep='-')
     >>> repr(locale) == "Locale('en', territory='US')"
     True
-    
+
     `Locale` objects provide access to a collection of locale data, such as
     territory and language names, number and date format patterns, and more:
-    
+
     >>> locale.number_symbols['decimal'] == '.'
     True
-    
+
     If a locale is requested for which no locale data is available, an
     `UnknownLocaleError` is raised:
-    
+
     >>> try:
     ...     Locale.parse('en_DE')
     ... except UnknownLocaleError as e:
     ...     msg = str(e)
     >>> msg
     "unknown locale 'en_DE'"
-    
+
     :see: `IETF RFC 3066 <http://www.ietf.org/rfc/rfc3066.txt>`_
     """
 
     def __init__(self, language, territory=None, script=None, variant=None):
         """Initialize the locale object from the given identifier components.
-        
+
         >>> locale = Locale('en', 'US')
         >>> locale.language == 'en'
         True
         >>> locale.territory == 'US'
         True
-        
+
         :param language: the language code
         :param territory: the territory (country or region) code
         :param script: the script code
     @classmethod
     def default(cls, category=None, aliases=LOCALE_ALIASES):
         """Return the system default locale for the specified category.
-        
-        >>> for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE']:
+
+        >>> for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE', 'LC_MESSAGES']:
         ...     os.environ[name] = ''
         >>> os.environ['LANG'] = 'fr_FR.UTF-8'
         >>> Locale.default('LC_MESSAGES')
     @classmethod
     def negotiate(cls, preferred, available, sep='_', aliases=LOCALE_ALIASES):
         """Find the best match between available and requested locale strings.
-        
+
         >>> Locale.negotiate(['de_DE', 'en_US'], ['de_DE', 'de_AT'])
         Locale('de', territory='DE')
         >>> Locale.negotiate(['de_DE', 'en_US'], ['en', 'de'])
         Locale('de')
         >>> Locale.negotiate(['de_DE', 'de'], ['en_US'])
-        
+
         You can specify the character used in the locale identifiers to separate
         the differnet components. This separator is applied to both lists. Also,
         case is ignored in the comparison:
-        
+
         >>> Locale.negotiate(['de-DE', 'de'], ['en-us', 'de-de'], sep='-')
         Locale('de', territory='DE')
-        
+
         :param preferred: the list of locale identifers preferred by the user
         :param available: the list of locale identifiers available
         :param aliases: a dictionary of aliases for locale identifiers
     @classmethod
     def parse(cls, identifier, sep='_'):
         """Create a `Locale` instance for the given locale identifier.
-        
+
         >>> l = Locale.parse('de-DE', sep='-')
         >>> l.display_name == 'Deutsch (Deutschland)'
         True
-        
+
         If the `identifier` parameter is not a string, but actually a `Locale`
         object, that object is returned:
-        
+
         >>> Locale.parse(l)
         Locale('de', territory='DE')
-        
+
         :param identifier: the locale identifier string
         :param sep: optional component separator
         :return: a corresponding `Locale` instance
 
     def get_display_name(self, locale=None):
         """Return the display name of the locale using the given locale.
-        
+
         The display name will include the language, territory, script, and
         variant, if those are specified.
-        
+
         >>> Locale('zh', 'CN', script='Hans').get_display_name('en') == 'Chinese (Simplified Han, China)'
         True
-        
+
         :param locale: the locale to use
         :return: the display name
         """
 
     display_name = property(get_display_name, doc="""\
         The localized display name of the locale.
-        
+
         >>> Locale('en').display_name == 'English'
         True
         >>> Locale('en', 'US').display_name == 'English (United States)'
         True
         >>> Locale('sv').display_name == 'svenska'
         True
-        
+
         :type: `unicode`
         """)
 
-    @property    
+    @property
     def english_name(self):
         """The english display name of the locale.
-        
+
         >>> Locale('de').english_name == 'German'
         True
         >>> Locale('de', 'DE').english_name == 'German (Germany)'
         True
-        
+
         :type: `unicode`"""
         return self.get_display_name(Locale('en'))
 
     #{ General Locale Display Names
 
-    @property    
+    @property
     def languages(self):
         """Mapping of language codes to translated language names.
-        
+
         >>> Locale('de', 'DE').languages['ja'] == 'Japanisch'
         True
-        
+
         :type: `dict`
         :see: `ISO 639 <http://www.loc.gov/standards/iso639-2/>`_"""
         return self._data['languages']
 
-    @property    
+    @property
     def scripts(self):
         """Mapping of script codes to translated script names.
-        
+
         >>> Locale('en', 'US').scripts['Hira'] == 'Hiragana'
         True
-        
+
         :type: `dict`
         :see: `ISO 15924 <http://www.evertype.com/standards/iso15924/>`_"""
         return self._data['scripts']
 
-    @property    
+    @property
     def territories(self):
         """Mapping of script codes to translated script names.
-        
+
         >>> Locale('es', 'CO').territories['DE'] == 'Alemania'
         True
-        
+
         :type: `dict`
         :see: `ISO 3166 <http://www.iso.org/iso/en/prods-services/iso3166ma/>`_"""
         return self._data['territories']
 
-    @property    
+    @property
     def variants(self):
         """Mapping of script codes to translated script names.
-        
+
         >>> Locale('de', 'DE').variants['1901'] == 'Alte deutsche Rechtschreibung'
         True
-        
+
         :type: `dict`"""
         return self._data['variants']
 
     #{ Number Formatting
 
-    @property    
+    @property
     def currencies(self):
         """Mapping of currency codes to translated currency names.
-        
+
         >>> Locale('en').currencies['COP'] == 'Colombian Peso'
         True
         >>> Locale('de', 'DE').currencies['COP'] == 'Kolumbianischer Peso'
         :type: `dict`"""
         return self._data['currency_names']
 
-    @property    
+    @property
     def currency_symbols(self):
         """Mapping of currency codes to symbols.
-        
+
         >>> Locale('en', 'US').currency_symbols['USD'] == '$'
         True
         >>> Locale('es', 'CO').currency_symbols['USD'] == 'US$'
         True
-        
+
         :type: `dict`"""
         return self._data['currency_symbols']
 
-    @property    
+    @property
     def number_symbols(self):
         """Symbols used in number formatting.
-        
+
         >>> Locale('fr', 'FR').number_symbols['decimal'] == ','
         True
-        
+
         :type: `dict`"""
         return self._data['number_symbols']
 
-    @property    
+    @property
     def decimal_formats(self):
         """Locale patterns for decimal number formatting.
-        
+
         >>> Locale('en', 'US').decimal_formats[None]
         <NumberPattern #,##0.###>
-        
+
         :type: `dict`"""
         return self._data['decimal_formats']
 
-    @property    
+    @property
     def currency_formats(self):
         """Locale patterns for currency number formatting.
-        
+
         >>> str(Locale('en', 'US').currency_formats[None]) == '<NumberPattern \\\\xa4#,##0.00>'
         True
-        
+
         :type: `dict`"""
         return self._data['currency_formats']
 
-    @property    
+    @property
     def percent_formats(self):
         """Locale patterns for percent number formatting.
-        
+
         >>> Locale('en', 'US').percent_formats[None]
         <NumberPattern #,##0%>
-        
+
         :type: `dict`"""
         return self._data['percent_formats']
 
-    @property    
+    @property
     def scientific_formats(self):
         """Locale patterns for scientific number formatting.
-        
+
         >>> Locale('en', 'US').scientific_formats[None]
         <NumberPattern #E0>
-        
+
         :type: `dict`"""
         return self._data['scientific_formats']
 
     #{ Calendar Information and Date Formatting
 
-    @property    
+    @property
     def periods(self):
         """Locale display names for day periods (AM/PM).
-        
+
         >>> Locale('en', 'US').periods['am'] == 'AM'
         True
-        
+
         :type: `dict`"""
         return self._data['periods']
 
-    @property    
+    @property
     def days(self):
         """Locale display names for weekdays.
-        
+
         >>> Locale('de', 'DE').days['format']['wide'][3] == 'Donnerstag'
         True
-        
+
         :type: `dict`"""
         return self._data['days']
 
-    @property    
+    @property
     def months(self):
         """Locale display names for months.
-        
+
         >>> Locale('de', 'DE').months['format']['wide'][10] == ('Oktober')
         True
-        
+
         :type: `dict`"""
         return self._data['months']
 
-    @property    
+    @property
     def quarters(self):
         """Locale display names for quarters.
-        
+
         >>> Locale('de', 'DE').quarters['format']['wide'][1] == '1. Quartal'
         True
-        
+
         :type: `dict`"""
         return self._data['quarters']
 
-    @property    
+    @property
     def eras(self):
         """Locale display names for eras.
-        
+
         >>> Locale('en', 'US').eras['wide'][1] == 'Anno Domini'
         True
         >>> Locale('en', 'US').eras['abbreviated'][0] == 'BC'
         True
-        
+
         :type: `dict`"""
         return self._data['eras']
 
-    @property    
+    @property
     def time_zones(self):
         """Locale display names for time zones.
-        
+
         >>> Locale('en', 'US').time_zones['Europe/London']['long']['daylight'] == 'British Summer Time'
         True
         >>> Locale('en', 'US').time_zones['America/St_Johns']['city'] == "St. John's"
         True
-        
+
         :type: `dict`"""
         return self._data['time_zones']
 
-    @property    
+    @property
     def meta_zones(self):
         """Locale display names for meta time zones.
-        
+
         Meta time zones are basically groups of different Olson time zones that
         have the same GMT offset and daylight savings time.
-        
+
         >>> Locale('en', 'US').meta_zones['Europe_Central']['long']['daylight'] == 'Central European Summer Time'
         True
-        
+
         :type: `dict`
         :since: version 0.9"""
         return self._data['meta_zones']
 
-    @property    
+    @property
     def zone_formats(self):
         """Patterns related to the formatting of time zones.
-        
+
         >>> Locale('en', 'US').zone_formats['fallback'] == '%(1)s (%(0)s)'
         True
         >>> Locale('pt', 'BR').zone_formats['region'] == 'Hor\xe1rio %s'
         True
-        
+
         :type: `dict`
         :since: version 0.9"""
         return self._data['zone_formats']
 
-    @property    
+    @property
     def first_week_day(self):
         """The first day of a week, with 0 being Monday.
-        
+
         >>> Locale('de', 'DE').first_week_day
         0
         >>> Locale('en', 'US').first_week_day
         6
-        
+
         :type: `int`"""
         return self._data['week_data']['first_day']
 
-    @property    
+    @property
     def weekend_start(self):
         """The day the weekend starts, with 0 being Monday.
-        
+
         >>> Locale('de', 'DE').weekend_start
         5
-        
+
         :type: `int`"""
         return self._data['week_data']['weekend_start']
 
-    @property    
+    @property
     def weekend_end(self):
         """The day the weekend ends, with 0 being Monday.
-        
+
         >>> Locale('de', 'DE').weekend_end
         6
-        
+
         :type: `int`"""
         return self._data['week_data']['weekend_end']
 
-    @property    
+    @property
     def min_week_days(self):
-        """The minimum number of days in a week so that the week is counted as 
+        """The minimum number of days in a week so that the week is counted as
         the first week of a year or month.
-        
+
         >>> Locale('de', 'DE').min_week_days
         4
-        
+
         :type: `int`"""
         return self._data['week_data']['min_days']
 
-    @property    
+    @property
     def date_formats(self):
         """Locale patterns for date formatting.
-        
+
         >>> Locale('en', 'US').date_formats['short']
         <DateTimePattern M/d/yy>
         >>> Locale('fr', 'FR').date_formats['long']
         <DateTimePattern d MMMM y>
-        
+
         :type: `dict`"""
         return self._data['date_formats']
 
-    @property    
+    @property
     def time_formats(self):
         """Locale patterns for time formatting.
-        
+
         >>> Locale('en', 'US').time_formats['short']
         <DateTimePattern h:mm a>
         >>> Locale('fr', 'FR').time_formats['long']
         <DateTimePattern HH:mm:ss z>
-        
+
         :type: `dict`"""
         return self._data['time_formats']
 
-    @property    
+    @property
     def datetime_formats(self):
         """Locale patterns for datetime formatting.
-        
+
         >>> Locale('en').datetime_formats['full'] == '{1} {0}'
         True
         >>> Locale('th').datetime_formats['medium'] == '{1}, {0}'
         True
-        
+
         :type: `dict`"""
         return self._data['datetime_formats']
 
-    @property    
+    @property
     def plural_form(self):
         """Plural rules for the locale.
-        
+
         >>> Locale('en').plural_form(1) == 'one'
         True
         >>> Locale('en').plural_form(0) == 'other'
         True
         >>> Locale('ru').plural_form(100) == 'many'
         True
-        
+
         :type: `PluralRule`"""
         return self._data['plural_form']
 
 def default_locale(category=None, aliases=LOCALE_ALIASES):
     """Returns the system default locale for a given category, based on
     environment variables.
-    
+
     >>> for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE']:
     ...     os.environ[name] = ''
     >>> os.environ['LANG'] = 'fr_FR.UTF-8'
 
 def negotiate_locale(preferred, available, sep='_', aliases=LOCALE_ALIASES):
     """Find the best match between available and requested locale strings.
-    
+
     >>> negotiate_locale(['de_DE', 'en_US'], ['de_DE', 'de_AT']) == 'de_DE'
     True
     >>> negotiate_locale(['de_DE', 'en_US'], ['en', 'de']) == 'de'
     True
-    
+
     Case is ignored by the algorithm, the result uses the case of the preferred
     locale identifier:
-    
+
     >>> negotiate_locale(['de_DE', 'en_US'], ['de_de', 'de_at']) == 'de_DE'
     True
-    
+
     >>> negotiate_locale(['de_DE', 'en_US'], ['de_de', 'de_at']) == 'de_DE'
     True
-    
+
     By default, some web browsers unfortunately do not include the territory
     in the locale identifier for many locales, and some don't even allow the
     user to easily add the territory. So while you may prefer using qualified
     the language-only locale sent by such browsers. To workaround that, this
     function uses a default mapping of commonly used langauge-only locale
     identifiers to identifiers including the territory:
-    
+
     >>> negotiate_locale(['ja', 'en_US'], ['ja_JP', 'en_US']) == 'ja_JP'
     True
-    
+
     Some browsers even use an incorrect or outdated language code, such as "no"
     for Norwegian, where the correct locale identifier would actually be "nb_NO"
     (Bokmål) or "nn_NO" (Nynorsk). The aliases are intended to take care of
     such cases, too:
-    
+
     >>> negotiate_locale(['no', 'sv'], ['nb_NO', 'sv_SE']) == 'nb_NO'
     True
-    
+
     You can override this default mapping by passing a different `aliases`
     dictionary to this function, or you can bypass the behavior althogher by
     setting the `aliases` parameter to `None`.
-    
+
     :param preferred: the list of locale strings preferred by the user
     :param available: the list of locale strings available
     :param sep: character that separates the different parts of the locale
 
 def parse_locale(identifier, sep='_'):
     """Parse a locale identifier into a tuple of the form::
-    
+
       ``(language, territory, script, variant)``
-    
+
     >>> parse_locale('zh_CN') == ('zh', 'CN', None, None)
     True
     >>> parse_locale('zh_Hans_CN') == ('zh', 'CN', 'Hans', None)
     True
-    
+
     The default component separator is "_", but a different separator can be
     specified using the `sep` parameter:
-    
+
     >>> parse_locale('zh-CN', sep='-') == ('zh', 'CN', None, None)
     True
-    
+
     If the identifier cannot be parsed into a locale, a `ValueError` exception
     is raised:
-    
+
     >>> parse_locale('not_a_LOCALE_String')
     Traceback (most recent call last):
       ...
     ValueError: 'not_a_LOCALE_String' is not a valid locale identifier
-    
+
     Encoding information and locale modifiers are removed from the identifier:
-    
+
     >>> parse_locale('it_IT@euro') == ('it', 'IT', None, None)
     True
     >>> parse_locale('en_US.UTF-8') == ('en', 'US', None, None)
     True
     >>> parse_locale('de_DE.iso885915@euro') == ('de', 'DE', None, None)
     True
-    
+
     :param identifier: the locale identifier string
     :param sep: character that separates the different components of the locale
                 identifier
     :rtype: `tuple`
     :raise `ValueError`: if the string does not appear to be a valid locale
                          identifier
-    
+
     :see: `IETF RFC 4646 <http://www.ietf.org/rfc/rfc4646.txt>`_
     """
     if '.' in identifier:
         raise ValueError('%r is not a valid locale identifier' % str(identifier))
 
     return lang, territory, script, variant
-

File babel/dates.py

 
 def get_period_names(locale=LC_TIME):
     """Return the names for day periods (AM/PM) used by the locale.
-    
+
     >>> get_period_names(locale='en_US')['am'] == 'AM'
     True
-    
+
     :param locale: the `Locale` object, or a locale string
     :return: the dictionary of period names
     :rtype: `dict`
 
 def get_day_names(width='wide', context='format', locale=LC_TIME):
     """Return the day names used by the locale for the specified format.
-    
+
     >>> get_day_names('wide', locale='en_US')[1] == 'Tuesday'
     True
     >>> get_day_names('abbreviated', locale='es')[1] == 'mar'
     True
     >>> get_day_names('narrow', context='stand-alone', locale='de_DE')[1] == 'D'
     True
-    
+
     :param width: the width to use, one of "wide", "abbreviated", or "narrow"
     :param context: the context, either "format" or "stand-alone"
     :param locale: the `Locale` object, or a locale string
 
 def get_month_names(width='wide', context='format', locale=LC_TIME):
     """Return the month names used by the locale for the specified format.
-    
+
     >>> get_month_names('wide', locale='en_US')[1] == 'January'
     True
     >>> get_month_names('abbreviated', locale='es')[1] == 'ene'
     True
     >>> get_month_names('narrow', context='stand-alone', locale='de_DE')[1] == 'J'
     True
-    
+
     :param width: the width to use, one of "wide", "abbreviated", or "narrow"
     :param context: the context, either "format" or "stand-alone"
     :param locale: the `Locale` object, or a locale string
 
 def get_quarter_names(width='wide', context='format', locale=LC_TIME):
     """Return the quarter names used by the locale for the specified format.
-    
+
     >>> get_quarter_names('wide', locale='en_US')[1] == '1st quarter'
     True
     >>> get_quarter_names('abbreviated', locale='de_DE')[1] == 'Q1'
     True
-    
+
     :param width: the width to use, one of "wide", "abbreviated", or "narrow"
     :param context: the context, either "format" or "stand-alone"
     :param locale: the `Locale` object, or a locale string
 
 def get_era_names(width='wide', locale=LC_TIME):
     """Return the era names used by the locale for the specified format.
-    
+
     >>> get_era_names('wide', locale='en_US')[1] == 'Anno Domini'
     True
     >>> get_era_names('abbreviated', locale='de_DE')[1] == 'n. Chr.'
     True
-    
+
     :param width: the width to use, either "wide", "abbreviated", or "narrow"
     :param locale: the `Locale` object, or a locale string
     :return: the dictionary of era names
 def get_date_format(format='medium', locale=LC_TIME):
     """Return the date formatting patterns used by the locale for the specified
     format.
-    
+
     >>> get_date_format(locale='en_US')
     <DateTimePattern MMM d, y>
     >>> get_date_format('full', locale='de_DE')
     <DateTimePattern EEEE, d. MMMM y>
-    
+
     :param format: the format to use, one of "full", "long", "medium", or
                    "short"
     :param locale: the `Locale` object, or a locale string
 def get_datetime_format(format='medium', locale=LC_TIME):
     """Return the datetime formatting patterns used by the locale for the
     specified format.
-    
+
     >>> get_datetime_format(locale='en_US') == '{1} {0}'
     True
-    
+
     :param format: the format to use, one of "full", "long", "medium", or
                    "short"
     :param locale: the `Locale` object, or a locale string
 def get_time_format(format='medium', locale=LC_TIME):
     """Return the time formatting patterns used by the locale for the specified
     format.
-    
+
     >>> get_time_format(locale='en_US')
     <DateTimePattern h:mm:ss a>
     >>> get_time_format('full', locale='de_DE')
     <DateTimePattern HH:mm:ss zzzz>
-    
+
     :param format: the format to use, one of "full", "long", "medium", or
                    "short"
     :param locale: the `Locale` object, or a locale string
 def get_timezone_gmt(datetime=None, width='long', locale=LC_TIME):
     """Return the timezone associated with the given `datetime` object formatted
     as string indicating the offset from GMT.
-    
+
     >>> dt = datetime(2007, 4, 1, 15, 30)
     >>> get_timezone_gmt(dt, locale='en') == 'GMT+00:00'
     True
-    
+
     >>> from pytz import timezone
     >>> tz = timezone('America/Los_Angeles')
     >>> dt = datetime(2007, 4, 1, 15, 30, tzinfo=tz)
     True
     >>> get_timezone_gmt(dt, 'short', locale='en') == '-0800'
     True
-    
+
     The long format depends on the locale, for example in France the acronym
     UTC string is used instead of GMT:
-    
+
     >>> get_timezone_gmt(dt, 'long', locale='fr_FR') == 'UTC-08:00'
     True
-    
+
     :param datetime: the ``datetime`` object; if `None`, the current date and
                      time in UTC is used
     :param width: either "long" or "short"
 
 def get_timezone_location(dt_or_tzinfo=None, locale=LC_TIME):
     """Return a representation of the given timezone using "location format".
-    
+
     The result depends on both the local display name of the country and the
     city associated with the time zone:
-    
+
     >>> from pytz import timezone
     >>> tz = timezone('America/St_Johns')
     >>> get_timezone_location(tz, locale='de_DE') == "Kanada (St. John's)"
     >>> tz = timezone('America/Mexico_City')
     >>> get_timezone_location(tz, locale='de_DE') == 'Mexiko (Mexiko-Stadt)'
     True
-    
+
     If the timezone is associated with a country that uses only a single
     timezone, just the localized country name is returned:
-    
+
     >>> tz = timezone('Europe/Berlin')
     >>> get_timezone_name(tz, locale='de_DE') == 'Deutschland'
     True
-    
+
     :param dt_or_tzinfo: the ``datetime`` or ``tzinfo`` object that determines
                          the timezone; if `None`, the current date and time in
                          UTC is assumed
                       locale=LC_TIME):
     r"""Return the localized display name for the given timezone. The timezone
     may be specified using a ``datetime`` or `tzinfo` object.
-    
+
     >>> from pytz import timezone
     >>> dt = time(15, 30, tzinfo=timezone('America/Los_Angeles'))
     >>> get_timezone_name(dt, locale='en_US') == 'Pacific Standard Time'
     True
     >>> get_timezone_name(dt, width='short', locale='en_US') == 'PST'
     True
-    
+
     If this function gets passed only a `tzinfo` object and no concrete
     `datetime`,  the returned display name is indenpendent of daylight savings
     time. This can be used for example for selecting timezones, or to set the
     time of events that recur across DST changes:
-    
+
     >>> tz = timezone('America/Los_Angeles')
     >>> get_timezone_name(tz, locale='en_US') == 'Pacific Time'
     True
     >>> get_timezone_name(tz, 'short', locale='en_US') == 'PT'
     True
-    
+
     If no localized display name for the timezone is available, and the timezone
     is associated with a country that uses only a single timezone, the name of
     that country is returned, formatted according to the locale:
-    
+
     >>> tz = timezone('Europe/Berlin')
     >>> get_timezone_name(tz, locale='de_DE') == 'Deutschland'
     True
     >>> get_timezone_name(tz, locale='pt_BR') == 'Hor\xe1rio Alemanha'
     True
-    
+
     On the other hand, if the country uses multiple timezones, the city is also
     included in the representation:
-    
+
     >>> tz = timezone('America/St_Johns')
     >>> get_timezone_name(tz, locale='de_DE') == "Kanada (St. John's)"
     True
-    
+
     The `uncommon` parameter can be set to `True` to enable the use of timezone
     representations that are not commonly used by the requested locale. For
     example, while in French the central European timezone is usually
     abbreviated as "HEC", in Canadian French, this abbreviation is not in
     common use, so a generic name would be chosen by default:
-    
+
     >>> tz = timezone('Europe/Paris')
     >>> get_timezone_name(tz, 'short', locale='fr_CA') == 'France'
     True
     >>> get_timezone_name(tz, 'short', uncommon=True, locale='fr_CA') == 'HEC'
     True
-    
+
     :param dt_or_tzinfo: the ``datetime`` or ``tzinfo`` object that determines
                          the timezone; if a ``tzinfo`` object is used, the
                          resulting display name will be generic, i.e.
 
 def format_date(date=None, format='medium', locale=LC_TIME):
     """Return a date formatted according to the given pattern.
-    
+
     >>> d = date(2007, 0o4, 0o1)
     >>> format_date(d, locale='en_US') == 'Apr 1, 2007'
     True
     >>> format_date(d, format='full', locale='de_DE') == 'Sonntag, 1. April 2007'
     True
-    
+
     If you don't want to use the locale default formats, you can specify a
     custom date pattern:
-    
+
     >>> format_date(d, "EEE, MMM d, ''yy", locale='en') == "Sun, Apr 1, '07"
     True
-    
+
     :param date: the ``date`` or ``datetime`` object; if `None`, the current
                  date is used
     :param format: one of "full", "long", "medium", or "short", or a custom
                    date/time pattern
     :param locale: a `Locale` object or a locale identifier
     :rtype: `unicode`
-    
+
     :note: If the pattern contains time fields, an `AttributeError` will be
            raised when trying to apply the formatting. This is also true if
            the value of ``date`` parameter is actually a ``datetime`` object,
 def format_datetime(datetime=None, format='medium', tzinfo=None,
                     locale=LC_TIME):
     r"""Return a date formatted according to the given pattern.
-    
+
     >>> dt = datetime(2007, 0o4, 0o1, 15, 30)
     >>> format_datetime(dt, locale='en_US') == 'Apr 1, 2007 3:30:00 PM'
     True
-    
+
     For any pattern requiring the display of the time-zone, the third-party
     ``pytz`` package is needed to explicitly specify the time-zone:
-    
+
     >>> from pytz import timezone
     >>> format_datetime(dt, 'full', tzinfo=timezone('Europe/Paris'),
     ...                 locale='fr_FR') == 'dimanche 1 avril 2007 17:30:00 Heure avanc\xe9e de l\u2019Europe centrale'
     >>> format_datetime(dt, "yyyy.MM.dd G 'at' HH:mm:ss zzz",
     ...                 tzinfo=timezone('US/Eastern'), locale='en') == '2007.04.01 AD at 11:30:00 EDT'
     True
-    
+
     :param datetime: the `datetime` object; if `None`, the current date and
                      time is used
     :param format: one of "full", "long", "medium", or "short", or a custom
 
 def format_time(time=None, format='medium', tzinfo=None, locale=LC_TIME):
     r"""Return a time formatted according to the given pattern.
-    
+
     >>> t = time(15, 30)
     >>> format_time(t, locale='en_US') == '3:30:00 PM'
     True
     >>> format_time(t, format='short', locale='de_DE') == '15:30'
     True
-    
+
     If you don't want to use the locale default formats, you can specify a
     custom time pattern:
-    
+
     >>> format_time(t, "hh 'o''clock' a", locale='en') == "03 o'clock PM"
     True
-    
+
     For any pattern requiring the display of the time-zone, the third-party
     ``pytz`` package is needed to explicitly specify the time-zone:
-    
+
     >>> from pytz import timezone
     >>> t = datetime(2007, 4, 1, 15, 30)
     >>> tzinfo = timezone('Europe/Paris')
     >>> format_time(t, "hh 'o''clock' a, zzzz", tzinfo=timezone('US/Eastern'),
     ...             locale='en') == "09 o'clock AM, Eastern Daylight Time"
     True
-    
+
     As that example shows, when this function gets passed a
     ``datetime.datetime`` value, the actual time in the formatted string is
     adjusted to the timezone specified by the `tzinfo` parameter. If the
     ``datetime`` is "naive" (i.e. it has no associated timezone information),
     it is assumed to be in UTC.
-    
+
     These timezone calculations are **not** performed if the value is of type
     ``datetime.time``, as without date information there's no way to determine
     what a given time would translate to in a different timezone without
     information about whether daylight savings time is in effect or not. This
     means that time values are left as-is, and the value of the `tzinfo`
     parameter is only used to display the timezone name if needed:
-    
+
     >>> t = time(15, 30)
     >>> format_time(t, format='full', tzinfo=timezone('Europe/Paris'),
     ...             locale='fr_FR') == '15:30:00 Heure normale de l\u2019Europe centrale'
     >>> format_time(t, format='full', tzinfo=timezone('US/Eastern'),
     ...             locale='en_US') == '3:30:00 PM Eastern Standard Time'
     True
-    
+
     :param time: the ``time`` or ``datetime`` object; if `None`, the current
                  time in UTC is used
     :param format: one of "full", "long", "medium", or "short", or a custom
     :param tzinfo: the time-zone to apply to the time for display
     :param locale: a `Locale` object or a locale identifier
     :rtype: `unicode`
-    
+
     :note: If the pattern contains date fields, an `AttributeError` will be
            raised when trying to apply the formatting. This is also true if
            the value of ``time`` parameter is actually a ``datetime`` object,
 
     The granularity parameter can be provided to alter the lowest unit
     presented, which defaults to a second.
-    
+
     >>> format_timedelta(timedelta(hours=3), granularity='day',
     ...                  locale='en_US') == '1 day'
     True
 
 def parse_date(string, locale=LC_TIME):
     """Parse a date from a string.
-    
+
     This function uses the date format for the locale as a hint to determine
     the order in which the date fields appear in the string.
-    
+
     >>> parse_date('4/1/04', locale='en_US')
     datetime.date(2004, 4, 1)
     >>> parse_date('01.04.2004', locale='de_DE')
     datetime.date(2004, 4, 1)
-    
+
     :param string: the string containing the date
     :param locale: a `Locale` object or a locale identifier
     :return: the parsed date
 
 def parse_datetime(string, locale=LC_TIME):
     """Parse a date and time from a string.
-    
+
     This function uses the date and time formats for the locale as a hint to
     determine the order in which the time fields appear in the string.
-    
+
     :param string: the string containing the date and time
     :param locale: a `Locale` object or a locale identifier
     :return: the parsed date/time
 
 def parse_time(string, locale=LC_TIME):
     """Parse a time from a string.
-    
+
     This function uses the time format for the locale as a hint to determine
     the order in which the time fields appear in the string.
-    
+
     >>> parse_time('15:30:00', locale='en_US')
     datetime.time(15, 30)
-    
+
     :param string: the string containing the time
     :param locale: a `Locale` object or a locale identifier
     :return: the parsed time
     def get_week_number(self, day_of_period, day_of_week=None):
         """Return the number of the week of a day within a period. This may be
         the week number in a year or the week number in a month.
-        
+
         Usually this will return a value equal to or greater than 1, but if the
         first week of the period is so short that it actually counts as the last
         week of the previous period, this function will return 0.
-        
+
         >>> format = DateTimeFormat(date(2006, 1, 8), Locale.parse('de_DE'))
         >>> format.get_week_number(6)
         1
-        
+
         >>> format = DateTimeFormat(date(2006, 1, 8), Locale.parse('en_US'))
         >>> format.get_week_number(6)
         2
-        
+
         :param day_of_period: the number of the day in the period (usually
                               either the day of month or the day of year)
         :param day_of_week: the week day; if ommitted, the week day of the
 
 def parse_pattern(pattern):
     """Parse date, time, and datetime format patterns.
-    
+
     >>> parse_pattern("MMMMd").format == '%(MMMM)s%(d)s'
     True
     >>> parse_pattern("MMM d, yyyy").format == '%(MMM)s %(d)s, %(yyyy)s'
     True
-    
+
     Pattern can contain literal strings in single quotes:
-    
+
     >>> parse_pattern("H:mm' Uhr 'z").format == '%(H)s:%(mm)s Uhr %(z)s'
     True
-    
+
     An actual single quote can be used by using two adjacent single quote
     characters:
-    
+
     >>> parse_pattern("hh' o''clock'").format == "%(hh)s o'clock"
     True
-    
+
     :param pattern: the formatting pattern to parse
     """
     if type(pattern) is DateTimePattern:
         append_chars()
 
     return DateTimePattern(pattern, ''.join(result).replace('\0', "'"))
-

File babel/localedata.py

 
 def exists(name):
     """Check whether locale data is available for the given locale.
-    
+
     :param name: the locale identifier string
     :return: `True` if the locale data exists, `False` otherwise
     :rtype: `bool`
 def locale_identifiers():
     """Return a list of all locale identifiers for which locale data is
     available.
-    
+
     :return: a list of locale identifiers (strings)
     :rtype: `list`
     :since: version 0.8.1
 
 def load(name, merge_inherited=True):
     """Load the locale data for the given locale.
-    
+
     The locale data is a dictionary that contains much of the data defined by
     the Common Locale Data Repository (CLDR). This data is stored as a
     collection of pickle files inside the ``babel`` package.
-    
+
     >>> d = load('en_US')
     >>> d['languages']['sv'] == 'Swedish'
     True
-    
+
     Note that the results are cached, and subsequent requests for the same
     locale return the same dictionary:
-    
+
     >>> d1 = load('en_US')
     >>> d2 = load('en_US')
     >>> d1 is d2
     True
-    
+
     :param name: the locale identifier string (or "root")
     :param merge_inherited: whether the inherited data should be merged into
                             the data of the requested locale
 def merge(dict1, dict2):
     """Merge the data from `dict2` into the `dict1` dictionary, making copies
     of nested dictionaries.
-    
+
     >>> d = {1: 'foo', 3: 'baz'}
     >>> merge(d, {1: 'Foo', 2: 'Bar'})
     >>> items = sorted(d.items()); items == [(1, 'Foo'), (2, 'Bar'), (3, 'baz')]
     True
-    
+
     :param dict1: the dictionary to merge into
     :param dict2: the dictionary containing the data that should be merged
     """
 
 class Alias(object):
     """Representation of an alias in the locale data.
-    
+
     An alias is a value that refers to some other part of the locale data,
     as specified by the `keys`.
     """
 
     def resolve(self, data):
         """Resolve the alias based on the given data.
-        
+
         This is done recursively, so if one alias resolves to a second alias,
         that second alias will also be resolved.
-        
+
         :param data: the locale data
         :type data: `dict`
         """
         return val
 
     def copy(self):
-        return LocaleDataDict(dict.copy(self), base=self.base)
-
+        return LocaleDataDict(self._data.copy(), base=self.base)

File babel/messages/catalog.py

 
     def __cmp__(self, obj):
         """Compare Messages, taking into account plural ids"""
-        
+
         def cmp(a, b):
             return ((a > b) - (a < b))
 
         ids = self.id
         if not isinstance(ids, (list, tuple)):
             ids = [ids]
-        return bool([_f for _f in [PYTHON_FORMAT.search(id) for id in ids] if _f])
+        return any(PYTHON_FORMAT.search(id) for id in ids)
 
 
 class TranslationError(Exception):
         :param revision_date: the date the catalog was revised
         :param last_translator: the name and email of the last translator
         :param language_team: the name and email of the language team
-        :param charset: the encoding to use in the output
+        :param charset: the encoding to use in the output (defaults to utf-8)
         :param fuzzy: the fuzzy bit on the catalog header
         """
         self.domain = domain #: The message domain
         >>> Catalog(locale='ga').plural_expr
         '(n==1 ? 0 : n==2 ? 1 : 2)'
 
-        :type: `basestring`"""
+        :type: `string_types`"""
         if self._plural_expr is None:
             expr = '(n != 1)'
             if self.locale:
 
     def delete(self, id, context=None):
         """Delete the message with the specified ID and context.
-        
+
         :param id: the message ID
         :param context: the message context, or ``None`` for no context
         """
         if context is not None:
             key = (key, context)
         return key
-

File babel/messages/checkers.py

                                            'and named placeholders')
         return bool(positional)
 
-    a, b = tuple(map(_parse, (format, alternative)))
+    a, b = map(_parse, (format, alternative))
 
     # now check if both strings are positional or named
-    a_positional, b_positional = tuple(map(_check_positional, (a, b)))
+    a_positional, b_positional = map(_check_positional, (a, b))
     if a_positional and not b_positional and not b:
         raise TranslationError('placeholders are incompatible')
     elif a_positional != b_positional:

File babel/messages/extract.py

             if line.startswith(tag):
                 return line[len(tag):].strip()
         return line
-    comments[:] = list(map(_strip, comments))
+    comments[:] = map(_strip, comments)
 
 
 def extract_from_dir(dirname=os.getcwd(), method_map=DEFAULT_MAPPING,
                 break
         if func is None:
             # if pkg_resources is not available or no usable egg-info was found
-            # (see #230), we resort to looking up the builtin extractors 
+            # (see #230), we resort to looking up the builtin extractors
             # directly
             builtin = {'ignore': extract_nothing, 'python': extract_python}
             func = builtin.get(method)
             funcname = token.value
 
         last_token = token
-

File babel/messages/frontend.py

                 try:
                     write_po(tmpfile, catalog,
                              ignore_obsolete=options.ignore_obsolete,
-                             include_previous=options.previous, 
+                             include_previous=options.previous,
                              width=options.width)
                 finally:
                     tmpfile.close()
     >>> buf = StringIO('''
     ... [extractors]
     ... custom = mypackage.module:myfunc
-    ... 
+    ...
     ... # Python source files
     ... [python: **.py]
     ...
     ... [genshi: **/templates/**.txt]
     ... template_class = genshi.template:TextTemplate
     ... encoding = latin-1
-    ... 
+    ...
     ... # Some custom extractor
     ... [custom: **/custom/*.*]
     ... ''')
 
 if __name__ == '__main__':
     main()
-

File babel/messages/mofile.py

 def read_mo(fileobj):
     """Read a binary MO file from the given file-like object and return a
     corresponding `Catalog` object.
-    
+
     :param fileobj: the file-like object to read the MO file from
     :return: a catalog object representing the parsed MO file
     :rtype: `Catalog`
-    
+
     :note: The implementation of this function is heavily based on the
            ``GNUTranslations._parse`` method of the ``gettext`` module in the
            standard library.
 def write_mo(fileobj, catalog, use_fuzzy=False):
     """Write a catalog to the specified file-like object using the GNU MO file
     format.
-    
+
     >>> from babel.messages import Catalog
     >>> from babel.compat import BytesIO, GNUTranslations
-    
+
     >>> catalog = Catalog(locale='en_US')
     >>> catalog.add('foo', 'Voh')
     <Message ...>
     True
     >>> translations.ugettext('Fuzzes') == 'Fuzzes'
     True
-    
+
     :param fileobj: the file-like object to write to
     :param catalog: the `Catalog` instance
     :param use_fuzzy: whether translations marked as "fuzzy" should be included

File babel/messages/pofile.py

                 _write_comment(comment)
             _write_message(message, prefix='#~ ')
             _write('\n')
-

File babel/messages/tests/catalog.py

 
         self.assertEqual(None, cat2['foo'].string)
         self.assertEqual(False, cat2['foo'].fuzzy)
-        
+
     def test_update_po_updates_pot_creation_date(self):
         template = catalog.Catalog()
         localized_catalog = copy.deepcopy(template)
         localized_catalog.update(template)
         self.assertEqual(template.creation_date,
                          localized_catalog.creation_date)
-        
+
     def test_update_po_keeps_po_revision_date(self):
         template = catalog.Catalog()
         localized_catalog = copy.deepcopy(template)
     def test_stores_datetime_correctly(self):
         localized = catalog.Catalog()
         localized.locale = 'de_DE'
-        localized[''] = catalog.Message('', 
+        localized[''] = catalog.Message('',
                        "POT-Creation-Date: 2009-03-09 15:47-0700\n" +
                        "PO-Revision-Date: 2009-03-09 15:47-0700\n")
         for key, value in localized.mime_headers:
             if key in ('POT-Creation-Date', 'PO-Revision-Date'):
                 self.assertEqual(value, '2009-03-09 15:47-0700')
-    
+
     def test_mime_headers_contain_same_information_as_attributes(self):
         cat = catalog.Catalog()
-        cat[''] = catalog.Message('', 
+        cat[''] = catalog.Message('',
                       "Last-Translator: Foo Bar <foo.bar@example.com>\n" +
                       "Language-Team: de <de@example.com>\n" +
                       "POT-Creation-Date: 2009-03-01 11:20+0200\n" +
                       "PO-Revision-Date: 2009-03-09 15:47-0700\n")
         self.assertEqual(None, cat.locale)
         mime_headers = dict(cat.mime_headers)
-        
+
         self.assertEqual('Foo Bar <foo.bar@example.com>', cat.last_translator)
-        self.assertEqual('Foo Bar <foo.bar@example.com>', 
+        self.assertEqual('Foo Bar <foo.bar@example.com>',
                          mime_headers['Last-Translator'])
-        
+
         self.assertEqual('de <de@example.com>', cat.language_team)
         self.assertEqual('de <de@example.com>', mime_headers['Language-Team'])
-        
+
         dt = datetime.datetime(2009, 3, 9, 15, 47, tzinfo=FixedOffsetTimezone(-7 * 60))
         self.assertEqual(dt, cat.revision_date)
         formatted_dt = format_datetime(dt, 'yyyy-MM-dd HH:mmZ', locale='en')

File babel/messages/tests/pofile.py

         self.assertEqual('Menu', message.context)
         message = catalog.get('bar', context='Mannu')
         self.assertEqual('Mannu', message.context)
-        
+
         # And verify it pass through write_po
         out_buf = BytesIO()
         pofile.write_po(out_buf, catalog, omit_header=True)
 msgstr ""''', buf.getvalue().strip())
 
     def test_wrap_long_lines(self):
-        text = """Here's some text where       
+        text = """Here's some text where%s
 white space and line breaks matter, and should
 
 not be removed
 
-"""
+""" % (" " * 7)
         catalog = Catalog()
         catalog.add(text, locations=[('main.py', 1)])
         buf = BytesIO()
 " throw us into an infinite "
 "loop\n"
 msgstr ""''', buf.getvalue().strip())
-        
+
     def test_wrap_long_lines_in_header(self):
         """
         Verify that long lines in the header comment are wrapped correctly.
 #: doupy/templates/job-offers/helpers.html:22
 msgid "foo"
 msgstr ""''', buf.getvalue().strip())
-        
+
     def test_no_wrap_and_width_behaviour_on_comments(self):
         catalog = Catalog()
         catalog.add("Pretty dam long message id, which must really be big "
     def test_unescape_of_quoted_newline(self):
         # regression test for #198
         self.assertEqual(r'\n', pofile.unescape(r'"\\n"'))
-    
+
     def test_denormalize_on_msgstr_without_empty_first_line(self):
-        # handle irregular multi-line msgstr (no "" as first line) 
+        # handle irregular multi-line msgstr (no "" as first line)
         # gracefully (#171)
         msgstr = '"multi-line\\n"\n" translation"'
         expected_denormalized = 'multi-line\n translation'
-        
+
         self.assertEqual(expected_denormalized, pofile.denormalize(msgstr))
-        self.assertEqual(expected_denormalized, 
+        self.assertEqual(expected_denormalized,
                          pofile.denormalize('""\n' + msgstr))
 
 

File babel/numbers.py

 
 def get_currency_name(currency, locale=LC_NUMERIC):
     """Return the name used by the locale for the specified currency.
-    
+
     >>> get_currency_name('USD', 'en_US') == 'US Dollar'
     True
 
 
 def get_currency_symbol(currency, locale=LC_NUMERIC):
     """Return the symbol used by the locale for the specified currency.
-    
+
     >>> get_currency_symbol('USD', 'en_US') == '$'
     True
 
 
 def get_decimal_symbol(locale=LC_NUMERIC):
     """Return the symbol used by the locale to separate decimal fractions.
-    
+
     >>> get_decimal_symbol('en_US') == '.'
     True
-    
+
     :param locale: the `Locale` object or locale identifier
     :return: the decimal symbol
     :rtype: `unicode`
 
 def get_plus_sign_symbol(locale=LC_NUMERIC):
     """Return the plus sign symbol used by the current locale.
-    
+
     >>> get_plus_sign_symbol('en_US') == '+'
     True
-    
+
     :param locale: the `Locale` object or locale identifier
     :return: the plus sign symbol
     :rtype: `unicode`
 
 def get_minus_sign_symbol(locale=LC_NUMERIC):
     """Return the plus sign symbol used by the current locale.
-    
+
     >>> get_minus_sign_symbol('en_US') == '-'
     True
-    
+
     :param locale: the `Locale` object or locale identifier
     :return: the plus sign symbol
     :rtype: `unicode`
 
 def get_exponential_symbol(locale=LC_NUMERIC):
     """Return the symbol used by the locale to separate mantissa and exponent.
-    
+
     >>> get_exponential_symbol('en_US') == 'E'
     True
 
 
 def get_group_symbol(locale=LC_NUMERIC):
     """Return the symbol used by the locale to separate groups of thousands.
-    
+
     >>> get_group_symbol('en_US') == ','
     True
-    
+
     :param locale: the `Locale` object or locale identifier
     :return: the group symbol
     :rtype: `unicode`
 
 def format_number(number, locale=LC_NUMERIC):
     """Return the given number formatted for a specific locale.
-    
+
     >>> format_number(1099, locale='en_US') == '1,099'
     True
     >>> format_number(1099, locale='de_DE') == '1.099'
     True
-    
+
     :param number: the number to format
     :param locale: the `Locale` object or locale identifier
     :return: the formatted number
 
 def format_decimal(number, format=None, locale=LC_NUMERIC):
     """Return the given decimal number formatted for a specific locale.
-    
+
     >>> format_decimal(1.2345, locale='en_US') == '1.234'
     True
     >>> format_decimal(1.2346, locale='en_US') == '1.235'
 
     The appropriate thousands grouping and the decimal separator are used for
     each locale:
-    
+
     >>> format_decimal(12345.5, locale='en_US') == '12,345.5'
     True
 
     :param number: the number to format
-    :param format: 
+    :param format:
     :param locale: the `Locale` object or locale identifier
     :return: the formatted decimal number
     :rtype: `unicode`
 
 def format_currency(number, currency, format=None, locale=LC_NUMERIC):
     """Return formatted currency value.
-    
+
     >>> format_currency(1099.98, 'USD', locale='en_US') == '$1,099.98'
     True
     >>> format_currency(1099.98, 'USD', locale='es_CO') == 'US$\\xa01.099,98'
     True
     >>> format_currency(1099.98, 'EUR', locale='de_DE') == '1.099,98\\xa0\\u20ac'
     True
-    
+
     The pattern can also be specified explicitly:
-    
+
     >>> format_currency(1099.98, 'EUR', '\u00a4\u00a4 #,##0.00', locale='en_US') == 'EUR 1,099.98'
     True
-    
+
     :param number: the number to format
     :param currency: the currency code
     :param locale: the `Locale` object or locale identifier
 
 def format_percent(number, format=None, locale=LC_NUMERIC):
     """Return formatted percent value for a specific locale.
-    
+
     >>> format_percent(0.34, locale='en_US') == '34%'
     True
     >>> format_percent(25.1234, locale='en_US') == '2,512%'
     True
 
     The format pattern can also be specified explicitly:
-    
+
     >>> format_percent(25.1234, '#,##0\u2030', locale='en_US') == '25,123\u2030'
     True
 
     :param number: the percent number to format
-    :param format: 
+    :param format:
     :param locale: the `Locale` object or locale identifier
     :return: the formatted percent number
     :rtype: `unicode`
 
 def format_scientific(number, format=None, locale=LC_NUMERIC):
     """Return value formatted in scientific notation for a specific locale.
-    
+
     >>> format_scientific(10000, locale='en_US') == '1E4'
     True
 
     The format pattern can also be specified explicitly:
-    
+
     >>> format_scientific(1234567, '##0E00', locale='en_US') == '1.23E06'
     True
 
     :param number: the number to format
-    :param format: 
+    :param format:
     :param locale: the `Locale` object or locale identifier
     :return: value formatted in scientific notation.
     :rtype: `unicode`
 
 def parse_number(string, locale=LC_NUMERIC):
     """Parse localized number string into a long integer.
-    
+
     >>> parse_number('1,099', locale='en_US') == long_type(1099)
     True
     >>> parse_number('1.099', locale='de_DE') == long_type(1099)
     True
 
     When the given string cannot be parsed, an exception is raised:
-    
+
     >>> try:
     ...     parse_number('1.099,98', locale='de')
     ... except NumberFormatError as e:
     ...     msg = str(e)
     >>> msg
     "'1.099,98' is not a valid number"
-    
+
     :param string: the string to parse
     :param locale: the `Locale` object or locale identifier
     :return: the parsed number
 
 def parse_decimal(string, locale=LC_NUMERIC):
     """Parse localized decimal string into a decimal.
-    
+
     >>> parse_decimal('1,099.98', locale='en_US')
     Decimal('1099.98')
     >>> parse_decimal('1.099,98', locale='de')
     Decimal('1099.98')
-    
+
     When the given string cannot be parsed, an exception is raised:
-    
+
     >>> try:
     ...     parse_decimal('2,109,998', locale='de')
     ... except NumberFormatError as e:
     if isinstance(value, Decimal):
         # NB can't just do text = str(value) as str repr of Decimal may be
         # in scientific notation, e.g. for small numbers.
-        
+
         sign, digits, exp = value.as_tuple()
         # build list of digits in reverse order, then reverse+join
         # as per http://docs.python.org/library/decimal.html#recipes
         int_part = []
         frac_part = []
-        
+
         digits = list(map(str, digits))
-        
+
         # get figures after decimal point
         for i in range(-exp):
             # add digit if available, else 0
                 frac_part.append(digits.pop())
             else:
                 frac_part.append('0')
-        
+
         # add in some zeroes...
         for i in range(exp):
             int_part.append('0')
-        
+
         # and the rest
         while digits:
             int_part.append(digits.pop())
-        
+
         # if < 1, int_part must be set to '0'
         if len(int_part) == 0:
             int_part = '0',
-        
+
         if sign:
             int_part.append('-')
-        
+
         return ''.join(reversed(int_part)), ''.join(reversed(frac_part))
     text = ('%.9f' % value).rstrip('0')
     if '.' in text:
         exp_plus = None
         exp_prec = None
     grouping = parse_grouping(integer)
-    return NumberPattern(pattern, (pos_prefix, neg_prefix), 
+    return NumberPattern(pattern, (pos_prefix, neg_prefix),
                          (pos_suffix, neg_suffix), grouping,
-                         int_prec, frac_prec, 
+                         int_prec, frac_prec,
                          exp_prec, exp_plus)
 
 
                 exp_sign = get_plus_sign_symbol(locale)
             exp = abs(exp)
             number = '%s%s%s%s' % \
-                 (self._format_sigdig(value, self.frac_prec[0], 
-                                     self.frac_prec[1]), 
+                 (self._format_sigdig(value, self.frac_prec[0],
+                                     self.frac_prec[1]),
                   get_exponential_symbol(locale),  exp_sign,
                   self._format_int(str(exp), self.exp_prec[0],
                                    self.exp_prec[1], locale))
             else:
                 number = self._format_int(text, 0, 1000, locale)
         else: # A normal number pattern
-            a, b = split_number(bankersround(abs(value), 
+            a, b = split_number(bankersround(abs(value),
                                              self.frac_prec[1]))
             b = b or '0'
             a = self._format_int(a, self.int_prec[0],
         while len(value) > min and value[-1] == '0':
             value = value[:-1]
         return get_decimal_symbol(locale) + value
-

File babel/plural.py

     @property
     def rules(self):
         """The `PluralRule` as a dict of unicode plural rules.
-        
+
         >>> rule = PluralRule({'one': 'n is 1'})
         >>> rule.rules
         {'one': 'n is 1'}
         (None, re.compile(r'\s+(?u)')),
         ('word', re.compile(r'\b(and|or|is|(?:with)?in|not|mod|n)\b')),
         ('value', re.compile(r'\d+')),
+        ('comma', re.compile(r',')),
         ('ellipsis', re.compile(r'\.\.'))
     ]
 

File babel/support.py

 class Format(object):
     """Wrapper class providing the various date and number formatting functions
     bound to a specific locale and time-zone.
-    
+
     >>> fmt = Format('en_US', UTC)
     >>> fmt.date(date(2007, 4, 1)) == 'Apr 1, 2007'
     True
 
     def __init__(self, locale, tzinfo=None):
         """Initialize the formatter.
-        
+
         :param locale: the locale identifier or `Locale` instance
         :param tzinfo: the time-zone info (a `tzinfo` instance or `None`)
         """
 
     def date(self, date=None, format='medium'):
         """Return a date formatted according to the given pattern.
-        
+
         >>> fmt = Format('en_US')
         >>> fmt.date(date(2007, 4, 1)) == 'Apr 1, 2007'
         True
-        
+
         :see: `babel.dates.format_date`
         """
         return format_date(date, format, locale=self.locale)
 
     def datetime(self, datetime=None, format='medium'):
         """Return a date and time formatted according to the given pattern.
-        
+
         >>> from pytz import timezone
         >>> fmt = Format('en_US', tzinfo=timezone('US/Eastern'))
         >>> fmt.datetime(datetime(2007, 4, 1, 15, 30)) == 'Apr 1, 2007 11:30:00 AM'
         True
-        
+
         :see: `babel.dates.format_datetime`
         """
         return format_datetime(datetime, format, tzinfo=self.tzinfo,
 
     def time(self, time=None, format='medium'):
         """Return a time formatted according to the given pattern.
-        
+
         >>> from pytz import timezone
         >>> fmt = Format('en_US', tzinfo=timezone('US/Eastern'))
         >>> fmt.time(datetime(2007, 4, 1, 15, 30)) == '11:30:00 AM'
         True
-        
+
         :see: `babel.dates.format_time`
         """
         return format_time(time, format, tzinfo=self.tzinfo, locale=self.locale)
 
     def timedelta(self, delta, granularity='second', threshold=.85):
         """Return a time delta according to the rules of the given locale.
-        
+
         >>> fmt = Format('en_US')
         >>> fmt.timedelta(timedelta(weeks=11)) == '3 mths'
         True
-        
+
         :see: `babel.dates.format_timedelta`
         """
         return format_timedelta(delta, granularity=granularity,
 
     def number(self, number):
         """Return an integer number formatted for the locale.
-        
+
         >>> fmt = Format('en_US')
         >>> fmt.number(1099) == '1,099'
         True
-        
+
         :see: `babel.numbers.format_number`
         """
         return format_number(number, locale=self.locale)
 
     def decimal(self, number, format=None):
         """Return a decimal number formatted for the locale.
-        
+
         >>> fmt = Format('en_US')
         >>> fmt.decimal(1.2345) == '1.234'
         True
-        
+
         :see: `babel.numbers.format_decimal`
         """
         return format_decimal(number, format, locale=self.locale)
 
     def currency(self, number, currency):
         """Return a number in the given currency formatted for the locale.
-        
+
         :see: `babel.numbers.format_currency`
         """
         return format_currency(number, currency, locale=self.locale)
 
     def percent(self, number, format=None):
         """Return a number formatted as percentage for the locale.
-        
+
         >>> fmt = Format('en_US')
         >>> fmt.percent(0.34) == '34%'
         True
-        
+
         :see: `babel.numbers.format_percent`
         """
         return format_percent(number, format, locale=self.locale)
 
     def scientific(self, number):
         """Return a number formatted using scientific notation for the locale.
-        
+
         :see: `babel.numbers.format_scientific`
         """
         return format_scientific(number, locale=self.locale)
 class LazyProxy(object):
     """Class for proxy objects that delegate to a specified function to evaluate
     the actual object.
-    
+
     >>> def greeting(name='world'):
     ...     return 'Hello, %s!' % name
     >>> lazy_greeting = LazyProxy(greeting, name='Joe')
     True
     >>> '(%s)' % lazy_greeting == '(Hello, Joe!)'
     True
-    
+
     This can be used, for example, to implement lazy translation functions that
     delay the actual translation until the string is actually used. The
     rationale for such behavior is that the locale of the user may not always
     be available. In web applications, you only know the locale when processing
     a request.
-    
+