summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAarni Koskela <akx@iki.fi>2018-01-19 13:39:07 +0200
committerAarni Koskela <akx@iki.fi>2018-01-19 17:44:26 +0200
commitbd2ac889827f55fc6d48b3e63fa38e3c090f8892 (patch)
treea1bc5de9f712463cad5d95c9acd03a92041b1223
parentff7e3d2e74ff2c271294ae850f5fa139ce981488 (diff)
downloadbabel-bd2ac889827f55fc6d48b3e63fa38e3c090f8892.tar.gz
Lists: add support for various list styles other than the default
This was inspired by the CLDR 32 release notes: > New “disjunctive” list style (eg “a, b, or c”)
-rw-r--r--babel/core.py6
-rw-r--r--babel/lists.py55
-rwxr-xr-xscripts/import_cldr.py10
-rw-r--r--tests/test_lists.py7
4 files changed, 63 insertions, 15 deletions
diff --git a/babel/core.py b/babel/core.py
index 5a9091f..5a1a912 100644
--- a/babel/core.py
+++ b/babel/core.py
@@ -857,11 +857,11 @@ class Locale(object):
.. note:: The format of the value returned may change between
Babel versions.
- >>> Locale('en').list_patterns['start']
+ >>> Locale('en').list_patterns['standard']['start']
u'{0}, {1}'
- >>> Locale('en').list_patterns['end']
+ >>> Locale('en').list_patterns['standard']['end']
u'{0}, and {1}'
- >>> Locale('en_GB').list_patterns['end']
+ >>> Locale('en_GB').list_patterns['standard']['end']
u'{0} and {1}'
"""
return self._data['list_patterns']
diff --git a/babel/lists.py b/babel/lists.py
index 82e5590..3294379 100644
--- a/babel/lists.py
+++ b/babel/lists.py
@@ -11,7 +11,7 @@
* ``LC_ALL``, and
* ``LANG``
- :copyright: (c) 2015 by the Babel Team.
+ :copyright: (c) 2015, 2018 by the Babel Team.
:license: BSD, see LICENSE for more details.
"""
@@ -20,16 +20,46 @@ from babel.core import Locale, default_locale
DEFAULT_LOCALE = default_locale()
-def format_list(lst, locale=DEFAULT_LOCALE):
+def format_list(lst, style='standard', locale=DEFAULT_LOCALE):
"""
Format the items in `lst` as a list.
- >>> format_list(['apples', 'oranges', 'pears'], 'en')
+ >>> format_list(['apples', 'oranges', 'pears'], locale='en')
u'apples, oranges, and pears'
- >>> format_list(['apples', 'oranges', 'pears'], 'zh')
+ >>> format_list(['apples', 'oranges', 'pears'], locale='zh')
u'apples\u3001oranges\u548cpears'
+ >>> format_list(['omena', 'peruna', 'aplari'], style='or', locale='fi')
+ u'omena, peruna tai aplari'
+
+ These styles are defined, but not all are necessarily available in all locales.
+ The following text is verbatim from the Unicode TR35-49 spec [1].
+
+ * standard:
+ A typical 'and' list for arbitrary placeholders.
+ eg. "January, February, and March"
+ * standard-short:
+ A short version of a 'and' list, suitable for use with short or abbreviated placeholder values.
+ eg. "Jan., Feb., and Mar."
+ * or:
+ A typical 'or' list for arbitrary placeholders.
+ eg. "January, February, or March"
+ * or-short:
+ A short version of an 'or' list.
+ eg. "Jan., Feb., or Mar."
+ * unit:
+ A list suitable for wide units.
+ eg. "3 feet, 7 inches"
+ * unit-short:
+ A list suitable for short units
+ eg. "3 ft, 7 in"
+ * unit-narrow:
+ A list suitable for narrow units, where space on the screen is very limited.
+ eg. "3′ 7″"
+
+ [1]: https://www.unicode.org/reports/tr35/tr35-49/tr35-general.html#ListPatterns
:param lst: a sequence of items to format in to a list
+ :param style: the style to format the list with. See above for description.
:param locale: the locale
"""
locale = Locale.parse(locale)
@@ -37,12 +67,21 @@ def format_list(lst, locale=DEFAULT_LOCALE):
return ''
if len(lst) == 1:
return lst[0]
+
+ if style not in locale.list_patterns:
+ raise ValueError('Locale %s does not support list formatting style %r (supported are %s)' % (
+ locale,
+ style,
+ list(sorted(locale.list_patterns)),
+ ))
+ patterns = locale.list_patterns[style]
+
if len(lst) == 2:
- return locale.list_patterns['2'].format(*lst)
+ return patterns['2'].format(*lst)
- result = locale.list_patterns['start'].format(lst[0], lst[1])
+ result = patterns['start'].format(lst[0], lst[1])
for elem in lst[2:-1]:
- result = locale.list_patterns['middle'].format(result, elem)
- result = locale.list_patterns['end'].format(result, lst[-1])
+ result = patterns['middle'].format(result, elem)
+ result = patterns['end'].format(result, lst[-1])
return result
diff --git a/scripts/import_cldr.py b/scripts/import_cldr.py
index 94fe85e..d50e146 100755
--- a/scripts/import_cldr.py
+++ b/scripts/import_cldr.py
@@ -397,7 +397,7 @@ def _process_local_datas(sup, srcdir, destdir, force=False, dump_json=False):
data["day_period_rules"] = day_period_rules[locale_id]
parse_locale_display_names(data, tree)
-
+ parse_list_patterns(data, tree)
parse_dates(data, tree, sup, regions, territory)
for calendar in tree.findall('.//calendars/calendar'):
@@ -478,12 +478,14 @@ def parse_locale_display_names(data, tree):
scripts = data.setdefault('scripts', {})
for elem in tree.findall('.//scripts/script'):
_import_type_text(scripts, elem)
+
+
+def parse_list_patterns(data, tree):
list_patterns = data.setdefault('list_patterns', {})
for listType in tree.findall('.//listPatterns/listPattern'):
- if 'type' in listType.attrib:
- continue
+ by_type = list_patterns.setdefault(listType.attrib.get('type', 'standard'), {})
for listPattern in listType.findall('listPatternPart'):
- list_patterns[listPattern.attrib['type']] = _text(listPattern)
+ by_type[listPattern.attrib['type']] = _text(listPattern)
def parse_dates(data, tree, sup, regions, territory):
diff --git a/tests/test_lists.py b/tests/test_lists.py
index bd297ec..e843a63 100644
--- a/tests/test_lists.py
+++ b/tests/test_lists.py
@@ -1,4 +1,6 @@
# coding=utf-8
+import pytest
+
from babel import lists
@@ -12,3 +14,8 @@ def test_format_list():
(['string1', 'string2', 'string3', 'string4'], 'ne', u'string1,string2, string3 र string4'),
]:
assert lists.format_list(list, locale=locale) == expected
+
+
+def test_format_list_error():
+ with pytest.raises(ValueError):
+ lists.format_list(['a', 'b', 'c'], style='orange', locale='en')