]> git.ipfire.org Git - thirdparty/babel.git/commitdiff
Lists: add support for various list styles other than the default
authorAarni Koskela <akx@iki.fi>
Fri, 19 Jan 2018 11:39:07 +0000 (13:39 +0200)
committerAarni Koskela <akx@iki.fi>
Fri, 19 Jan 2018 15:44:26 +0000 (17:44 +0200)
This was inspired by the CLDR 32 release notes:

> New “disjunctive” list style (eg “a, b, or c”)

babel/core.py
babel/lists.py
scripts/import_cldr.py
tests/test_lists.py

index 5a9091faeab607332dc83e80a37ab74d5ee46ccf..5a1a9125dc01661bba03b6f71cd854fd595b2242 100644 (file)
@@ -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']
index 82e5590c1475ffb5a4d5223657e26990e7853c9a..329437975591b042b0e93d0f5a6f131370f482bc 100644 (file)
@@ -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
index 94fe85ea267d3640c90ef624d1068b01e4fe1912..d50e146676ed5f2a767203d1b0236021505372be 100755 (executable)
@@ -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):
index bd297ec38a5cb90c9b94f38dd4eaae48bff57331..e843a6358490eb0108a9028fc3c185d3f143aa70 100644 (file)
@@ -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')