]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
xgettext: Enable ITS by default, add --itstool
authorDaiki Ueno <ueno@gnu.org>
Wed, 30 Sep 2015 03:53:39 +0000 (12:53 +0900)
committerDaiki Ueno <ueno@gnu.org>
Wed, 30 Sep 2015 03:53:39 +0000 (12:53 +0900)
gettext-tools/doc/gettext.texi
gettext-tools/src/its.c
gettext-tools/src/its.h
gettext-tools/src/locating-rule.c
gettext-tools/src/locating-rule.h
gettext-tools/src/xgettext.c
gettext-tools/tests/xgettext-its-1

index 0d6e55798cd3a787db4e95cf510e46333c1cd852..c56c2d5a64faea75710f2cabf9f73e3722f169cb 100644 (file)
@@ -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
 <?xml version="1.0"?>
@@ -12287,18 +12274,17 @@ translatable string"), but not the second ("A non-translatable string").
 </its:rules>
 @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
 <?xml version="1.0"?>
 <locatingRules>
-  <locatingRule pattern="*.xml">
+  <locatingRule language="Messages" pattern="*.xml">
     <documentRule localName="messages" target="messages.its"/>
   </locatingRule>
-  <locatingRule pattern="*.msg" target="messages.its"/>
+  <locatingRule language="Messages" pattern="*.msg" target="messages.its"/>
 </locatingRules>
 @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{<messages>}.
+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{<messages>}.
 
 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
index 56b9a598105dfd54c0334abc3ebdf48f5db8cb3c..2af2a267d48e14850a94cc3cba7b756d41abfe9b 100644 (file)
@@ -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);
index c9e5dec599f53a14bf0a1b03fb9877f240bf3fb7..7e780a319b60809c2ab8b243ddc13212061350a7 100644 (file)
@@ -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
 }
index 15c3308ea33c6efda8009baadd3b9900959a5198..908976dae2c53e7cd5dcaaefa1fe4997de43d79a 100644 (file)
@@ -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
index 9f0f25667bf1983c6b2ce5391bd848faf2b33283..46189090a13c85f636a9c4a98a1d6c90beb839c4 100644 (file)
@@ -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);
index b241151b75872436bb18124dde065f741a48af83..a896b0f2ea465c0146eff395be7720846ef50105 100644 (file)
@@ -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"
 #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)
 {
index 0b2b4894e649bbfae0d68b03a3646d8d22c6334b..0ba55ce08f0ce03e95eb92d7e83e7e488931c461 100755 (executable)
@@ -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
 <empty></empty>
 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
 <locatingRules/>
 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
 <?xml version="1.0"?>
@@ -33,7 +33,7 @@ cat <<\EOF > its/empty-2.loc
 </locatingRules>
 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
 <?xml version="1.0"?>
@@ -41,7 +41,7 @@ cat <<\EOF > its/empty.its
 </its:rules>
 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
 <?xml version="1.0"?>
@@ -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=$?