26
26
DEFAULT_LOCALE = default_locale ()
27
27
28
28
29
- def format_list (lst : Sequence [str ],
30
- style : Literal ['standard' , 'standard-short' , 'or' , 'or-short' , 'unit' , 'unit-short' , 'unit-narrow' ] = 'standard' ,
31
- locale : Locale | str | None = DEFAULT_LOCALE ) -> str :
29
+ def format_list (
30
+ lst : Sequence [str ],
31
+ style : Literal ['standard' , 'standard-short' , 'or' , 'or-short' , 'unit' , 'unit-short' , 'unit-narrow' ] = 'standard' ,
32
+ locale : Locale | str | None = DEFAULT_LOCALE ,
33
+ ) -> str :
32
34
"""
33
35
Format the items in `lst` as a list.
34
36
@@ -39,7 +41,11 @@ def format_list(lst: Sequence[str],
39
41
>>> format_list(['omena', 'peruna', 'aplari'], style='or', locale='fi')
40
42
u'omena, peruna tai aplari'
41
43
42
- These styles are defined, but not all are necessarily available in all locales.
44
+ Not all styles are necessarily available in all locales.
45
+ The function will attempt to fall back to replacement styles according to the rules
46
+ set forth in the CLDR root XML file, and raise a ValueError if no suitable replacement
47
+ can be found.
48
+
43
49
The following text is verbatim from the Unicode TR35-49 spec [1].
44
50
45
51
* standard:
@@ -76,14 +82,9 @@ def format_list(lst: Sequence[str],
76
82
if len (lst ) == 1 :
77
83
return lst [0 ]
78
84
79
- if style not in locale .list_patterns :
80
- raise ValueError (
81
- f'Locale { locale } does not support list formatting style { style !r} '
82
- f'(supported are { sorted (locale .list_patterns )} )' ,
83
- )
84
- patterns = locale .list_patterns [style ]
85
+ patterns = _resolve_list_style (locale , style )
85
86
86
- if len (lst ) == 2 :
87
+ if len (lst ) == 2 and '2' in patterns :
87
88
return patterns ['2' ].format (* lst )
88
89
89
90
result = patterns ['start' ].format (lst [0 ], lst [1 ])
@@ -92,3 +93,31 @@ def format_list(lst: Sequence[str],
92
93
result = patterns ['end' ].format (result , lst [- 1 ])
93
94
94
95
return result
96
+
97
+
98
+ # Based on CLDR 45's root.xml file's `<alias>`es.
99
+ # The root file defines both `standard` and `or`,
100
+ # so they're always available.
101
+ # TODO: It would likely be better to use the
102
+ # babel.localedata.Alias mechanism for this,
103
+ # but I'm not quite sure how it's supposed to
104
+ # work with inheritance and data in the root.
105
+ _style_fallbacks = {
106
+ "or-narrow" : ["or-short" , "or" ],
107
+ "or-short" : ["or" ],
108
+ "standard-narrow" : ["standard-short" , "standard" ],
109
+ "standard-short" : ["standard" ],
110
+ "unit" : ["unit-short" , "standard" ],
111
+ "unit-narrow" : ["unit-short" , "unit" , "standard" ],
112
+ "unit-short" : ["standard" ],
113
+ }
114
+
115
+
116
+ def _resolve_list_style (locale : Locale , style : str ):
117
+ for style in (style , * (_style_fallbacks .get (style , []))): # noqa: B020
118
+ if style in locale .list_patterns :
119
+ return locale .list_patterns [style ]
120
+ raise ValueError (
121
+ f"Locale { locale } does not support list formatting style { style !r} "
122
+ f"(supported are { sorted (locale .list_patterns )} )" ,
123
+ )
0 commit comments