@@ -194,7 +194,7 @@ def negotiate(cls, preferred, available, sep='_', aliases=LOCALE_ALIASES):
194194 return Locale .parse (identifier , sep = sep )
195195
196196 @classmethod
197- def parse (cls , identifier , sep = '_' ):
197+ def parse (cls , identifier , sep = '_' , resolve_likely_subtags = True ):
198198 """Create a `Locale` instance for the given locale identifier.
199199
200200 >>> l = Locale.parse('de-DE', sep='-')
@@ -207,8 +207,22 @@ def parse(cls, identifier, sep='_'):
207207 >>> Locale.parse(l)
208208 Locale('de', territory='DE')
209209
210+ This also can perform resolving of likely subtags which it does
211+ by default.
212+
210213 :param identifier: the locale identifier string
211214 :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.
212226 :return: a corresponding `Locale` instance
213227 :rtype: `Locale`
214228 :raise `ValueError`: if the string does not appear to be a valid locale
@@ -217,9 +231,72 @@ def parse(cls, identifier, sep='_'):
217231 requested locale
218232 :see: `parse_locale`
219233 """
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 )
223300
224301 def __eq__ (self , other ):
225302 for key in ('language' , 'territory' , 'script' , 'variant' ):
0 commit comments