@@ -194,7 +194,7 @@ def negotiate(cls, preferred, available, sep='_', aliases=LOCALE_ALIASES):
194
194
return Locale .parse (identifier , sep = sep )
195
195
196
196
@classmethod
197
- def parse (cls , identifier , sep = '_' ):
197
+ def parse (cls , identifier , sep = '_' , resolve_likely_subtags = True ):
198
198
"""Create a `Locale` instance for the given locale identifier.
199
199
200
200
>>> l = Locale.parse('de-DE', sep='-')
@@ -207,8 +207,22 @@ def parse(cls, identifier, sep='_'):
207
207
>>> Locale.parse(l)
208
208
Locale('de', territory='DE')
209
209
210
+ This also can perform resolving of likely subtags which it does
211
+ by default.
212
+
210
213
:param identifier: the locale identifier string
211
214
:param sep: optional component separator
215
+ :param resolve_likely_subtags: if this is specified then a locale will
216
+ have its likely subtag resolved if the
217
+ locale otherwise does not exist. For
218
+ instance ``zh_TW`` by itself is not a
219
+ locale that exists but Babel can
220
+ automatically expand it to the full
221
+ form of ``zh_hant_TW``. Note that this
222
+ expansion is only taking place if no
223
+ locale exists otherwise. For instance
224
+ there is a locale ``en`` that can exist
225
+ by itself.
212
226
:return: a corresponding `Locale` instance
213
227
:rtype: `Locale`
214
228
:raise `ValueError`: if the string does not appear to be a valid locale
@@ -217,9 +231,72 @@ def parse(cls, identifier, sep='_'):
217
231
requested locale
218
232
:see: `parse_locale`
219
233
"""
220
- if isinstance (identifier , string_types ):
221
- return cls (* parse_locale (identifier , sep = sep ))
222
- return identifier
234
+ if identifier is None :
235
+ return None
236
+ elif isinstance (identifier , Locale ):
237
+ return identifier
238
+ elif not isinstance (identifier , string_types ):
239
+ raise TypeError ('Unxpected value for identifier: %r' % (identifier ,))
240
+
241
+ parts = parse_locale (identifier , sep = sep )
242
+
243
+ def _make_id (language , territory , script , variant ):
244
+ return '_' .join (filter (None , [language , script ,
245
+ territory , variant ]))
246
+
247
+ input_id = _make_id (* parts )
248
+
249
+ def _try_load (parts ):
250
+ try :
251
+ return cls (* parts )
252
+ except UnknownLocaleError :
253
+ return None
254
+
255
+ locale = _try_load (parts )
256
+ if locale is not None :
257
+ return locale
258
+ if not resolve_likely_subtags :
259
+ raise UnknownLocaleError (input_id )
260
+
261
+ # From here onwards is some very bad likely subtag resolving. This
262
+ # whole logic is not entirely correct but good enough (tm) for the
263
+ # time being. This has been added so that zh_TW does not cause
264
+ # errors for people when they upgrade. Later we should properly
265
+ # implement ICU like fuzzy locale objects and provide a way to
266
+ # maximize and minimize locale tags.
267
+
268
+ language , territory , script , variant = parts
269
+ language = get_global ('language_aliases' ).get (language , language )
270
+ territory = get_global ('territory_aliases' ).get (territory , territory )
271
+ script = get_global ('script_aliases' ).get (script , script )
272
+ variant = get_global ('variant_aliases' ).get (variant , variant )
273
+
274
+ if territory == 'ZZ' :
275
+ territory = None
276
+ if script == 'Zzzz' :
277
+ script = None
278
+
279
+ parts = language , territory , script , variant
280
+
281
+ new_id = _make_id (* parts )
282
+ likely_subtag = get_global ('likely_subtags' ).get (new_id )
283
+ if likely_subtag is None :
284
+ raise UnknownLocaleError (input_id )
285
+
286
+ parts2 = parse_locale (likely_subtag )
287
+
288
+ # Success on first hit, return it.
289
+ locale = _try_load (parts2 )
290
+ if locale is not None :
291
+ return locale
292
+
293
+ # Now try without script and variant
294
+ lcoale = _try_load (parts2 [:2 ])
295
+ if locale is not None :
296
+ return locale
297
+
298
+ # Give up.
299
+ raise UnknownLocaleError (input_id )
223
300
224
301
def __eq__ (self , other ):
225
302
for key in ('language' , 'territory' , 'script' , 'variant' ):
0 commit comments