From: Daiki Ueno Date: Wed, 30 Sep 2015 03:53:39 +0000 (+0900) Subject: xgettext: Enable ITS by default, add --itstool X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f2277df7f1a985a580899141966ccfed11e7f9ff;p=thirdparty%2Fgettext.git xgettext: Enable ITS by default, add --itstool --- diff --git a/gettext-tools/doc/gettext.texi b/gettext-tools/doc/gettext.texi index 0d6e55798..c56c2d5a6 100644 --- a/gettext-tools/doc/gettext.texi +++ b/gettext-tools/doc/gettext.texi @@ -470,7 +470,7 @@ Internationalizable Data * Glade:: Glade - GNOME user interface description * GSettings:: GSettings - GNOME user configuration schema * AppData:: AppData - freedesktop.org application description -* XML:: XML - Generic XML files +* Preparing ITS Rules:: Preparing Rules for XML Internationalization Concluding Remarks @@ -12156,7 +12156,7 @@ using GNU gettext. * Glade:: Glade - GNOME user interface description * GSettings:: GSettings - GNOME user configuration schema * AppData:: AppData - freedesktop.org application description -* XML:: XML - Generic XML files +* Preparing ITS Rules:: Preparing Rules for XML Internationalization @end menu @node POT, RST, List of Data Formats, List of Data Formats @@ -12216,7 +12216,7 @@ glib2 @code{xgettext}, @code{intltool-extract} @end table -@node AppData, XML, GSettings, List of Data Formats +@node AppData, Preparing ITS Rules, GSettings, List of Data Formats @subsection AppData - freedesktop.org application description @table @asis @@ -12230,25 +12230,11 @@ appdata-tools, appstream, libappstream-glib, libappstream-glib-builder @code{xgettext}, @code{intltool-extract}, @code{itstool} @end table -@node XML, , AppData, List of Data Formats -@subsection XML - Generic XML files - -@table @asis -@item RPMs - -@item File extension -@code{xml}, or anything else - -@item Extractor -@code{xgettext}, @code{itstool} -@end table - @menu -* Preparing ITS Rules:: Preparing Rules for XML Internationalization @end menu -@node Preparing ITS Rules, , XML, XML -@subsubsection Preparing Rules for XML Internationalization +@node Preparing ITS Rules, , AppData, List of Data Formats +@subsection Preparing Rules for XML Internationalization @cindex preparing rules for XML translation Marking translatable strings in an XML file is done with a separate @@ -12257,7 +12243,8 @@ Marking translatable strings in an XML file is done with a separate categories are: @samp{Translate}, @samp{Localization Note}, @samp{Elements Within Text}, and @samp{Preserve Space}. -For example, given the following XML document: +For example, given the following XML document in a file +@file{messages.xml}: @example @@ -12287,18 +12274,17 @@ translatable string"), but not the second ("A non-translatable string"). @end example -@samp{xgettext} uses another file called "locating rule" to associate an -ITS rule with an XML file. For example, if the above XML file is saved -as @file{messages.xml} and the corresponding ITS file is saved as -@file{messages.its}, the locating rule would look like the following. +@samp{xgettext} needs another file called "locating rule" to associate +an ITS rule with an XML file. For example, if the above ITS file is +saved as @file{messages.its}, the locating rule would look like: @example - + - + @end example @@ -12306,23 +12292,25 @@ The @code{locatingRule} element must have a @code{pattern} attribute, which denotes either a literal file name or a wildcard pattern of the XML file. The @code{locatingRule} element can have child @code{documentRule} element, which adds checks on the content of the XML -file. The first rule matches any file with the @file{.xml} file -extension, but only applies to XML files whose root node is -@samp{}. +file. + +The first rule matches any file with the @file{.xml} file extension, but +it only applies to XML files whose root element is @samp{}. The second rule also allows any file with the @file{.msg} file extension -to be handled with the same ITS rule file. +to be handled with the same ITS rule file. The optional @code{language} +attribute of @code{locatingRule} allows @code{xgettext} to choose rules +with @code{-L} option, instead of the file name matching. -The associated ITS file is indicated by @code{target} attribute of +The associated ITS file is indicated by the @code{target} attribute of @code{locatingRule} or @code{documentRule}. -Locating rule file must have the @file{.loc} file extension. Both ITS +Locating rule files must have the @file{.loc} file extension. Both ITS rule files and locating rule files must be installed in the -@file{GETTEXTDATADIR/its} directory, where @code{GETTEXTDATADIR} is the -gettext data directory (typically @file{/usr/share/gettext}). +@file{$prefix/share/gettext/its} directory. -Once those files are properly installed, extracting translatable strings -with @code{xgettext} is done through @code{--its} option. +Once those files are properly installed, @code{xgettext} can extract +translatable strings from the matching XML files. @c This is the template for new data formats. @ignore diff --git a/gettext-tools/src/its.c b/gettext-tools/src/its.c index 56b9a5981..2af2a267d 100644 --- a/gettext-tools/src/its.c +++ b/gettext-tools/src/its.c @@ -1380,7 +1380,8 @@ its_rule_list_extract_text (its_rule_list_ty *rules, xmlNode *node, const char *logical_filename, flag_context_list_table_ty *flag_table, - message_list_ty *mlp) + message_list_ty *mlp, + its_extract_callback_ty callback) { if (node->type == XML_ELEMENT_NODE || node->type == XML_ATTRIBUTE_NODE) @@ -1413,42 +1414,36 @@ its_rule_list_extract_text (its_rule_list_ty *rules, free (values); content = _its_collect_text_content (node, whitespace); - if (*content == '\0') - free (content); - else + if (*content != '\0') { lex_pos_ty pos; message_ty *message; - char *dot; + char *marker; pos.file_name = xstrdup (logical_filename); pos.line_number = xmlGetLineNo (node); - message = remember_a_message (mlp, NULL, - content, - null_context, &pos, - comment, NULL); - if (whitespace == preserve) - message->do_wrap = no; - if (node->type == XML_ELEMENT_NODE) { assert (node->parent); - dot = xasprintf ("(itstool) path: %s/%s", - node->parent->name, - node->name); + marker = xasprintf ("%s/%s", node->parent->name, node->name); } else { assert (node->parent && node->parent->parent); - dot = xasprintf ("(itstool) path: %s/%s@%s", - node->parent->parent->name, - node->parent->name, - node->name); + marker = xasprintf ("%s/%s@%s", + node->parent->parent->name, + node->parent->name, + node->name); } - message_comment_dot_append (message, dot); - free (dot); + + message = callback (mlp, content, &pos, comment, marker); + free (marker); + + if (whitespace == preserve) + message->do_wrap = no; } + free (content); free (comment); } } @@ -1458,7 +1453,8 @@ its_rule_list_extract (its_rule_list_ty *rules, FILE *fp, const char *real_filename, const char *logical_filename, flag_context_list_table_ty *flag_table, - msgdomain_list_ty *mdlp) + msgdomain_list_ty *mdlp, + its_extract_callback_ty callback) { xmlDoc *doc; struct its_node_list_ty nodes; @@ -1487,7 +1483,8 @@ its_rule_list_extract (its_rule_list_ty *rules, its_rule_list_extract_text (rules, nodes.items[i], logical_filename, flag_table, - mdlp->item[0]->messages); + mdlp->item[0]->messages, + callback); free (nodes.items); xmlFreeDoc (doc); diff --git a/gettext-tools/src/its.h b/gettext-tools/src/its.h index c9e5dec59..7e780a319 100644 --- a/gettext-tools/src/its.h +++ b/gettext-tools/src/its.h @@ -28,6 +28,12 @@ extern "C" { typedef struct its_rule_list_ty its_rule_list_ty; +typedef message_ty * (*its_extract_callback_ty) (message_list_ty *mlp, + const char *msgid, + lex_pos_ty *pos, + const char *extracted_comment, + const char *marker); + /* Creates a fresh its_rule_list_ty holding global ITS rules. */ extern its_rule_list_ty *its_rule_list_alloc (void); @@ -43,7 +49,8 @@ extern void its_rule_list_extract (its_rule_list_ty *rules, FILE *fp, const char *real_filename, const char *logical_filename, flag_context_list_table_ty *flag_table, - msgdomain_list_ty *mdlp); + msgdomain_list_ty *mdlp, + its_extract_callback_ty callback); #ifdef __cplusplus } diff --git a/gettext-tools/src/locating-rule.c b/gettext-tools/src/locating-rule.c index 15c3308ea..908976dae 100644 --- a/gettext-tools/src/locating-rule.c +++ b/gettext-tools/src/locating-rule.c @@ -67,6 +67,7 @@ struct document_locating_rule_list_ty struct locating_rule_ty { char *pattern; + char *language; struct document_locating_rule_list_ty doc_rules; char *target; @@ -118,9 +119,14 @@ document_locating_rule_match (struct document_locating_rule_ty *rule, static const char * locating_rule_match (struct locating_rule_ty *rule, - const char *filename) + const char *filename, + const char *language) { - if (fnmatch (rule->pattern, filename, FNM_PATHNAME) != 0) + if (language == NULL && fnmatch (rule->pattern, filename, FNM_PATHNAME) != 0) + return NULL; + + if (language != NULL + && (rule->language == NULL || strcmp (language, rule->language) != 0)) return NULL; if (rule->target != NULL) @@ -157,14 +163,15 @@ locating_rule_match (struct locating_rule_ty *rule, const char * locating_rule_list_locate (struct locating_rule_list_ty *rules, - const char *path) + const char *filename, + const char *language) { const char *target = NULL; size_t i; for (i = 0; i < rules->nitems; i++) { - target = locating_rule_match (&rules->items[i], path); + target = locating_rule_match (&rules->items[i], filename, language); if (target != NULL) return target; } @@ -226,6 +233,7 @@ locating_rule_destroy (struct locating_rule_ty *rule) for (i = 0; i < rule->doc_rules.nitems; i++) document_locating_rule_destroy (&rule->doc_rules.items[i]); + free (rule->language); free (rule->pattern); free (rule->target); } @@ -276,6 +284,8 @@ locating_rule_list_add_file (struct locating_rule_list_ty *rules, memset (&rule, 0, sizeof (struct locating_rule_ty)); rule.pattern = get_attribute (node, "pattern"); + if (xmlHasProp (node, BAD_CAST "language")) + rule.language = get_attribute (node, "language"); if (xmlHasProp (node, BAD_CAST "target")) rule.target = get_attribute (node, "target"); else diff --git a/gettext-tools/src/locating-rule.h b/gettext-tools/src/locating-rule.h index 9f0f25667..46189090a 100644 --- a/gettext-tools/src/locating-rule.h +++ b/gettext-tools/src/locating-rule.h @@ -34,10 +34,11 @@ extern bool locating_rule_list_add_directory (locating_rule_list_ty *rules, const char *directory); -/* Determines the location of resource associated with PATH, accoding - to the loaded locating rules. */ +/* Determines the location of resource associated with FILENAME, + accoding to the loaded locating rules. */ extern const char *locating_rule_list_locate (locating_rule_list_ty *rules, - const char *path); + const char *filename, + const char *language); /* Releases memory allocated for RULES. */ extern void locating_rule_list_free (locating_rule_list_ty *rules); diff --git a/gettext-tools/src/xgettext.c b/gettext-tools/src/xgettext.c index b241151b7..a896b0f2e 100644 --- a/gettext-tools/src/xgettext.c +++ b/gettext-tools/src/xgettext.c @@ -78,8 +78,6 @@ /* A convenience macro. I don't like writing gettext() every time. */ #define _(str) gettext (str) -#define SIZEOF(a) (sizeof(a) / sizeof(a[0])) - #include "x-c.h" #include "x-po.h" @@ -109,6 +107,10 @@ #include "x-desktop.h" +#define SIZEOF(a) (sizeof(a) / sizeof(a[0])) +#define ENDOF(a) ((a) + SIZEOF(a)) + + /* If nonzero add all comments immediately preceding one of the keywords. */ static bool add_all_comments = false; @@ -212,6 +214,9 @@ iconv_t xgettext_current_source_iconv; static locating_rule_list_ty *its_locating_rules; +/* If nonzero add comments used by itstool. */ +static bool add_itstool_comments = false; + /* Long options. */ static const struct option long_options[] = { @@ -235,7 +240,7 @@ static const struct option long_options[] = { "from-code", required_argument, NULL, CHAR_MAX + 3 }, { "help", no_argument, NULL, 'h' }, { "indent", no_argument, NULL, 'i' }, - { "its", no_argument, NULL, CHAR_MAX + 19 }, + { "itstool", no_argument, NULL, CHAR_MAX + 19 }, { "join-existing", no_argument, NULL, 'j' }, { "kde", no_argument, NULL, CHAR_MAX + 10 }, { "keyword", optional_argument, NULL, 'k' }, @@ -317,7 +322,6 @@ main (int argc, char *argv[]) bool some_additional_keywords = false; bool sort_by_msgid = false; bool sort_by_filepos = false; - bool its = false; char *its_dirs[2] = { NULL, NULL }; const char *file_name; const char *files_from = NULL; @@ -391,7 +395,6 @@ main (int argc, char *argv[]) x_tcl_extract_all (); x_perl_extract_all (); x_php_extract_all (); - x_glade_extract_all (); x_lua_extract_all (); x_javascript_extract_all (); x_vala_extract_all (); @@ -471,7 +474,6 @@ main (int argc, char *argv[]) x_tcl_keyword (optarg); x_perl_keyword (optarg); x_php_keyword (optarg); - x_glade_keyword (optarg); x_lua_keyword (optarg); x_javascript_keyword (optarg); x_vala_keyword (optarg); @@ -655,8 +657,8 @@ main (int argc, char *argv[]) error (EXIT_FAILURE, 0, _("sentence end type '%s' unknown"), optarg); break; - case CHAR_MAX + 19: /* --its */ - its = true; + case CHAR_MAX + 19: /* --itstool */ + add_itstool_comments = true; break; default: @@ -719,30 +721,29 @@ xgettext cannot work without keywords to look for")); usage (EXIT_FAILURE); } - if (its) - { - const char *gettextdatadir; - char *versioned_gettextdatadir; - - /* Make it possible to override the locator file location. This - is necessary for running the testsuite before "make - install". */ - gettextdatadir = getenv ("GETTEXTDATADIR"); - if (gettextdatadir == NULL || gettextdatadir[0] == '\0') - gettextdatadir = relocate (GETTEXTDATADIR); - - its_dirs[0] = xconcatenated_filename (gettextdatadir, "its", NULL); - - versioned_gettextdatadir = - xasprintf ("%s%s", relocate (GETTEXTDATADIR), PACKAGE_SUFFIX); - its_dirs[1] = xconcatenated_filename (versioned_gettextdatadir, "its", - NULL); - free (versioned_gettextdatadir); - - its_locating_rules = locating_rule_list_alloc (); - for (i = 0; i < SIZEOF (its_dirs); i++) - locating_rule_list_add_directory (its_locating_rules, its_dirs[i]); - } + { + const char *gettextdatadir; + char *versioned_gettextdatadir; + + /* Make it possible to override the locator file location. This + is necessary for running the testsuite before "make + install". */ + gettextdatadir = getenv ("GETTEXTDATADIR"); + if (gettextdatadir == NULL || gettextdatadir[0] == '\0') + gettextdatadir = relocate (GETTEXTDATADIR); + + its_dirs[0] = xconcatenated_filename (gettextdatadir, "its", NULL); + + versioned_gettextdatadir = + xasprintf ("%s%s", relocate (GETTEXTDATADIR), PACKAGE_SUFFIX); + its_dirs[1] = xconcatenated_filename (versioned_gettextdatadir, "its", + NULL); + free (versioned_gettextdatadir); + + its_locating_rules = locating_rule_list_alloc (); + for (i = 0; i < SIZEOF (its_dirs); i++) + locating_rule_list_add_directory (its_locating_rules, its_dirs[i]); + } /* Determine extractor from language. */ if (language != NULL) @@ -884,7 +885,8 @@ This version was built without iconv()."), if (language == NULL && its_locating_rules != NULL) { const char *its_basename = - locating_rule_list_locate (its_locating_rules, filename); + locating_rule_list_locate (its_locating_rules, filename, + language); if (its_basename != NULL) { size_t j; @@ -1118,10 +1120,6 @@ Language specific options:\n")); printf (_("\ (only language C++)\n")); printf (_("\ - --its extract from XML file using ITS rules\n")); - printf (_("\ - (only XML files)\n")); - printf (_("\ --debug more detailed formatstring recognition result\n")); printf ("\n"); printf (_("\ @@ -1151,6 +1149,8 @@ Output details:\n")); printf (_("\ --stringtable-output write out a NeXTstep/GNUstep .strings file\n")); printf (_("\ + --itstool write out itstool comments\n")); + printf (_("\ -w, --width=NUMBER set output page width\n")); printf (_("\ --no-wrap do not break long message lines, longer than\n\ @@ -2212,6 +2212,30 @@ extract_from_file (const char *file_name, extractor_ty extractor, free (real_file_name); } +static message_ty * +xgettext_its_extract_callback (message_list_ty *mlp, + const char *msgid, + lex_pos_ty *pos, + const char *extracted_comment, + const char *marker) +{ + message_ty *message; + + message = remember_a_message (mlp, NULL, + xstrdup (msgid), + null_context, pos, + extracted_comment, NULL); + + if (add_itstool_comments) + { + char *dot = xasprintf ("(itstool) path: %s", marker); + message_comment_dot_append (message, dot); + free (dot); + } + + return message; +} + static void extract_from_xml_file (const char *file_name, its_rule_list_ty *rules, @@ -2230,7 +2254,8 @@ extract_from_xml_file (const char *file_name, its_rule_list_extract (rules, fp, real_file_name, logical_file_name, NULL, - mdlp); + mdlp, + xgettext_its_extract_callback); if (fp != stdin) fclose (fp); @@ -3838,10 +3863,6 @@ finalize_header (msgdomain_list_ty *mdlp) } -#define SIZEOF(a) (sizeof(a) / sizeof(a[0])) -#define ENDOF(a) ((a) + SIZEOF(a)) - - static extractor_ty language_to_extractor (const char *name) { diff --git a/gettext-tools/tests/xgettext-its-1 b/gettext-tools/tests/xgettext-its-1 index 0b2b4894e..0ba55ce08 100755 --- a/gettext-tools/tests/xgettext-its-1 +++ b/gettext-tools/tests/xgettext-its-1 @@ -4,8 +4,8 @@ # Test of ITS support. : ${XGETTEXT=xgettext} -: ${GETTEXTDATADIR=.} +GETTEXTDATADIR=. export GETTEXTDATADIR cat <<\EOF > empty.xml @@ -13,7 +13,7 @@ cat <<\EOF > empty.xml EOF -${XGETTEXT} --its -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; } +${XGETTEXT} --itstool -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; } test -d its || mkdir its @@ -22,7 +22,7 @@ cat <<\EOF > its/empty-1.loc EOF -${XGETTEXT} --its -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; } +${XGETTEXT} --itstool -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; } cat <<\EOF > its/empty-2.loc @@ -33,7 +33,7 @@ cat <<\EOF > its/empty-2.loc EOF -${XGETTEXT} --its -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; } +${XGETTEXT} --itstool -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; } cat <<\EOF > its/empty.its @@ -41,7 +41,7 @@ cat <<\EOF > its/empty.its EOF -${XGETTEXT} --its -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; } +${XGETTEXT} --itstool -o empty.pot empty.xml 2>empty.err || { cat empty.err; exit 1; } cat <<\EOF > its/messages.loc @@ -192,7 +192,7 @@ msgid " This is a message with space preserved" msgstr "" EOF -${XGETTEXT} --its --no-wrap --omit-header -o messages.pot messages.xml 2>messages.err || { cat messages.err; exit 1; } +${XGETTEXT} --itstool --no-wrap --omit-header -o messages.pot messages.xml 2>messages.err || { cat messages.err; exit 1; } : ${DIFF=diff} ${DIFF} messages.ok messages.pot result=$?