]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
msgmerge: New option --for-msgfmt.
authorBruno Haible <bruno@clisp.org>
Wed, 24 Oct 2018 23:09:38 +0000 (01:09 +0200)
committerBruno Haible <bruno@clisp.org>
Wed, 24 Oct 2018 23:09:38 +0000 (01:09 +0200)
* gettext-tools/src/msgmerge.c (for_msgfmt): New variable.
(long_options): Add option --for-msgfmt.
(main): Handle option --for-msgfmt.
(usage): Document option --for-msgfmt.
(match_domain): When --for-msgfmt is given, omit untranslated and fuzzy messages
from the result.
(merge): When --for-msgfmt is given, don't add obsolete messages to the result.
* gettext-tools/tests/msgmerge-26: New file.
* gettext-tools/tests/Makefile.am (TESTS): Add it.
* gettext-tools/doc/msgmerge.texi: Mention the option --for-msgfmt.
* NEWS: Mention the change.

NEWS
gettext-tools/doc/msgmerge.texi
gettext-tools/src/msgmerge.c
gettext-tools/tests/Makefile.am
gettext-tools/tests/msgmerge-26 [new file with mode: 0755]

diff --git a/NEWS b/NEWS
index 9de1cbd491916f96334f8c4f683397deb575f74e..05c0ed2415655d635bb96e172023e1abef5cdc8d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,12 @@
 * Improvements for translators:
   - update-po target in Makefile.in.in now uses msgmerge --previous.
 
+* Improvements for maintainers:
+  - msgmerge now has an option --for-msgfmt, that produces a PO file meant
+    for use by msgfmt only.  This option saves processing time, in particular
+    by omitting fuzzy matching that is not useful in this situation.
+  - The .pot file in a 'po' directory is now erased by "make maintainer-clean".
+
 * Programming languages support:
   - C, C++:
     xgettext now supports 'p'/'P' exponent markers in number tokens, as
@@ -43,9 +49,6 @@
     compliant.  There is no conflict any more between these replacements
     and other possible replacements provided by gnulib or mingw.
 
-* Improvements for maintainers:
-  - The .pot file in a 'po' directory is now erased by "make maintainer-clean".
-
 Version 0.19.8 - June 2016
 
 * Support for reproducible builds:
index ad76f0e7df41bd3bad0612bc2dc671392f8a2ab2..e74541f7b00f467ab98ef10d37c056c17a847f07 100644 (file)
@@ -120,6 +120,14 @@ The backup suffix is @samp{~}, unless set with @code{--suffix} or the
 @opindex --multi-domain@r{, @code{msgmerge} option}
 Apply @var{ref}.pot to each of the domains in @var{def}.po.
 
+@item --for-msgfmt
+@opindex --for-msgfmt@r{, @code{msgmerge} option}
+Produce a PO file meant for @code{msgfmt} only, not for a translator.
+This option omits untranslated messages, fuzzy messages (except the header
+entry), and obsolete messages from the output.  Also, it omits translator
+comments and @samp{#: @var{filename}:@var{line}} lines from the output.
+In particular, this option implies @samp{--no-fuzzy-matching}.
+
 @item -N
 @itemx --no-fuzzy-matching
 @opindex -N@r{, @code{msgmerge} option}
index 90c2b69a1eeadcb44750f08829eb7526976ca4a8..60b51221a4a532ab5656b09d09fa288eaf5c3b4c 100644 (file)
@@ -85,6 +85,14 @@ static int force_po;
 /* Apply the .pot file to each of the domains in the PO file.  */
 static bool multi_domain_mode = false;
 
+/* Produce output for msgfmt, not for a translator.
+   msgfmt ignores
+     - untranslated messages,
+     - fuzzy messages, except the header entry,
+     - obsolete messages.
+   Therefore output for msgfmt does not need to include such messages.  */
+static bool for_msgfmt = false;
+
 /* Determines whether to use fuzzy matching.  */
 static bool use_fuzzy_matching = true;
 
@@ -114,6 +122,7 @@ static const struct option long_options[] =
   { "compendium", required_argument, NULL, 'C' },
   { "directory", required_argument, NULL, 'D' },
   { "escape", no_argument, NULL, 'E' },
+  { "for-msgfmt", no_argument, NULL, CHAR_MAX + 12 },
   { "force-po", no_argument, &force_po, 1 },
   { "help", no_argument, NULL, 'h' },
   { "indent", no_argument, NULL, 'i' },
@@ -344,6 +353,10 @@ main (int argc, char **argv)
         message_print_style_filepos (filepos_comment_none);
         break;
 
+      case CHAR_MAX + 12: /* --for-msgfmt */
+        for_msgfmt = true;
+        break;
+
       default:
         usage (EXIT_FAILURE);
         break;
@@ -388,6 +401,11 @@ There is NO WARRANTY, to the extent permitted by law.\n\
           error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
                  "--update", "--output-file");
         }
+      if (for_msgfmt)
+        {
+          error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
+                 "--update", "--for-msgfmt");
+        }
       if (color != NULL)
         {
           error (EXIT_FAILURE, 0, _("%s and %s are mutually exclusive"),
@@ -426,6 +444,22 @@ There is NO WARRANTY, to the extent permitted by law.\n\
   if (update_mode && input_syntax == &input_format_stringtable)
     output_syntax = &output_format_stringtable;
 
+  if (for_msgfmt)
+    {
+      /* With --for-msgfmt, no fuzzy matching.  */
+      use_fuzzy_matching = false;
+
+      /* With --for-msgfmt, merging is fast, therefore no need for a progress
+         indicator.  */
+      quiet = true;
+
+      /* With --for-msgfmt, no need for comments.  */
+      message_print_style_comment (false);
+
+      /* With --for-msgfmt, no need for source location lines.  */
+      message_print_style_filepos (filepos_comment_none);
+    }
+
   /* Merge the two files.  */
   result = merge (argv[optind], argv[optind + 1], input_syntax, &def);
 
@@ -567,6 +601,9 @@ Operation modifiers:\n"));
       printf (_("\
   -m, --multi-domain          apply ref.pot to each of the domains in def.po\n"));
       printf (_("\
+      --for-msgfmt            produce output for '%s', not for a translator\n"),
+              "msgfmt");
+      printf (_("\
   -N, --no-fuzzy-matching     do not use fuzzy matching\n"));
       printf (_("\
       --previous              keep previous msgids of translated messages\n"));
@@ -1500,11 +1537,19 @@ match_domain (const char *fn1, const char *fn2,
           message_ty *mp =
             message_merge (defmsg, refmsg, false, &distribution);
 
-          message_list_append (resultmlp, mp);
+          /* When producing output for msgfmt, omit messages that are
+             untranslated or fuzzy (except the header entry).  */
+          if (!(for_msgfmt
+                && (mp->msgstr[0] == '\0' /* untranslated? */
+                    || (mp->is_fuzzy && !is_header (mp))))) /* fuzzy? */
+            {
+              message_list_append (resultmlp, mp);
+
+              /* Remember that this message has been used, when we scan
+                 later to see if anything was omitted.  */
+              defmsg->used = 1;
+            }
 
-          /* Remember that this message has been used, when we scan
-             later to see if anything was omitted.  */
-          defmsg->used = 1;
           stats->merged++;
         }
       else if (!is_header (refmsg))
@@ -1538,6 +1583,7 @@ this message is used but not defined..."));
               /* Remember that this message has been used, when we scan
                  later to see if anything was omitted.  */
               defmsg->used = 1;
+
               stats->fuzzied++;
               if (!quiet && verbosity_level <= 1)
                 /* Always print a dot if we handled a fuzzy match.  */
@@ -1556,27 +1602,31 @@ this message is used but not defined in %s"), fn1);
 
               mp = message_copy (refmsg);
 
-              if (mp->msgid_plural != NULL)
+              /* Test if mp is untranslated.  (It most likely is.)  */
+              is_untranslated = true;
+              for (p = mp->msgstr, pend = p + mp->msgstr_len; p < pend; p++)
+                if (*p != '\0')
+                  {
+                    is_untranslated = false;
+                    break;
+                  }
+
+              if (mp->msgid_plural != NULL && is_untranslated)
                 {
-                  /* Test if mp is untranslated.  (It most likely is.)  */
-                  is_untranslated = true;
-                  for (p = mp->msgstr, pend = p + mp->msgstr_len; p < pend; p++)
-                    if (*p != '\0')
-                      {
-                        is_untranslated = false;
-                        break;
-                      }
-                  if (is_untranslated)
-                    {
-                      /* Change mp->msgstr_len consecutive empty strings into
-                         nplurals consecutive empty strings.  */
-                      if (nplurals > mp->msgstr_len)
-                        mp->msgstr = untranslated_plural_msgstr;
-                      mp->msgstr_len = nplurals;
-                    }
+                  /* Change mp->msgstr_len consecutive empty strings into
+                     nplurals consecutive empty strings.  */
+                  if (nplurals > mp->msgstr_len)
+                    mp->msgstr = untranslated_plural_msgstr;
+                  mp->msgstr_len = nplurals;
+                }
+
+              /* When producing output for msgfmt, omit messages that are
+                 untranslated or fuzzy (except the header entry).  */
+              if (!(for_msgfmt && (is_untranslated || mp->is_fuzzy)))
+                {
+                  message_list_append (resultmlp, mp);
                 }
 
-              message_list_append (resultmlp, mp);
               stats->missing++;
             }
         }
@@ -1998,48 +2048,51 @@ merge (const char *fn1, const char *fn2, catalog_input_format_ty input_syntax,
 
   definitions_destroy (&definitions);
 
-  /* Look for messages in the definition file, which are not present
-     in the reference file, indicating messages which defined but not
-     used in the program.  Don't scan the compendium(s).  */
-  for (k = 0; k < def->nitems; ++k)
+  if (!for_msgfmt)
     {
-      const char *domain = def->item[k]->domain;
-      message_list_ty *defmlp = def->item[k]->messages;
-
-      for (j = 0; j < defmlp->nitems; j++)
+      /* Look for messages in the definition file, which are not present
+         in the reference file, indicating messages which defined but not
+         used in the program.  Don't scan the compendium(s).  */
+      for (k = 0; k < def->nitems; ++k)
         {
-          message_ty *defmsg = defmlp->item[j];
+          const char *domain = def->item[k]->domain;
+          message_list_ty *defmlp = def->item[k]->messages;
 
-          if (!defmsg->used)
+          for (j = 0; j < defmlp->nitems; j++)
             {
-              /* Remember the old translation although it is not used anymore.
-                 But we mark it as obsolete.  */
-              message_ty *mp;
+              message_ty *defmsg = defmlp->item[j];
 
-              mp = message_copy (defmsg);
-              /* Clear the extracted comments.  */
-              if (mp->comment_dot != NULL)
-                {
-                  string_list_free (mp->comment_dot);
-                  mp->comment_dot = NULL;
-                }
-              /* Clear the file position comments.  */
-              if (mp->filepos != NULL)
+              if (!defmsg->used)
                 {
-                  size_t i;
+                  /* Remember the old translation although it is not used anymore.
+                     But we mark it as obsolete.  */
+                  message_ty *mp;
 
-                  for (i = 0; i < mp->filepos_count; i++)
-                    free ((char *) mp->filepos[i].file_name);
-                  mp->filepos_count = 0;
-                  free (mp->filepos);
-                  mp->filepos = NULL;
-                }
-              /* Mark as obsolete.   */
-              mp->obsolete = true;
+                  mp = message_copy (defmsg);
+                  /* Clear the extracted comments.  */
+                  if (mp->comment_dot != NULL)
+                    {
+                      string_list_free (mp->comment_dot);
+                      mp->comment_dot = NULL;
+                    }
+                  /* Clear the file position comments.  */
+                  if (mp->filepos != NULL)
+                    {
+                      size_t i;
 
-              message_list_append (msgdomain_list_sublist (result, domain, true),
-                                   mp);
-              stats.obsolete++;
+                      for (i = 0; i < mp->filepos_count; i++)
+                        free ((char *) mp->filepos[i].file_name);
+                      mp->filepos_count = 0;
+                      free (mp->filepos);
+                      mp->filepos = NULL;
+                    }
+                  /* Mark as obsolete.   */
+                  mp->obsolete = true;
+
+                  message_list_append (msgdomain_list_sublist (result, domain, true),
+                                       mp);
+                  stats.obsolete++;
+                }
             }
         }
     }
index 5a59e9979156b39be8dccfd8da12c255ecbd6c02..e8a4a8207eab3ca56e07b69ae80a55bbc9ef8173 100644 (file)
@@ -60,7 +60,7 @@ TESTS = gettext-1 gettext-2 \
        msgmerge-7 msgmerge-8 msgmerge-9 msgmerge-10 msgmerge-11 msgmerge-12 \
        msgmerge-13 msgmerge-14 msgmerge-15 msgmerge-16 msgmerge-17 \
        msgmerge-18 msgmerge-19 msgmerge-20 msgmerge-21 msgmerge-22 \
-       msgmerge-23 msgmerge-24 msgmerge-25 \
+       msgmerge-23 msgmerge-24 msgmerge-25 msgmerge-26 \
        msgmerge-compendium-1 msgmerge-compendium-2 msgmerge-compendium-3 \
        msgmerge-compendium-4 msgmerge-compendium-5 msgmerge-compendium-6 \
        msgmerge-properties-1 msgmerge-properties-2 \
diff --git a/gettext-tools/tests/msgmerge-26 b/gettext-tools/tests/msgmerge-26
new file mode 100755 (executable)
index 0000000..cd3862e
--- /dev/null
@@ -0,0 +1,79 @@
+#! /bin/sh
+. "${srcdir=.}/init.sh"; path_prepend_ . ../src
+
+# Test --for-msgfmt option.
+
+cat <<EOF > mm-test26.in1
+#: fruits.c:14
+msgid "cherry"
+msgstr "cerise"
+
+#: fruits.c:17
+msgid "pear"
+msgstr "poire"
+
+#: fruits.c:19
+msgid "orange"
+msgstr ""
+
+#, fuzzy
+#: fruits.c:20
+msgid "apple"
+msgstr "pommes"
+EOF
+
+cat <<EOF > mm-test26.in2
+# Fuzzy already in the PO file.
+#: fruits.c:10
+msgid "apple"
+msgstr ""
+
+# Fuzzy match to fuzzy already in the PO file.
+#: fruits.c:11
+msgid "apples"
+msgstr ""
+
+# Translated.
+#: fruits.c:16
+msgid "pear"
+msgstr ""
+
+# Fuzzy match.
+#: fruits.c:17
+msgid "pears"
+msgstr ""
+
+# Untranslated, in the PO file.
+#: fruits.c:18
+msgid "orange"
+msgstr ""
+
+# Untranslated, not in the PO file.
+#: fruits.c:20
+msgid "banana"
+msgstr ""
+
+# Translated already in the POT file.
+#: fruits.c:25
+msgid "papaya"
+msgstr "Papaya"
+EOF
+
+: ${MSGMERGE=msgmerge}
+${MSGMERGE} --for-msgfmt -o mm-test26.tmp mm-test26.in1 mm-test26.in2 \
+    || Exit 1
+LC_ALL=C tr -d '\r' < mm-test26.tmp > mm-test26.out || Exit 1
+
+cat << EOF > mm-test26.ok
+msgid "pear"
+msgstr "poire"
+
+msgid "papaya"
+msgstr "Papaya"
+EOF
+
+: ${DIFF=diff}
+${DIFF} mm-test26.ok mm-test26.out
+result=$?
+
+exit $result