diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index c75f694516..b0ecaef914 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -1120,6 +1120,13 @@ COMPOSITE_TEMPLATES = \
gtkstatusbar.ui \
gtkvolumebutton.ui
+template_headers = $(COMPOSITE_TEMPLATES:.ui=.ui.h)
+
+MAINTAINERCLEANFILES += $(template_headers)
+
+%.ui.h: %.ui extract-strings
+ $(AM_V_GEN) ./extract-strings $< > $@
+
#
# rules to generate built sources
#
@@ -1164,7 +1171,7 @@ gtktypebuiltins.c: @REBUILD@ $(gtk_public_h_sources) $(deprecated_h_sources) gtk
gtkresources.h: gtk.gresource.xml
$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) $(srcdir)/gtk.gresource.xml \
--target=$@ --sourcedir=$(srcdir) --c-name _gtk --generate-header --manual-register
-gtkresources.c: gtk.gresource.xml gtk-default.css gtk-win32.css gtk-win32-xp.css gtk-win32-base.css gtk-win32-classic.css $(DND_CURSORS) $(COMPOSITE_TEMPLATES)
+gtkresources.c: gtk.gresource.xml gtk-default.css gtk-win32.css gtk-win32-xp.css gtk-win32-base.css gtk-win32-classic.css $(DND_CURSORS) $(COMPOSITE_TEMPLATES) $(template_headers)
$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) $(srcdir)/gtk.gresource.xml \
--target=$@ --sourcedir=$(srcdir) --c-name _gtk --generate-source --manual-register
@@ -1390,6 +1397,11 @@ gtk_launch_LDADD = $(LDADDS)
gtk_launch_SOURCES = gtk-launch.c
endif
+noinst_PROGRAMS = extract-strings
+
+extract_strings_SOURCES = extract-strings.c
+extract_strings_LDADD = $(GLIB_LIBS)
+
.PHONY: files test test-debug
files:
diff --git a/gtk/extract-strings.c b/gtk/extract-strings.c
new file mode 100644
index 0000000000..613e73838c
--- /dev/null
+++ b/gtk/extract-strings.c
@@ -0,0 +1,159 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2013 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ */
+
+#include
+
+typedef struct {
+ GString *output;
+ gboolean translatable;
+ gchar *context;
+ gchar *comments;
+ GString *text;
+} ParserData;
+
+static void
+start_element_handler (GMarkupParseContext *contexts,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ gpointer user_data,
+ GError **error)
+{
+ ParserData *data = user_data;
+
+ if (g_str_equal (element_name, "property"))
+ {
+ gboolean translatable;
+ gchar *context;
+ gchar *comments;
+
+ g_markup_collect_attributes (element_name,
+ attribute_names,
+ attribute_values,
+ error,
+ G_MARKUP_COLLECT_STRING, "name", NULL,
+ G_MARKUP_COLLECT_TRISTATE, "translatable", &translatable,
+ G_MARKUP_COLLECT_STRDUP|G_MARKUP_COLLECT_OPTIONAL, "context", &context,
+ G_MARKUP_COLLECT_STRDUP|G_MARKUP_COLLECT_OPTIONAL, "comments", &comments,
+ G_MARKUP_COLLECT_INVALID);
+
+ if (translatable == TRUE)
+ {
+ data->translatable = TRUE;
+ data->context = context;
+ data->comments = comments;
+ data->text = g_string_new ("");
+ }
+ }
+}
+
+static void
+end_element_handler (GMarkupParseContext *context,
+ const gchar *element_name,
+ gpointer user_data,
+ GError **error)
+{
+ ParserData *data = user_data;
+
+ if (!data->translatable)
+ return;
+
+ if (data->comments)
+ g_string_append_printf (data->output, "\n/* %s */\n",
+ data->comments);
+
+ if (data->context)
+ g_string_append_printf (data->output, "C_(\"%s\", \"%s\")\n",
+ data->context,
+ data->text->str);
+ else
+ g_string_append_printf (data->output, "N_(\"%s\")\n",
+ data->text->str);
+
+ g_free (data->comments);
+ g_free (data->context);
+ g_string_free (data->text, TRUE);
+
+ data->comments = NULL;
+ data->context = NULL;
+ data->text = NULL;
+ data->translatable = FALSE;
+}
+
+static void
+text_handler (GMarkupParseContext *context,
+ const gchar *text,
+ gsize text_len,
+ gpointer user_data,
+ GError **error)
+{
+ ParserData *data = user_data;
+
+ if (!data->translatable)
+ return;
+
+ g_string_append_len (data->text, text, text_len);
+}
+
+static const GMarkupParser parser = {
+ start_element_handler,
+ end_element_handler,
+ text_handler,
+ NULL,
+ NULL
+};
+
+int
+main (int argc, char *argv[])
+{
+ gchar *contents;
+ gsize length;
+ GError *error;
+ GMarkupParseContext *context;
+ ParserData data;
+
+ if (argc < 2)
+ {
+ g_printerr ("Expect a filename\n");
+ return 1;
+ }
+
+ error = NULL;
+ if (!g_file_get_contents (argv[1], &contents, &length, &error))
+ {
+ g_printerr ("%s\n", error->message);
+ g_error_free (error);
+ return 1;
+ }
+
+ data.output = g_string_new ("");
+ data.translatable = FALSE;
+
+ context = g_markup_parse_context_new (&parser, 0, &data, NULL);
+ if (!g_markup_parse_context_parse (context, contents, length, &error))
+ {
+ g_markup_parse_context_free (context);
+ g_free (contents);
+ g_printerr ("%s\n", error->message);
+ g_error_free (error);
+ return 1;
+ }
+
+ g_print ("%s", g_string_free (data.output, FALSE));
+
+ return 0;
+}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index dfb77eb451..763e5c58f2 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -274,3 +274,26 @@ modules/printbackends/file/gtkprintbackendfile.c
modules/printbackends/lpr/gtkprintbackendlpr.c
modules/printbackends/papi/gtkprintbackendpapi.c
modules/printbackends/test/gtkprintbackendtest.c
+gtk/gtkaboutdialog.ui.h
+gtk/gtkappchooserdialog.ui.h
+gtk/gtkappchooserwidget.ui.h
+gtk/gtkassistant.ui.h
+gtk/gtkcolorchooserdialog.ui.h
+gtk/gtkcoloreditor.ui.h
+gtk/gtkdialog.ui.h
+gtk/gtkfilechooserbutton.ui.h
+gtk/gtkfilechooserdefault.ui.h
+gtk/gtkfilechooserdialog.ui.h
+gtk/gtkfontbutton.ui.h
+gtk/gtkfontchooserdialog.ui.h
+gtk/gtkfontchooserwidget.ui.h
+gtk/gtkinfobar.ui.h
+gtk/gtklockbutton.ui.h
+gtk/gtkmessagedialog.ui.h
+gtk/gtkpagesetupunixdialog.ui.h
+gtk/gtkpathbar.ui.h
+gtk/gtkprintunixdialog.ui.h
+gtk/gtkrecentchooserdefault.ui.h
+gtk/gtkscalebutton.ui.h
+gtk/gtkstatusbar.ui.h
+gtk/gtkvolumebutton.ui.h