[gnome-software] appstream: add support for translations



commit 5b5d58c4abde7229f39246ccf3e42bb04d68bd15
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Sat Sep 7 17:02:56 2013 +0200

    appstream: add support for translations
    
    Recognize xml:lang tags in the appstream files and use them to
    provide translated names, summaries and descriptions.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=707728
    
    Signed-off-by: Richard Hughes <richard hughsie com>

 src/plugins/appstream-app.c   |   69 +++++++++++++++++++++++++++++++++++++---
 src/plugins/appstream-app.h   |    3 ++
 src/plugins/appstream-cache.c |   45 +++++++++++++++++++-------
 3 files changed, 99 insertions(+), 18 deletions(-)
---
diff --git a/src/plugins/appstream-app.c b/src/plugins/appstream-app.c
index bef5db9..fd58b88 100644
--- a/src/plugins/appstream-app.c
+++ b/src/plugins/appstream-app.c
@@ -21,6 +21,8 @@
 
 #include "config.h"
 
+#include <string.h>
+
 #include "appstream-app.h"
 
 struct AppstreamApp
@@ -28,9 +30,12 @@ struct AppstreamApp
        gchar                   *id;
        gchar                   *pkgname;
        gchar                   *name;
+       guint                    name_value;
        gchar                   *summary;
-       gchar                   *url;
+       guint                    summary_value;
        gchar                   *description;
+       guint                    description_value;
+       gchar                   *url;
        gchar                   *icon;
        AppstreamAppIconKind     icon_kind;
        GPtrArray               *appcategories;
@@ -39,6 +44,31 @@ struct AppstreamApp
 };
 
 /**
+ * appstream_app_get_locale_value:
+ *
+ * Returns a metric on how good a match the locale is, with 0 being an
+ * exact match and higher numbers meaning further away from perfect.
+ */
+static guint
+appstream_app_get_locale_value (const gchar *lang)
+{
+       const gchar * const *locales;
+       guint i;
+
+       /* shortcut as C will always match */
+       if (lang == NULL || strcmp (lang, "C") == 0)
+               return G_MAXUINT - 1;
+
+       locales = g_get_language_names ();
+       for (i = 0; locales[i] != NULL; i++) {
+               if (g_ascii_strcasecmp (locales[i], lang) == 0)
+                       return i;
+       }
+
+       return G_MAXUINT;
+}
+
+/**
  * appstream_app_free:
  */
 void
@@ -46,11 +76,11 @@ appstream_app_free (AppstreamApp *app)
 {
        g_free (app->id);
        g_free (app->pkgname);
+       g_free (app->url);
+       g_free (app->icon);
        g_free (app->name);
        g_free (app->summary);
-       g_free (app->url);
        g_free (app->description);
-       g_free (app->icon);
        g_ptr_array_unref (app->appcategories);
        if (app->userdata_destroy_func != NULL)
                app->userdata_destroy_func (app->userdata);
@@ -87,6 +117,9 @@ appstream_app_new (void)
        AppstreamApp *app;
        app = g_slice_new0 (AppstreamApp);
        app->appcategories = g_ptr_array_new_with_free_func (g_free);
+       app->name_value = G_MAXUINT;
+       app->summary_value = G_MAXUINT;
+       app->description_value = G_MAXUINT;
        app->icon_kind = APPSTREAM_APP_ICON_KIND_UNKNOWN;
        return app;
 }
@@ -207,10 +240,18 @@ appstream_app_set_pkgname (AppstreamApp *app,
  */
 void 
 appstream_app_set_name (AppstreamApp *app,
+                       const gchar *lang,
                        const gchar *name,
                        gsize length)
 {
-       app->name = g_strndup (name, length);
+       guint new_value;
+
+       new_value = appstream_app_get_locale_value (lang);
+       if (new_value < app->name_value) {
+               g_free (app->name);
+               app->name = g_strndup (name, length);
+               app->name_value = new_value;
+       }
 }
 
 /**
@@ -218,10 +259,18 @@ appstream_app_set_name (AppstreamApp *app,
  */
 void 
 appstream_app_set_summary (AppstreamApp *app,
+                          const gchar *lang,
                           const gchar *summary,
                           gsize length)
 {
-       app->summary = g_strndup (summary, length);
+       guint new_value;
+
+       new_value = appstream_app_get_locale_value (lang);
+       if (new_value < app->summary_value) {
+               g_free (app->summary);
+               app->summary = g_strndup (summary, length);
+               app->summary_value = new_value;
+       }
 }
 
 /**
@@ -240,10 +289,18 @@ appstream_app_set_url (AppstreamApp *app,
  */
 void 
 appstream_app_set_description (AppstreamApp *app,
+                              const gchar *lang,
                               const gchar *description,
                               gsize length)
 {
-       app->description = g_strndup (description, length);
+       guint new_value;
+
+       new_value = appstream_app_get_locale_value (lang);
+       if (new_value < app->description_value) {
+               g_free (app->description);
+               app->description = g_strndup (description, length);
+               app->description_value = new_value;
+       }
 }
 
 /**
diff --git a/src/plugins/appstream-app.h b/src/plugins/appstream-app.h
index f37a6a4..c963da2 100644
--- a/src/plugins/appstream-app.h
+++ b/src/plugins/appstream-app.h
@@ -56,15 +56,18 @@ void                 appstream_app_set_pkgname              (AppstreamApp   *app,
                                                         const gchar    *pkgname,
                                                         gsize           length);
 void            appstream_app_set_name                 (AppstreamApp   *app,
+                                                        const gchar    *lang,
                                                         const gchar    *name,
                                                         gsize           length);
 void            appstream_app_set_summary              (AppstreamApp   *app,
+                                                        const gchar    *lang,
                                                         const gchar    *summary,
                                                         gsize           length);
 void            appstream_app_set_url                  (AppstreamApp   *app,
                                                         const gchar    *summary,
                                                         gsize           length);
 void            appstream_app_set_description          (AppstreamApp   *app,
+                                                        const gchar    *lang,
                                                         const gchar    *description,
                                                         gsize           length);
 void            appstream_app_set_icon                 (AppstreamApp   *app,
diff --git a/src/plugins/appstream-cache.c b/src/plugins/appstream-cache.c
index 97a282b..baa6f5a 100644
--- a/src/plugins/appstream-cache.c
+++ b/src/plugins/appstream-cache.c
@@ -184,6 +184,7 @@ appstream_cache_icon_kind_from_string (const gchar *kind_str)
 typedef struct {
        const gchar             *path_icons;
        AppstreamApp            *item_temp;
+       char                    *lang_temp;
        AppstreamCache          *cache;
        AppstreamCacheSection    section;
 } AppstreamCacheHelper;
@@ -246,9 +247,21 @@ appstream_cache_start_element_cb (GMarkupParseContext *context,
                break;
        case APPSTREAM_CACHE_SECTION_ID:
        case APPSTREAM_CACHE_SECTION_PKGNAME:
+       case APPSTREAM_CACHE_SECTION_URL:
+               if (helper->item_temp == NULL ||
+                   helper->section != APPSTREAM_CACHE_SECTION_APPLICATION) {
+                       g_set_error (error,
+                                    APPSTREAM_CACHE_ERROR,
+                                    APPSTREAM_CACHE_ERROR_FAILED,
+                                    "XML start %s invalid, section %s",
+                                    element_name,
+                                    appstream_cache_selection_to_string (helper->section));
+                       return;
+               }
+               break;
+
        case APPSTREAM_CACHE_SECTION_NAME:
        case APPSTREAM_CACHE_SECTION_SUMMARY:
-       case APPSTREAM_CACHE_SECTION_URL:
        case APPSTREAM_CACHE_SECTION_DESCRIPTION:
                if (helper->item_temp == NULL ||
                    helper->section != APPSTREAM_CACHE_SECTION_APPLICATION) {
@@ -260,6 +273,13 @@ appstream_cache_start_element_cb (GMarkupParseContext *context,
                                     appstream_cache_selection_to_string (helper->section));
                        return;
                }
+               if (!g_markup_collect_attributes (element_name, attribute_names, attribute_values, error,
+                                                 G_MARKUP_COLLECT_STRDUP | G_MARKUP_COLLECT_OPTIONAL,
+                                                 "xml:lang", &helper->lang_temp,
+                                                 G_MARKUP_COLLECT_INVALID))
+                       return;
+               if (!helper->lang_temp)
+                       helper->lang_temp = g_strdup ("C");
                break;
        default:
                /* ignore unknown entries */
@@ -314,12 +334,16 @@ appstream_cache_end_element_cb (GMarkupParseContext *context,
        case APPSTREAM_CACHE_SECTION_ID:
        case APPSTREAM_CACHE_SECTION_PKGNAME:
        case APPSTREAM_CACHE_SECTION_APPCATEGORIES:
-       case APPSTREAM_CACHE_SECTION_NAME:
+       case APPSTREAM_CACHE_SECTION_URL:
        case APPSTREAM_CACHE_SECTION_ICON:
+               helper->section = APPSTREAM_CACHE_SECTION_APPLICATION;
+               break;
+       case APPSTREAM_CACHE_SECTION_NAME:
        case APPSTREAM_CACHE_SECTION_SUMMARY:
-       case APPSTREAM_CACHE_SECTION_URL:
        case APPSTREAM_CACHE_SECTION_DESCRIPTION:
                helper->section = APPSTREAM_CACHE_SECTION_APPLICATION;
+               g_free (helper->lang_temp);
+               helper->lang_temp = NULL;
                break;
        default:
                /* ignore unknown entries */
@@ -387,26 +411,24 @@ appstream_cache_text_cb (GMarkupParseContext *context,
                appstream_app_set_pkgname (helper->item_temp, text, text_len);
                break;
        case APPSTREAM_CACHE_SECTION_NAME:
-               if (helper->item_temp == NULL ||
-                   appstream_app_get_name (helper->item_temp) != NULL) {
+               if (helper->item_temp == NULL) {
                        g_set_error_literal (error,
                                             APPSTREAM_CACHE_ERROR,
                                             APPSTREAM_CACHE_ERROR_FAILED,
                                             "item_temp name invalid");
                        return;
                }
-               appstream_app_set_name (helper->item_temp, text, text_len);
+               appstream_app_set_name (helper->item_temp, helper->lang_temp, text, text_len);
                break;
        case APPSTREAM_CACHE_SECTION_SUMMARY:
-               if (helper->item_temp == NULL ||
-                   appstream_app_get_summary (helper->item_temp) != NULL) {
+               if (helper->item_temp == NULL) {
                        g_set_error_literal (error,
                                             APPSTREAM_CACHE_ERROR,
                                             APPSTREAM_CACHE_ERROR_FAILED,
                                             "item_temp summary invalid");
                        return;
                }
-               appstream_app_set_summary (helper->item_temp, text, text_len);
+               appstream_app_set_summary (helper->item_temp, helper->lang_temp, text, text_len);
                break;
        case APPSTREAM_CACHE_SECTION_URL:
                if (helper->item_temp == NULL ||
@@ -420,15 +442,14 @@ appstream_cache_text_cb (GMarkupParseContext *context,
                appstream_app_set_url (helper->item_temp, text, text_len);
                break;
        case APPSTREAM_CACHE_SECTION_DESCRIPTION:
-               if (helper->item_temp == NULL ||
-                   appstream_app_get_description (helper->item_temp) != NULL) {
+               if (helper->item_temp == NULL) {
                        g_set_error_literal (error,
                                             APPSTREAM_CACHE_ERROR,
                                             APPSTREAM_CACHE_ERROR_FAILED,
                                             "item_temp description invalid");
                        return;
                }
-               appstream_app_set_description (helper->item_temp, text, text_len);
+               appstream_app_set_description (helper->item_temp, helper->lang_temp, text, text_len);
                break;
        case APPSTREAM_CACHE_SECTION_ICON:
                if (helper->item_temp == NULL ||


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]