+"""Locale utility routines."""
+
+import sys
+
+try:
+ import locale
+except ImportError:
+ locale = None
+
+try:
+ import codecs
+except ImportError:
+ codecs = None
+
+__all__ = ["localelist"]
+
+def localelist(*locales):
+ """Normalize and return a list of locales, with appended defaults.
+
+ e.g. on a system with en_US as the default locale,
+
+ localelist('en_GB.utf8', 'de_DE') =>
+ ['en_GB', 'en', 'de_DE', 'de', 'en_US', 'C']
+
+ """
+
+ locales = list(locales)
+
+ if locale is not None:
+ # Set the locale if it hasn't already been set, but don't fail
+ # if we can't set it for some reason.
+ if locale.getlocale(locale.LC_COLLATE)[0] is None:
+ try:
+ locale.setlocale(locale.LC_COLLATE, '')
+ except locale.Error:
+ pass
+
+ # Throw in the user's specified collation locale, the current locale,
+ # the default locale, and POSIX, for free.
+ locales.append(locale.getlocale(locale.LC_COLLATE)[0])
+ locales.append(locale.getlocale()[0])
+ locales.append(locale.getdefaultlocale()[0])
+ locales.append("C")
+
+ # Don't put the same locale in the return list more than twice.
+ added = set()
+ retlist = []
+
+ for code in locales:
+ if not code:
+ continue
+ if locale is not None:
+ code = locale.normalize(code)
+ # Strip off encoding if present.
+ code = code.split(".")[0]
+ if code.lower() not in added:
+ retlist.append(code)
+ added.add(code.lower())
+ # Strip off territory if present.
+ code = code.split("_")[0]
+ if code.lower() not in added:
+ retlist.append(code)
+ added.add(code.lower())
+
+ return retlist
+
+def encoding(preferred=None):
+ """Try to find an optimal encoding.
+
+ Arguments:
+ preferred - use this encoding if possible
+
+ Otherwise, the locale encoding or the Python system encoding are
+ used.
+ """
+ # can't use any codecs, use the system one (ascii).
+ if codecs is None:
+ return sys.getdefaultencoding()
+
+ # if preferred is a valid codec, use it.
+ if preferred is not None:
+ try:
+ return codecs.lookup(preferred).name
+ except (LookupError, AttributeError):
+ pass
+
+ # preferred is bad and can't get it from locale.
+ if locale is None:
+ return sys.getdefaultencoding()
+
+ # try to get it from the locale, if not there, set it and try again.
+ fromlocale = locale.getlocale(locale.LC_COLLATE)[1]
+ if fromlocale is not None:
+ return fromlocale
+ try:
+ locale.setlocale(locale.LC_COLLATE, '')[1]
+ except locale.Error:
+ pass
+ else:
+ fromlocale = locale.getlocale(locale.LC_COLLATE)
+ if fromlocale is not None:
+ return fromlocale
+
+ # okay, LC_COLLATE isn't set, maybe the generic locale is.
+ fromlocale = locale.getlocale()[1]
+ if fromlocale is not None:
+ return fromlocale
+
+ # but we won't reset the generic locale if it isn't, that'd be
+ # rude.
+
+ # if the locale can't even give us a simple encoding, go back
+ # to the system one, and give up.
+ return locale.getpreferredencoding() or sys.getdefaultencoding()
+
+def getpair(locale_, encoding_):
+ if "." in locale_:
+ if encoding_ is None:
+ locale_, encoding_ = locale_.rsplit(".", 1)
+ else:
+ locale_ = locale_.rsplit(".")[0]
+ return locale_, encoding(encoding_)
+