]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
Use the range flag to allow some specific plural form translations.
authorBruno Haible <bruno@clisp.org>
Sat, 4 Oct 2008 14:54:19 +0000 (14:54 +0000)
committerBruno Haible <bruno@clisp.org>
Tue, 23 Jun 2009 10:15:54 +0000 (12:15 +0200)
gettext-tools/src/ChangeLog
gettext-tools/src/format.c
gettext-tools/src/format.h
gettext-tools/src/msgl-check.c
gettext-tools/src/msgmerge.c
gettext-tools/src/plural-distrib.h

index a1171cb9b1213dccb35fd31cd3cb588d83830079..e1cfad64560e7ef9bc127520978d5ff21b0f449a 100644 (file)
@@ -1,3 +1,21 @@
+2008-10-04  Bruno Haible  <bruno@clisp.org>
+
+       * plural-distrib.h (struct plural_distribution): New field 'histogram'.
+       * format.h (check_msgid_msgstr_format_i, check_msgid_msgstr_format):
+       Add range argument.
+       * format.c (check_msgid_msgstr_format_i): Add range argument. Set
+       strict_checking to false if, due to the range, the plural forms applies
+       to only one value of n.
+       (check_msgid_msgstr_format): Add range argument.
+       * msgl-check.c (plural_expression_histogram): New function.
+       (check_plural_eval, check_plural): Update.
+       (check_pair): Pass the range to check_msgid_msgstr_format.
+       (check_message_list): Update.
+       * msgmerge.c (message_merge): Pass the range to
+       check_msgid_msgstr_format_i.
+       Reported by Anatoly Techtonik <techtonik@gmail.com>
+       via <https://savannah.gnu.org/bugs/?24433>.
+
 2008-10-04  Bruno Haible  <bruno@clisp.org>
 
        * message.h (struct argument_range): New type.
index cd56afee5cc598ab83920799e7fcb85ff1a27b4a..592a398dd36377024e1049c0326086fd06bbc223 100644 (file)
@@ -64,6 +64,7 @@ int
 check_msgid_msgstr_format_i (const char *msgid, const char *msgid_plural,
                             const char *msgstr, size_t msgstr_len,
                             size_t i,
+                            struct argument_range range,
                             const struct plural_distribution *distribution,
                             formatstring_error_logger_t error_logger)
 {
@@ -112,19 +113,24 @@ check_msgid_msgstr_format_i (const char *msgid, const char *msgid_plural,
              /* Use strict checking (require same number of format
                 directives on both sides) if the message has no plurals,
                 or if msgid_plural exists but on the msgstr[] side
-                there is only msgstr[0], or if plural_distribution[j]
+                there is only msgstr[0], or if distribution->often[j]
                 indicates that the variant applies to infinitely many
-                values of N.
+                values of N and the N range is not restricted in a way
+                that the variant applies to only one N.
                 Use relaxed checking when there are at least two
-                msgstr[] forms and the plural_distribution array does
-                not give more precise information.  */
+                msgstr[] forms and the distribution does not give more
+                precise information.  */
              bool strict_checking =
                (msgid_plural == NULL
                 || !has_plural_translations
                 || (distribution != NULL
                     && distribution->often != NULL
                     && j < distribution->often_length
-                    && distribution->often[j]));
+                    && distribution->often[j]
+                    && !(has_range_p (range)
+                         && distribution->histogram (distribution,
+                                                     range.min, range.max, j)
+                            <= 1)));
 
              if (parser->check (msgid_descr, msgstr_descr,
                                 strict_checking,
@@ -159,6 +165,7 @@ int
 check_msgid_msgstr_format (const char *msgid, const char *msgid_plural,
                           const char *msgstr, size_t msgstr_len,
                           const enum is_format is_format[NFORMATS],
+                          struct argument_range range,
                           const struct plural_distribution *distribution,
                           formatstring_error_logger_t error_logger)
 {
@@ -175,6 +182,7 @@ check_msgid_msgstr_format (const char *msgid, const char *msgid_plural,
     if (possible_format_p (is_format[i]))
       seen_errors += check_msgid_msgstr_format_i (msgid, msgid_plural,
                                                  msgstr, msgstr_len, i,
+                                                 range,
                                                  distribution,
                                                  error_logger);
 
index 38bbadcfe20cadd3fbdb3499c5cf2a5da9055f4a..8de202ae0c185014adbe266dbb75172365494a00 100644 (file)
@@ -146,6 +146,7 @@ extern int
        check_msgid_msgstr_format_i (const char *msgid, const char *msgid_plural,
                                    const char *msgstr, size_t msgstr_len,
                                    size_t i,
+                                   struct argument_range range,
                                    const struct plural_distribution *distribution,
                                    formatstring_error_logger_t error_logger);
 
@@ -156,6 +157,7 @@ extern int
        check_msgid_msgstr_format (const char *msgid, const char *msgid_plural,
                                  const char *msgstr, size_t msgstr_len,
                                  const enum is_format is_format[NFORMATS],
+                                 struct argument_range range,
                                  const struct plural_distribution *distribution,
                                  formatstring_error_logger_t error_logger);
 
index 00c93c0f0389675337bae2a93bd6fffad665f9f3..74737cf7656a2a4b53f7a427134d2a2178c6d3e7 100644 (file)
 #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
 
 
+/* Evaluates the plural formula for min <= n <= max
+   and returns the estimated number of times the value j was assumed.  */
+static unsigned int
+plural_expression_histogram (const struct plural_distribution *self,
+                            int min, int max, unsigned long j)
+{
+  if (min < 0)
+    min = 0;
+  /* Limit the number of evaluations.  Nothing interesting happens beyond
+     1000.  */
+  if (max - min > 1000)
+    max = min + 1000;
+  if (min <= max)
+    {
+      const struct expression *expr = self->expr;
+      unsigned long n;
+      unsigned int count;
+
+      /* Protect against arithmetic exceptions.  */
+      install_sigfpe_handler ();
+
+      count = 0;
+      for (n = min; n <= max; n++)
+       {
+         unsigned long val = plural_eval (expr, n);
+
+         if (val == j)
+           count++;
+       }
+
+      /* End of protection against arithmetic exceptions.  */
+      uninstall_sigfpe_handler ();
+
+      return count;
+    }
+  else
+    return 0;
+}
+
+
 /* Check the values returned by plural_eval.
    Signals the errors through po_xerror.
    Return the number of errors that were seen.
@@ -125,6 +165,7 @@ check_plural_eval (const struct expression *plural_expr,
       distribution->expr = plural_expr;
       distribution->often = array;
       distribution->often_length = (array != NULL ? nplurals_value : 0);
+      distribution->histogram = plural_expression_histogram;
 
       return 0;
     }
@@ -260,6 +301,7 @@ check_plural (message_list_ty *mlp, struct plural_distribution *distributionp)
   distribution.expr = NULL;
   distribution.often = NULL;
   distribution.often_length = 0;
+  distribution.histogram = NULL;
   for (j = 0; j < mlp->nitems; j++)
     {
       message_ty *mp = mlp->item[j];
@@ -475,6 +517,7 @@ check_plural (message_list_ty *mlp, struct plural_distribution *distributionp)
        distribution.often = array;
       }
       distribution.often_length = 2;
+      distribution.histogram = plural_expression_histogram;
     }
 
   /* distribution is not needed if we report errors.
@@ -645,7 +688,7 @@ plural handling is a GNU gettext extension"));
       curr_msgid_pos = *msgid_pos;
       seen_errors +=
        check_msgid_msgstr_format (msgid, msgid_plural, msgstr, msgstr_len,
-                                  is_format, distribution,
+                                  is_format, mp->range, distribution,
                                   formatstring_error_logger);
     }
 
@@ -832,6 +875,7 @@ check_message_list (message_list_ty *mlp,
   distribution.expr = NULL;
   distribution.often = NULL;
   distribution.often_length = 0;
+  distribution.histogram = NULL;
 
   if (check_header)
     seen_errors += check_plural (mlp, &distribution);
index 4ab4c5e0b78db7922c655ef21bc35d5ff8eb877c..352c5940955b239637adbe8c9cc47b3d27ee7591 100644 (file)
@@ -1271,7 +1271,7 @@ message_merge (message_ty *def, message_ty *ref, bool force_fuzzy,
          && possible_format_p (ref->is_format[i])
          && !possible_format_p (def->is_format[i])
          && check_msgid_msgstr_format_i (ref->msgid, ref->msgid_plural,
-                                         msgstr, msgstr_len, i,
+                                         msgstr, msgstr_len, i, ref->range,
                                          distribution, silent_error_logger)
             > 0)
        result->is_fuzzy = true;
index f25f918913f9ac02c320bc7e3078578b32a2ac05..decde3c2ceb6da0ebd1426848c4dfe9b7f80233b 100644 (file)
@@ -41,6 +41,11 @@ struct plural_distribution
 
   /* The length of the OFTEN array.  */
   unsigned long often_length;
+
+  /* A function which evaluates the plural formula for min <= n <= max
+     and returns the estimated number of times the value j was assumed.  */
+  unsigned int (*histogram) (const struct plural_distribution *self,
+                            int min, int max, unsigned long j);
 };