GNOME Bugzilla – Bug 397742
Shouldn't use xdg.DesktopEntry for launcher names
Last modified: 2009-08-30 12:31:46 UTC
In sabayon/lib/sources/paneldelegate.py we use the python-xdg module for xdg.DesktopEntry. Not all distributions carry python-xdg yet. We should simply be able to use GKeyFile, load the .desktop file directly, and get the "Name" key out of it (or its localized version, of course).
I'm not sure whether there is any binding for GKeyFile in Python. However, the following code snippet seems to work in my own system, though I think it needs to be slightly more robust (what if the entry is the form "Name = blahApp" or something like that. f = open(desktop_file) for line in f: if line[:5] == "Name=": appname = line[5:]
You're right, that code is not robust, it's also awkward (counting the number of characters). Regular expressions are much more elegant and robust. Example: key_value_re = re.compile("(\w+)\s*=\s*(\S+)") try: f = open(desktop_file) except IOError, e: # return something meaningful for line in f.readlines(): match = key_value_re.search(line) if match: key = match.group(1) value = match.group(2) if key == 'Name': appname = value You may have to adjust your regular expression for what you expect to parse, but with regexp's you won't be confused by white space formatting, illegal formatting, etc. I'm not sure if the file format allows comments or not but if so you should probably also strip out comments first, something like this (assuming comments are #): comment_re = re.compile('#.*') for line in f.readlines(): line = comment_re.sub('', line) line = line.strip() if line:
Hmmm - regular expressions are definitely the way to go. However, I looked at how Alacarte does the parsing - and it uses the ConfigParser module built into Python (arrggh!! should have thought of this earlier). The following code snippet seems to work - will come up with a patch by tonight (IST). from ConfigParser import ConfigParser c = ConfigParser() c.read(['/usr/share/applications/gedit.desktop']) appname = c.get('Desktop Entry', 'name') ConfigParser probably uses regexp internally.
Created attachment 80567 [details] [review] Alternative approach using ConfigParser ConfigParser should be available in all recent versions of Python.
Comment on attachment 80567 [details] [review] Alternative approach using ConfigParser Thanks! One thing I noticed - doing name_from_desktop_file + " launcher" is not very i18n-friendly. It should be something like "%s launcher" % name instead. Also, is it possible to extract the localized name from the desktop file instead of the English one?
Marking as blocker for the 2.18 release, since this keeps Sabayon from running on distros.
Created attachment 81737 [details] [review] Update of previous patch, with l10n issues properly handled. This should work. I did not use the getdefaultlocale() method of the locale module in Python for getting the locale, since I get the following error when I used bn_IN In [1]: import locale In [2]: locale.getdefaultlocale() --------------------------------------------------------------------------- exceptions.ValueError Traceback (most recent call last) /home/sayamindu/Development/sabayon/lib/sources/<ipython console> /home/sayamindu/Development/sabayon/lib/sources/locale.py in getdefaultlocale(envvars) 344 else: 345 localename = 'C' --> 346 return _parse_localename(localename) 347 348 /home/sayamindu/Development/sabayon/lib/sources/locale.py in _parse_localename(localename) 276 elif code == 'C': 277 return None, None --> 278 raise ValueError, 'unknown locale: %s' % localename 279 280 def _build_localename(localetuple): ValueError: unknown locale: bn_IN
Comment on attachment 81737 [details] [review] Update of previous patch, with l10n issues properly handled. Which distribution are you using? Python doesn't throw an exception for me with locale.getdefaultlocale() if I use LANG=bn_IN.UTF-8. Using ConfigParser is fine, but we need to support fallbacks for key files which don't have all the locales in them. For example, the translation for "bn" may be suitable if one for a more explicit "bn_IN" is not found. You can steal this logic from g_key_file_get_locale_string(). It calls g_get_language_names() to find all the possibilities for the current language. I'm not sure if the pygtk bindings expose that function; you may need to port that code from glib/gutils.c to Python.
L10n issue has been resolved in bug #402089 before string freeze. Please update your patch, and sorry for interruption.
I'm using Ubuntu 6.10. Looking into g_key_file_get_locale_string() and g_get_language_names()....
Created attachment 83054 [details] [review] updated patch This version first tries language_territory for the launcher name, then tries language, and if unsuccessful, falls back to the default name.
Comment on attachment 83054 [details] [review] updated patch But this is not robust at all. Read the code for g_get_language_names() (in glib/glib/gutils.c) and its helper function, guess_category_value(). You have to use a series of fallbacks: - LANGUAGE - LC_ALL - LC_MESSAGES (as passed to guess_category_value()) - LANG Also, each of those may contain multiple fallbacks in turn, like LC_MESSAGES=es_MX.UTF-8:en_GB.UTF-8 which means, "use Mexican Spanish if available, otherwise try British English if available".
For 2.18.0, I think we should just keep the existing _("%s launcher") string and print the .desktop file name: calculator.desktop launcher instead of the nicer name Calculator launcher We can fix this correctly after 2.18.0.
Created attachment 84444 [details] [review] sabayon-397742-temporary-fix.diff
Created attachment 84676 [details] [review] Patch based on port of g_get_language_names() Ok - here's a patch based on the function at http://sayamindu.randomink.org/misc/get_language_names2.pytxt. I compared its output with http://sayamindu.randomink.org/misc/test_get_language_names.c (which uses the g_get_language_names() from glib) and the outputs match. The patch is against the gnome-2-18 branch.
Created attachment 84724 [details] [review] More robust version of the previous patch Based on our IRC discussion yesterday, I'm attaching a new patch. The only difference between this one's output and that of g_get_language_names is in case of situations where LANGUAGE looks like "en_US:en". In this case the python function returns en_US en C while g_get_language_names() returns en_US en en C ..in simpler words, the list returned by the python function does not have any duplicate entries :-).
(In reply to comment #0) > In sabayon/lib/sources/paneldelegate.py we use the python-xdg module for > xdg.DesktopEntry. Not all distributions carry python-xdg yet. > doh.. I'm so stupid. Federico - could you see if your distribution has the gnomedesktop module installed (import gnomedesktop). In that case, extracting the name becomes as simple as: import gnomedesktop item = gnomedesktop.item_new_from_file(filename, gnomedesktop.LOAD_ONLY_IF_EXISTS) name = item.get_localestring(gnomedesktop.KEY_NAME) I feel like kicking myself :-(
These days Sabayon actually checks for python-xdg at configure time, so I'll close this bug.