[PATCH] Use langtable instead of our magic tables and hacks

Vratislav Podzimek vpodzime at redhat.com
Tue Jun 11 14:57:23 UTC 2013


This great new package allows us to remove our magic tables and hacks dealing
with languages, locales and some more things.

Signed-off-by: Vratislav Podzimek <vpodzime at redhat.com>
---
 anaconda.spec.in           |   3 +
 pyanaconda/localization.py | 172 ++++++++++++++++++++++-----------------------
 2 files changed, 86 insertions(+), 89 deletions(-)

diff --git a/anaconda.spec.in b/anaconda.spec.in
index f6a3f37..20a020a 100644
--- a/anaconda.spec.in
+++ b/anaconda.spec.in
@@ -38,6 +38,7 @@ Source0: %{name}-%{version}.tar.bz2
 %define isomd5sum 1.0.10
 %define fcoeutilsver 1.0.12-3.20100323git
 %define iscsiver 6.2.0.870-3
+%define langtablever 0.0.5-1
 
 BuildRequires: audit-libs-devel
 BuildRequires: gettext >= %{gettextver}
@@ -88,6 +89,8 @@ Requires: python-urlgrabber >= %{pythonurlgrabberver}
 Requires: system-logos
 Requires: pykickstart >= %{pykickstartver}
 Requires: python-babel
+Requires: langtable-data >= %{langtablever}
+Requires: langtable-python >= %{langtablever}
 Requires: libuser-python
 Requires: authconfig
 Requires: firewalld >= %{firewalldver}
diff --git a/pyanaconda/localization.py b/pyanaconda/localization.py
index ae8d9e4..f9d0037 100644
--- a/pyanaconda/localization.py
+++ b/pyanaconda/localization.py
@@ -1,6 +1,6 @@
 # Localization classes and functions
 #
-# Copyright (C) 2012  Red Hat, Inc.
+# Copyright (C) 2012-2013 Red Hat, Inc.
 #
 # This copyrighted material is made available to anyone wishing to use,
 # modify, copy, or redistribute it subject to the terms and conditions of
@@ -17,6 +17,7 @@
 # Red Hat, Inc.
 #
 # Red Hat Author(s): Martin Gracik <mgracik at redhat.com>
+#                    Vratislav Podzimek <vpodzime at redhat.com>
 #
 
 from collections import defaultdict, deque
@@ -28,6 +29,7 @@ import logging
 log = logging.getLogger("anaconda")
 
 import babel
+import langtable
 
 from pyanaconda.constants import DEFAULT_LANG
 
@@ -46,29 +48,73 @@ class LocalizationConfigError(Exception):
 
     pass
 
+class InvalidLocaleSpec(LocalizationConfigError):
+    """Exception class for the errors related to invalid locale specs"""
+
+    pass
+
 class LocaleInfo(object):
+    """
+    Class unifying the glibc-like and CLDR-like locales by providing a single
+    API based on properties.
+
+    """
 
-    def __init__(self, localedata, encoding="", script=""):
+    def __init__(self, localespec):
         """
-        :param encoding: encoding from the locale specification, e.g. UTF-8
-                         (localedata object has no attribute for that)
-        :param script: script from the locale specification (e.g. latin)
-                       (changing localedata.script attribute results in
-                       problems)
+        Constructor for the LocaleInfo class.
+
+        :param localespec: locale string such as "sr_RS.UTF-8 at latin"
+                           (glibc-like format) or "sr_Latn_RS" (CLDR-format)
+        :type localespec: str
 
         """
 
-        self._localedata = localedata
-        self._encoding = encoding or "UTF-8"
-        self._script = script
+        # get the basic values
+        parsed_values = parse_langcode(localespec)
+        if parsed_values:
+            # successfully parsed -> a glibc-like locale, try to get some more
+            # information by querying langtable
+
+            # language must be specified
+            language = parsed_values["language"]
+            territory = parsed_values.get("territory", "")
+            script = parsed_values.get("modifier", "")
+
+            locales = langtable.list_locales(languageId=language,
+                                             territoryId=territory,
+                                             scriptId=script)
+        else:
+            # not in the glibc-like format, use langtable to get it
+            locales = langtable.list_locales(languageId=localespec)
+
+        if not locales:
+            msg = "'%s' is not a valid locale" % localespec
+            raise InvalidLocaleSpec(msg)
+
+        # locales are sorted from the most probable to the least probable
+        self._locale = locales[0]
+
+        parsed_values = parse_langcode(self._locale)
+
+        # language must be specified
+        self._language = parsed_values["language"]
+
+        # try to get the other values
+        self._territory = parsed_values.get("territory", "")
+        self._encoding = parsed_values.get("codeset", "")
+        self._script = parsed_values.get("modifier", "")
+
+        # TODO: never appeared so far, needs to be parsed and stored?
+        self._variant = None
 
     @property
     def language(self):
-        return self._localedata.language
+        return self._language
 
     @property
     def territory(self):
-        return self._localedata.territory
+        return self._territory
 
     @property
     def script(self):
@@ -76,23 +122,32 @@ class LocaleInfo(object):
 
     @property
     def variant(self):
-        return self._localedata.variant
+        return self._variant
 
     @property
     def encoding(self):
         return self._encoding
 
     @property
+    def locale(self):
+        return self._locale
+
+    @property
     def english_name(self):
-        return self._localedata.english_name or u''
+        name = langtable.language_name(languageId=self.language,
+                                       territoryId=self.territory,
+                                       scriptId=self.script,
+                                       languageIdQuery="en")
+        # some languages don't start with a capital letter
+        return name.title()
 
     @property
     def display_name(self):
-        # some languages don't have a display_name
-        display_name = self._localedata.display_name or self.english_name
-        # some start with lowercase
-        display_name = display_name.title()
-        return display_name
+        name = langtable.language_name(languageId=self.language,
+                                       territoryId=self.territory,
+                                       scriptId=self.script)
+        # some languages don't start with a capital letter
+        return name.title()
 
     @property
     def short_name(self):
@@ -120,29 +175,6 @@ class LocaleInfo(object):
     def __eq__(self, other):
         return repr(self) == repr(other)
 
-def mangleLocale(inLocale):
-    mangleMap = {"af":  "af_ZA",  "am":  "am_ET",  "ar":  "ar_SA",  "as":  "as_IN",
-                 "ast": "ast_ES", "be":  "be_BY",  "bg":  "bg_BG",  "bn":  "bn_BD",
-                 "bs":  "bs_BA",  "ca":  "ca_ES",  "cs":  "cs_CZ",  "cy":  "cy_GB",
-                 "da":  "da_DK",  "de":  "de_DE",  "el":  "el_GR",  "en":  "en_US",
-                 "es":  "es_ES",  "et":  "et_EE",  "eu":  "eu_ES",  "fa":  "fa_IR",
-                 "fi":  "fi_FI",  "fr":  "fr_FR",  "gl":  "gl_ES",  "gu":  "gu_IN",
-                 "he":  "he_IL",  "hi":  "hi_IN",  "hr":  "hr_HR",  "hu":  "hu_HU",
-                 "hy":  "hy_AM",  "id":  "id_ID",  "ilo": "ilo_PH", "is":  "is_IS",
-                 "it":  "it_IT",  "ja":  "ja_JP",  "ka":  "ka_GE",  "kk":  "kk_KZ",
-                 "kn":  "kn_IN",  "ko":  "ko_KR",  "lt":  "lt_LT",  "lv":  "lv_LV",
-                 "mai": "mai_IN", "mk":  "mk_MK",  "ml":  "ml_IN",  "mr":  "mr_IN",
-                 "ms":  "ms_MY",  "nb":  "nb_NO",  "nds": "nds_DE", "ne":  "ne_NP",
-                 "nl":  "nl_NL",  "nn":  "nn_NO",  "nso": "nso_ZA", "or":  "or_IN",
-                 "pa":  "pa_IN",  "pl":  "pl_PL",  "pt":  "pt_PT",  "ro":  "ro_RO",
-                 "ru":  "ru_RU",  "si":  "si_LK",  "sk":  "sk_SK",  "sl":  "sl_SI",
-                 "sq":  "sq_AL",  "sr":  "sr_RS",  "sr at latin": "sr_Latn_RS",
-                 "sv":  "sv_SE",  "ta":  "ta_IN",  "te":  "te_IN",  "tg":  "tg_TJ",
-                 "th":  "th_TH",  "tr":  "tr_TR",  "uk":  "uk_UA",  "ur":  "ur_PK",
-                 "vi":  "vi_VN",  "zu":  "zu_ZA"}
-
-    return mangleMap.get(inLocale, inLocale)
-
 # XXX this should probably be somewhere else
 def partition(seq, func=bool, func_range=(True, False)):
     buffers = dict(((x, deque()) for x in func_range))
@@ -162,21 +194,17 @@ def get_all_locales():
     localeset = set()
     for localename in sorted(babel.localedata.list()):
         try:
-            localedata = babel.Locale.parse(localename)
-        except babel.core.UnknownLocaleError:
+            locale = LocaleInfo(localename)
+        except InvalidLocaleSpec:
             continue
 
-        # BUG: babel.Locale.parse does not parse @script
-        script = _get_locale_script(localename)
-        encoding = _get_locale_encoding(localename)
-
-        locale = LocaleInfo(localedata, encoding, script)
         if repr(locale) not in localeset:
             localeset.add(repr(locale))
             yield locale
 
 
 def get_available_translations(domain=None, localedir=None):
+    localeset = set()
     domain = domain or gettext._current_domain
     localedir = localedir or gettext._default_localedir
 
@@ -190,17 +218,13 @@ def get_available_translations(domain=None, localedir=None):
 
     for langcode in languages:
         try:
-            localedata = babel.Locale.parse(mangleLocale(langcode))
-        except babel.core.UnknownLocaleError:
+            locale = LocaleInfo(langcode)
+        except InvalidLocaleSpec:
             continue
 
-        encoding = _get_locale_encoding(langcode)
-
-        # BUG: babel.Locale.parse does not parse @script
-        script = _get_locale_script(langcode)
-
-        localeinfo = LocaleInfo(localedata, encoding, script)
-        yield localeinfo
+        if repr(locale) not in localeset:
+            localeset.add(repr(locale))
+            yield locale
 
 def parse_langcode(langcode):
     """
@@ -264,30 +288,6 @@ def expand_langs(astring):
 
     return list(langs)
 
-def _get_locale_encoding(locale):
-    """
-    If locale specification includes encoding (e.g. cs_CZ.UTF-8) returns
-    the encoding. Otherwise returns "".
-
-    """
-
-    if "@" in locale:
-        # remove @script suffix
-        locale = locale.split("@", -1)[0]
-
-    if "." in locale:
-        return locale.split(".", -1)[1]
-    else:
-        return ""
-
-def _get_locale_script(locale):
-    """Same as _get_locale_encoding but with the script."""
-
-    if "@" in locale:
-        return locale.split("@", -1)[1]
-    else:
-        return ""
-
 def write_language_configuration(lang, root):
     """
     Write language configuration to the $root/etc/locale.conf file.
@@ -300,13 +300,7 @@ def write_language_configuration(lang, root):
     try:
         fpath = os.path.normpath(root + LOCALE_CONF_FILE_PATH)
         with open(fpath, "w") as fobj:
-            # FIXME:  Remove this annoying hack once python-babel includes the
-            # right information.
-            if lang.lang == "ia":
-                fobj.write('LANG="ia_FR.UTF-8"\n')
-            else:
-                fobj.write('LANG="%s"\n' % lang.lang)
-
+            fobj.write('LANG="%s"\n' % lang.lang)
     except IOError as ioerr:
         msg = "Cannot write language configuration file: %s" % ioerr.strerror
         raise LocalizationConfigError(msg)
-- 
1.7.11.7



More information about the anaconda-patches mailing list