]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
Attach a numeric range to each message.
authorBruno Haible <bruno@clisp.org>
Sat, 4 Oct 2008 11:23:41 +0000 (11:23 +0000)
committerBruno Haible <bruno@clisp.org>
Tue, 23 Jun 2009 10:15:54 +0000 (12:15 +0200)
14 files changed:
gettext-tools/src/ChangeLog
gettext-tools/src/message.c
gettext-tools/src/message.h
gettext-tools/src/msgl-cat.c
gettext-tools/src/msgl-equal.c
gettext-tools/src/msgmerge.c
gettext-tools/src/read-catalog-abstract.c
gettext-tools/src/read-catalog-abstract.h
gettext-tools/src/read-catalog.c
gettext-tools/src/read-catalog.h
gettext-tools/src/write-po.c
gettext-tools/src/write-po.h
gettext-tools/src/write-stringtable.c
gettext-tools/src/xgettext.c

index 9b66e31f9483ccdac1a7f883fc28dfaa40a7abb7..a1171cb9b1213dccb35fd31cd3cb588d83830079 100644 (file)
@@ -1,3 +1,32 @@
+2008-10-04  Bruno Haible  <bruno@clisp.org>
+
+       * message.h (struct argument_range): New type.
+       (has_range_p): New macro.
+       (struct message_ty): Add field 'range'.
+       * message.c (message_alloc): Initialize the 'range' field.
+       (message_copy): Copy the 'range' field.
+       * read-catalog-abstract.h (po_parse_comment_special): Add 'rangep'
+       argument.
+       * read-catalog-abstract.c: Include <limits.h>.
+       (po_parse_comment_special): Add 'rangep' argument. Parse the range
+       description syntax.
+       * read-catalog.h (DEFAULT_CATALOG_READER_TY): Add 'range' field.
+       * read-catalog.c (default_constructor): Initialize the 'range' field.
+       (default_copy_comment_state): Copy the 'range' field into the new
+       message.
+       (default_reset_comment_state): Clear the 'range' field.
+       (default_comment_special): Update.
+       * write-po.h (make_range_description_string): New declaration.
+       * write-po.c (make_range_description_string): New function.
+       (message_print_comment_flags): Also print the range.
+       * write-stringtable.c (write_message): Likewise.
+       * msgl-cat.c: Include <limits.h>.
+       (catenate_msgdomain_list): Fill in the range of the resulting messages.
+       * msgl-equal.c (message_equal): Compare also the ranges.
+       * msgmerge.c (message_merge): Fill in the range of the resulting
+       message. Set it fuzzy if a range was introduced or extended.
+       * xgettext.c (remember_a_message): Set the range of the new message.
+
 2008-10-03  Bruno Haible  <bruno@clisp.org>
 
        * plural-distrib.h: New file.
index 75fae5e0bb53f65d4e27dcc21675f4ed7a122a00..121240eac9bfe0620689db464ad16e5003d7eaa1 100644 (file)
@@ -117,6 +117,8 @@ message_alloc (const char *msgctxt,
   mp->is_fuzzy = false;
   for (i = 0; i < NFORMATS; i++)
     mp->is_format[i] = undecided;
+  mp->range.min = -1;
+  mp->range.max = -1;
   mp->do_wrap = undecided;
   mp->prev_msgctxt = NULL;
   mp->prev_msgid = NULL;
@@ -221,6 +223,7 @@ message_copy (message_ty *mp)
   result->is_fuzzy = mp->is_fuzzy;
   for (i = 0; i < NFORMATS; i++)
     result->is_format[i] = mp->is_format[i];
+  result->range = mp->range;
   result->do_wrap = mp->do_wrap;
   for (j = 0; j < mp->filepos_count; ++j)
     {
index c052696d159438c1dd6b323bcf5a05c13d852b72..6142055b25b1dc8eb8206bc0f1d5b478d483f073 100644 (file)
@@ -85,6 +85,17 @@ extern bool
        possible_format_p (enum is_format);
 
 
+/* Range of an unsigned integer argument.  */
+struct argument_range
+{
+  int min;
+  int max;
+};
+
+/* Tests whether a range is present.  */
+#define has_range_p(range)  ((range).min >= 0 && (range).max >= 0)
+
+
 /* Is current msgid wrappable?  */
 #if 0
 enum is_wrap
@@ -141,10 +152,21 @@ struct message_ty
   size_t filepos_count;
   lex_pos_ty *filepos;
 
-  /* Informations from special comments (e.g. generated by msgmerge).  */
+  /* Informations from special comments (#,).
+     Some of them come from extracted comments.  They are manipulated by
+     the tools, e.g. msgmerge.  */
+
+  /* Fuzzy means "needs translator review".  */
   bool is_fuzzy;
+
+  /* Designation of format string syntax requirements for specific
+     programming languages.  */
   enum is_format is_format[NFORMATS];
 
+  /* Lower and upper bound for the argument whose format directive can be
+     omitted in specific cases of singular or plural.  */
+  struct argument_range range;
+
   /* Do we want the string to be wrapped in the emitted PO file?  */
   enum is_wrap do_wrap;
 
index 8d2fdc2579792f308c5d053288b0d06393b097e3..560a7219160e54a76c8810ed617d13e380eea54b 100644 (file)
@@ -1,5 +1,5 @@
 /* Message list concatenation and duplicate handling.
-   Copyright (C) 2001-2003, 2005-2007 Free Software Foundation, Inc.
+   Copyright (C) 2001-2003, 2005-2008 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
@@ -24,6 +24,7 @@
 /* Specification.  */
 #include "msgl-cat.h"
 
+#include <limits.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdlib.h>
@@ -304,6 +305,8 @@ domain \"%s\" in input file `%s' doesn't contain a header entry with a charset s
                  tmp->is_fuzzy = true; /* may be set to false later */
                  for (i = 0; i < NFORMATS; i++)
                    tmp->is_format[i] = undecided; /* may be set to yes/no later */
+                 tmp->range.min = - INT_MAX;
+                 tmp->range.max = - INT_MAX;
                  tmp->do_wrap = yes; /* may be set to no later */
                  tmp->obsolete = true; /* may be set to false later */
                  tmp->alternative_count = 0;
@@ -530,6 +533,7 @@ UTF-8 encoded from the beginning, i.e. already in your source code files.\n"),
                  tmp->is_fuzzy = mp->is_fuzzy;
                  for (i = 0; i < NFORMATS; i++)
                    tmp->is_format[i] = mp->is_format[i];
+                 tmp->range = mp->range;
                  tmp->do_wrap = mp->do_wrap;
                  tmp->prev_msgctxt = mp->prev_msgctxt;
                  tmp->prev_msgid = mp->prev_msgid;
@@ -562,6 +566,21 @@ UTF-8 encoded from the beginning, i.e. already in your source code files.\n"),
                  for (i = 0; i < NFORMATS; i++)
                    if (tmp->is_format[i] == undecided)
                      tmp->is_format[i] = mp->is_format[i];
+                 if (tmp->range.min == - INT_MAX
+                     && tmp->range.max == - INT_MAX)
+                   tmp->range = mp->range;
+                 else if (has_range_p (mp->range) && has_range_p (tmp->range))
+                   {
+                     if (mp->range.min < tmp->range.min)
+                       tmp->range.min = mp->range.min;
+                     if (mp->range.max > tmp->range.max)
+                       tmp->range.max = mp->range.max;
+                   }
+                 else
+                   {
+                     tmp->range.min = -1;
+                     tmp->range.max = -1;
+                   }
                  if (tmp->do_wrap == undecided)
                    tmp->do_wrap = mp->do_wrap;
                  tmp->obsolete = false;
@@ -599,6 +618,21 @@ UTF-8 encoded from the beginning, i.e. already in your source code files.\n"),
                    else if (mp->is_format[i] == no
                             && tmp->is_format[i] == undecided)
                      tmp->is_format[i] = no;
+                 if (tmp->range.min == - INT_MAX
+                     && tmp->range.max == - INT_MAX)
+                   tmp->range = mp->range;
+                 else if (has_range_p (mp->range) && has_range_p (tmp->range))
+                   {
+                     if (mp->range.min < tmp->range.min)
+                       tmp->range.min = mp->range.min;
+                     if (mp->range.max > tmp->range.max)
+                       tmp->range.max = mp->range.max;
+                   }
+                 else
+                   {
+                     tmp->range.min = -1;
+                     tmp->range.max = -1;
+                   }
                  if (mp->do_wrap == no)
                    tmp->do_wrap = no;
                  /* Don't fill tmp->prev_msgid in this case.  */
index c78333bd7c0bbaf65076dfda0a704e0012a16519..f8d2e9f88960dd20331e7577104b4e8899470fa4 100644 (file)
@@ -1,5 +1,5 @@
 /* Message list test for equality.
-   Copyright (C) 2001-2002, 2005-2006 Free Software Foundation, Inc.
+   Copyright (C) 2001-2002, 2005-2006, 2008 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
@@ -180,6 +180,9 @@ message_equal (const message_ty *mp1, const message_ty *mp2,
     if (mp1->is_format[i] != mp2->is_format[i])
       return false;
 
+  if (!(mp1->range.min == mp2->range.min && mp1->range.max == mp2->range.max))
+    return false;
+
   if (!(mp1->prev_msgctxt != NULL
        ? mp2->prev_msgctxt != NULL
          && strcmp (mp1->prev_msgctxt, mp2->prev_msgctxt) == 0
index b5817607bd623b6721155b58b2cb69144e9e0df7..4ab4c5e0b78db7922c655ef21bc35d5ff8eb877c 100644 (file)
@@ -1277,6 +1277,20 @@ message_merge (message_ty *def, message_ty *ref, bool force_fuzzy,
        result->is_fuzzy = true;
     }
 
+  result->range = ref->range;
+  /* If the definition message was assuming a certain range, but the reference
+     message does not specify a range any more or specifies a range that is
+     not the same or a subset, we add a fuzzy marker, because
+       1. the message needs the translator's attention,
+       2. msgmerge must not transform a PO file which passes "msgfmt -c"
+         into a PO file which doesn't.  */
+  if (!result->is_fuzzy
+      && has_range_p (def->range)
+      && !(has_range_p (ref->range)
+          && ref->range.min >= def->range.min
+          && ref->range.max <= def->range.max))
+    result->is_fuzzy = true;
+
   result->do_wrap = ref->do_wrap;
 
   /* Insert previous msgid, commented out with "#|".
index e78a031b93d145727554fc04d347a65192bf1316..05a739a46fbdac7e716e4a0ff3855f3d4a35d593 100644 (file)
@@ -1,5 +1,5 @@
 /* Reading PO files, abstract class.
-   Copyright (C) 1995-1996, 1998, 2000-2007 Free Software Foundation, Inc.
+   Copyright (C) 1995-1996, 1998, 2000-2008 Free Software Foundation, Inc.
 
    This file was written by Peter Miller <millerp@canb.auug.org.au>
 
@@ -24,6 +24,7 @@
 /* Specification.  */
 #include "read-catalog-abstract.h"
 
+#include <limits.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -258,7 +259,7 @@ po_callback_comment_special (const char *s)
 void
 po_parse_comment_special (const char *s,
                          bool *fuzzyp, enum is_format formatp[NFORMATS],
-                         enum is_wrap *wrapp)
+                         struct argument_range *rangep, enum is_wrap *wrapp)
 {
   size_t i;
 
@@ -332,6 +333,61 @@ po_parse_comment_special (const char *s,
                continue;
            }
 
+         /* Accept range description "range: <min>..<max>".  */
+         if (len == 6 && memcmp (t, "range:", 6) == 0)
+           {
+             /* Skip whitespace.  */
+             while (*s != '\0' && strchr ("\n \t\r\f\v,", *s) != NULL)
+               s++;
+
+             /* Collect a token.  */
+             t = s;
+             while (*s != '\0' && strchr ("\n \t\r\f\v,", *s) == NULL)
+               s++;
+             /* Parse it.  */
+             if (*t >= '0' && *t <= '9')
+               {
+                 unsigned int min = 0;
+
+                 for (; *t >= '0' && *t <= '9'; t++)
+                   {
+                     if (min <= INT_MAX / 10)
+                       {
+                         min = 10 * min + (*t - '0');
+                         if (min > INT_MAX)
+                           min = INT_MAX;
+                       }
+                     else
+                       /* Avoid integer overflow.  */
+                       min = INT_MAX;
+                   }
+                 if (*t++ == '.')
+                   if (*t++ == '.')
+                     if (*t >= '0' && *t <= '9')
+                       {
+                         unsigned int max = 0;
+                         for (; *t >= '0' && *t <= '9'; t++)
+                           {
+                             if (max <= INT_MAX / 10)
+                               {
+                                 max = 10 * max + (*t - '0');
+                                 if (max > INT_MAX)
+                                   max = INT_MAX;
+                               }
+                             else
+                               /* Avoid integer overflow.  */
+                               max = INT_MAX;
+                           }
+                         if (min <= max)
+                           {
+                             rangep->min = min;
+                             rangep->max = max;
+                             continue;
+                           }
+                       }
+               }
+           }
+
          /* Accept wrap description.  */
          if (len == 4 && memcmp (t, "wrap", 4) == 0)
            {
index 1a5b26b11743bc97c125617653e996276615821b..17af04cf74cfa8ec31d12bb802cdbfe748446360 100644 (file)
@@ -1,5 +1,5 @@
 /* Reading PO files, abstract class.
-   Copyright (C) 1995-1996, 1998, 2000-2003, 2005-2006 Free Software Foundation, Inc.
+   Copyright (C) 1995-1996, 1998, 2000-2003, 2005-2006, 2008 Free Software Foundation, Inc.
 
    This file was written by Peter Miller <millerp@canb.auug.org.au>
 
@@ -182,6 +182,7 @@ extern void po_callback_comment_dispatcher (const char *s);
 /* Parse a special comment and put the result in *fuzzyp, formatp, *wrapp.  */
 extern void po_parse_comment_special (const char *s, bool *fuzzyp,
                                      enum is_format formatp[NFORMATS],
+                                     struct argument_range *rangep,
                                      enum is_wrap *wrapp);
 
 
index dae03c90ad101f69e5a8f703a7e8905413f341e5..f35ceb0d04cf33d06ed2074576c6073f3ed3b592 100644 (file)
@@ -1,5 +1,5 @@
 /* Reading PO files.
-   Copyright (C) 1995-1998, 2000-2003, 2005-2006 Free Software Foundation, Inc.
+   Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008 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
@@ -102,6 +102,8 @@ default_constructor (abstract_catalog_reader_ty *that)
   this->is_fuzzy = false;
   for (i = 0; i < NFORMATS; i++)
     this->is_format[i] = undecided;
+  this->range.min = -1;
+  this->range.max = -1;
   this->do_wrap = undecided;
 }
 
@@ -175,6 +177,7 @@ default_copy_comment_state (default_catalog_reader_ty *this, message_ty *mp)
   mp->is_fuzzy = this->is_fuzzy;
   for (i = 0; i < NFORMATS; i++)
     mp->is_format[i] = this->is_format[i];
+  mp->range = this->range;
   mp->do_wrap = this->do_wrap;
 }
 
@@ -209,6 +212,8 @@ default_reset_comment_state (default_catalog_reader_ty *this)
   this->is_fuzzy = false;
   for (i = 0; i < NFORMATS; i++)
     this->is_format[i] = undecided;
+  this->range.min = -1;
+  this->range.max = -1;
   this->do_wrap = undecided;
 }
 
@@ -307,7 +312,7 @@ default_comment_special (abstract_catalog_reader_ty *that, const char *s)
 {
   default_catalog_reader_ty *this = (default_catalog_reader_ty *) that;
 
-  po_parse_comment_special (s, &this->is_fuzzy, this->is_format,
+  po_parse_comment_special (s, &this->is_fuzzy, this->is_format, &this->range,
                            &this->do_wrap);
 }
 
index 60fecb280864f7412669bd99add8117f2991da1d..e6f592d3c3b6c196ad79196a89ba2ee55178ab8f 100644 (file)
@@ -1,5 +1,5 @@
 /* Reading PO files.
-   Copyright (C) 1995-1998, 2000-2003, 2005-2006 Free Software Foundation, Inc.
+   Copyright (C) 1995-1998, 2000-2003, 2005-2006, 2008 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
@@ -112,6 +112,7 @@ struct default_catalog_reader_class_ty
   /* Flags transported in special comments.  */                                \
   bool is_fuzzy;                                                       \
   enum is_format is_format[NFORMATS];                                  \
+  struct argument_range range;                                         \
   enum is_wrap do_wrap;                                                        \
 
 typedef struct default_catalog_reader_ty default_catalog_reader_ty;
index ceda8205dbeba3cbd4de9dac4e39b32481d1e207..d0acdb17432a75921f6fc8940ed77a2ae6c85e7d 100644 (file)
@@ -120,6 +120,15 @@ has_significant_format_p (const enum is_format is_format[NFORMATS])
 }
 
 
+/* Convert a RANGE to a freshly allocated string for use in #, flags.  */
+
+char *
+make_range_description_string (struct argument_range range)
+{
+  return xasprintf ("range: %d..%d", range.min, range.max);
+}
+
+
 /* Convert a wrapping flag DO_WRAP to a string for use in #, flags.  */
 
 static const char *
@@ -373,13 +382,15 @@ message_print_comment_filepos (const message_ty *mp, ostream_t stream,
 }
 
 
-/* Output mp->is_fuzzy, mp->is_format, mp->do_wrap as a comment line.  */
+/* Output mp->is_fuzzy, mp->is_format, mp->range, mp->do_wrap as a comment
+   line.  */
 
 void
 message_print_comment_flags (const message_ty *mp, ostream_t stream, bool debug)
 {
   if ((mp->is_fuzzy && mp->msgstr[0] != '\0')
       || has_significant_format_p (mp->is_format)
+      || has_range_p (mp->range)
       || mp->do_wrap == no)
     {
       bool first_flag = true;
@@ -419,6 +430,22 @@ message_print_comment_flags (const message_ty *mp, ostream_t stream, bool debug)
            first_flag = false;
          }
 
+      if (has_range_p (mp->range))
+       {
+         char *string;
+
+         if (!first_flag)
+           ostream_write_str (stream, ",");
+
+         ostream_write_str (stream, " ");
+         begin_css_class (stream, class_flag);
+         string = make_range_description_string (mp->range);
+         ostream_write_str (stream, string);
+         free (string);
+         end_css_class (stream, class_flag);
+         first_flag = false;
+       }
+
       if (mp->do_wrap == no)
        {
          if (!first_flag)
index 6916c903d464230962fbb4d5545e4234d70d602e..b832b005b083332e5e5a76a53f804785fbc9f19a 100644 (file)
@@ -1,5 +1,5 @@
 /* GNU gettext - internationalization aids
-   Copyright (C) 1995-1998, 2000-2003, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1995-1998, 2000-2003, 2006, 2008 Free Software Foundation, Inc.
 
    This file was written by Peter Miller <millerp@canb.auug.org.au>
 
@@ -37,6 +37,8 @@ extern const char *
 extern bool
        significant_format_p (enum is_format is_format);
 
+extern char *
+       make_range_description_string (struct argument_range range);
 
 /* These functions output parts of a message, as comments.  */
 extern void
index ddd03f2cb5c329467420f3e9dde62b25c1c07f92..348e4224c2b5f1e9bae67b6eb0c99f47b563c70c 100644 (file)
@@ -223,6 +223,16 @@ write_message (ostream_t stream, const message_ty *mp,
          ostream_write_str (stream, " */\n");
        }
   }
+  if (has_range_p (mp->range))
+    {
+      char *string;
+
+      ostream_write_str (stream, "/* Flag: ");
+      string = make_range_description_string (mp->range);
+      ostream_write_str (stream, string);
+      free (string);
+      ostream_write_str (stream, " */\n");
+    }
 
   /* Now write the untranslated string and the translated string.  */
   write_escaped_string (stream, mp->msgid);
index 241d4d2963e6b8b2d304b3378fc96669480d3f53..640667e61e0dfb3bb76ff5bf0361910e294ad9bf 100644 (file)
@@ -2050,6 +2050,7 @@ remember_a_message (message_list_ty *mlp, char *msgctxt, char *msgid,
                    refcounted_string_list_ty *comment)
 {
   enum is_format is_format[NFORMATS];
+  struct argument_range range;
   enum is_wrap do_wrap;
   message_ty *mp;
   char *msgstr;
@@ -2074,6 +2075,8 @@ remember_a_message (message_list_ty *mlp, char *msgctxt, char *msgid,
 
   for (i = 0; i < NFORMATS; i++)
     is_format[i] = undecided;
+  range.min = -1;
+  range.max = -1;
   do_wrap = undecided;
 
   if (msgctxt != NULL)
@@ -2155,12 +2158,14 @@ meta information, not the empty string.\n")));
          {
            bool tmp_fuzzy;
            enum is_format tmp_format[NFORMATS];
+           struct argument_range tmp_range;
            enum is_wrap tmp_wrap;
            bool interesting;
 
            t += strlen ("xgettext:");
 
-           po_parse_comment_special (t, &tmp_fuzzy, tmp_format, &tmp_wrap);
+           po_parse_comment_special (t, &tmp_fuzzy, tmp_format, &tmp_range,
+                                     &tmp_wrap);
 
            interesting = false;
            for (i = 0; i < NFORMATS; i++)
@@ -2169,6 +2174,11 @@ meta information, not the empty string.\n")));
                  is_format[i] = tmp_format[i];
                  interesting = true;
                }
+           if (has_range_p (tmp_range))
+             {
+               range = tmp_range;
+               interesting = true;
+             }
            if (tmp_wrap != undecided)
              {
                do_wrap = tmp_wrap;
@@ -2269,6 +2279,19 @@ meta information, not the empty string.\n")));
       mp->is_format[i] = is_format[i];
     }
 
+  if (has_range_p (range))
+    {
+      if (has_range_p (mp->range))
+       {
+         if (range.min < mp->range.min)
+           mp->range.min = range.min;
+         if (range.max > mp->range.max)
+           mp->range.max = range.max;
+       }
+      else
+       mp->range = range;
+    }
+
   mp->do_wrap = do_wrap == no ? no : yes;      /* By default we wrap.  */
 
   /* Warn about the use of non-reorderable format strings when the programming