@@ -113,7 +113,7 @@ def locale2str(value: Locale) -> str:
113
113
114
114
def best_match (accept_languages , available_locales ) -> Locale :
115
115
"""
116
- Takes an Accept-Languages string (from header or request query params)
116
+ Takes an Accept-Languages sorted list (from header or request query params)
117
117
and finds the best matching locale from a list of available locales.
118
118
119
119
This function provides a framework-independent alternative to the
@@ -131,12 +131,12 @@ def best_match(accept_languages, available_locales) -> Locale:
131
131
or unknown locale is ignored. However, if no
132
132
`available_locales` are specified, a `LocaleError` is raised.
133
133
134
- :param accept_languages: A Locale or string with one or more languages.
134
+ :param accept_languages: A Locale or list of one or more languages.
135
135
This can be as simple as "de" for example,
136
136
but it's also possible to include a territory
137
137
(e.g. "en-US" or "fr_BE") or even a complex
138
- string with quality values, e.g.
139
- "fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5" .
138
+ list sorted by quality values, e.g.
139
+ [ "fr-CH, "fr", "en", "de", "*"] .
140
140
:param available_locales: A list containing the available locales.
141
141
For example, a pygeoapi provider might only
142
142
support ["de", "en"].
@@ -170,49 +170,12 @@ def get_match(locale_, available_locales_):
170
170
171
171
if isinstance (accept_languages , Locale ):
172
172
# If a Babel Locale was used as input, transform back into a string
173
- accept_languages = locale2str (accept_languages )
173
+ accept_languages = [ locale2str (accept_languages )]
174
174
175
- if not isinstance (accept_languages , str ):
175
+ if not isinstance (accept_languages , list ):
176
176
# If `accept_languages` is not a string, ignore it
177
177
LOGGER .debug (f"ignoring invalid accept-languages '{ accept_languages } '" )
178
- accept_languages = ''
179
-
180
- tags = accept_languages .split (',' )
181
- num_tags = len (tags )
182
- req_locales = {}
183
- for i , lang in enumerate (tags ):
184
- q_raw = None
185
- q_out = None
186
- if not lang :
187
- continue
188
-
189
- # Check if complex (i.e. with quality weights)
190
- try :
191
- lang , q_raw = (v .strip () for v in lang .split (';' ))
192
- except ValueError :
193
- # Tuple unpacking failed: tag is not complex (or too complex :))
194
- pass
195
-
196
- # Validate locale tag
197
- loc = str2locale (lang , True )
198
- if not loc :
199
- LOGGER .debug (f"ignoring invalid accept-language '{ lang } '" )
200
- continue
201
-
202
- # Validate quality weight (e.g. "q=0.7")
203
- if q_raw :
204
- try :
205
- q_out = float ([v .strip () for v in q_raw .split ('=' )][1 ])
206
- except (ValueError , IndexError ):
207
- # Tuple unpacking failed: not a valid q tag
208
- pass
209
-
210
- # If there's no actual q, set one based on the language order
211
- if not q_out :
212
- q_out = num_tags - i
213
-
214
- # Store locale
215
- req_locales [q_out ] = loc
178
+ accept_languages = []
216
179
217
180
# Process supported locales
218
181
prv_locales = OrderedDict ()
@@ -221,7 +184,11 @@ def get_match(locale_, available_locales_):
221
184
prv_locales .setdefault (loc .language , []).append (loc .territory )
222
185
223
186
# Return best match from accepted languages
224
- for _ , loc in sorted (req_locales .items (), reverse = True ):
187
+ for lang in accept_languages :
188
+ loc = str2locale (lang , True )
189
+ if not loc :
190
+ LOGGER .debug (f"ignoring invalid accept-language '{ lang } '" )
191
+ continue
225
192
match = get_match (loc , prv_locales )
226
193
if match :
227
194
LOGGER .debug (f"'{ match } ' matches requested '{ accept_languages } '" )
@@ -281,7 +248,7 @@ def translate(value, language: Union[Locale, str]):
281
248
return value
282
249
283
250
# Find best language match and return value by its key
284
- out_locale = best_match (language , loc_items .keys ())
251
+ out_locale = best_match ([ language ] , loc_items .keys ())
285
252
return value [loc_items [out_locale ]]
286
253
287
254
@@ -340,42 +307,6 @@ def _translate_dict(obj, level: int = 0):
340
307
return result
341
308
342
309
343
- def locale_from_headers (headers ) -> str :
344
- """
345
- Gets a valid Locale from a request headers dictionary.
346
- Supported are complex strings (e.g. "fr-CH, fr;q=0.9, en;q=0.8"),
347
- web locales (e.g. "en-US") or basic language tags (e.g. "en").
348
- A value of `None` is returned if the locale was not found or invalid.
349
-
350
- :param headers: Mapping of request headers.
351
-
352
- :returns: locale string or None
353
- """
354
-
355
- lang = {k .lower (): v for k , v in headers .items ()}.get ('accept-language' )
356
- if lang :
357
- LOGGER .debug (f"Got locale '{ lang } ' from 'Accept-Language' header" )
358
- return lang
359
-
360
-
361
- def locale_from_params (params ) -> str :
362
- """
363
- Gets a valid Locale from a request query parameters dictionary.
364
- Supported are complex strings (e.g. "fr-CH, fr;q=0.9, en;q=0.8"),
365
- web locales (e.g. "en-US") or basic language tags (e.g. "en").
366
- A value of `None` is returned if the locale was not found or invalid.
367
-
368
- :param params: Mapping of request query parameters.
369
-
370
- :returns: locale string or None
371
- """
372
-
373
- lang = params .get (QUERY_PARAM )
374
- if lang :
375
- LOGGER .debug (f"Got locale '{ lang } ' from query parameter '{ QUERY_PARAM } '" ) # noqa
376
- return lang
377
-
378
-
379
310
def set_response_language (headers : dict , * locale_ : Locale ):
380
311
"""
381
312
Sets the Content-Language on the given HTTP response headers dict.
0 commit comments