Better i18n support in GtkBuilder

Let descriptions of accessible actions be translated, by specifying
the description as content of the <action> element, and allowing
"translatable", "context" and "comment" as attributes. (#518642)
This commit is contained in:
Matthias Clasen 2009-04-06 12:12:08 -04:00
parent c338228a86
commit 1ad8bfb69a
3 changed files with 107 additions and 53 deletions

View File

@ -49,7 +49,7 @@ internal child "accessible" of a <structname>GtkWidget</structname>.
</object>
<object class="GtkButton" id="button1">
<accessibility>
<action action_name="click" description="Click the button."/>
<action action_name="click" translatable="yes">Click the button.</action>
<relation target="label1" type="labelled-by"/>
</accessibility>
<child internal-child="accessible">

View File

@ -9466,12 +9466,16 @@ gtk_widget_buildable_set_buildable_property (GtkBuildable *buildable,
g_object_set_property (G_OBJECT (buildable), name, value);
}
typedef struct {
typedef struct
{
gchar *action_name;
gchar *description;
GString *description;
gchar *context;
gboolean translatable;
} AtkActionData;
typedef struct {
typedef struct
{
gchar *target;
gchar *type;
} AtkRelationData;
@ -9480,7 +9484,8 @@ static void
free_action (AtkActionData *data, gpointer user_data)
{
g_free (data->action_name);
g_free (data->description);
g_string_free (data->description, TRUE);
g_free (data->context);
g_slice_free (AtkActionData, data);
}
@ -9548,10 +9553,10 @@ gtk_widget_buildable_parser_finished (GtkBuildable *buildable,
g_object_set_qdata (G_OBJECT (buildable), quark_builder_atk_relations,
NULL);
}
}
typedef struct {
typedef struct
{
GSList *actions;
GSList *relations;
} AccessibilitySubParserData;
@ -9624,14 +9629,27 @@ accessibility_start_element (GMarkupParseContext *context,
{
gchar *action_name = NULL;
gchar *description = NULL;
gchar *context = NULL;
gboolean translatable = FALSE;
AtkActionData *action;
for (i = 0; names[i]; i++)
{
if (strcmp (names[i], "action_name") == 0)
action_name = g_strdup (values[i]);
action_name = values[i];
else if (strcmp (names[i], "description") == 0)
description = g_strdup (values[i]);
description = values[i];
else if (strcmp (names[i], "translatable") == 0)
{
if (!_gtk_builder_boolean_from_string (values[i], &translatable, error))
return;
}
else if (strcmp (names[i], "comments") == 0)
{
/* do nothing, comments are for translators */
}
else if (strcmp (names[i], "context") == 0)
context = values[i];
else
{
g_markup_parse_context_get_position (context,
@ -9643,13 +9661,11 @@ accessibility_start_element (GMarkupParseContext *context,
"%s:%d:%d '%s' is not a valid attribute of <%s>",
"<input>",
line_number, char_number, names[i], "action");
g_free (action_name);
g_free (description);
return;
}
}
if (!action_name || !description)
if (!action_name)
{
g_markup_parse_context_get_position (context,
&line_number,
@ -9660,15 +9676,15 @@ accessibility_start_element (GMarkupParseContext *context,
"%s:%d:%d <%s> requires attribute \"%s\"",
"<input>",
line_number, char_number, "action",
description ? "action_name" : "description");
g_free (action_name);
g_free (description);
"action_name");
return;
}
action = g_slice_new (AtkActionData);
action->action_name = action_name;
action->description = description;
action->action_name = g_strdup (action_name);
action->description = g_string_new (description);
action->context = g_strdup (context);
action->translatable = translatable;
data->actions = g_slist_prepend (data->actions, action);
}
@ -9678,12 +9694,32 @@ accessibility_start_element (GMarkupParseContext *context,
g_warning ("Unsupported tag for GtkWidget: %s\n", element_name);
}
static void
accessibility_text (GMarkupParseContext *context,
const gchar *text,
gsize text_len,
gpointer user_data,
GError **error)
{
AccessibilitySubParserData *data = (AccessibilitySubParserData*)user_data;
if (strcmp (g_markup_parse_context_get_element (context), "action") == 0)
{
AtkActionData *action = data->actions->data;
g_string_append_len (action->description, text, text_len);
}
}
static const GMarkupParser accessibility_parser =
{
accessibility_start_element,
NULL,
accessibility_text,
};
typedef struct {
typedef struct
{
GObject *object;
guint key;
guint modifiers;
@ -9833,8 +9869,18 @@ gtk_widget_buildable_custom_finished (GtkBuildable *buildable,
break;
if (i < n_actions)
atk_action_set_description (action, i,
action_data->description);
{
gchar *description;
if (action_data->translatable && action_data->description->len)
description = _gtk_builder_parser_translate (gtk_builder_get_translation_domain (builder),
action_data->context,
action_data->description->str);
else
description = action_data->description->str;
atk_action_set_description (action, i, description);
}
}
g_slist_foreach (a11y_data->actions, (GFunc)free_action, NULL);
@ -9846,7 +9892,6 @@ gtk_widget_buildable_custom_finished (GtkBuildable *buildable,
a11y_data->relations);
g_slice_free (AccessibilitySubParserData, a11y_data);
}
}

View File

@ -44,10 +44,18 @@ builder_new_from_string (const gchar *buffer,
const gchar *domain)
{
GtkBuilder *builder;
GError *error = NULL;
builder = gtk_builder_new ();
if (domain)
gtk_builder_set_translation_domain (builder, domain);
gtk_builder_add_from_string (builder, buffer, length, NULL);
gtk_builder_add_from_string (builder, buffer, length, &error);
if (error)
{
g_print ("ERROR: %s", error->message);
g_error_free (error);
}
return builder;
}
@ -1580,6 +1588,7 @@ test_widget (void)
" <object class=\"GtkButton\" id=\"button1\">"
" <accessibility>"
" <action action_name=\"click\" description=\"Sliff\"/>"
" <action action_name=\"clack\" translatable=\"yes\">Sniff</action>"
" </accessibility>"
" </object>"
" </child>"