bug-gettext
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[bug-gettext] msgmerge --diff-to-previous (feature request)


From: Ineiev
Subject: [bug-gettext] msgmerge --diff-to-previous (feature request)
Date: Sat, 29 Oct 2011 14:02:46 +0000
User-agent: Thunderbird 2.0.0.14 (X11/20080501)

Hello!

We use gettext to maintain translations of www.gnu.org:
using another package, PO4A, we convert English HTML
files to POTs, and generate HTML files for translations
from POs.

When the English page changes, our scripts merge new POT with POs,
and the translators can figure out what parts are outdated;
naturally, we use --previous to make it easier to see what
has changed; however, it doesn't help so much as desired
when the passage is more than 100 words long,
and the change is small --- a recent real life example is

#| msgid ""
#| "Below is a detailed compatibility matrix for various combinations of the "
#| "GNU licenses, to provide an easy-to-use reference for specific cases.  It "
#| "assumes that someone else has written some software under one of these "
#| "licenses, and you want to somehow incorporate code from that into a "
#| "project that you're releasing (either your own original work, or a "
#| "modified version of someone else's GPLed software). Find the license for "
#| "your own work in a column at the top of the table, and the license for "
#| "the other code in a row on the left. The cell where they meet will tell "
#| "you whether or not this combination is permitted."
msgid ""
"Below is a detailed compatibility matrix for various combinations of the GNU "
"licenses, to provide an easy-to-use reference for specific cases.  It "
"assumes that someone else has written some software under one of these "
"licenses, and you want to somehow incorporate code from that into a project "
"that you're releasing (either your own original work, or a modified version "
"of someone else's software). Find the license for your project in a column "
"at the top of the table, and the license for the other code in a row on the "
"left. The cell where they meet will tell you whether or not this combination "
"is permitted."

It would be considerably more convenient if the translator could see a diff
(in particular, wdiff) instead of just previous msgid; a prototype patch
is attached (another gnulib module, clean-temp, should be added to libgettextpo
to make it build).
diff --git a/gettext-tools/src/message.h b/gettext-tools/src/message.h
index af9244a..c9db1cf 100644
--- a/gettext-tools/src/message.h
+++ b/gettext-tools/src/message.h
@@ -177,6 +177,12 @@ struct message_ty
   const char *prev_msgctxt;
   const char *prev_msgid;
   const char *prev_msgid_plural;
+  /* Command to produce diff to previous msgids.
+     Supplied by msgmerge.  */
+  const char *diff_to_previous;
+  /* Whether prev_msgid and prev_msgid_plural strings will appear.
+     Supplied by msgmerge.  */
+  int keep_previous;
 
   /* If set the message is obsolete and while writing out it should be
      commented out.  */
diff --git a/gettext-tools/src/msgmerge.c b/gettext-tools/src/msgmerge.c
index 6fe5fdb..3993d49 100644
--- a/gettext-tools/src/msgmerge.c
+++ b/gettext-tools/src/msgmerge.c
@@ -103,6 +103,7 @@ static string_list_ty *compendium_filenames;
 static bool update_mode = false;
 static const char *version_control_string;
 static const char *backup_suffix_string;
+static const char *diff_to_previous;
 
 /* Long options.  */
 static const struct option long_options[] =
@@ -112,6 +113,7 @@ static const struct option long_options[] =
   { "color", optional_argument, NULL, CHAR_MAX + 9 },
   { "compendium", required_argument, NULL, 'C', },
   { "directory", required_argument, NULL, 'D' },
+  { "diff-to-previous", optional_argument, NULL, CHAR_MAX + 11 },
   { "escape", no_argument, NULL, 'E' },
   { "force-po", no_argument, &force_po, 1 },
   { "help", no_argument, NULL, 'h' },
@@ -331,6 +333,10 @@ main (int argc, char **argv)
         handle_style_option (optarg);
         break;
 
+      case CHAR_MAX + 11: /* --diff-to-previous */
+        diff_to_previous = optarg == NULL? "wdiff": optarg;
+        break;
+
       default:
         usage (EXIT_FAILURE);
         break;
@@ -597,6 +603,13 @@ Output details:\n"));
   -s, --sort-output           generate sorted output\n"));
       printf (_("\
   -F, --sort-by-file          sort output by file location\n"));
+      printf (_("\
+      --diff-to-previous=COMMAND\n\
+                              add diffs to previous msgids.\n"));
+      printf (_("\
+Diff COMMAND is expected to accept two input file names as its arguments\n\
+and to write the result to standard output; wdiff is used\n\
+when no COMMAND is specified.\n"));
       printf ("\n");
       printf (_("\
 Informative output:\n"));
@@ -1321,11 +1334,13 @@ message_merge (message_ty *def, message_ty *ref, bool 
force_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->keep_previous = keep_previous;
+  if (keep_previous || diff_to_previous != NULL)
     {
       result->prev_msgctxt = prev_msgctxt;
       result->prev_msgid = prev_msgid;
       result->prev_msgid_plural = prev_msgid_plural;
+      result->diff_to_previous = diff_to_previous;
     }
 
   /* If the reference message was obsolete, make the resulting message
diff --git a/gettext-tools/src/write-po.c b/gettext-tools/src/write-po.c
index dd516f2..cea2cf5 100644
--- a/gettext-tools/src/write-po.c
+++ b/gettext-tools/src/write-po.c
@@ -49,6 +49,8 @@
 #endif
 #include "xvasprintf.h"
 #include "po-xerror.h"
+#include "concat-filename.h"
+#include "clean-temp.h"
 #include "gettext.h"
 
 /* Our regular abbreviation.  */
@@ -1183,6 +1185,116 @@ print_blank_line (ostream_t stream)
     ostream_write_str (stream, "\n");
 }
 
+static struct temp_dir *tmp_dir;
+
+static void
+create_temporary_directory (void)
+{
+  static int failed = 0;
+
+  if (tmp_dir != NULL || failed)
+    return;
+
+  tmp_dir = create_temp_dir  ("msg", NULL, false);
+
+  if (tmp_dir == NULL)
+    {
+      error (0, 0, "failed to create temporary directory\n");
+      failed = 1;
+    }
+}
+
+static int
+write_tmp_file (const char *name, const char *content)
+{
+  FILE *f;
+
+  register_temp_file (tmp_dir, name);
+  f = fopen_temp (name, "w");
+  if (f == NULL)
+    {
+      error (0, errno, _("failed to create \"%s\""), name);
+      unregister_temp_file (tmp_dir, name);
+      return 1;
+    }
+  fwrite (content, strlen (content), 1, f);
+  if (fwriteerror_temp (f))
+    {
+      error (0, errno, _("error while writing \"%s\" file"), name);
+      return 2;
+    }
+  return 0;
+}
+
+static char *
+load_file (const char *name)
+{
+  char *retval = NULL;
+  int size = 0, used = 0, read = 0;
+  FILE *f;
+
+  f = fopen_temp (name, "r");
+  if (f == NULL)
+    {
+      error (0, errno, _("failed to open \"%s\""), name);
+      return NULL;
+    }
+  do
+    {
+      size = (size + 0x11) * 3 / 2;
+      retval = xrealloc (retval, size);
+      read = fread (retval + used, 1, size - used - 1, f);
+      used += read;
+    }
+  while (read > 0);
+  if (ferror (f))
+    {
+      error (0, errno, _("failed to read \"%s\""), name);
+      free (retval);
+      retval = NULL;
+    }
+  else
+    retval [used] = 0;
+  fclose_temp (f);
+  return retval;
+}
+
+static char *
+get_diff (const char *diff, const char *prev_msgid, const char *msgid)
+{
+  FILE *f;
+  char *prev_name;
+  char *msgid_name;
+  char *output_name;
+  char *command;
+  size_t command_size;
+  char *retval = NULL;
+
+  if (tmp_dir == NULL)
+    return NULL;
+
+  prev_name = xconcatenated_filename (tmp_dir->dir_name, "prev_msgid", NULL);
+  msgid_name = xconcatenated_filename (tmp_dir->dir_name, "msgid", NULL);
+  output_name = xconcatenated_filename (tmp_dir->dir_name, "msgid_diff", NULL);
+  if (write_tmp_file (prev_name, prev_msgid))
+    goto free_names;
+  if (write_tmp_file (msgid_name, msgid))
+    goto free_names;
+  register_temp_file (tmp_dir, output_name);
+  command_size = strlen (diff) + 1 + strlen (prev_name) + 1
+                 + strlen (msgid_name) + 3 + strlen (output_name) + 1;
+  command = (char *) xmalloc (command_size);
+  sprintf (command, "%s %s %s > %s", diff, prev_name, msgid_name, output_name);
+  system (command);
+  retval = load_file (output_name);
+  free (command);
+ free_names:
+  free (output_name);
+  free (msgid_name);
+  free (prev_name);
+  cleanup_temp_dir_contents (tmp_dir);
+  return retval;
+}
 
 static void
 message_print (const message_ty *mp, ostream_t stream,
@@ -1190,6 +1302,7 @@ message_print (const message_ty *mp, ostream_t stream,
                bool debug)
 {
   int extra_indent;
+  char *diff;
 
   /* Separate messages with a blank line.  Uniforum doesn't like blank
      lines, so use an empty comment (unless there already is one).  */
@@ -1227,15 +1340,35 @@ message_print (const message_ty *mp, ostream_t stream,
   /* Print the previous msgid.  This helps the translator when the msgid has
      only slightly changed.  */
   begin_css_class (stream, class_previous_comment);
-  if (mp->prev_msgctxt != NULL)
+  if (mp->keep_previous && mp->prev_msgctxt != NULL)
     wrap (mp, stream, "#| ", 0, class_previous, "msgctxt", mp->prev_msgctxt,
           mp->do_wrap, page_width, charset);
-  if (mp->prev_msgid != NULL)
+  if (mp->keep_previous && mp->prev_msgid != NULL)
     wrap (mp, stream, "#| ", 0, class_previous, "msgid", mp->prev_msgid,
           mp->do_wrap, page_width, charset);
-  if (mp->prev_msgid_plural != NULL)
+  if (mp->keep_previous && mp->prev_msgid_plural != NULL)
     wrap (mp, stream, "#| ", 0, class_previous, "msgid_plural",
           mp->prev_msgid_plural, mp->do_wrap, page_width, charset);
+  if (mp->diff_to_previous != NULL && mp->prev_msgid != NULL)
+    {
+      create_temporary_directory ();
+      diff = get_diff (mp->diff_to_previous, mp->prev_msgid, mp->msgid);
+      if (diff != NULL)
+        wrap (mp, stream, "#| ", 0, class_previous, "msgid_diff",
+              diff, mp->do_wrap, page_width, charset);
+      free (diff);
+    }
+  if (mp->diff_to_previous != NULL && mp->prev_msgid_plural != NULL)
+    {
+      create_temporary_directory ();
+      diff = get_diff (mp->diff_to_previous, mp->prev_msgid_plural,
+                       mp->msgid_plural);
+      if (diff != NULL)
+        wrap (mp, stream, "#| ", 0, class_previous, "msgid_plural_diff",
+              diff, mp->do_wrap, page_width, charset);
+      free (diff);
+    }
+
   end_css_class (stream, class_previous_comment);
   extra_indent = (mp->prev_msgctxt != NULL || mp->prev_msgid != NULL
                   || mp->prev_msgid_plural != NULL
@@ -1526,6 +1659,9 @@ msgdomain_list_print_po (msgdomain_list_ty *mdlp, 
ostream_t stream,
       if (allocated_charset != NULL)
         freea (allocated_charset);
     }
+  if (tmp_dir != NULL)
+    cleanup_temp_dir (tmp_dir);
+  tmp_dir = NULL;
 }
 
 

reply via email to

[Prev in Thread] Current Thread [Next in Thread]