Commit 5b5d58c4 authored by Giovanni Campagna's avatar Giovanni Campagna Committed by Richard Hughes

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=707728Signed-off-by: Richard Hughes's avatarRichard Hughes <richard@hughsie.com>
parent 0c7596e9
......@@ -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;
......@@ -38,6 +43,31 @@ struct AppstreamApp
GDestroyNotify userdata_destroy_func;
};
/**
* 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:
*/
......@@ -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;
}
}
/**
......
......@@ -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,
......
......@@ -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 ||
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment