diff --git a/babel/localedata.py b/babel/localedata.py index 437f49fae..1f4373798 100644 --- a/babel/localedata.py +++ b/babel/localedata.py @@ -15,6 +15,7 @@ import os import threading from collections import MutableMapping +from itertools import chain from babel._compat import pickle @@ -24,15 +25,29 @@ _dirname = os.path.join(os.path.dirname(__file__), 'locale-data') +def normalize_locale(name): + """Normalize a locale ID by stripping spaces and apply proper casing. + + Returns the normalized locale ID string or `None` if the ID is not + recognized. + """ + name = name.strip().lower() + for locale_id in chain.from_iterable([_cache, locale_identifiers()]): + if name == locale_id.lower(): + return locale_id + + def exists(name): - """Check whether locale data is available for the given locale. Ther - return value is `True` if it exists, `False` otherwise. + """Check whether locale data is available for the given locale. + + Returns `True` if it exists, `False` otherwise. :param name: the locale identifier string """ if name in _cache: return True - return os.path.exists(os.path.join(_dirname, '%s.dat' % name)) + file_found = os.path.exists(os.path.join(_dirname, '%s.dat' % name)) + return True if file_found else bool(normalize_locale(name)) def locale_identifiers(): diff --git a/tests/test_localedata.py b/tests/test_localedata.py index 80dd118c4..d0d92f61c 100644 --- a/tests/test_localedata.py +++ b/tests/test_localedata.py @@ -13,6 +13,8 @@ import doctest import unittest +import random +from operator import methodcaller from babel import localedata @@ -73,6 +75,23 @@ def test_merge(): localedata.merge(d, {1: 'Foo', 2: 'Bar'}) assert d == {1: 'Foo', 2: 'Bar', 3: 'baz'} + def test_locale_identification(): for l in localedata.locale_identifiers(): assert localedata.exists(l) + + +def test_unique_ids(): + # Check all locale IDs are uniques. + all_ids = localedata.locale_identifiers() + assert len(all_ids) == len(set(all_ids)) + # Check locale IDs don't collide after lower-case normalization. + lower_case_ids = list(map(methodcaller('lower'), all_ids)) + assert len(lower_case_ids) == len(set(lower_case_ids)) + + +def test_mixedcased_locale(): + for l in localedata.locale_identifiers(): + locale_id = ''.join([ + methodcaller(random.choice(['lower', 'upper']))(c) for c in l]) + assert localedata.exists(locale_id)