diff options
author | Miguel Ángel Arruga Vivas <rosen644835@gmail.com> | 2013-06-13 16:28:42 +0900 |
---|---|---|
committer | Daiki Ueno <ueno@gnu.org> | 2013-06-13 17:45:34 +0900 |
commit | 2c3f428a748eaa9a8cc2cc2f457ed8633e438d20 (patch) | |
tree | 05dcc5247ef1240168f802e0847006a8687bc7a8 /gettext-tools | |
parent | f9d637f8dd3d435c2cd53c97ee1ddd336ed050a4 (diff) | |
download | external_gettext-2c3f428a748eaa9a8cc2cc2f457ed8633e438d20.zip external_gettext-2c3f428a748eaa9a8cc2cc2f457ed8633e438d20.tar.gz external_gettext-2c3f428a748eaa9a8cc2cc2f457ed8633e438d20.tar.bz2 |
Support GtkBuilder file format in the Glade scanner.
Diffstat (limited to 'gettext-tools')
-rw-r--r-- | gettext-tools/src/ChangeLog | 23 | ||||
-rw-r--r-- | gettext-tools/src/x-glade.c | 282 | ||||
-rw-r--r-- | gettext-tools/src/x-glade.h | 1 |
3 files changed, 247 insertions, 59 deletions
diff --git a/gettext-tools/src/ChangeLog b/gettext-tools/src/ChangeLog index 9387115..1cb64a3 100644 --- a/gettext-tools/src/ChangeLog +++ b/gettext-tools/src/ChangeLog @@ -1,3 +1,26 @@ +2013-06-13 Miguel Angel Arruga Vivas <rosen644835@gmail.com> + Daiki Ueno <ueno@gnu.org> + + Support for GtkBuilder file format in the Glade scanner. + * x-glade.h (EXTENSIONS_GLADE): Recognize .ui. + * x-glade.c (element_parser): New struct. + (start_element_glade1): New function split from start_element_handler. + (end_element_glade1): New function split from end_element_handler. + (start_element_glade2): New function split from start_element_handler. + (end_element_glade2): New function split from end_element_handler. + (start_element_gtkbuilder): New function. + (end_element_gtkbuilder): New function. + (element_parser_glade1): New variable. + (element_parser_glade2): New variable. + (element_parser_gtkbuilder): New variable. + (start_element_handler): Delegate the actual parsing logic to + specific element_parser. + (end_element_handler): Likewise. + Thanks to Miguel Ángel Arruga Vivas for the initial implementation + and the discussion in + <https://lists.gnu.org/archive/html/bug-gettext/2013-03/msg00074.html> + footnote 2. + 2013-06-10 Daiki Ueno <ueno@gnu.org> * Makefile.am: Use $(MKDIR_P) instead of $(mkdir_p). diff --git a/gettext-tools/src/x-glade.c b/gettext-tools/src/x-glade.c index 85ed21c..2c06621 100644 --- a/gettext-tools/src/x-glade.c +++ b/gettext-tools/src/x-glade.c @@ -52,8 +52,17 @@ #define _(s) gettext(s) -/* glade is an XML based format. Some example files are contained in - libglade-0.16. */ +/* Glade is an XML based format with three variants. The syntax for + each format is defined as follows. + + - Glade 1 + Some example files are contained in libglade-0.16. + + - Glade 2 + See http://library.gnome.org/devel/libglade/unstable/libglade-dtd.html + + - GtkBuilder + See https://developer.gnome.org/gtk3/stable/GtkBuilder.html#BUILDER-UI */ /* ====================== Keyword set customization. ====================== */ @@ -61,6 +70,7 @@ /* If true extract all strings. */ static bool extract_all = false; +/* Keywords are only used by Glade 1 support. */ static hash_table keywords; static bool default_keywords = true; @@ -385,8 +395,9 @@ static XML_Parser parser; struct element_state { bool extract_string; - bool extract_context; - char *extracted_comment; + bool extract_context; /* used by Glade 2 */ + char *extracted_comment; /* used by Glade 2 or GtkBuilder */ + char *extracted_context; /* used by GtkBuilder */ int lineno; char *buffer; size_t bufmax; @@ -412,35 +423,55 @@ ensure_stack_size (size_t size) static size_t stack_depth; -/* Callback called when <element> is seen. */ +/* Parser logic for each Glade compatible file format. */ +struct element_parser +{ + void (*start_element) (struct element_state *p, const char *name, + const char **attributes); + void (*end_element) (struct element_state *p, const char *name); +}; +static struct element_parser *element_parser; + static void -start_element_handler (void *userData, const char *name, - const char **attributes) +start_element_glade1 (struct element_state *p, const char *name, + const char **attributes) { - struct element_state *p; void *hash_result; - /* Increase stack depth. */ - stack_depth++; - ensure_stack_size (stack_depth + 1); - - /* Don't extract a string for the containing element. */ - stack[stack_depth - 1].extract_string = false; - - p = &stack[stack_depth]; - p->extract_string = extract_all; - p->extract_context = false; - p->extracted_comment = NULL; /* In Glade 1, a few specific elements are translatable. */ if (!p->extract_string) p->extract_string = (hash_find_entry (&keywords, name, strlen (name), &hash_result) == 0); +} + +static void +end_element_glade1 (struct element_state *p, const char *name) +{ + lex_pos_ty pos; + + pos.file_name = logical_file_name; + pos.line_number = p->lineno; + + if (p->buffer != NULL) + { + remember_a_message (mlp, NULL, p->buffer, + null_context, &pos, + p->extracted_comment, savable_comment); + p->buffer = NULL; + } +} + +static void +start_element_glade2 (struct element_state *p, const char *name, + const char **attributes) +{ /* In Glade 2, all <property> and <atkproperty> elements are translatable that have the attribute translatable="yes". See <http://library.gnome.org/devel/libglade/unstable/libglade-dtd.html>. The translator comment is found in the attribute comments="...". See <http://live.gnome.org/TranslationProject/DevGuidelines/Use comments>. - */ + If the element has the attribute context="yes", the content of + the element in the form "msgctxt|msgid". */ if (!p->extract_string && (strcmp (name, "property") == 0 || strcmp (name, "atkproperty") == 0)) { @@ -465,6 +496,9 @@ start_element_handler (void *userData, const char *name, ? xstrdup (extracted_comment) : NULL); } + + /* In Glade 2, the attribute description="..." of <atkaction> + element is also translatable. */ if (!p->extract_string && strcmp (name, "atkaction") == 0) { @@ -489,6 +523,170 @@ start_element_handler (void *userData, const char *name, attp += 2; } } +} + +static void +end_element_glade2 (struct element_state *p, const char *name) +{ + lex_pos_ty pos; + char *msgid = NULL; + char *msgctxt = NULL; + + pos.file_name = logical_file_name; + pos.line_number = p->lineno; + + if (p->extract_context) + { + char *separator = strchr (p->buffer, '|'); + + if (separator == NULL) + { + error_with_progname = false; + error_at_line (0, 0, + pos.file_name, + pos.line_number, + _("\ +Missing context for the string extracted from '%s' element"), + name); + error_with_progname = true; + } + else + { + *separator = '\0'; + msgid = xstrdup (separator + 1); + msgctxt = xstrdup (p->buffer); + } + } + else + { + msgid = p->buffer; + p->buffer = NULL; + } + + if (msgid != NULL) + remember_a_message (mlp, msgctxt, msgid, + null_context, &pos, + p->extracted_comment, savable_comment); +} + +static void +start_element_gtkbuilder (struct element_state *p, const char *name, + const char **attributes) +{ + /* In GtkBuilder (used by Glade 3), all elements are translatable + that have the attribute translatable="yes". + See <https://developer.gnome.org/gtk3/stable/GtkBuilder.html#BUILDER-UI>. + The translator comment is found in the attribute comments="..." + and context is found in the attribute context="...". + */ + if (!p->extract_string) + { + bool has_translatable = false; + const char *extracted_comment = NULL; + const char *extracted_context = NULL; + const char **attp = attributes; + while (*attp != NULL) + { + if (strcmp (attp[0], "translatable") == 0) + has_translatable = (strcmp (attp[1], "yes") == 0); + else if (strcmp (attp[0], "comments") == 0) + extracted_comment = attp[1]; + else if (strcmp (attp[0], "context") == 0) + extracted_context = attp[1]; + attp += 2; + } + p->extract_string = has_translatable; + p->extracted_comment = + (has_translatable && extracted_comment != NULL + ? xstrdup (extracted_comment) + : NULL); + p->extracted_context = + (has_translatable && extracted_context != NULL + ? xstrdup (extracted_context) + : NULL); + } +} + +static void +end_element_gtkbuilder (struct element_state *p, const char *name) +{ + lex_pos_ty pos; + + pos.file_name = logical_file_name; + pos.line_number = p->lineno; + + if (p->buffer != NULL) + { + remember_a_message (mlp, p->extracted_context, p->buffer, + null_context, &pos, + p->extracted_comment, savable_comment); + p->buffer = NULL; + p->extracted_context = NULL; + } +} + +static struct element_parser element_parser_glade1 = +{ + start_element_glade1, + end_element_glade1 +}; + +static struct element_parser element_parser_glade2 = +{ + start_element_glade2, + end_element_glade2 +}; + +static struct element_parser element_parser_gtkbuilder = +{ + start_element_gtkbuilder, + end_element_gtkbuilder +}; + +/* Callback called when <element> is seen. */ +static void +start_element_handler (void *userData, const char *name, + const char **attributes) +{ + struct element_state *p; + + if (!stack_depth) + { + if (strcmp (name, "GTK-Interface") == 0) + element_parser = &element_parser_glade1; + else if (strcmp (name, "glade-interface") == 0) + element_parser = &element_parser_glade2; + else if (strcmp (name, "interface") == 0) + element_parser = &element_parser_gtkbuilder; + else + { + error_with_progname = false; + error_at_line (0, 0, + logical_file_name, + XML_GetCurrentLineNumber (parser), + _("\ +The root element <%s> is not allowed in a valid Glade file"), + name); + error_with_progname = true; + } + } + + /* Increase stack depth. */ + stack_depth++; + ensure_stack_size (stack_depth + 1); + + /* Don't extract a string for the containing element. */ + stack[stack_depth - 1].extract_string = false; + + p = &stack[stack_depth]; + p->extract_string = extract_all; + p->extract_context = false; + p->extracted_comment = NULL; + p->extracted_context = NULL; + + if (element_parser != NULL) + element_parser->start_element (p, name, attributes); + p->lineno = XML_GetCurrentLineNumber (parser); p->buffer = NULL; p->bufmax = 0; @@ -509,55 +707,20 @@ end_element_handler (void *userData, const char *name) /* Don't extract the empty string. */ if (p->buflen > 0) { - lex_pos_ty pos; - char *msgid = NULL; - char *msgctxt = NULL; - if (p->buflen == p->bufmax) p->buffer = (char *) xrealloc (p->buffer, p->buflen + 1); p->buffer[p->buflen] = '\0'; - pos.file_name = logical_file_name; - pos.line_number = p->lineno; - - if (p->extract_context) - { - char *separator = strchr (p->buffer, '|'); - - if (separator == NULL) - { - error_with_progname = false; - error_at_line (0, 0, - pos.file_name, - pos.line_number, - _("\ -Missing context for the string extracted from '%s' element"), - name); - error_with_progname = true; - } - else - { - *separator = '\0'; - msgid = xstrdup (separator + 1); - msgctxt = xstrdup (p->buffer); - } - } - else - { - msgid = p->buffer; - p->buffer = NULL; - } - - if (msgid != NULL) - remember_a_message (mlp, msgctxt, msgid, - null_context, &pos, - p->extracted_comment, savable_comment); + if (element_parser != NULL) + element_parser->end_element (p, name); } } /* Free memory for this stack level. */ if (p->extracted_comment != NULL) free (p->extracted_comment); + if (p->extracted_context != NULL) + free (p->extracted_context); if (p->buffer != NULL) free (p->buffer); @@ -641,6 +804,7 @@ do_extract_glade (FILE *fp, XML_SetCommentHandler (parser, comment_handler); stack_depth = 0; + element_parser = NULL; while (!feof (fp)) { diff --git a/gettext-tools/src/x-glade.h b/gettext-tools/src/x-glade.h index 0af3385..e3cc253 100644 --- a/gettext-tools/src/x-glade.h +++ b/gettext-tools/src/x-glade.h @@ -30,6 +30,7 @@ extern "C" { #define EXTENSIONS_GLADE \ { "glade", "glade" }, \ { "glade2", "glade" }, \ + { "ui", "glade" }, \ #define SCANNERS_GLADE \ { "glade", extract_glade, NULL, NULL, NULL }, \ |