summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmin Ronacher <armin.ronacher@active-4.com>2014-04-07 23:30:28 +0200
committerArmin Ronacher <armin.ronacher@active-4.com>2014-04-07 23:30:28 +0200
commit246996b0ee51e49ebcd504e234d3bcdcb178996c (patch)
tree569bce7a0dd8a5af96fc01bafc757d1ab4da6f09
parent7edfab980eb89e06ee97c576b0778283f1c40707 (diff)
parent514d41c0e73c58d43ace3ec310585bc48775196a (diff)
downloadbabel-246996b0ee51e49ebcd504e234d3bcdcb178996c.tar.gz
Merge branch 'master' of github.com:mitsuhiko/babel
-rw-r--r--CHANGES158
-rw-r--r--Makefile2
-rw-r--r--babel/_compat.py5
-rw-r--r--babel/core.py6
-rw-r--r--babel/dates.py4
-rw-r--r--babel/messages/catalog.py88
-rwxr-xr-xbabel/messages/frontend.py20
-rw-r--r--babel/messages/mofile.py4
-rw-r--r--babel/numbers.py2
-rw-r--r--babel/util.py2
-rw-r--r--docs/conf.py8
-rwxr-xr-xsetup.py3
-rw-r--r--tests/messages/test_catalog.py14
-rw-r--r--tests/test_core.py4
-rw-r--r--tests/test_numbers.py11
-rw-r--r--tests/test_plural.py8
-rw-r--r--tox.ini3
17 files changed, 190 insertions, 152 deletions
diff --git a/CHANGES b/CHANGES
index 7ccd8c9..7f44c5f 100644
--- a/CHANGES
+++ b/CHANGES
@@ -30,7 +30,7 @@ Version 1.3
- Fixed a bug in likely-subtag resolving for some common locales.
This primarily makes ``zh_CN`` work again which was broken
due to how it was defined in the likely subtags combined with
- our broken resolving. This fixes #37.
+ our broken resolving. This fixes :gh:`37`.
- Fixed a bug that caused pybabel to break when writing to stdout
on Python 3.
- Removed a stray print that was causing issues when writing to
@@ -65,8 +65,8 @@ Version 1.0
- use tox for testing on different pythons
- Added support for the locale plural rules defined by the CLDR.
- Added `format_timedelta` function to support localized formatting of
- relative times with strings such as "2 days" or "1 month" (ticket #126).
-- Fixed negative offset handling of Catalog._set_mime_headers (ticket #165).
+ relative times with strings such as "2 days" or "1 month" (:trac:`126`).
+- Fixed negative offset handling of Catalog._set_mime_headers (:trac:`165`).
- Fixed the case where messages containing square brackets would break with
an unpack error.
- updated to CLDR 23
@@ -74,52 +74,56 @@ Version 1.0
- Fix various typos.
- Sort output of list-locales.
- Make the POT-Creation-Date of the catalog being updated equal to
- POT-Creation-Date of the template used to update (ticket #148).
+ POT-Creation-Date of the template used to update (:trac:`148`).
- Use a more explicit error message if no option or argument (command) is
- passed to pybabel (ticket #81).
-- Keep the PO-Revision-Date if it is not the default value (ticket #148).
+ passed to pybabel (:trac:`81`).
+- Keep the PO-Revision-Date if it is not the default value (:trac:`148`).
- Make --no-wrap work by reworking --width's default and mimic xgettext's
- behaviour of always wrapping comments (ticket #145).
-- Add --project and --version options for commandline (ticket #173).
+ behaviour of always wrapping comments (:trac:`145`).
+- Add --project and --version options for commandline (:trac:`173`).
- Add a __ne__() method to the Local class.
- Explicitly sort instead of using sorted() and don't assume ordering
(Jython compatibility).
- Removed ValueError raising for string formatting message checkers if the
- string does not contain any string formattings (ticket #150).
-- Fix Serbian plural forms (ticket #213).
-- Small speed improvement in format_date() (ticket #216).
+ string does not contain any string formattings (:trac:`150`).
+- Fix Serbian plural forms (:trac:`213`).
+- Small speed improvement in format_date() (:trac:`216`).
- Fix so frontend.CommandLineInterface.run does not accumulate logging
- handlers (#227, reported with initial patch by dfraser)
-- Fix exception if environment contains an invalid locale setting (#200)
-- use cPickle instead of pickle for better performance (#225)
+ handlers (:trac:`227`, reported with initial patch by dfraser)
+- Fix exception if environment contains an invalid locale setting
+ (:trac:`200`)
+- use cPickle instead of pickle for better performance (:trac:`225`)
- Only use bankers round algorithm as a tie breaker if there are two nearest
- numbers, round as usual if there is only one nearest number (#267, patch by
- Martin)
-- Allow disabling cache behaviour in LazyProxy (#208, initial patch from Pedro
- Algarvio)
-- Support for context-aware methods during message extraction (#229, patch
- from David Rios)
-- "init" and "update" commands support "--no-wrap" option (#289)
+ numbers, round as usual if there is only one nearest number (:trac:`267`,
+ patch by Martin)
+- Allow disabling cache behaviour in LazyProxy (:trac:`208`, initial patch
+ from Pedro Algarvio)
+- Support for context-aware methods during message extraction (:trac:`229`,
+ patch from David Rios)
+- "init" and "update" commands support "--no-wrap" option (:trac:`289`)
- fix formatting of fraction in format_decimal() if the input value is a float
- with more than 7 significant digits (#183)
-- fix format_date() with datetime parameter (#282, patch from Xavier Morel)
-- fix format_decimal() with small Decimal values (#214, patch from George Lund)
-- fix handling of messages containing '\\n' (#198)
-- handle irregular multi-line msgstr (no "" as first line) gracefully (#171)
-- parse_decimal() now returns Decimals not floats, API change (#178)
-- no warnings when running setup.py without installed setuptools (#262)
+ with more than 7 significant digits (:trac:`183`)
+- fix format_date() with datetime parameter (:trac:`282`, patch from Xavier
+ Morel)
+- fix format_decimal() with small Decimal values (:trac:`214`, patch from
+ George Lund)
+- fix handling of messages containing '\\n' (:trac:`198`)
+- handle irregular multi-line msgstr (no "" as first line) gracefully
+ (:trac:`171`)
+- parse_decimal() now returns Decimals not floats, API change (:trac:`178`)
+- no warnings when running setup.py without installed setuptools (:trac:`262`)
- modified Locale.__eq__ method so Locales are only equal if all of their
attributes (language, territory, script, variant) are equal
-- resort to hard-coded message extractors/checkers if pkg_resources is
- installed but no egg-info was found (#230)
-- format_time() and format_datetime() now accept also floats (#242)
+- resort to hard-coded message extractors/checkers if pkg_resources is
+ installed but no egg-info was found (:trac:`230`)
+- format_time() and format_datetime() now accept also floats (:trac:`242`)
- add babel.support.NullTranslations class similar to gettext.NullTranslations
- but with all of Babel's new gettext methods (#277)
-- "init" and "update" commands support "--width" option (#284)
-- fix 'input_dirs' option for setuptools integration (#232, initial patch by
- Étienne Bersac)
-- ensure .mo file header contains the same information as the source .po file
- (#199)
+ but with all of Babel's new gettext methods (:trac:`277`)
+- "init" and "update" commands support "--width" option (:trac:`284`)
+- fix 'input_dirs' option for setuptools integration (:trac:`232`, initial
+ patch by Étienne Bersac)
+- ensure .mo file header contains the same information as the source .po file
+ (:trac:`199`)
- added support for get_language_name() on the locale objects.
- added support for get_territory_name() on the locale objects.
- added support for get_script_name() on the locale objects.
@@ -143,31 +147,32 @@ Version 0.9.6
- Backport r493-494: documentation typo fixes.
- Make the CLDR import script work with Python 2.7.
- Fix various typos.
-- Fixed Python 2.3 compatibility (ticket #146, #233).
+- Fixed Python 2.3 compatibility (:trac:`146`, :trac:`233`).
- Sort output of list-locales.
- Make the POT-Creation-Date of the catalog being updated equal to
- POT-Creation-Date of the template used to update (ticket #148).
+ POT-Creation-Date of the template used to update (:trac:`148`).
- Use a more explicit error message if no option or argument (command) is
- passed to pybabel (ticket #81).
-- Keep the PO-Revision-Date if it is not the default value (ticket #148).
+ passed to pybabel (:trac:`81`).
+- Keep the PO-Revision-Date if it is not the default value (:trac:`148`).
- Make --no-wrap work by reworking --width's default and mimic xgettext's
- behaviour of always wrapping comments (ticket #145).
-- Fixed negative offset handling of Catalog._set_mime_headers (ticket #165).
-- Add --project and --version options for commandline (ticket #173).
+ behaviour of always wrapping comments (:trac:`145`).
+- Fixed negative offset handling of Catalog._set_mime_headers (:trac:`165`).
+- Add --project and --version options for commandline (:trac:`173`).
- Add a __ne__() method to the Local class.
- Explicitly sort instead of using sorted() and don't assume ordering
(Python 2.3 and Jython compatibility).
- Removed ValueError raising for string formatting message checkers if the
- string does not contain any string formattings (ticket #150).
-- Fix Serbian plural forms (ticket #213).
-- Small speed improvement in format_date() (ticket #216).
+ string does not contain any string formattings (:trac:`150`).
+- Fix Serbian plural forms (:trac:`213`).
+- Small speed improvement in format_date() (:trac:`216`).
- Fix number formatting for locales where CLDR specifies alt or draft
- items (ticket #217)
-- Fix bad check in format_time (ticket #257, reported with patch and tests by
+ items (:trac:`217`)
+- Fix bad check in format_time (:trac:`257`, reported with patch and tests by
jomae)
- Fix so frontend.CommandLineInterface.run does not accumulate logging
- handlers (#227, reported with initial patch by dfraser)
-- Fix exception if environment contains an invalid locale setting (#200)
+ handlers (:trac:`227`, reported with initial patch by dfraser)
+- Fix exception if environment contains an invalid locale setting
+ (:trac:`200`)
Version 0.9.5
@@ -179,7 +184,7 @@ Version 0.9.5
an unpack error.
- Backport of r467: Fuzzy matching regarding plurals should *NOT* be checked
against len(message.id) because this is always 2, instead, it's should be
- checked against catalog.num_plurals (ticket #212).
+ checked against catalog.num_plurals (:trac:`212`).
Version 0.9.4
@@ -191,17 +196,17 @@ Version 0.9.4
CLDR data are no longer imported, so the symbol code will be used instead.
- Fixed quarter support in date formatting.
- Fixed a serious memory leak that was introduces by the support for CLDR
- aliases in 0.9.3 (ticket #128).
+ aliases in 0.9.3 (:trac:`128`).
- Locale modifiers such as "@euro" are now stripped from locale identifiers
- when parsing (ticket #136).
+ when parsing (:trac:`136`).
- The system locales "C" and "POSIX" are now treated as aliases for
"en_US_POSIX", for which the CLDR provides the appropriate data. Thanks to
Manlio Perillo for the suggestion.
-- Fixed JavaScript extraction for regular expression literals (ticket #138)
+- Fixed JavaScript extraction for regular expression literals (:trac:`138`)
and concatenated strings.
- The `Translation` class in `babel.support` can now manage catalogs with
different message domains, and exposes the family of `d*gettext` functions
- (ticket #137).
+ (:trac:`137`).
Version 0.9.3
@@ -211,11 +216,11 @@ Version 0.9.3
- Fixed invalid message extraction methods causing an UnboundLocalError.
- Extraction method specification can now use a dot instead of the colon to
- separate module and function name (ticket #105).
+ separate module and function name (:trac:`105`).
- Fixed message catalog compilation for locales with more than two plural
- forms (ticket #95).
+ forms (:trac:`95`).
- Fixed compilation of message catalogs for locales with more than two plural
- forms where the translations were empty (ticket #97).
+ forms where the translations were empty (:trac:`97`).
- The stripping of the comment tags in comments is optional now and
is done for each line in a comment.
- Added a JavaScript message extractor.
@@ -225,7 +230,7 @@ Version 0.9.3
correct plural forms for a locale as tuple.
- Added support for alias definitions in the CLDR data files, meaning that
the chance for items missing in certain locales should be greatly reduced
- (ticket #68).
+ (:trac:`68`).
Version 0.9.2
@@ -233,15 +238,15 @@ Version 0.9.2
(released on February 4th 2008)
-- Fixed catalogs' charset values not being recognized (ticket #66).
+- Fixed catalogs' charset values not being recognized (:trac:`66`).
- Numerous improvements to the default plural forms.
-- Fixed fuzzy matching when updating message catalogs (ticket #82).
+- Fixed fuzzy matching when updating message catalogs (:trac:`82`).
- Fixed bug in catalog updating, that in some cases pulled in translations
from different catalogs based on the same template.
- Location lines in PO files do no longer get wrapped at hyphens in file
- names (ticket #79).
+ names (:trac:`79`).
- Fixed division by zero error in catalog compilation on empty catalogs
- (ticket #60).
+ (:trac:`60`).
Version 0.9.1
@@ -254,7 +259,7 @@ Version 0.9.1
`ngettext`, or vice versa.
- Fixed time formatting for 12 am and 12 pm.
- Fixed output encoding of the `pybabel --list-locales` command.
-- MO files are now written in binary mode on windows (ticket #61).
+- MO files are now written in binary mode on windows (:trac:`61`).
Version 0.9
@@ -264,23 +269,24 @@ Version 0.9
- The `new_catalog` distutils command has been renamed to `init_catalog` for
consistency with the command-line frontend.
-- Added compilation of message catalogs to MO files (ticket #21).
-- Added updating of message catalogs from POT files (ticket #22).
+- Added compilation of message catalogs to MO files (:trac:`21`).
+- Added updating of message catalogs from POT files (:trac:`22`).
- Support for significant digits in number formatting.
- Apply proper "banker's rounding" in number formatting in a cross-platform
manner.
- The number formatting functions now also work with numbers represented by
- Python `Decimal` objects (ticket #53).
+ Python `Decimal` objects (:trac:`53`).
- Added extensible infrastructure for validating translation catalogs.
- Fixed the extractor not filtering out messages that didn't validate against
- the keyword's specification (ticket #39).
+ the keyword's specification (:trac:`39`).
- Fixed the extractor raising an exception when encountering an empty string
msgid. It now emits a warning to stderr.
- Numerous Python message extractor fixes: it now handles nested function
calls within a gettext function call correctly, uses the correct line number
- for multi-line function calls, and other small fixes (tickets #38 and #39).
+ for multi-line function calls, and other small fixes (tickets :trac:`38` and
+ :trac:`39`).
- Improved support for detecting Python string formatting fields in message
- strings (ticket #57).
+ strings (:trac:`57`).
- CLDR upgraded to the 1.5 release.
- Improved timezone formatting.
- Implemented scientific number formatting.
@@ -302,21 +308,21 @@ Version 0.8.1
that way.
- The character set specified in PO template files is now respected when
creating new catalog files based on that template. This allows the use of
- characters outside the ASCII range in POT files (ticket #17).
+ characters outside the ASCII range in POT files (:trac:`17`).
- The default ordering of messages in generated POT files, which is based on
the order those messages are found when walking the source tree, is no
longer subject to differences between platforms; directory and file names
are now always sorted alphabetically.
- The Python message extractor now respects the special encoding comment to be
- able to handle files containing non-ASCII characters (ticket #23).
+ able to handle files containing non-ASCII characters (:trac:`23`).
- Added ``N_`` (gettext noop) to the extractor's default keywords.
- Made locale string parsing more robust, and also take the script part into
- account (ticket #27).
+ account (:trac:`27`).
- Added a function to list all locales for which locale data is available.
- Added a command-line option to the `pybabel` command which prints out all
- available locales (ticket #24).
+ available locales (:trac:`24`).
- The name of the command-line script has been changed from just `babel` to
- `pybabel` to avoid a conflict with the OpenBabel project (ticket #34).
+ `pybabel` to avoid a conflict with the OpenBabel project (:trac:`34`).
Version 0.8
diff --git a/Makefile b/Makefile
index f2cdc96..5bb68a9 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
test: import-cldr
- @py.test tests
+ @PYTHONWARNINGS=default py.test
test-env:
@virtualenv test-env
diff --git a/babel/_compat.py b/babel/_compat.py
index 86096da..0f7640d 100644
--- a/babel/_compat.py
+++ b/babel/_compat.py
@@ -1,4 +1,5 @@
import sys
+import array
PY2 = sys.version_info[0] == 2
@@ -26,6 +27,8 @@ if not PY2:
cmp = lambda a, b: (a > b) - (a < b)
+ array_tobytes = array.array.tobytes
+
else:
text_type = unicode
string_types = (str, unicode)
@@ -47,5 +50,7 @@ else:
cmp = cmp
+ array_tobytes = array.array.tostring
+
number_types = integer_types + (float,)
diff --git a/babel/core.py b/babel/core.py
index 56dbf55..df38572 100644
--- a/babel/core.py
+++ b/babel/core.py
@@ -13,12 +13,14 @@ import os
from babel import localedata
from babel._compat import pickle, string_types
+from babel.plural import PluralRule
__all__ = ['UnknownLocaleError', 'Locale', 'default_locale', 'negotiate_locale',
'parse_locale']
_global_data = None
+_default_plural_rule = PluralRule({})
def _raise_no_data_error():
@@ -737,7 +739,7 @@ class Locale(object):
>>> Locale('ru').plural_form(100)
'many'
"""
- return self._data['plural_form']
+ return self._data.get('plural_form', _default_plural_rule)
def default_locale(category=None, aliases=LOCALE_ALIASES):
@@ -775,7 +777,7 @@ def default_locale(category=None, aliases=LOCALE_ALIASES):
# the LANGUAGE variable may contain a colon-separated list of
# language codes; we just pick the language on the list
locale = locale.split(':')[0]
- if locale in ('C', 'POSIX'):
+ if locale.split('.')[0] in ('C', 'POSIX'):
locale = 'en_US_POSIX'
elif aliases and locale in aliases:
locale = aliases[locale]
diff --git a/babel/dates.py b/babel/dates.py
index 72674e8..73d54fa 100644
--- a/babel/dates.py
+++ b/babel/dates.py
@@ -733,9 +733,9 @@ def format_timedelta(delta, granularity='second', threshold=.85,
In addition directional information can be provided that informs
the user if the date is in the past or in the future:
- >>> format_timedelta(timedelta(hours=1), add_direction=True)
+ >>> format_timedelta(timedelta(hours=1), add_direction=True, locale='en')
u'In 1 hour'
- >>> format_timedelta(timedelta(hours=-1), add_direction=True)
+ >>> format_timedelta(timedelta(hours=-1), add_direction=True, locale='en')
u'1 hour ago'
:param delta: a ``timedelta`` object representing the time difference to
diff --git a/babel/messages/catalog.py b/babel/messages/catalog.py
index 501763b..67c5425 100644
--- a/babel/messages/catalog.py
+++ b/babel/messages/catalog.py
@@ -40,6 +40,38 @@ PYTHON_FORMAT = re.compile(r'''(?x)
''')
+def _parse_datetime_header(value):
+ match = re.match(r'^(?P<datetime>.*?)(?P<tzoffset>[+-]\d{4})?$', value)
+
+ tt = time.strptime(match.group('datetime'), '%Y-%m-%d %H:%M')
+ ts = time.mktime(tt)
+ dt = datetime.fromtimestamp(ts)
+
+ # Separate the offset into a sign component, hours, and # minutes
+ tzoffset = match.group('tzoffset')
+ if tzoffset is not None:
+ plus_minus_s, rest = tzoffset[0], tzoffset[1:]
+ hours_offset_s, mins_offset_s = rest[:2], rest[2:]
+
+ # Make them all integers
+ plus_minus = int(plus_minus_s + '1')
+ hours_offset = int(hours_offset_s)
+ mins_offset = int(mins_offset_s)
+
+ # Calculate net offset
+ net_mins_offset = hours_offset * 60
+ net_mins_offset += mins_offset
+ net_mins_offset *= plus_minus
+
+ # Create an offset object
+ tzoffset = FixedOffsetTimezone(net_mins_offset)
+
+ # Store the offset in a datetime object
+ dt = dt.replace(tzinfo=tzoffset)
+
+ return dt
+
+
class Message(object):
"""Representation of a single message in a catalog."""
@@ -379,63 +411,11 @@ class Catalog(object):
self._num_plurals = int(params.get('nplurals', 2))
self._plural_expr = params.get('plural', '(n != 1)')
elif name == 'pot-creation-date':
- # FIXME: this should use dates.parse_datetime as soon as that
- # is ready
- value, tzoffset, _ = re.split('([+-]\d{4})$', value, 1)
-
- tt = time.strptime(value, '%Y-%m-%d %H:%M')
- ts = time.mktime(tt)
-
- # Separate the offset into a sign component, hours, and minutes
- plus_minus_s, rest = tzoffset[0], tzoffset[1:]
- hours_offset_s, mins_offset_s = rest[:2], rest[2:]
-
- # Make them all integers
- plus_minus = int(plus_minus_s + '1')
- hours_offset = int(hours_offset_s)
- mins_offset = int(mins_offset_s)
-
- # Calculate net offset
- net_mins_offset = hours_offset * 60
- net_mins_offset += mins_offset
- net_mins_offset *= plus_minus
-
- # Create an offset object
- tzoffset = FixedOffsetTimezone(net_mins_offset)
-
- # Store the offset in a datetime object
- dt = datetime.fromtimestamp(ts)
- self.creation_date = dt.replace(tzinfo=tzoffset)
+ self.creation_date = _parse_datetime_header(value)
elif name == 'po-revision-date':
# Keep the value if it's not the default one
if 'YEAR' not in value:
- # FIXME: this should use dates.parse_datetime as soon as
- # that is ready
- value, tzoffset, _ = re.split('([+-]\d{4})$', value, 1)
- tt = time.strptime(value, '%Y-%m-%d %H:%M')
- ts = time.mktime(tt)
-
- # Separate the offset into a sign component, hours, and
- # minutes
- plus_minus_s, rest = tzoffset[0], tzoffset[1:]
- hours_offset_s, mins_offset_s = rest[:2], rest[2:]
-
- # Make them all integers
- plus_minus = int(plus_minus_s + '1')
- hours_offset = int(hours_offset_s)
- mins_offset = int(mins_offset_s)
-
- # Calculate net offset
- net_mins_offset = hours_offset * 60
- net_mins_offset += mins_offset
- net_mins_offset *= plus_minus
-
- # Create an offset object
- tzoffset = FixedOffsetTimezone(net_mins_offset)
-
- # Store the offset in a datetime object
- dt = datetime.fromtimestamp(ts)
- self.revision_date = dt.replace(tzinfo=tzoffset)
+ self.revision_date = _parse_datetime_header(value)
mime_headers = property(_get_mime_headers, _set_mime_headers, doc="""\
The MIME headers of the catalog, used for the special ``msgid ""`` entry.
diff --git a/babel/messages/frontend.py b/babel/messages/frontend.py
index 144bc98..cd79ebf 100755
--- a/babel/messages/frontend.py
+++ b/babel/messages/frontend.py
@@ -65,7 +65,7 @@ class compile_catalog(Command):
'name of the input file'),
('output-file=', 'o',
"name of the output file (default "
- "'<output_dir>/<locale>/LC_MESSAGES/<domain>.po')"),
+ "'<output_dir>/<locale>/LC_MESSAGES/<domain>.mo')"),
('locale=', 'l',
'locale of the catalog to compile'),
('use-fuzzy', 'f',
@@ -89,7 +89,7 @@ class compile_catalog(Command):
raise DistutilsOptionError('you must specify either the input file '
'or the base directory')
if not self.output_file and not self.directory:
- raise DistutilsOptionError('you must specify either the input file '
+ raise DistutilsOptionError('you must specify either the output file '
'or the base directory')
def run(self):
@@ -128,7 +128,7 @@ class compile_catalog(Command):
for idx, (locale, po_file) in enumerate(po_files):
mo_file = mo_files[idx]
- infile = open(po_file, 'r')
+ infile = open(po_file, 'rb')
try:
catalog = read_po(infile, locale)
finally:
@@ -439,7 +439,7 @@ class init_catalog(Command):
log.info('creating catalog %r based on %r', self.output_file,
self.input_file)
- infile = open(self.input_file, 'r')
+ infile = open(self.input_file, 'rb')
try:
# Although reading from the catalog template, read_po must be fed
# the locale in order to correctly calculate plurals
@@ -554,7 +554,7 @@ class update_catalog(Command):
if not domain:
domain = os.path.splitext(os.path.basename(self.input_file))[0]
- infile = open(self.input_file, 'U')
+ infile = open(self.input_file, 'rb')
try:
template = read_po(infile)
finally:
@@ -566,7 +566,7 @@ class update_catalog(Command):
for locale, filename in po_files:
log.info('updating catalog %r based on %r', filename,
self.input_file)
- infile = open(filename, 'U')
+ infile = open(filename, 'rb')
try:
catalog = read_po(infile, locale=locale, domain=domain)
finally:
@@ -577,7 +577,7 @@ class update_catalog(Command):
tmpname = os.path.join(os.path.dirname(filename),
tempfile.gettempprefix() +
os.path.basename(filename))
- tmpfile = open(tmpname, 'w')
+ tmpfile = open(tmpname, 'wb')
try:
try:
write_po(tmpfile, catalog,
@@ -750,7 +750,7 @@ class CommandLineInterface(object):
mo_files.append(options.output_file)
else:
if not options.directory:
- parser.error('you must specify either the input file or '
+ parser.error('you must specify either the output file or '
'the base directory')
mo_files.append(os.path.join(options.directory, options.locale,
'LC_MESSAGES',
@@ -760,7 +760,7 @@ class CommandLineInterface(object):
for idx, (locale, po_file) in enumerate(po_files):
mo_file = mo_files[idx]
- infile = open(po_file, 'r')
+ infile = open(po_file, 'rb')
try:
catalog = read_po(infile, locale)
finally:
@@ -1121,7 +1121,7 @@ class CommandLineInterface(object):
tmpname = os.path.join(os.path.dirname(filename),
tempfile.gettempprefix() +
os.path.basename(filename))
- tmpfile = open(tmpname, 'w')
+ tmpfile = open(tmpname, 'wb')
try:
try:
write_po(tmpfile, catalog,
diff --git a/babel/messages/mofile.py b/babel/messages/mofile.py
index 5dd20ae..1850328 100644
--- a/babel/messages/mofile.py
+++ b/babel/messages/mofile.py
@@ -13,7 +13,7 @@ import array
import struct
from babel.messages.catalog import Catalog, Message
-from babel._compat import range_type
+from babel._compat import range_type, array_tobytes
LE_MAGIC = 0x950412de
@@ -206,4 +206,4 @@ def write_mo(fileobj, catalog, use_fuzzy=False):
7 * 4, # start of key index
7 * 4 + len(messages) * 8, # start of value index
0, 0 # size and offset of hash table
- ) + array.array("i", offsets).tostring() + ids + strs)
+ ) + array_tobytes(array.array("i", offsets)) + ids + strs)
diff --git a/babel/numbers.py b/babel/numbers.py
index 2f7fe16..587d640 100644
--- a/babel/numbers.py
+++ b/babel/numbers.py
@@ -389,7 +389,7 @@ def parse_decimal(string, locale=LC_NUMERIC):
PREFIX_END = r'[^0-9@#.,]'
-NUMBER_TOKEN = r'[0-9@#.\-,E+]'
+NUMBER_TOKEN = r'[0-9@#.,E+]'
PREFIX_PATTERN = r"(?P<prefix>(?:'[^']*'|%s)*)" % PREFIX_END
NUMBER_PATTERN = r"(?P<number>%s+)" % NUMBER_TOKEN
diff --git a/babel/util.py b/babel/util.py
index f46ee2b..a65fce3 100644
--- a/babel/util.py
+++ b/babel/util.py
@@ -80,7 +80,7 @@ def parse_encoding(fp):
raise SyntaxError(
"python refuses to compile code with both a UTF8 "
"byte-order-mark and a magic encoding comment")
- return 'utf_8'
+ return 'utf-8'
elif m:
return m.group(1).decode('latin-1')
else:
diff --git a/docs/conf.py b/docs/conf.py
index b1467c7..c84ebae 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -27,7 +27,8 @@ sys.path.append(os.path.abspath('_themes'))
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc',
- 'sphinx.ext.intersphinx']
+ 'sphinx.ext.intersphinx',
+ 'sphinx.ext.extlinks']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@@ -254,3 +255,8 @@ texinfo_documents = [
intersphinx_mapping = {
'http://docs.python.org/2': None,
}
+
+extlinks = {
+ 'gh': ('https://github.com/mitsuhiko/babel/issues/%s', '#'),
+ 'trac': ('http://babel.edgewall.org/ticket/%s', 'ticket #'),
+}
diff --git a/setup.py b/setup.py
index c7b39c3..b89a4ec 100755
--- a/setup.py
+++ b/setup.py
@@ -48,7 +48,10 @@ setup(
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.3',
'Topic :: Software Development :: Libraries :: Python Modules',
],
packages=['babel', 'babel.messages', 'babel.localtime'],
diff --git a/tests/messages/test_catalog.py b/tests/messages/test_catalog.py
index fcac34d..aac71ee 100644
--- a/tests/messages/test_catalog.py
+++ b/tests/messages/test_catalog.py
@@ -454,3 +454,17 @@ def test_catalog_update():
assert not 'head' in cat
assert list(cat.obsolete.values())[0].id == 'head'
+
+
+def test_datetime_parsing():
+ val1 = catalog._parse_datetime_header('2006-06-28 23:24+0200')
+ assert val1.year == 2006
+ assert val1.month == 6
+ assert val1.day == 28
+ assert val1.tzinfo.zone == 'Etc/GMT+120'
+
+ val2 = catalog._parse_datetime_header('2006-06-28 23:24')
+ assert val2.year == 2006
+ assert val2.month == 6
+ assert val2.day == 28
+ assert val2.tzinfo is None
diff --git a/tests/test_core.py b/tests/test_core.py
index ec3f9ea..ac2611d 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -238,6 +238,10 @@ def test_default_locale(os_environ):
os_environ['LC_MESSAGES'] = 'POSIX'
assert default_locale('LC_MESSAGES') == 'en_US_POSIX'
+ for value in ['C', 'C.UTF-8', 'POSIX']:
+ os_environ['LANGUAGE'] = value
+ assert default_locale() == 'en_US_POSIX'
+
def test_negotiate_locale():
assert (core.negotiate_locale(['de_DE', 'en_US'], ['de_DE', 'de_AT']) ==
diff --git a/tests/test_numbers.py b/tests/test_numbers.py
index 99e0d1b..02332fb 100644
--- a/tests/test_numbers.py
+++ b/tests/test_numbers.py
@@ -175,7 +175,8 @@ class NumberParsingTestCase(unittest.TestCase):
def test_get_currency_name():
- assert numbers.get_currency_name('USD', 'en_US') == u'US dollars'
+ assert numbers.get_currency_name('USD', locale='en_US') == u'US Dollar'
+ assert numbers.get_currency_name('USD', count=2, locale='en_US') == u'US dollars'
def test_get_currency_symbol():
@@ -213,6 +214,7 @@ def test_get_plus_sign_symbol():
def test_get_minus_sign_symbol():
assert numbers.get_minus_sign_symbol('en_US') == u'-'
+ assert numbers.get_minus_sign_symbol('nl_NL') == u'-'
def test_get_exponential_symbol():
@@ -247,6 +249,8 @@ def test_format_currency():
assert (numbers.format_currency(1099.98, 'EUR', u'\xa4\xa4 #,##0.00',
locale='en_US')
== u'EUR 1,099.98')
+ assert (numbers.format_currency(1099.98, 'EUR', locale='nl_NL')
+ != numbers.format_currency(-1099.98, 'EUR', locale='nl_NL'))
def test_format_percent():
@@ -298,3 +302,8 @@ def test_parse_grouping():
assert numbers.parse_grouping('##') == (1000, 1000)
assert numbers.parse_grouping('#,###') == (3, 3)
assert numbers.parse_grouping('#,####,###') == (3, 4)
+
+
+def test_parse_pattern():
+ assert numbers.parse_pattern(u'¤#,##0.00;(¤#,##0.00)').suffix == (u'', u')')
+ assert numbers.parse_pattern(u'¤ #,##0.00;¤ #,##0.00-').suffix == (u'', u'-')
diff --git a/tests/test_plural.py b/tests/test_plural.py
index 5fe67a5..7f31fd9 100644
--- a/tests/test_plural.py
+++ b/tests/test_plural.py
@@ -90,3 +90,11 @@ def test_plural_within_rules():
assert p(7) == 'few'
assert p(8) == 'few'
assert p(9) == 'few'
+
+
+def test_locales_with_no_plural_rules_have_default():
+ from babel import Locale
+ aa_plural = Locale.parse('aa').plural_form
+ assert aa_plural(1) == 'other'
+ assert aa_plural(2) == 'other'
+ assert aa_plural(15) == 'other'
diff --git a/tox.ini b/tox.ini
index 52d8df9..6d4eb03 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,4 +4,5 @@ envlist = py26, py27, pypy, py33
[testenv]
deps =
pytest
-commands = py.test tests
+whitelist_externals = make
+commands = make clean-cldr test