[rhel7-branch][PATCH] Make layout and switching options description translated (#1015209)

Vratislav Podzimek vpodzime at redhat.com
Wed Jan 8 16:22:17 UTC 2014


We have the translations of layout and switching options available we just need
to use them in the GUI.

(ported and squashed commits from the master branch)

Signed-off-by: Vratislav Podzimek <vpodzime at redhat.com>
---
 pyanaconda/iutil.py                  |  21 +++++
 pyanaconda/keyboard.py               | 160 ++++++++++++-----------------------
 pyanaconda/localization.py           |  27 +-----
 pyanaconda/ui/gui/spokes/keyboard.py |  18 ++--
 4 files changed, 87 insertions(+), 139 deletions(-)

diff --git a/pyanaconda/iutil.py b/pyanaconda/iutil.py
index 7e6496f..fcacb94 100644
--- a/pyanaconda/iutil.py
+++ b/pyanaconda/iutil.py
@@ -722,3 +722,24 @@ def is_unsupported_hw():
     if status:
         log.debug("Installing on Unsupported Hardware")
     return status
+
+def upcase_first_letter(text):
+    """
+    Helper function that upcases the first letter of the string. Python's
+    standard string.capitalize() not only upcases the first letter but also
+    lowercases all the others. string.title() capitalizes all words in the
+    string.
+
+    :type text: either a str or unicode object
+    :return: the given text with the first letter upcased
+    :rtype: str or unicode (depends on the input)
+
+    """
+
+    if not text:
+        # cannot change anything
+        return text
+    elif len(text) == 1:
+        return text.upper()
+    else:
+        return text[0].upper() + text[1:]
diff --git a/pyanaconda/keyboard.py b/pyanaconda/keyboard.py
index c8e1924..46c1a4d 100755
--- a/pyanaconda/keyboard.py
+++ b/pyanaconda/keyboard.py
@@ -36,6 +36,10 @@ import types
 import os
 import re
 import shutil
+import ctypes
+import gettext
+
+from collections import namedtuple
 
 from pyanaconda import iutil
 from pyanaconda import flags
@@ -59,6 +63,12 @@ LAYOUT_VARIANT_RE = re.compile(r'^\s*(\w+)\s*' # layout plus
                                r'(?:(?:\(\s*([-\w]+)\s*\))' # variant in parentheses
                                r'|(?:$))\s*') # or nothing
 
+# namedtuple for information about a keyboard layout (its language and description)
+LayoutInfo = namedtuple("LayoutInfo", ["lang", "desc"])
+
+Xkb_ = lambda x: gettext.ldgettext("xkeyboard-config", x)
+iso_ = lambda x: gettext.ldgettext("iso_639", x)
+
 class KeyboardConfigError(Exception):
     """Exception class for keyboard configuration related problems"""
 
@@ -351,28 +361,10 @@ def item_str(s):
     elif type(s) == types.ListType:
         # XXX: this is the wrong case that should be fixed (rhbz#920595)
         i = s.index(0)
-        s = "".join(chr(char) for char in s[:i] if char in xrange(256))
+        s = "".join(chr(ctypes.c_uint8(char).value) for char in s[:i])
 
     return s.decode("utf-8") #there are some non-ascii layout descriptions
 
-class _Layout(object):
-    """Internal class representing a single layout variant"""
-
-    def __init__(self, name, desc):
-        self.name = name
-        self.desc = desc
-
-    def __str__(self):
-        return '%s (%s)' % (self.name, self.desc)
-
-    def __eq__(self, obj):
-        return isinstance(obj, self.__class__) and \
-            self.name == obj.name
-
-    @property
-    def description(self):
-        return self.desc
-
 class XklWrapperError(KeyboardConfigError):
     """Exception class for reporting libxklavier-related problems"""
 
@@ -436,16 +428,8 @@ class XklWrapper(object):
         self.configreg = Xkl.ConfigRegistry.get_instance(self._engine)
         self.configreg.load(False)
 
-        self._language_keyboard_variants = dict()
-        self._country_keyboard_variants = dict()
-        self._switching_options = list()
-
-        #we want to display layouts as 'language (description)'
-        self.name_to_show_str = dict()
-
-        #we want to display layout switching options as e.g. "Alt + Shift" not
-        #as "grp:alt_shift_toggle"
-        self.switch_to_show_str = dict()
+        self._layout_infos = dict()
+        self._switch_opt_infos = dict()
 
         #this might take quite a long time
         self.configreg.foreach_language(self._get_language_variants, None)
@@ -464,14 +448,9 @@ class XklWrapper(object):
 
         #if this layout has already been added for some other language,
         #do not add it again (would result in duplicates in our lists)
-        if name not in self.name_to_show_str:
-            if lang and not description.startswith(lang):
-                self.name_to_show_str[name] = "%s (%s)" % (lang.encode("utf-8"),
-                                                    description.encode("utf-8"))
-            else:
-                self.name_to_show_str[name] = "%s" % description.encode("utf-8")
-
-            self._variants_list.append(_Layout(name, description))
+        if name not in self._layout_infos:
+            self._layout_infos[name] = LayoutInfo(lang.encode("utf-8"),
+                                                  description.encode("utf-8"))
 
     def _get_country_variant(self, c_reg, item, subitem, country):
         if subitem:
@@ -482,109 +461,76 @@ class XklWrapper(object):
             description = item_str(item.description)
 
         # if the layout was not added with any language, add it with a country
-        if name not in self.name_to_show_str:
-            if country:
-                self.name_to_show_str[name] = "%s (%s)" % (country.encode("utf-8"),
-                                                    description.encode("utf-8"))
-            else:
-                self.name_to_show_str[name] = "%s" % description.encode("utf-8")
-
-        self._variants_list.append(_Layout(name, description))
+        if name not in self._layout_infos:
+            self._layout_infos[name] = LayoutInfo(country.encode("utf-8"),
+                                                  description.encode("utf-8"))
 
     def _get_language_variants(self, c_reg, item, user_data=None):
-        #helper "global" variable
-        self._variants_list = list()
         lang_name, lang_desc = item_str(item.name), item_str(item.description)
 
         c_reg.foreach_language_variant(lang_name, self._get_lang_variant, lang_desc)
 
-        self._language_keyboard_variants[lang_desc] = self._variants_list
-
     def _get_country_variants(self, c_reg, item, user_data=None):
-        #helper "global" variable
-        self._variants_list = list()
         country_name, country_desc = item_str(item.name), item_str(item.description)
 
         c_reg.foreach_country_variant(country_name, self._get_country_variant,
                                       country_desc)
 
-        self._country_keyboard_variants[country_name] = self._variants_list
-
     def _get_switch_option(self, c_reg, item, user_data=None):
         """Helper function storing layout switching options in foreach cycle"""
         desc = item_str(item.description)
         name = item_str(item.name)
 
-        self._switching_options.append(name)
-        self.switch_to_show_str[name] = desc.encode("utf-8")
+        self._switch_opt_infos[name] = desc.encode("utf-8")
+
 
     def get_available_layouts(self):
         """A generator yielding layouts (no need to store them as a bunch)"""
 
-        return self.name_to_show_str.iterkeys()
+        return self._layout_infos.iterkeys()
 
     def get_switching_options(self):
         """Method returning list of available layout switching options"""
 
-        return self._switching_options
-
-    def get_default_language_layout(self, language):
-        """Get the default layout for a given language."""
-
-        layouts = self.get_language_layouts(language)
-        if layouts:
-            #first layout (should exist for every language)
-            return layouts[0].name
-        else:
-            return None
-
-    def get_language_layouts(self, language):
-        """Get layouts for a given language."""
-
-        language_layouts = self._language_keyboard_variants.get(language, None)
-
-        if language_layouts:
-            return language_layouts
+        return self._switch_opt_infos.iterkeys()
 
-        #else try some magic and if everything fails, return None
-        for (lang, layouts) in self._language_keyboard_variants.iteritems():
-            #XXX: some languages are returned in a weird form from the
-            #     libxklavier iterations (e.g. "Greek, Modern (1453-)")
-            if lang.startswith(language):
-                return layouts
-
-        return None
-
-    def get_default_lang_country_layout(self, language, country):
+    def get_layout_variant_description(self, layout_variant, with_lang=True):
         """
-        Get default layout matching both language and country. If none such
-        layout is found, get default layout for language. If no layout for
-        the given language is found but there is layout for the given country,
-        return the one for the country.
+        Get description of the given layout-variant.
+
+        :param layout_variant: layout-variant specification (e.g. 'cz (qwerty)')
+        :type layout_variant: str
+        :param with_lang: whether to include language of the layout-variant (if defined)
+                          in the description or not
+        :type with_lang: bool
+        :return: description of the layout-variant specification (e.g. 'Czech (qwerty)')
+        :rtype: str
 
         """
 
-        language_layouts = self.get_language_layouts(language)
-        country_layouts = self._country_keyboard_variants.get(country, None)
-        if not language_layouts and not country_layouts:
-            return None
+        layout_info = self._layout_infos[layout_variant]
+        if with_lang and layout_info.lang:
+            # translate language and upcase its first letter, translate the
+            # layout-variant description
+            xlated_lang = iso_(layout_info.lang)
+            return "%s (%s)" % (iutil.upcase_first_letter(xlated_lang.decode("utf-8")),
+                                Xkb_(layout_info.desc).decode("utf-8"))
+        else:
+            return layout_info.desc
 
-        if not country_layouts:
-            return language_layouts[0].name
+    def get_switch_opt_description(self, switch_opt):
+        """
+        Get description of the given layout switching option.
 
-        if not language_layouts:
-            return country_layouts[0].name
+        :param switch_opt: switching option name/ID (e.g. 'grp:alt_shift_toggle')
+        :type switch_opt: str
+        :return: description of the layout switching option (e.g. 'Alt + Shift')
+        :rtype: str
 
-        matches_both = (layout for layout in language_layouts
-                                if layout in country_layouts)
+        """
 
-        try:
-            return matches_both.next().name
-        except StopIteration:
-            if country_layouts:
-                return country_layouts[0].name
-            else:
-                return language_layouts[0].name
+        # translate the description of the switching option
+        return Xkb_(self._switch_opt_infos[switch_opt])
 
     def activate_default_layout(self):
         """
@@ -598,7 +544,7 @@ class XklWrapper(object):
     def is_valid_layout(self, layout):
         """Return if given layout is valid layout or not"""
 
-        return layout in self.name_to_show_str
+        return layout in self._layout_infos
 
     def add_layout(self, layout):
         """
diff --git a/pyanaconda/localization.py b/pyanaconda/localization.py
index 191e1a9..b13e047 100644
--- a/pyanaconda/localization.py
+++ b/pyanaconda/localization.py
@@ -26,6 +26,8 @@ import re
 import langtable
 import glob
 
+from pyanaconda.iutil import upcase_first_letter
+
 import logging
 log = logging.getLogger("anaconda")
 
@@ -47,27 +49,6 @@ class InvalidLocaleSpec(LocalizationConfigError):
 
     pass
 
-def _upcase_first_letter(string):
-    """
-    Helper function that upcases the first letter of the string. Python's
-    standard string.capitalize() not only upcases the first letter but also
-    lowercases all the others. string.title() capitalizes all words in the
-    string.
-
-    :type string: either a str or unicode object
-    :return: the given string with the first letter upcased
-    :rtype: str or unicode (depends on the input)
-
-    """
-
-    if not string:
-        # cannot change anything
-        return string
-    elif len(string) == 1:
-        return string.upper()
-    else:
-        return string[0].upper() + string[1:]
-
 def parse_langcode(langcode):
     """
     For a given langcode (e.g. 'SR_RS.UTF-8 at latin') returns a dictionary
@@ -237,7 +218,7 @@ def get_english_name(locale):
                                    scriptId=parts.get("script", ""),
                                    languageIdQuery="en")
 
-    return _upcase_first_letter(name)
+    return upcase_first_letter(name)
 
 def get_native_name(locale):
     """
@@ -261,7 +242,7 @@ def get_native_name(locale):
                                    languageIdQuery=parts["language"],
                                    scriptIdQuery=parts.get("script", ""))
 
-    return _upcase_first_letter(name)
+    return upcase_first_letter(name)
 
 def get_available_translations(localedir=None):
     """
diff --git a/pyanaconda/ui/gui/spokes/keyboard.py b/pyanaconda/ui/gui/spokes/keyboard.py
index 7ba4cdf..3b76a50 100644
--- a/pyanaconda/ui/gui/spokes/keyboard.py
+++ b/pyanaconda/ui/gui/spokes/keyboard.py
@@ -40,11 +40,11 @@ __all__ = ["KeyboardSpoke"]
 LAYOUT_SWITCHING_INFO = N_("%s to switch layouts.")
 
 def _show_layout(column, renderer, model, itr, wrapper):
-    value = wrapper.name_to_show_str[model[itr][0]]
+    value = wrapper.get_layout_variant_description(model[itr][0])
     renderer.set_property("text", value)
 
 def _show_description(column, renderer, model, itr, wrapper):
-    value = wrapper.switch_to_show_str[model[itr][0]]
+    value = wrapper.get_switch_opt_description(model[itr][0])
     if model[itr][1]:
         value = "<b>%s</b>" % value
     renderer.set_property("markup", value)
@@ -61,7 +61,7 @@ class AddLayoutDialog(GUIObject):
 
     def matches_entry(self, model, itr, user_data=None):
         value = model[itr][0]
-        value = self._xkl_wrapper.name_to_show_str[value]
+        value = self._xkl_wrapper.get_layout_variant_description(value)
         entry_text = self._entry.get_text()
         if entry_text is not None:
             entry_text = entry_text.lower()
@@ -87,8 +87,8 @@ class AddLayoutDialog(GUIObject):
 
         value1 = model[itr1][0]
         value2 = model[itr2][0]
-        show_str1 = self._xkl_wrapper.name_to_show_str[value1]
-        show_str2 = self._xkl_wrapper.name_to_show_str[value2]
+        show_str1 = self._xkl_wrapper.get_layout_variant_description(value1)
+        show_str2 = self._xkl_wrapper.get_layout_variant_description(value2)
 
         if show_str1 < show_str2:
             return -1
@@ -223,8 +223,8 @@ class ConfigureSwitchingDialog(GUIObject):
 
         value1 = model[itr1][0]
         value2 = model[itr2][0]
-        show_str1 = self._xkl_wrapper.switch_to_show_str[value1]
-        show_str2 = self._xkl_wrapper.switch_to_show_str[value2]
+        show_str1 = self._xkl_wrapper.get_switch_opt_description(value1)
+        show_str2 = self._xkl_wrapper.get_switch_opt_description(value2)
 
         if show_str1 < show_str2:
             return -1
@@ -285,7 +285,7 @@ class KeyboardSpoke(NormalSpoke):
     @property
     def status(self):
         # We don't need to check that self._store is empty, because that isn't allowed.
-        descriptions = (self._xkl_wrapper.name_to_show_str[row[0]]
+        descriptions = (self._xkl_wrapper.get_layout_variant_description(row[0])
                         for row in self._store)
         return ", ".join(descriptions)
 
@@ -374,7 +374,7 @@ class KeyboardSpoke(NormalSpoke):
     def _refresh_switching_info(self):
         if self.data.keyboard.switch_options:
             first_option = self.data.keyboard.switch_options[0]
-            desc = self._xkl_wrapper.switch_to_show_str[first_option]
+            desc = self._xkl_wrapper.get_switch_opt_description(first_option)
 
             self._layoutSwitchLabel.set_text(_(LAYOUT_SWITCHING_INFO) % desc)
         else:
-- 
1.8.4.2



More information about the anaconda-patches mailing list