]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
Extend the PO file syntax: Allow to store previous msgids.
authorBruno Haible <bruno@clisp.org>
Thu, 5 Oct 2006 11:24:13 +0000 (11:24 +0000)
committerBruno Haible <bruno@clisp.org>
Tue, 23 Jun 2009 10:14:05 +0000 (12:14 +0200)
29 files changed:
NEWS
gettext-tools/doc/ChangeLog
gettext-tools/doc/gettext.texi
gettext-tools/doc/msgattrib.texi
gettext-tools/doc/msgmerge.texi
gettext-tools/src/ChangeLog
gettext-tools/src/gettext-po.c
gettext-tools/src/message.c
gettext-tools/src/message.h
gettext-tools/src/msgattrib.c
gettext-tools/src/msgfmt.c
gettext-tools/src/msgl-ascii.c
gettext-tools/src/msgl-cat.c
gettext-tools/src/msgl-equal.c
gettext-tools/src/msgl-iconv.c
gettext-tools/src/msgmerge.c
gettext-tools/src/po-gram-gen.y
gettext-tools/src/po-lex.c
gettext-tools/src/read-po-abstract.c
gettext-tools/src/read-po-abstract.h
gettext-tools/src/read-po.c
gettext-tools/src/read-po.h
gettext-tools/src/read-properties.c
gettext-tools/src/read-stringtable.c
gettext-tools/src/write-po.c
gettext-tools/src/x-po.c
gettext-tools/src/xgettext.c
gettext-tools/tests/ChangeLog
gettext-tools/tests/Makefile.am

diff --git a/NEWS b/NEWS
index ace4acd5aa6458aae12c5c1f707aac35885ef164..e4805b4c0c1f4bada0d2615a300376840f86fba4 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,21 @@ Version 0.15.1 - October 2006
 
 * Interoperability with automake-1.10.
 
+* msgmerge has a new option --previous that has the effect of saving the
+  previous msgid of message when making them fuzzy. These previous msgids are
+  stored in the resulting PO file, using a pseudo-comment syntax like this:
+
+     #, fuzzy
+     #| msgid "too many arguments"
+     msgid "too few arguments"
+     msgstr "trop d'arguments"
+
+  The translator then only needs to compare the previous and the current
+  msgid ("too many arguments" and "too few arguments"), and infer which
+  parts of the translation she needs to change.
+
+  msgattrib has a new option --clear-previous that removes these #| lines.
+
 * msgmerge is faster now on CPUs with multiple execution units, if compiled
   with GCC 4.2 or newer.
 
index 0d6a6d3b086a94e2ecfed7fb77bab2329a2a5abb..a43dac95472f8b1dd724cc8788a34113dc96d4ec 100644 (file)
@@ -1,3 +1,9 @@
+2006-10-03  Bruno Haible  <bruno@clisp.org>
+
+       * gettext.texi (PO Files): Document the "previous msgid" syntax.
+       * msgmerge.texi: Document the --previous option.
+       * msgattrib.texi: Document the --clear-previous option.
+
 2006-10-03  Bruno Haible  <bruno@clisp.org>
 
        * msgcmp.texi: Document --use-fuzzy and --use-untranslated options.
index 25c85ce2d79e40db7e00ca2720a8ea5ea145e1ae..feeecb51ddc30cf7008ea7c4e1b3712866876e83 100644 (file)
@@ -1147,6 +1147,7 @@ structure:
 #. @var{extracted-comments}
 #: @var{reference}@dots{}
 #, @var{flag}@dots{}
+#| msgid @var{previous-untranslated-string}
 msgid @var{untranslated-string}
 msgstr @var{translated-string}
 @end example
@@ -1180,7 +1181,10 @@ at the translator; these comments are called @var{extracted comments}
 because the @code{xgettext} program extracts them from the program's
 source code.  Comment lines starting with @code{#:} contain references to
 the program's source code.  Comment lines starting with @code{#,} contain
-flags; more about these below.
+flags; more about these below.  Comment lines starting with @code{#|}
+contain the previous untranslated string for which the translator gave
+a translation.
+
 All comments, of either kind, are optional.
 
 @kwindex msgid
@@ -1372,6 +1376,8 @@ this:
 #. @var{extracted-comments}
 #: @var{reference}@dots{}
 #, @var{flag}@dots{}
+#| msgctxt @var{previous-context}
+#| msgid @var{previous-untranslated-string}
 msgctxt @var{context}
 msgid @var{untranslated-string}
 msgstr @var{translated-string}
@@ -1394,6 +1400,8 @@ plural forms.
 #. @var{extracted-comments}
 #: @var{reference}@dots{}
 #, @var{flag}@dots{}
+#| msgid @var{previous-untranslated-string-singular}
+#| msgid_plural @var{previous-untranslated-string-plural}
 msgid @var{untranslated-string-singular}
 msgid_plural @var{untranslated-string-plural}
 msgstr[0] @var{translated-string-case-0}
@@ -1415,6 +1423,11 @@ msgstr[1] "s'han trobat %d errors fatals"
 Here also, a @code{msgctxt} context can be specified before @code{msgid},
 like above.
 
+The @var{previous-untranslated-string} is optionally inserted by the
+@code{msgmerge} program, at the same time when it marks a message fuzzy.
+It helps the translator to see which changes were done by the developers
+on the @var{untranslated-string}.
+
 It happens that some lines, usually whitespace or comments, follow the
 very last entry of a PO file.  Such lines are not part of any entry,
 and will be dropped when the PO file is processed by the tools, or may
index 9baa603fbe7758898adc9b8dc0f67e3ca44715fd..596d6184f6b3b37cef153bced8b7c2b48fc26b97 100644 (file)
@@ -122,6 +122,10 @@ Set all messages obsolete.
 @opindex --clear-obsolete@r{, @code{msgattrib} option}
 Set all messages non-obsolete.
 
+@item --clear-previous
+@opindex --clear-previous@r{, @code{msgattrib} option}
+Remove the ``previous msgid'' (@samp{#|}) comments from all messages.
+
 @item --only-file=@var{file}
 @opindex --only-file@r{, @code{msgattrib} option}
 Limit the attribute changes to entries that are listed in @var{file}.
index 90dccd5b9c05598daab11abc5e96290ce3453529..874ecae498ba649aab15e16691dcff289f8dcebf 100644 (file)
@@ -126,6 +126,11 @@ Apply @var{ref}.pot to each of the domains in @var{def}.po.
 @opindex --no-fuzzy-matching@r{, @code{msgmerge} option}
 Do not use fuzzy matching when an exact match is not found.  This may speed
 up the operation considerably.
+
+@item --previous
+@opindex --previous@r{, @code{msgmerge} option}
+Keep the previous msgids of translated messages, marked with @samp{#|}, when
+adding the fuzzy marker to such messages.
 @end table
 
 @subsection Input file syntax
index fa3d520fb8424b41da30dc81fb49e8965fb14f73..d04f9c721848ab2243fcbab10784a88ecf1d6690 100644 (file)
@@ -1,3 +1,79 @@
+2006-10-03  Bruno Haible  <bruno@clisp.org>
+
+       * message.h (struct message_ty): New fields prev_msgctxt, prev_msgid,
+       prev_msgid_plural.
+       * message.c (message_alloc): Initialize the prev_msg* fields.
+       (message_free): Free the prev_msg* fields.
+       (message_copy): Copy the prev_msg* fields.
+       * msgl-ascii.c (is_ascii_message): Consider also the prev_msg* fields.
+       * msgl-cat.c (catenate_msgdomain_list): Copy the prev_msg* fields if
+       a message is copied, not merged.
+       * msgl-equal.c (message_equal): Consider also the prev_msg* fields.
+       * msgl-iconv.c (convert_prev_msgid): New function.
+       (iconv_message_list): Call it.
+       iconvable_prev_msgid): New function.
+       (is_message_list_iconvable): Call it.
+
+       * po-lex.c (po_lex_previous): New variable.
+       (lex_start, lex_end): Reset it.
+       (keyword_p): Test it. New return values PREV_MSGID, PREV_MSGID_PLURAL,
+       PREV_MSGCTXT.
+       (po_gram_lex): Recognize #| and #~| syntax. New return value
+       PREV_STRING.
+       * po-gram-gen.y (do_callback_message): Add prev_msgctxt, prev_msgid,
+       prev_msgid_plural arguments.
+       (free_message_intro): New macro.
+       (PREV_MSGCTXT, PREV_MSGID, PREV_MSGID_PLURAL, PREV_STRING): New tokens.
+       (prev, message_intro): New structures.
+       (po_file): Renamed from msgfmt.
+       (message): Pass prev_* fields around. Call free_message_intro.
+       (message_intro, prev): New rules.
+       (msg_intro): Renamed from message_intro.
+       (prev_msg_intro, prev_msgid_pluralform, prev_string_list): New rules.
+       * read-po-abstract.h (struct abstract_po_reader_class_ty): Add
+       prev_msgctxt, prev_msgid, prev_msgid_plural arguments to the
+       'directive_message' method.
+       (po_callback_message): Add prev_msgctxt, prev_msgid,
+       prev_msgid_plural arguments.
+       * read-po-abstract.c (call_directive_message, po_callback_message): Add
+       prev_msgctxt, prev_msgid, prev_msgid_plural arguments.
+       * read-po.h (struct default_po_reader_class_ty): Add prev_msgctxt,
+       prev_msgid, prev_msgid_plural arguments to the 'add_message' method.
+       (default_directive_message, default_add_message): Add prev_msgctxt,
+       prev_msgid, prev_msgid_plural arguments.
+       * read-po.c (call_add_message, default_directive_message,
+       default_add_message): Add prev_msgctxt, prev_msgid, prev_msgid_plural
+       arguments.
+       * read-properties.c (properties_parse): Update.
+       * read-stringtable.c (stringtable_parse): Update.
+       * xgettext.c (exclude_directive_message): Add prev_msgctxt, prev_msgid,
+       prev_msgid_plural arguments.
+       * x-po.c (extract_add_message): Add prev_msgctxt, prev_msgid,
+       prev_msgid_plural arguments.
+
+       * write-po.c (wrap): Add extra_indent argument.
+       (message_print, message_print_obsolete): Print the prev_msgctxt,
+       prev_msgid, prev_msgid_plural fields. Compute an extra_indent.
+
+       * msgmerge.c (keep_previous): New variable.
+       (long_options): Add --previous option.
+       (main): Handle it.
+       (usage): Document --previous option.
+       (message_merge): Add force_fuzzy argument. Set the new message's
+       prev_msg* fields.
+       (match_domain): Update.
+       * msgattrib.c (REMOVE_PREV): New enum item.
+       (long_options): Add --clear-previous option.
+       (main): Handle it.
+       (usage): Document --clear-previous option.
+       (process_message_list): Handle REMOVE_PREV.
+       * msgfmt.c (msgfmt_add_message): Add prev_msgctxt, prev_msgid,
+       prev_msgid_plural arguments.
+       * gettext-po.c (po_message_prev_msgctxt, po_message_set_prev_msgctxt,
+       po_message_prev_msgid, po_message_set_prev_msgid,
+       po_message_prev_msgid_plural, po_message_set_prev_msgid_plural): New
+       functions.
+
 2006-10-03  Bruno Haible  <bruno@clisp.org>
 
        * msgmerge.c (definitions_init): Fix initialization of fresh_lock.
index b17ec5a949e753d581e3f9c6c379748dd97e6610..597f14852fe9a7bd4937557e6ffcd73603894d99 100644 (file)
@@ -1,5 +1,5 @@
 /* Public API for GNU gettext PO files.
-   Copyright (C) 2003-2005 Free Software Foundation, Inc.
+   Copyright (C) 2003-2006 Free Software Foundation, Inc.
    Written by Bruno Haible <bruno@clisp.org>, 2003.
 
    This program is free software; you can redistribute it and/or modify
@@ -906,6 +906,98 @@ po_message_add_filepos (po_message_t message, const char *file, size_t start_lin
 }
 
 
+/* Return the previous context of a message, or NULL for none.  */
+
+const char *
+po_message_prev_msgctxt (po_message_t message)
+{
+  message_ty *mp = (message_ty *) message;
+
+  return mp->prev_msgctxt;
+}
+
+
+/* Change the previous context of a message.  NULL is allowed.  */
+
+void
+po_message_set_prev_msgctxt (po_message_t message, const char *prev_msgctxt)
+{
+  message_ty *mp = (message_ty *) message;
+
+  if (prev_msgctxt != mp->prev_msgctxt)
+    {
+      char *old_prev_msgctxt = (char *) mp->prev_msgctxt;
+
+      mp->prev_msgctxt = (prev_msgctxt != NULL ? xstrdup (prev_msgctxt) : NULL);
+      if (old_prev_msgctxt != NULL)
+       free (old_prev_msgctxt);
+    }
+}
+
+
+/* Return the previous msgid (untranslated English string) of a message, or
+   NULL for none.  */
+
+const char *
+po_message_prev_msgid (po_message_t message)
+{
+  message_ty *mp = (message_ty *) message;
+
+  return mp->prev_msgid;
+}
+
+
+/* Change the previous msgid (untranslated English string) of a message.
+   NULL is allowed.  */
+
+void
+po_message_set_prev_msgid (po_message_t message, const char *prev_msgid)
+{
+  message_ty *mp = (message_ty *) message;
+
+  if (prev_msgid != mp->prev_msgid)
+    {
+      char *old_prev_msgid = (char *) mp->prev_msgid;
+
+      mp->prev_msgid = (prev_msgid != NULL ? xstrdup (prev_msgid) : NULL);
+      if (old_prev_msgid != NULL)
+       free (old_prev_msgid);
+    }
+}
+
+
+/* Return the previous msgid_plural (untranslated English plural string) of a
+   message, or NULL for none.  */
+
+const char *
+po_message_prev_msgid_plural (po_message_t message)
+{
+  message_ty *mp = (message_ty *) message;
+
+  return mp->prev_msgid_plural;
+}
+
+
+/* Change the previous msgid_plural (untranslated English plural string) of a
+   message.  NULL is allowed.  */
+
+void
+po_message_set_prev_msgid_plural (po_message_t message, const char *prev_msgid_plural)
+{
+  message_ty *mp = (message_ty *) message;
+
+  if (prev_msgid_plural != mp->prev_msgid_plural)
+    {
+      char *old_prev_msgid_plural = (char *) mp->prev_msgid_plural;
+
+      mp->prev_msgid_plural =
+       (prev_msgid_plural != NULL ? xstrdup (prev_msgid_plural) : NULL);
+      if (old_prev_msgid_plural != NULL)
+       free (old_prev_msgid_plural);
+    }
+}
+
+
 /* Return true if the message is marked obsolete.  */
 
 int
index bc6350e2895776a11b080508ceb00807ac828216..1bf04511047041b438623bfeb1fad47af36d2a08 100644 (file)
@@ -117,6 +117,9 @@ message_alloc (const char *msgctxt,
   for (i = 0; i < NFORMATS; i++)
     mp->is_format[i] = undecided;
   mp->do_wrap = undecided;
+  mp->prev_msgctxt = NULL;
+  mp->prev_msgid = NULL;
+  mp->prev_msgid_plural = NULL;
   mp->used = 0;
   mp->obsolete = false;
   return mp;
@@ -140,6 +143,12 @@ message_free (message_ty *mp)
     free ((char *) mp->filepos[j].file_name);
   if (mp->filepos != NULL)
     free (mp->filepos);
+  if (mp->prev_msgctxt != NULL)
+    free ((char *) mp->prev_msgctxt);
+  if (mp->prev_msgid != NULL)
+    free ((char *) mp->prev_msgid);
+  if (mp->prev_msgid_plural != NULL)
+    free ((char *) mp->prev_msgid_plural);
   free (mp);
 }
 
@@ -217,6 +226,12 @@ message_copy (message_ty *mp)
       lex_pos_ty *pp = &mp->filepos[j];
       message_comment_filepos (result, pp->file_name, pp->line_number);
     }
+  result->prev_msgctxt =
+    (mp->prev_msgctxt != NULL ? xstrdup (mp->prev_msgctxt) : NULL);
+  result->prev_msgid =
+    (mp->prev_msgid != NULL ? xstrdup (mp->prev_msgid) : NULL);
+  result->prev_msgid_plural =
+    (mp->prev_msgid_plural != NULL ? xstrdup (mp->prev_msgid_plural) : NULL);
   return result;
 }
 
index 5a0730172071c86230f8f9c4dbd25cd3a777b870..1e04049ad0551905419cc22bf5d2ab7507b91b01 100644 (file)
@@ -137,6 +137,12 @@ struct message_ty
   /* Do we want the string to be wrapped in the emitted PO file?  */
   enum is_wrap do_wrap;
 
+  /* The prev_msgctxt, prev_msgid and prev_msgid_plural strings appearing
+     before the message, if present.  Generated by msgmerge.  */
+  const char *prev_msgctxt;
+  const char *prev_msgid;
+  const char *prev_msgid_plural;
+
   /* If set the message is obsolete and while writing out it should be
      commented out.  */
   bool obsolete;
index ad22c1b19fc015deea7408aecf9162676f959dd1..276ff098b32b8fe58aad00e26af216fa5956b3db 100644 (file)
@@ -65,7 +65,8 @@ enum
   SET_FUZZY            = 1 << 0,
   RESET_FUZZY          = 1 << 1,
   SET_OBSOLETE         = 1 << 2,
-  RESET_OBSOLETE       = 1 << 3
+  RESET_OBSOLETE       = 1 << 3,
+  REMOVE_PREV          = 1 << 4
 };
 static int to_change;
 
@@ -75,6 +76,7 @@ static const struct option long_options[] =
   { "add-location", no_argument, &line_comment, 1 },
   { "clear-fuzzy", no_argument, NULL, CHAR_MAX + 8 },
   { "clear-obsolete", no_argument, NULL, CHAR_MAX + 10 },
+  { "clear-previous", no_argument, NULL, CHAR_MAX + 18 },
   { "directory", required_argument, NULL, 'D' },
   { "escape", no_argument, NULL, 'E' },
   { "force-po", no_argument, &force_po, 1 },
@@ -300,6 +302,10 @@ main (int argc, char **argv)
        message_print_syntax_stringtable ();
        break;
 
+      case CHAR_MAX + 18: /* --clear-previous */
+       to_change |= REMOVE_PREV;
+       break;
+
       default:
        usage (EXIT_FAILURE);
        /* NOTREACHED */
@@ -430,6 +436,8 @@ Attribute manipulation:\n"));
       printf (_("\
       --clear-obsolete        set all messages non-obsolete\n"));
       printf (_("\
+      --clear-previous        remove the \"previous msgid\" from all messages\n"));
+      printf (_("\
       --only-file=FILE.po     manipulate only entries listed in FILE.po\n"));
       printf (_("\
       --ignore-file=FILE.po   manipulate only entries not listed in FILE.po\n"));
@@ -554,6 +562,12 @@ process_message_list (message_list_ty *mlp,
                mp->obsolete = true;
              if (to_change & RESET_OBSOLETE)
                mp->obsolete = false;
+             if (to_change & REMOVE_PREV)
+               {
+                 mp->prev_msgctxt = NULL;
+                 mp->prev_msgid = NULL;
+                 mp->prev_msgid_plural = NULL;
+               }
            }
        }
     }
index a181f71db81d4f78c811a6f3607af62d51d1e4f6..405e385f6cebd9f6740e2cd6190d27bd77768435 100644 (file)
@@ -936,6 +936,9 @@ msgfmt_add_message (default_po_reader_ty *this,
                    char *msgid_plural,
                    char *msgstr, size_t msgstr_len,
                    lex_pos_ty *msgstr_pos,
+                   char *prev_msgctxt,
+                   char *prev_msgid,
+                   char *prev_msgid_plural,
                    bool force_fuzzy, bool obsolete)
 {
   /* Check whether already a domain is specified.  If not, use default
@@ -951,7 +954,9 @@ msgfmt_add_message (default_po_reader_ty *this,
 
   /* Invoke superclass method.  */
   default_add_message (this, msgctxt, msgid, msgid_pos, msgid_plural,
-                      msgstr, msgstr_len, msgstr_pos, force_fuzzy, obsolete);
+                      msgstr, msgstr_len, msgstr_pos,
+                      prev_msgctxt, prev_msgid, prev_msgid_plural,
+                      force_fuzzy, obsolete);
 }
 
 
index d1e4bd3ea7ee3ea9c6171af16462754735609b57..1ba53d8def2fcff06d7636a9d8a816770564f996 100644 (file)
@@ -1,5 +1,5 @@
 /* Message list test for ASCII character set.
-   Copyright (C) 2001-2002, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2001-2002, 2005-2006 Free Software Foundation, Inc.
    Written by Bruno Haible <haible@clisp.cons.org>, 2001.
 
    This program is free software; you can redistribute it and/or modify
@@ -77,6 +77,14 @@ is_ascii_message (message_ty *mp)
   if (mp->msgctxt != NULL && !is_ascii_string (mp->msgctxt))
     return false;
 
+  /* Likewise for the prev_* fields.  */
+  if (mp->prev_msgctxt != NULL && !is_ascii_string (mp->prev_msgctxt))
+    return false;
+  if (mp->prev_msgid != NULL && !is_ascii_string (mp->prev_msgid))
+    return false;
+  if (mp->prev_msgid_plural != NULL && !is_ascii_string (mp->prev_msgid_plural))
+    return false;
+
   return true;
 }
 
index eed4a6e8af0662ddabea7d6b5fee1235d07fe295..241179cc1e9671f84460847973c610ea2f22d9a6 100644 (file)
@@ -524,6 +524,9 @@ UTF-8 encoded from the beginning, i.e. already in your source code files.\n"),
                  for (i = 0; i < NFORMATS; i++)
                    tmp->is_format[i] = mp->is_format[i];
                  tmp->do_wrap = mp->do_wrap;
+                 tmp->prev_msgctxt = mp->prev_msgctxt;
+                 tmp->prev_msgid = mp->prev_msgid;
+                 tmp->prev_msgid_plural = mp->prev_msgid_plural;
                  tmp->obsolete = mp->obsolete;
                }
              else if (msgcomm_mode)
@@ -535,6 +538,9 @@ UTF-8 encoded from the beginning, i.e. already in your source code files.\n"),
                      tmp->msgstr_len = mp->msgstr_len;
                      tmp->pos = mp->pos;
                      tmp->is_fuzzy = mp->is_fuzzy;
+                     tmp->prev_msgctxt = mp->prev_msgctxt;
+                     tmp->prev_msgid = mp->prev_msgid;
+                     tmp->prev_msgid_plural = mp->prev_msgid_plural;
                    }
                  if (mp->comment && tmp->comment == NULL)
                    for (i = 0; i < mp->comment->nitems; i++)
@@ -588,6 +594,7 @@ UTF-8 encoded from the beginning, i.e. already in your source code files.\n"),
                      tmp->is_format[i] = no;
                  if (mp->do_wrap == no)
                    tmp->do_wrap = no;
+                 /* Don't fill tmp->prev_msgid in this case.  */
                  if (!mp->obsolete)
                    tmp->obsolete = false;
                }
index 69a2602520436c77a96489104cbd84429c622e1b..3485709e0f11727c722ef91cd9a13d3be0faaf97 100644 (file)
@@ -1,5 +1,5 @@
 /* Message list test for equality.
-   Copyright (C) 2001-2002, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2001-2002, 2005-2006 Free Software Foundation, Inc.
    Written by Bruno Haible <haible@clisp.cons.org>, 2001.
 
    This program is free software; you can redistribute it and/or modify
@@ -181,6 +181,24 @@ message_equal (const message_ty *mp1, const message_ty *mp2,
     if (mp1->is_format[i] != mp2->is_format[i])
       return false;
 
+  if (!(mp1->prev_msgctxt != NULL
+       ? mp2->prev_msgctxt != NULL
+         && strcmp (mp1->prev_msgctxt, mp2->prev_msgctxt) == 0
+       : mp2->prev_msgctxt == NULL))
+    return false;
+
+  if (!(mp1->prev_msgid != NULL
+       ? mp2->prev_msgid != NULL
+         && strcmp (mp1->prev_msgid, mp2->prev_msgid) == 0
+       : mp2->prev_msgid == NULL))
+    return false;
+
+  if (!(mp1->prev_msgid_plural != NULL
+       ? mp2->prev_msgid_plural != NULL
+         && strcmp (mp1->prev_msgid_plural, mp2->prev_msgid_plural) == 0
+       : mp2->prev_msgid_plural == NULL))
+    return false;
+
   if (mp1->obsolete != mp2->obsolete)
     return false;
 
index 61afda8e6e6a9c54c7fdf187ee68e185b5bb5987..0a451c26034ff97190865da4eff2245071103f8e 100644 (file)
@@ -104,6 +104,18 @@ convert_string_list (iconv_t cd, string_list_ty *slp,
       slp->item[i] = convert_string (cd, slp->item[i], context);
 }
 
+static void
+convert_prev_msgid (iconv_t cd, message_ty *mp,
+                   const struct conversion_context* context)
+{
+  if (mp->prev_msgctxt != NULL)
+    mp->prev_msgctxt = convert_string (cd, mp->prev_msgctxt, context);
+  if (mp->prev_msgid != NULL)
+    mp->prev_msgid = convert_string (cd, mp->prev_msgid, context);
+  if (mp->prev_msgid_plural != NULL)
+    mp->prev_msgid_plural = convert_string (cd, mp->prev_msgid_plural, context);
+}
+
 static void
 convert_msgid (iconv_t cd, message_ty *mp,
               const struct conversion_context* context)
@@ -289,6 +301,7 @@ and iconv() does not support this conversion."),
          context.message = mp;
          convert_string_list (cd, mp->comment, &context);
          convert_string_list (cd, mp->comment_dot, &context);
+         convert_prev_msgid (cd, mp, &context);
          convert_msgid (cd, mp, &context);
          convert_msgstr (cd, mp, &context);
        }
@@ -371,6 +384,21 @@ iconvable_string_list (iconv_t cd, string_list_ty *slp)
   return true;
 }
 
+static bool
+iconvable_prev_msgid (iconv_t cd, message_ty *mp)
+{
+  if (mp->prev_msgctxt != NULL)
+    if (!iconvable_string (cd, mp->prev_msgctxt))
+      return false;
+  if (mp->prev_msgid != NULL)
+    if (!iconvable_string (cd, mp->prev_msgid))
+      return false;
+  if (mp->msgid_plural != NULL)
+    if (!iconvable_string (cd, mp->prev_msgid_plural))
+      return false;
+  return true;
+}
+
 static bool
 iconvable_msgid (iconv_t cd, message_ty *mp)
 {
@@ -524,6 +552,7 @@ is_message_list_iconvable (message_list_ty *mlp,
 
          if (!(iconvable_string_list (cd, mp->comment)
                && iconvable_string_list (cd, mp->comment_dot)
+               && iconvable_prev_msgid (cd, mp)
                && iconvable_msgid (cd, mp)
                && iconvable_msgstr (cd, mp)))
            return false;
index 11753387100f2a4f2c1547d0eb39038cfabb4d31..12725879a16a9e27745af14177c038881a5b863d 100644 (file)
@@ -80,6 +80,9 @@ static bool multi_domain_mode = false;
 /* Determines whether to use fuzzy matching.  */
 static bool use_fuzzy_matching = true;
 
+/* Determines whether to keep old msgids as previous msgids.  */
+static bool keep_previous = false;
+
 /* List of user-specified compendiums.  */
 static message_list_list_ty *compendiums;
 
@@ -108,6 +111,7 @@ static const struct option long_options[] =
   { "no-location", no_argument, &line_comment, 0 },
   { "no-wrap", no_argument, NULL, CHAR_MAX + 4 },
   { "output-file", required_argument, NULL, 'o' },
+  { "previous", no_argument, NULL, CHAR_MAX + 7 },
   { "properties-input", no_argument, NULL, 'P' },
   { "properties-output", no_argument, NULL, 'p' },
   { "quiet", no_argument, NULL, 'q' },
@@ -293,6 +297,10 @@ main (int argc, char **argv)
        message_print_syntax_stringtable ();
        break;
 
+      case CHAR_MAX + 7: /* --previous */
+       keep_previous = true;
+       break;
+
       default:
        usage (EXIT_FAILURE);
        break;
@@ -503,6 +511,8 @@ Operation modifiers:\n"));
   -m, --multi-domain          apply ref.pot to each of the domains in def.po\n"));
       printf (_("\
   -N, --no-fuzzy-matching     do not use fuzzy matching\n"));
+      printf (_("\
+      --previous              keep previous msgids of translated messages\n"));
       printf ("\n");
       printf (_("\
 Input file syntax:\n"));
@@ -758,10 +768,13 @@ msgfmt_check_pair_fails (const lex_pos_ty *pos,
 
 
 static message_ty *
-message_merge (message_ty *def, message_ty *ref)
+message_merge (message_ty *def, message_ty *ref, bool force_fuzzy)
 {
   const char *msgstr;
   size_t msgstr_len;
+  const char *prev_msgctxt;
+  const char *prev_msgid;
+  const char *prev_msgid_plural;
   message_ty *result;
   size_t j, i;
 
@@ -968,11 +981,28 @@ message_merge (message_ty *def, message_ty *ref)
 
       msgstr = cp;
       msgstr_len = strlen (cp) + 1;
+
+      prev_msgctxt = NULL;
+      prev_msgid = NULL;
+      prev_msgid_plural = NULL;
     }
   else
     {
       msgstr = def->msgstr;
       msgstr_len = def->msgstr_len;
+
+      if (def->is_fuzzy)
+       {
+         prev_msgctxt = def->prev_msgctxt;
+         prev_msgid = def->prev_msgid;
+         prev_msgid_plural = def->prev_msgid_plural;
+       }
+      else
+       {
+         prev_msgctxt = def->msgctxt;
+         prev_msgid = def->msgid;
+         prev_msgid_plural = def->msgid_plural;
+       }
     }
 
   result = message_alloc (ref->msgctxt != NULL ? xstrdup (ref->msgctxt) : NULL,
@@ -995,7 +1025,7 @@ message_merge (message_ty *def, message_ty *ref)
   /* The flags are mixed in a special way.  Some informations come
      from the reference message (such as format/no-format), others
      come from the definition file (fuzzy or not).  */
-  result->is_fuzzy = def->is_fuzzy;
+  result->is_fuzzy = def->is_fuzzy | force_fuzzy;
 
   for (i = 0; i < NFORMATS; i++)
     {
@@ -1018,6 +1048,21 @@ message_merge (message_ty *def, message_ty *ref)
 
   result->do_wrap = ref->do_wrap;
 
+  /* Insert previous msgid, commented out with "#|".
+     Do so only when --previous is specified, for backward compatibility.
+     Since the "previous msgid" represents the original msgid that led to
+     the current msgstr,
+       - we can omit it if the resulting message is not fuzzy,
+       - otherwise, if the corresponding message from the definition file
+         was translated (not fuzzy), we use that message's msgid,
+       - otherwise, we use that message's prev_msgid.  */
+  if (keep_previous && result->is_fuzzy)
+    {
+      result->prev_msgctxt = prev_msgctxt;
+      result->prev_msgid = prev_msgid;
+      result->prev_msgid_plural = prev_msgid_plural;
+    }
+
   /* Take the file position comments from the reference file, as they
      are generated by xgettext.  Any in the definition file are old ones
      collected by previous runs of xgettext and msgmerge.  */
@@ -1135,7 +1180,7 @@ match_domain (const char *fn1, const char *fn2,
             #: comments from the reference, take the # comments from
             the definition, take the msgstr from the definition.  Add
             this merged entry to the output message list.  */
-         message_ty *mp = message_merge (defmsg, refmsg);
+         message_ty *mp = message_merge (defmsg, refmsg, false);
 
          message_list_append (resultmlp, mp);
 
@@ -1168,9 +1213,7 @@ this message is used but not defined..."));
                 #: comments from the reference, take the # comments from
                 the definition, take the msgstr from the definition.  Add
                 this merged entry to the output message list.  */
-             mp = message_merge (defmsg, refmsg);
-
-             mp->is_fuzzy = true;
+             mp = message_merge (defmsg, refmsg, true);
 
              message_list_append (resultmlp, mp);
 
index 042db110055fa06888bb86b7b33ddd7c91515205..145f2735127d8a40d7b499b61ee69afa4c34f88f 100644 (file)
@@ -1,5 +1,5 @@
 /* GNU gettext - internationalization aids
-   Copyright (C) 1995-1996, 1998, 2000-2001, 2003, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1995-1996, 1998, 2000-2001, 2003, 2005-2006 Free Software Foundation, Inc.
 
    This file was written by Peter Miller <pmiller@agso.gov.au>
 
@@ -97,6 +97,8 @@ static inline void
 do_callback_message (char *msgctxt,
                     char *msgid, lex_pos_ty *msgid_pos, char *msgid_plural,
                     char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos,
+                    char *prev_msgctxt,
+                    char *prev_msgid, char *prev_msgid_plural,
                     bool obsolete)
 {
   /* Test for header entry.  Ignore fuzziness of the header entry.  */
@@ -106,14 +108,29 @@ do_callback_message (char *msgctxt,
   po_callback_message (msgctxt,
                       msgid, msgid_pos, msgid_plural,
                       msgstr, msgstr_len, msgstr_pos,
+                      prev_msgctxt, prev_msgid, prev_msgid_plural,
                       false, obsolete);
 }
 
+#define free_message_intro(value) \
+  if ((value).prev_ctxt != NULL)       \
+    free ((value).prev_ctxt);          \
+  if ((value).prev_id != NULL)         \
+    free ((value).prev_id);            \
+  if ((value).prev_id_plural != NULL)  \
+    free ((value).prev_id_plural);     \
+  if ((value).ctxt != NULL)            \
+    free ((value).ctxt);
+
 %}
 
 %token COMMENT
 %token DOMAIN
 %token JUNK
+%token PREV_MSGCTXT
+%token PREV_MSGID
+%token PREV_MSGID_PLURAL
+%token PREV_STRING
 %token MSGCTXT
 %token MSGID
 %token MSGID_PLURAL
@@ -129,27 +146,43 @@ do_callback_message (char *msgctxt,
   struct { string_list_ty stringlist; lex_pos_ty pos; bool obsolete; } stringlist;
   struct { long number; lex_pos_ty pos; bool obsolete; } number;
   struct { lex_pos_ty pos; bool obsolete; } pos;
+  struct { char *ctxt; char *id; char *id_plural; lex_pos_ty pos; bool obsolete; } prev;
+  struct { char *prev_ctxt; char *prev_id; char *prev_id_plural; char *ctxt; lex_pos_ty pos; bool obsolete; } message_intro;
   struct { struct msgstr_def rhs; lex_pos_ty pos; bool obsolete; } rhs;
 }
 
-%type <string> STRING COMMENT NAME message_intro msgid_pluralform
-%type <stringlist> string_list
+%type <string> STRING PREV_STRING COMMENT NAME
+               msg_intro prev_msg_intro msgid_pluralform prev_msgid_pluralform
+%type <stringlist> string_list prev_string_list
 %type <number> NUMBER
-%type <pos> DOMAIN MSGCTXT MSGID MSGID_PLURAL MSGSTR '[' ']'
+%type <pos> DOMAIN
+            PREV_MSGCTXT PREV_MSGID PREV_MSGID_PLURAL
+            MSGCTXT MSGID MSGID_PLURAL MSGSTR '[' ']'
+%type <prev> prev
+%type <message_intro> message_intro
 %type <rhs> pluralform pluralform_list
 
 %right MSGSTR
 
 %%
 
-msgfmt
+po_file
        : /* empty */
-       | msgfmt comment
-       | msgfmt domain
-       | msgfmt message
-       | msgfmt error
+       | po_file comment
+       | po_file domain
+       | po_file message
+       | po_file error
+       ;
+
+
+comment
+       : COMMENT
+               {
+                 po_callback_comment_dispatcher ($1.string);
+               }
        ;
 
+
 domain
        : DOMAIN STRING
                {
@@ -157,6 +190,7 @@ domain
                }
        ;
 
+
 message
        : message_intro string_list MSGSTR string_list
                {
@@ -167,11 +201,14 @@ message
                  check_obsolete ($1, $3);
                  check_obsolete ($1, $4);
                  if (!$1.obsolete || pass_obsolete_entries)
-                   do_callback_message ($1.string, string2, &$1.pos, NULL,
+                   do_callback_message ($1.ctxt, string2, &$1.pos, NULL,
                                         string4, strlen (string4) + 1, &$3.pos,
+                                        $1.prev_ctxt,
+                                        $1.prev_id, $1.prev_id_plural,
                                         $1.obsolete);
                  else
                    {
+                     free_message_intro ($1);
                      free (string2);
                      free (string4);
                    }
@@ -184,11 +221,14 @@ message
                  check_obsolete ($1, $3);
                  check_obsolete ($1, $4);
                  if (!$1.obsolete || pass_obsolete_entries)
-                   do_callback_message ($1.string, string2, &$1.pos, $3.string,
+                   do_callback_message ($1.ctxt, string2, &$1.pos, $3.string,
                                         $4.rhs.msgstr, $4.rhs.msgstr_len, &$4.pos,
+                                        $1.prev_ctxt,
+                                        $1.prev_id, $1.prev_id_plural,
                                         $1.obsolete);
                  else
                    {
+                     free_message_intro ($1);
                      free (string2);
                      free ($3.string);
                      free ($4.rhs.msgstr);
@@ -199,6 +239,7 @@ message
                  check_obsolete ($1, $2);
                  check_obsolete ($1, $3);
                  po_gram_error_at_line (&$1.pos, _("missing `msgstr[]' section"));
+                 free_message_intro ($1);
                  string_list_destroy (&$2.stringlist);
                  free ($3.string);
                }
@@ -207,6 +248,7 @@ message
                  check_obsolete ($1, $2);
                  check_obsolete ($1, $3);
                  po_gram_error_at_line (&$1.pos, _("missing `msgid_plural' section"));
+                 free_message_intro ($1);
                  string_list_destroy (&$2.stringlist);
                  free ($3.rhs.msgstr);
                }
@@ -214,11 +256,59 @@ message
                {
                  check_obsolete ($1, $2);
                  po_gram_error_at_line (&$1.pos, _("missing `msgstr' section"));
+                 free_message_intro ($1);
                  string_list_destroy (&$2.stringlist);
                }
        ;
 
+
 message_intro
+       : msg_intro
+               {
+                 $$.prev_ctxt = NULL;
+                 $$.prev_id = NULL;
+                 $$.prev_id_plural = NULL;
+                 $$.ctxt = $1.string;
+                 $$.pos = $1.pos;
+                 $$.obsolete = $1.obsolete;
+               }
+       | prev msg_intro
+               {
+                 check_obsolete ($1, $2);
+                 $$.prev_ctxt = $1.ctxt;
+                 $$.prev_id = $1.id;
+                 $$.prev_id_plural = $1.id_plural;
+                 $$.ctxt = $2.string;
+                 $$.pos = $2.pos;
+                 $$.obsolete = $2.obsolete;
+               }
+       ;
+
+
+prev
+       : prev_msg_intro prev_string_list
+               {
+                 check_obsolete ($1, $2);
+                 $$.ctxt = $1.string;
+                 $$.id = string_list_concat_destroy (&$2.stringlist);
+                 $$.id_plural = NULL;
+                 $$.pos = $1.pos;
+                 $$.obsolete = $1.obsolete;
+               }
+       | prev_msg_intro prev_string_list prev_msgid_pluralform
+               {
+                 check_obsolete ($1, $2);
+                 check_obsolete ($1, $3);
+                 $$.ctxt = $1.string;
+                 $$.id = string_list_concat_destroy (&$2.stringlist);
+                 $$.id_plural = $3.string;
+                 $$.pos = $1.pos;
+                 $$.obsolete = $1.obsolete;
+               }
+       ;
+
+
+msg_intro
        : MSGID
                {
                  $$.string = NULL;
@@ -235,6 +325,24 @@ message_intro
                }
        ;
 
+prev_msg_intro
+       : PREV_MSGID
+               {
+                 $$.string = NULL;
+                 $$.pos = $1.pos;
+                 $$.obsolete = $1.obsolete;
+               }
+       | PREV_MSGCTXT prev_string_list PREV_MSGID
+               {
+                 check_obsolete ($1, $2);
+                 check_obsolete ($1, $3);
+                 $$.string = string_list_concat_destroy (&$2.stringlist);
+                 $$.pos = $3.pos;
+                 $$.obsolete = $3.obsolete;
+               }
+       ;
+
+
 msgid_pluralform
        : MSGID_PLURAL string_list
                {
@@ -246,6 +354,17 @@ msgid_pluralform
                }
        ;
 
+prev_msgid_pluralform
+       : PREV_MSGID_PLURAL prev_string_list
+               {
+                 check_obsolete ($1, $2);
+                 $$.string = string_list_concat_destroy (&$2.stringlist);
+                 $$.pos = $1.pos;
+                 $$.obsolete = $1.obsolete;
+               }
+       ;
+
+
 pluralform_list
        : pluralform
                {
@@ -287,6 +406,7 @@ pluralform
                }
        ;
 
+
 string_list
        : STRING
                {
@@ -305,9 +425,20 @@ string_list
                }
        ;
 
-comment
-       : COMMENT
+prev_string_list
+       : PREV_STRING
                {
-                 po_callback_comment_dispatcher ($1.string);
+                 string_list_init (&$$.stringlist);
+                 string_list_append (&$$.stringlist, $1.string);
+                 $$.pos = $1.pos;
+                 $$.obsolete = $1.obsolete;
+               }
+       | prev_string_list PREV_STRING
+               {
+                 check_obsolete ($1, $2);
+                 $$.stringlist = $1.stringlist;
+                 string_list_append (&$$.stringlist, $2.string);
+                 $$.pos = $1.pos;
+                 $$.obsolete = $1.obsolete;
                }
        ;
index c57786430a188f08b26fd60831aad774710f33fb..e806e9e886076d4dc6621d4afdc7c3930f9b5a6d 100644 (file)
@@ -602,6 +602,7 @@ mbfile_ungetc (const mbchar_t mbc, mbfile_t mbf)
 static mbfile_t mbf;
 unsigned int gram_max_allowed_errors = 20;
 static bool po_lex_obsolete;
+static bool po_lex_previous;
 static bool pass_comments = false;
 bool pass_obsolete_entries = false;
 
@@ -620,6 +621,7 @@ lex_start (FILE *fp, const char *real_filename, const char *logical_filename)
   gram_pos_column = 0;
   signal_eilseq = true;
   po_lex_obsolete = false;
+  po_lex_previous = false;
   po_lex_charset_init ();
 }
 
@@ -633,6 +635,7 @@ lex_end ()
   gram_pos_column = 0;
   signal_eilseq = false;
   po_lex_obsolete = false;
+  po_lex_previous = false;
   po_lex_charset_close ();
 }
 
@@ -718,16 +721,29 @@ lex_ungetc (const mbchar_t mbc)
 static int
 keyword_p (const char *s)
 {
-  if (!strcmp (s, "domain"))
-    return DOMAIN;
-  if (!strcmp (s, "msgid"))
-    return MSGID;
-  if (!strcmp (s, "msgid_plural"))
-    return MSGID_PLURAL;
-  if (!strcmp (s, "msgstr"))
-    return MSGSTR;
-  if (!strcmp (s, "msgctxt"))
-    return MSGCTXT;
+  if (!po_lex_previous)
+    {
+      if (!strcmp (s, "domain"))
+       return DOMAIN;
+      if (!strcmp (s, "msgid"))
+       return MSGID;
+      if (!strcmp (s, "msgid_plural"))
+       return MSGID_PLURAL;
+      if (!strcmp (s, "msgstr"))
+       return MSGSTR;
+      if (!strcmp (s, "msgctxt"))
+       return MSGCTXT;
+    }
+  else
+    {
+      /* Inside a "#|" context, the keywords have a different meaning.  */
+      if (!strcmp (s, "msgid"))
+       return PREV_MSGID;
+      if (!strcmp (s, "msgid_plural"))
+       return PREV_MSGID_PLURAL;
+      if (!strcmp (s, "msgctxt"))
+       return PREV_MSGCTXT;
+    }
   po_gram_error_at_line (&gram_pos, _("keyword \"%s\" unknown"), s);
   return NAME;
 }
@@ -866,6 +882,7 @@ po_gram_lex ()
          {
          case '\n':
            po_lex_obsolete = false;
+           po_lex_previous = false;
            /* Ignore whitespace, not relevant for the grammar.  */
            break;
 
@@ -886,6 +903,24 @@ po_gram_lex ()
                 characters are expected to be well formed.  */
              {
                po_lex_obsolete = true;
+               /* A pseudo-comment beginning with #~| denotes a previous
+                  untranslated string in an obsolete entry.  This does not
+                  make much sense semantically, and is implemented here
+                  for completeness only.  */
+               lex_getc (mbc);
+               if (mb_iseq (mbc, '|'))
+                 po_lex_previous = true;
+               else
+                 lex_ungetc (mbc);
+               break;
+             }
+           if (mb_iseq (mbc, '|'))
+             /* A pseudo-comment beginning with #| is found.  This is
+                the previous untranslated string.  We discard the "#|"
+                prefix, but change the keywords and string returns
+                accordingly.  */
+             {
+               po_lex_previous = true;
                break;
              }
 
@@ -924,7 +959,7 @@ po_gram_lex ()
              {
                /* We do this in separate loop because collecting large
                   comments while they get not passed to the upper layers
-                  is not very effective.  */
+                  is not very efficient.  */
                while (!mb_iseof (mbc) && !mb_iseq (mbc, '\n'))
                  lex_getc (mbc);
                po_lex_obsolete = false;
@@ -979,7 +1014,7 @@ po_gram_lex ()
            po_gram_lval.string.string = xstrdup (buf);
            po_gram_lval.string.pos = gram_pos;
            po_gram_lval.string.obsolete = po_lex_obsolete;
-           return STRING;
+           return (po_lex_previous ? PREV_STRING : STRING);
 
          case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
          case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
index b3c2790ca600213fc623662f182152f452ca8dc1..c330b4d176e6ea30fedcf39192329d635675eb73 100644 (file)
@@ -99,12 +99,18 @@ call_directive_message (abstract_po_reader_ty *pop,
                        char *msgid_plural,
                        char *msgstr, size_t msgstr_len,
                        lex_pos_ty *msgstr_pos,
+                       char *prev_msgctxt,
+                       char *prev_msgid,
+                       char *prev_msgid_plural,
                        bool force_fuzzy, bool obsolete)
 {
   if (pop->methods->directive_message)
     pop->methods->directive_message (pop, msgctxt,
                                     msgid, msgid_pos, msgid_plural,
                                     msgstr, msgstr_len, msgstr_pos,
+                                    prev_msgctxt,
+                                    prev_msgid,
+                                    prev_msgid_plural,
                                     force_fuzzy, obsolete);
 }
 
@@ -221,12 +227,16 @@ void
 po_callback_message (char *msgctxt,
                     char *msgid, lex_pos_ty *msgid_pos, char *msgid_plural,
                     char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos,
+                    char *prev_msgctxt,
+                    char *prev_msgid,
+                    char *prev_msgid_plural,
                     bool force_fuzzy, bool obsolete)
 {
   /* assert(callback_arg); */
   call_directive_message (callback_arg, msgctxt,
                          msgid, msgid_pos, msgid_plural,
                          msgstr, msgstr_len, msgstr_pos,
+                         prev_msgctxt, prev_msgid, prev_msgid_plural,
                          force_fuzzy, obsolete);
 }
 
index 8026bffd1ed42ab71be8cb6e775f67a1d753cca0..f3c9a323bce751d7cf90e6bf968b6f0fba8dab0c 100644 (file)
@@ -1,5 +1,5 @@
 /* Reading PO files, abstract class.
-   Copyright (C) 1995-1996, 1998, 2000-2003, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1995-1996, 1998, 2000-2003, 2005-2006 Free Software Foundation, Inc.
 
    This file was written by Peter Miller <millerp@canb.auug.org.au>
 
@@ -80,6 +80,8 @@ struct abstract_po_reader_class_ty
                             char *msgid_plural,
                             char *msgstr, size_t msgstr_len,
                             lex_pos_ty *msgstr_pos,
+                            char *prev_msgctxt,
+                            char *prev_msgid, char *prev_msgid_plural,
                             bool force_fuzzy, bool obsolete);
 
   /* What to do with a plain-vanilla comment - the expectation is that
@@ -159,6 +161,8 @@ extern void po_callback_message (char *msgctxt,
                                 char *msgid_plural,
                                 char *msgstr, size_t msgstr_len,
                                 lex_pos_ty *msgstr_pos,
+                                char *prev_msgctxt,
+                                char *prev_msgid, char *prev_msgid_plural,
                                 bool force_fuzzy, bool obsolete);
 extern void po_callback_comment (const char *s);
 extern void po_callback_comment_dot (const char *s);
index 4fea79b15963e1c176ece3840550bb442030814b..2ea14187d10abee1601cbc834d7b45f8d33a1aae 100644 (file)
@@ -1,5 +1,5 @@
 /* Reading PO files.
-   Copyright (C) 1995-1998, 2000-2003, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1995-1998, 2000-2003, 2005-2006 Free Software Foundation, Inc.
    This file was written by Peter Miller <millerp@canb.auug.org.au>
 
    This program is free software; you can redistribute it and/or modify
@@ -54,6 +54,7 @@ call_add_message (struct default_po_reader_ty *this,
                  char *msgctxt,
                  char *msgid, lex_pos_ty *msgid_pos, char *msgid_plural,
                  char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos,
+                 char *prev_msgctxt, char *prev_msgid, char *prev_msgid_plural,
                  bool force_fuzzy, bool obsolete)
 {
   default_po_reader_class_ty *methods =
@@ -63,6 +64,7 @@ call_add_message (struct default_po_reader_ty *this,
     methods->add_message (this, msgctxt,
                          msgid, msgid_pos, msgid_plural,
                          msgstr, msgstr_len, msgstr_pos,
+                         prev_msgctxt, prev_msgid, prev_msgid_plural,
                          force_fuzzy, obsolete);
 }
 
@@ -236,12 +238,16 @@ default_directive_message (abstract_po_reader_ty *that,
                           char *msgid_plural,
                           char *msgstr, size_t msgstr_len,
                           lex_pos_ty *msgstr_pos,
+                          char *prev_msgctxt,
+                          char *prev_msgid, char *prev_msgid_plural,
                           bool force_fuzzy, bool obsolete)
 {
   default_po_reader_ty *this = (default_po_reader_ty *) that;
 
   call_add_message (this, msgctxt, msgid, msgid_pos, msgid_plural,
-                   msgstr, msgstr_len, msgstr_pos, force_fuzzy, obsolete);
+                   msgstr, msgstr_len, msgstr_pos,
+                   prev_msgctxt, prev_msgid, prev_msgid_plural,
+                   force_fuzzy, obsolete);
 
   /* Prepare for next message.  */
   default_reset_comment_state (this);
@@ -334,6 +340,9 @@ default_add_message (default_po_reader_ty *this,
                     char *msgid_plural,
                     char *msgstr, size_t msgstr_len,
                     lex_pos_ty *msgstr_pos,
+                    char *prev_msgctxt,
+                    char *prev_msgid,
+                    char *prev_msgid_plural,
                     bool force_fuzzy, bool obsolete)
 {
   message_ty *mp;
@@ -367,10 +376,18 @@ default_add_message (default_po_reader_ty *this,
        }
       /* We don't need the just constructed entries' parameter string
         (allocated in po-gram-gen.y).  */
-      free (msgstr);
       free (msgid);
+      if (msgid_plural != NULL)
+       free (msgid_plural);
+      free (msgstr);
       if (msgctxt != NULL)
        free (msgctxt);
+      if (prev_msgctxt != NULL)
+       free (prev_msgctxt);
+      if (prev_msgid != NULL)
+       free (prev_msgid);
+      if (prev_msgid_plural != NULL)
+       free (prev_msgid_plural);
 
       /* Add the accumulated comments to the message.  */
       default_copy_comment_state (this, mp);
@@ -383,6 +400,9 @@ default_add_message (default_po_reader_ty *this,
         appropriate.  */
       mp = message_alloc (msgctxt, msgid, msgid_plural, msgstr, msgstr_len,
                          msgstr_pos);
+      mp->prev_msgctxt = prev_msgctxt;
+      mp->prev_msgid = prev_msgid;
+      mp->prev_msgid_plural = prev_msgid_plural;
       mp->obsolete = obsolete;
       default_copy_comment_state (this, mp);
       if (force_fuzzy)
index c1065a1c274916d9e5649489b6bdbb51663cf2eb..268de395be3dabefd1e8e0a57cc0320c27d322a9 100644 (file)
@@ -1,5 +1,5 @@
 /* Reading PO files.
-   Copyright (C) 1995-1998, 2000-2003, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1995-1998, 2000-2003, 2005-2006 Free Software Foundation, Inc.
    This file was written by Bruno Haible <haible@clisp.cons.org>.
 
    This program is free software; you can redistribute it and/or modify
@@ -59,6 +59,9 @@ struct default_po_reader_class_ty
                       char *msgctxt,
                       char *msgid, lex_pos_ty *msgid_pos, char *msgid_plural,
                       char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos,
+                      char *prev_msgctxt,
+                      char *prev_msgid,
+                      char *prev_msgid_plural,
                       bool force_fuzzy, bool obsolete);
 
   /* How to modify a new message before adding it to the list.  */
@@ -129,6 +132,9 @@ extern void default_directive_message (abstract_po_reader_ty *that,
                                       char *msgid_plural,
                                       char *msgstr, size_t msgstr_len,
                                       lex_pos_ty *msgstr_pos,
+                                      char *prev_msgctxt,
+                                      char *prev_msgid,
+                                      char *prev_msgid_plural,
                                       bool force_fuzzy, bool obsolete);
 extern void default_comment (abstract_po_reader_ty *that, const char *s);
 extern void default_comment_dot (abstract_po_reader_ty *that, const char *s);
@@ -144,6 +150,9 @@ extern void default_add_message (default_po_reader_ty *this,
                                 char *msgid_plural,
                                 char *msgstr, size_t msgstr_len,
                                 lex_pos_ty *msgstr_pos,
+                                char *prev_msgctxt,
+                                char *prev_msgid,
+                                char *prev_msgid_plural,
                                 bool force_fuzzy, bool obsolete);
 
 /* Allocate a fresh default_po_reader_ty (or derived class) instance and
index c08839cb5fde96694562e66475e2575cb8a85b32..755627551dc6d57f946454f709479381f0b9b371 100644 (file)
@@ -538,6 +538,7 @@ properties_parse (abstract_po_reader_ty *this, FILE *file,
 
              po_callback_message (NULL, msgid, &msgid_pos, NULL,
                                   msgstr, strlen (msgstr) + 1, &msgstr_pos,
+                                  NULL, NULL, NULL,
                                   force_fuzzy, false);
            }
        }
index 1565ed39732c092c3b23e8c5b2712353e0050527..1228f3c7f3c99764a7b0470d80a9585388082c31 100644 (file)
@@ -881,6 +881,7 @@ stringtable_parse (abstract_po_reader_ty *pop, FILE *file,
          msgstr_pos = msgid_pos;
          po_callback_message (NULL, msgid, &msgid_pos, NULL,
                               msgstr, strlen (msgstr) + 1, &msgstr_pos,
+                              NULL, NULL, NULL,
                               false, next_is_obsolete);
        }
       else if (c == '=')
@@ -930,6 +931,7 @@ stringtable_parse (abstract_po_reader_ty *pop, FILE *file,
              /* A key/value pair.  */
              po_callback_message (NULL, msgid, &msgid_pos, NULL,
                                   msgstr, strlen (msgstr) + 1, &msgstr_pos,
+                                  NULL, NULL, NULL,
                                   false, next_is_obsolete);
            }
          else
index 1c474de49bbc79066247d6802bb4006a269be840..de35b7b9f2190618649e2c06fa61a5e196ec249b 100644 (file)
@@ -418,7 +418,7 @@ memcpy_small (void *dst, const void *src, size_t n)
 
 
 static void
-wrap (const message_ty *mp, FILE *fp, const char *line_prefix,
+wrap (const message_ty *mp, FILE *fp, const char *line_prefix, int extra_indent,
       const char *name, const char *value, enum is_wrap do_wrap,
       const char *charset)
 {
@@ -711,7 +711,7 @@ internationalized messages should not contain the `\\%c' escape sequence"),
         See INDENT-S.  */
       startcol_after_break = (line_prefix ? strlen (line_prefix) : 0);
       if (indent)
-       startcol_after_break = (startcol_after_break + 8) & ~7;
+       startcol_after_break = (startcol_after_break + extra_indent + 8) & ~7;
       startcol_after_break++;
 
       /* The line width.  Allow room for the closing quote character.  */
@@ -728,14 +728,14 @@ internationalized messages should not contain the `\\%c' escape sequence"),
        {
          startcol += strlen (name);
          if (indent)
-           startcol = (startcol + 8) & ~7;
+           startcol = (startcol + extra_indent + 8) & ~7;
          else
            startcol++;
        }
       else
        {
          if (indent)
-           startcol = (startcol + 8) & ~7;
+           startcol = (startcol + extra_indent + 8) & ~7;
        }
       /* Allow room for the opening quote character.  */
       startcol++;
@@ -772,13 +772,24 @@ internationalized messages should not contain the `\\%c' escape sequence"),
       if (first_line)
        {
          fputs (name, fp);
-         putc (indent ? '\t' : ' ', fp);
+         if (indent)
+           {
+             if (extra_indent > 0)
+               fwrite ("        ", 1, extra_indent, fp);
+             putc ('\t', fp);
+           }
+         else
+           putc (' ', fp);
          first_line = false;
        }
       else
        {
          if (indent)
-           putc ('\t', fp);
+           {
+             if (extra_indent > 0)
+               fwrite ("        ", 1, extra_indent, fp);
+             putc ('\t', fp);
+           }
        }
 
       /* Print the portion itself, with linebreaks where necessary.  */
@@ -829,6 +840,8 @@ static void
 message_print (const message_ty *mp, FILE *fp, const char *charset,
               bool blank_line, bool debug)
 {
+  int extra_indent;
+
   /* Separate messages with a blank line.  Uniforum doesn't like blank
      lines, so use an empty comment (unless there already is one).  */
   if (blank_line && (!uniforum
@@ -851,6 +864,20 @@ message_print (const message_ty *mp, FILE *fp, const char *charset,
   /* Print flag information in special comment.  */
   message_print_comment_flags (mp, fp, debug);
 
+  /* Print the previous msgid.  This helps the translator when the msgid has
+     only slightly changed.  */
+  if (mp->prev_msgctxt != NULL)
+    wrap (mp, fp, "#| ", 0, "msgctxt", mp->prev_msgctxt, mp->do_wrap, charset);
+  if (mp->prev_msgid != NULL)
+    wrap (mp, fp, "#| ", 0, "msgid", mp->prev_msgid, mp->do_wrap, charset);
+  if (mp->prev_msgid_plural != NULL)
+    wrap (mp, fp, "#| ", 0, "msgid_plural", mp->prev_msgid_plural, mp->do_wrap,
+         charset);
+  extra_indent = (mp->prev_msgctxt != NULL || mp->prev_msgid != NULL
+                 || mp->prev_msgid_plural != NULL
+                 ? 3
+                 : 0);
+
   /* Print each of the message components.  Wrap them nicely so they
      are as readable as possible.  If there is no recorded msgstr for
      this domain, emit an empty string.  */
@@ -879,13 +906,16 @@ different from yours. Consider using a pure ASCII msgid instead.\n\
       free (warning_message);
     }
   if (mp->msgctxt != NULL)
-    wrap (mp, fp, NULL, "msgctxt", mp->msgctxt, mp->do_wrap, charset);
-  wrap (mp, fp, NULL, "msgid", mp->msgid, mp->do_wrap, charset);
+    wrap (mp, fp, NULL, extra_indent, "msgctxt", mp->msgctxt, mp->do_wrap,
+         charset);
+  wrap (mp, fp, NULL, extra_indent, "msgid", mp->msgid, mp->do_wrap, charset);
   if (mp->msgid_plural != NULL)
-    wrap (mp, fp, NULL, "msgid_plural", mp->msgid_plural, mp->do_wrap, charset);
+    wrap (mp, fp, NULL, extra_indent, "msgid_plural", mp->msgid_plural,
+         mp->do_wrap, charset);
 
   if (mp->msgid_plural == NULL)
-    wrap (mp, fp, NULL, "msgstr", mp->msgstr, mp->do_wrap, charset);
+    wrap (mp, fp, NULL, extra_indent, "msgstr", mp->msgstr, mp->do_wrap,
+         charset);
   else
     {
       char prefix_buf[20];
@@ -897,7 +927,8 @@ different from yours. Consider using a pure ASCII msgid instead.\n\
           p += strlen (p) + 1, i++)
        {
          sprintf (prefix_buf, "msgstr[%u]", i);
-         wrap (mp, fp, NULL, prefix_buf, p, mp->do_wrap, charset);
+         wrap (mp, fp, NULL, extra_indent, prefix_buf, p, mp->do_wrap,
+               charset);
        }
     }
 }
@@ -907,6 +938,8 @@ static void
 message_print_obsolete (const message_ty *mp, FILE *fp, const char *charset,
                        bool blank_line)
 {
+  int extra_indent;
+
   /* If msgstr is the empty string we print nothing.  */
   if (mp->msgstr[0] == '\0')
     return;
@@ -942,6 +975,20 @@ message_print_obsolete (const message_ty *mp, FILE *fp, const char *charset,
       putc ('\n', fp);
     }
 
+  /* Print the previous msgid.  This helps the translator when the msgid has
+     only slightly changed.  */
+  if (mp->prev_msgctxt != NULL)
+    wrap (mp, fp, "#~| ", 0, "msgctxt", mp->prev_msgctxt, mp->do_wrap, charset);
+  if (mp->prev_msgid != NULL)
+    wrap (mp, fp, "#~| ", 0, "msgid", mp->prev_msgid, mp->do_wrap, charset);
+  if (mp->prev_msgid_plural != NULL)
+    wrap (mp, fp, "#~| ", 0, "msgid_plural", mp->prev_msgid_plural, mp->do_wrap,
+         charset);
+  extra_indent = (mp->prev_msgctxt != NULL || mp->prev_msgid != NULL
+                 || mp->prev_msgid_plural != NULL
+                 ? 1
+                 : 0);
+
   /* Print each of the message components.  Wrap them nicely so they
      are as readable as possible.  */
   if (mp->msgctxt != NULL && !is_ascii_string (mp->msgctxt)
@@ -969,14 +1016,16 @@ different from yours. Consider using a pure ASCII msgid instead.\n\
       free (warning_message);
     }
   if (mp->msgctxt != NULL)
-    wrap (mp, fp, "#~ ", "msgctxt", mp->msgctxt, mp->do_wrap, charset);
-  wrap (mp, fp, "#~ ", "msgid", mp->msgid, mp->do_wrap, charset);
-  if (mp->msgid_plural != NULL)
-    wrap (mp, fp, "#~ ", "msgid_plural", mp->msgid_plural, mp->do_wrap,
+    wrap (mp, fp, "#~ ", extra_indent, "msgctxt", mp->msgctxt, mp->do_wrap,
          charset);
+  wrap (mp, fp, "#~ ", extra_indent, "msgid", mp->msgid, mp->do_wrap, charset);
+  if (mp->msgid_plural != NULL)
+    wrap (mp, fp, "#~ ", extra_indent, "msgid_plural", mp->msgid_plural,
+         mp->do_wrap, charset);
 
   if (mp->msgid_plural == NULL)
-    wrap (mp, fp, "#~ ", "msgstr", mp->msgstr, mp->do_wrap, charset);
+    wrap (mp, fp, "#~ ", extra_indent, "msgstr", mp->msgstr, mp->do_wrap,
+         charset);
   else
     {
       char prefix_buf[20];
@@ -988,7 +1037,8 @@ different from yours. Consider using a pure ASCII msgid instead.\n\
           p += strlen (p) + 1, i++)
        {
          sprintf (prefix_buf, "msgstr[%u]", i);
-         wrap (mp, fp, "#~ ", prefix_buf, p, mp->do_wrap, charset);
+         wrap (mp, fp, "#~ ", extra_indent, prefix_buf, p, mp->do_wrap,
+               charset);
        }
     }
 }
index f57ab70b1bbeb384085d7208a3b8d3efaf6eb6ff..5db3af3f5caab70aad08b8398960f86a1f1065b4 100644 (file)
@@ -1,5 +1,5 @@
 /* xgettext PO and JavaProperties backends.
-   Copyright (C) 1995-1998, 2000-2003, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1995-1998, 2000-2003, 2005-2006 Free Software Foundation, Inc.
 
    This file was written by Peter Miller <millerp@canb.auug.org.au>
 
@@ -53,6 +53,9 @@ extract_add_message (default_po_reader_ty *this,
                     char *msgid_plural,
                     char *msgstr, size_t msgstr_len,
                     lex_pos_ty *msgstr_pos,
+                    char *prev_msgctxt,
+                    char *prev_msgid,
+                    char *prev_msgid_plural,
                     bool force_fuzzy, bool obsolete)
 {
   /* See whether we shall exclude this message.  */
@@ -87,13 +90,23 @@ extract_add_message (default_po_reader_ty *this,
       if (msgctxt != NULL)
        free (msgctxt);
       free (msgid);
+      if (msgid_plural != NULL)
+       free (msgid_plural);
       free (msgstr);
+      if (prev_msgctxt != NULL)
+       free (prev_msgctxt);
+      if (prev_msgid != NULL)
+       free (prev_msgid);
+      if (prev_msgid_plural != NULL)
+       free (prev_msgid_plural);
       return;
     }
 
   /* Invoke superclass method.  */
   default_add_message (this, msgctxt, msgid, msgid_pos, msgid_plural,
-                      msgstr, msgstr_len, msgstr_pos, force_fuzzy, obsolete);
+                      msgstr, msgstr_len, msgstr_pos,
+                      prev_msgctxt, prev_msgid, prev_msgid_plural,
+                      force_fuzzy, obsolete);
 }
 
 
index aaabe8c49beb429d39caa6e8af6a604c2844df30..6c0c81c24a04b777ca1d48112b1a478293074d6d 100644 (file)
@@ -914,6 +914,9 @@ exclude_directive_message (abstract_po_reader_ty *pop,
                           char *msgid_plural,
                           char *msgstr, size_t msgstr_len,
                           lex_pos_ty *msgstr_pos,
+                          char *prev_msgctxt,
+                          char *prev_msgid,
+                          char *prev_msgid_plural,
                           bool force_fuzzy, bool obsolete)
 {
   message_ty *mp;
index 9567ab7b7d16696151de4a427c891e9deccf39aa..459be674c7b9a76164517c5a99ba182cecd74d16 100644 (file)
@@ -1,3 +1,17 @@
+2006-10-03  Bruno Haible  <bruno@clisp.org>
+
+       * msgattrib-16: New file.
+       * msgattrib-17: New file.
+       * msgcat-15: New file.
+       * msgcat-16: New file.
+       * msgcmp-4: New file.
+       * msgcomm-26: New file.
+       * msgconv-6: New file.
+       * msgfmt-16: New file.
+       * msgmerge-19: New file.
+       * msguniq-6: New file.
+       * Makefile.am (TESTS): Add them.
+
 2006-10-03  Bruno Haible  <bruno@clisp.org>
 
        * msgmerge-18: Invoke msgcmp with options --use-fuzzy and
index c74903db8c48f535502c0e9c0f3e70a0115b1c3b..72dd48f5ac387d6db382bb6d9ca310fa8c09b363 100644 (file)
@@ -25,24 +25,27 @@ TESTS = gettext-1 gettext-2 gettext-3 gettext-4 gettext-5 gettext-6 gettext-7 \
        msgattrib-1 msgattrib-2 msgattrib-3 msgattrib-4 msgattrib-5 \
        msgattrib-6 msgattrib-7 msgattrib-8 msgattrib-9 msgattrib-10 \
        msgattrib-11 msgattrib-12 msgattrib-13 msgattrib-14 msgattrib-15 \
+       msgattrib-16 msgattrib-17 \
        msgattrib-properties-1 \
        msgcat-1 msgcat-2 msgcat-3 msgcat-4 msgcat-5 msgcat-6 msgcat-7 \
        msgcat-8 msgcat-9 msgcat-10 msgcat-11 msgcat-12 msgcat-13 msgcat-14 \
+       msgcat-15 msgcat-16 \
        msgcat-properties-1 msgcat-properties-2 \
        msgcat-stringtable-1 \
-       msgcmp-1 msgcmp-2 msgcmp-3 \
+       msgcmp-1 msgcmp-2 msgcmp-3 msgcmp-4 \
        msgcomm-1 msgcomm-2 msgcomm-3 msgcomm-4 msgcomm-5 msgcomm-6 msgcomm-7 \
        msgcomm-8 msgcomm-9 msgcomm-10 msgcomm-11 msgcomm-12 msgcomm-13 \
        msgcomm-14 msgcomm-15 msgcomm-16 msgcomm-17 msgcomm-18 msgcomm-19 \
        msgcomm-20 msgcomm-21 msgcomm-22 msgcomm-23 msgcomm-24 msgcomm-25 \
-       msgconv-1 msgconv-2 msgconv-3 msgconv-4 msgconv-5 \
+       msgcomm-26 \
+       msgconv-1 msgconv-2 msgconv-3 msgconv-4 msgconv-5 msgconv-6 \
        msgen-1 msgen-2 msgen-3 \
        msgexec-1 msgexec-2 msgexec-3 msgexec-4 \
        msgfilter-1 msgfilter-2 msgfilter-3 msgfilter-4 \
        msgfilter-sr-latin-1 \
        msgfmt-1 msgfmt-2 msgfmt-3 msgfmt-4 msgfmt-5 msgfmt-6 msgfmt-7 \
        msgfmt-8 msgfmt-9 msgfmt-10 msgfmt-11 msgfmt-12 msgfmt-13 msgfmt-14 \
-       msgfmt-15 \
+       msgfmt-15 msgfmt-16 \
        msgfmt-properties-1 \
        msgfmt-qt-1 msgfmt-qt-2 \
        msggrep-1 msggrep-2 msggrep-3 msggrep-4 msggrep-5 msggrep-6 msggrep-7 \
@@ -51,7 +54,7 @@ TESTS = gettext-1 gettext-2 gettext-3 gettext-4 gettext-5 gettext-6 gettext-7 \
        msgmerge-1 msgmerge-2 msgmerge-3 msgmerge-4 msgmerge-5 msgmerge-6 \
        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-18 msgmerge-19 \
        msgmerge-compendium-1 msgmerge-compendium-2 msgmerge-compendium-3 \
        msgmerge-compendium-4 msgmerge-compendium-5 msgmerge-compendium-6 \
        msgmerge-properties-1 msgmerge-properties-2 \
@@ -61,7 +64,7 @@ TESTS = gettext-1 gettext-2 gettext-3 gettext-4 gettext-5 gettext-6 gettext-7 \
        msgunfmt-java-1 \
        msgunfmt-properties-1 \
        msgunfmt-tcl-1 \
-       msguniq-1 msguniq-2 msguniq-3 msguniq-4 msguniq-5 \
+       msguniq-1 msguniq-2 msguniq-3 msguniq-4 msguniq-5 msguniq-6 \
        recode-sr-latin-1 recode-sr-latin-2 \
        xgettext-1 xgettext-2 xgettext-3 xgettext-4 xgettext-5 xgettext-6 \
        xgettext-7 xgettext-8 xgettext-9 \