]> git.ipfire.org Git - thirdparty/gettext.git/commitdiff
xgettext: Signal a warning when the same msgid is used with and without plural.
authorBruno Haible <bruno@clisp.org>
Sun, 29 Sep 2019 18:52:48 +0000 (20:52 +0200)
committerBruno Haible <bruno@clisp.org>
Sun, 29 Sep 2019 18:52:48 +0000 (20:52 +0200)
* gettext-tools/src/xg-message.h (remember_a_message): Add pluralp argument.
* gettext-tools/src/xg-message.c (remember_a_message): Likewise. Signal a
warning when the same msgid is used with and without plural.
* gettext-tools/src/xg-arglist-parser.c (arglist_parser_done): Update
remember_a_message invocation.
* gettext-tools/src/xgettext.c (xgettext_its_extract_callback): Update
remember_a_message invocations.
* gettext-tools/src/x-awk.c (extract_parenthesized): Likewise.
* gettext-tools/src/x-c.c (extract_parenthesized): Likewise.
* gettext-tools/src/x-csharp.c (extract_parenthesized): Likewise.
* gettext-tools/src/x-desktop.c (extract_desktop_handle_pair): Likewise.
* gettext-tools/src/x-elisp.c (read_object): Likewise.
* gettext-tools/src/x-java.c (extract_parenthesized): Likewise.
* gettext-tools/src/x-javascript.c (extract_balanced): Likewise.
* gettext-tools/src/x-librep.c (read_object): Likewise.
* gettext-tools/src/x-lisp.c (read_object): Likewise.
* gettext-tools/src/x-lua.c (extract_balanced): Likewise.
* gettext-tools/src/x-perl.c (extract_variable, interpolate_keywords,
extract_balanced): Likewise.
* gettext-tools/src/x-php.c (extract_balanced): Likewise.
* gettext-tools/src/x-python.c (extract_balanced): Likewise.
* gettext-tools/src/x-rst.c (extract_rst, extract_rsj): Likewise.
* gettext-tools/src/x-scheme.c (read_object): Likewise.
* gettext-tools/src/x-sh.c (read_word, read_command): Likewise.
* gettext-tools/src/x-tcl.c (read_command): Likewise.
* gettext-tools/src/x-vala.c (extract_balanced): Likewise.
* gettext-tools/src/x-smalltalk.c (phase3_pushback, phase3_pushback_length): New
variables.
(phase3_get): Renamed from x_smalltalk_lex. Handle pushback.
(phase3_unget): New function.
(extract_smalltalk): Update remember_a_message invocations through a lookahead
of one token.
* gettext-tools/src/x-ycp.c (phase8_pushback, phase8_pushback_length): New
variables.
(phase8_get): Handle pushback.
(phase8_unget): New function.
(extract_parenthesized): Update remember_a_message invocations through a
lookahead of one token.
* gettext-tools/tests/xgettext-15: New file.
* gettext-tools/tests/Makefile.am (TESTS): Add it.

26 files changed:
gettext-tools/src/x-awk.c
gettext-tools/src/x-c.c
gettext-tools/src/x-csharp.c
gettext-tools/src/x-desktop.c
gettext-tools/src/x-elisp.c
gettext-tools/src/x-java.c
gettext-tools/src/x-javascript.c
gettext-tools/src/x-librep.c
gettext-tools/src/x-lisp.c
gettext-tools/src/x-lua.c
gettext-tools/src/x-perl.c
gettext-tools/src/x-php.c
gettext-tools/src/x-python.c
gettext-tools/src/x-rst.c
gettext-tools/src/x-scheme.c
gettext-tools/src/x-sh.c
gettext-tools/src/x-smalltalk.c
gettext-tools/src/x-tcl.c
gettext-tools/src/x-vala.c
gettext-tools/src/x-ycp.c
gettext-tools/src/xg-arglist-parser.c
gettext-tools/src/xg-message.c
gettext-tools/src/xg-message.h
gettext-tools/src/xgettext.c
gettext-tools/tests/Makefile.am
gettext-tools/tests/xgettext-15 [new file with mode: 0755]

index da74c004245a63ccebe34f8dfb5cd85d0850ef44..af066ff15a87f870d7a35ed33d19a7037148074c 100644 (file)
@@ -1,5 +1,5 @@
 /* xgettext awk backend.
-   Copyright (C) 2002-2003, 2005-2009, 2018 Free Software Foundation, Inc.
+   Copyright (C) 2002-2003, 2005-2009, 2018-2019 Free Software Foundation, Inc.
 
    This file was written by Bruno Haible <haible@clisp.cons.org>, 2002.
 
@@ -789,8 +789,9 @@ extract_parenthesized (message_list_ty *mlp,
             pos.line_number = token.line_number;
 
             if (extract_all)
-              remember_a_message (mlp, NULL, token.string, false, inner_context,
-                                  &pos, NULL, savable_comment, false);
+              remember_a_message (mlp, NULL, token.string, false, false,
+                                  inner_context, &pos,
+                                  NULL, savable_comment, false);
             else
               {
                 mixed_string_ty *ms =
@@ -814,8 +815,9 @@ extract_parenthesized (message_list_ty *mlp,
             pos.file_name = logical_file_name;
             pos.line_number = token.line_number;
 
-            remember_a_message (mlp, NULL, token.string, false, inner_context,
-                                &pos, NULL, savable_comment, false);
+            remember_a_message (mlp, NULL, token.string, false, false,
+                                inner_context, &pos,
+                                NULL, savable_comment, false);
           }
           next_is_argument = false;
           next_context_iter = null_context_list_iterator;
index a81b85101130445d3d2792c25e05051b95c60d1f..de99a707cedec7b9fd884eae74dba12859b9df0c 100644 (file)
@@ -1,5 +1,5 @@
 /* xgettext C/C++/ObjectiveC backend.
-   Copyright (C) 1995-1998, 2000-2009, 2012-2015, 2018 Free Software Foundation, Inc.
+   Copyright (C) 1995-1998, 2000-2009, 2012-2015, 2018-2019 Free Software Foundation, Inc.
 
    This file was written by Peter Miller <millerp@canb.auug.org.au>
 
@@ -2297,8 +2297,9 @@ extract_parenthesized (message_list_ty *mlp,
               {
                 char *string = mixed_string_contents (token.mixed_string);
                 mixed_string_free (token.mixed_string);
-                remember_a_message (mlp, NULL, string, true, inner_context,
-                                    &token.pos, NULL, token.comment, false);
+                remember_a_message (mlp, NULL, string, true, false,
+                                    inner_context, &token.pos,
+                                    NULL, token.comment, false);
               }
             else
               arglist_parser_remember (argparser, arg, token.mixed_string,
index 4e3c5904bbcde038ea5bec21f4ddaab9f38c2a64..71678b3ef9b32fe799fc09a04323b3e5e81f87f9 100644 (file)
@@ -2009,8 +2009,9 @@ extract_parenthesized (message_list_ty *mlp, token_type_ty terminator,
               {
                 char *string = mixed_string_contents (token.mixed_string);
                 mixed_string_free (token.mixed_string);
-                remember_a_message (mlp, NULL, string, true, inner_context,
-                                    &pos, NULL, token.comment, true);
+                remember_a_message (mlp, NULL, string, true, false,
+                                    inner_context, &pos,
+                                    NULL, token.comment, true);
               }
             else
               arglist_parser_remember (argparser, arg, token.mixed_string,
index 93e206ee9c188fd01c1a3f563f628fd56de19ed9..6efcaa62d9d1d54f9b86f336d1a0b7dd99901976 100644 (file)
@@ -128,7 +128,7 @@ extract_desktop_handle_pair (struct desktop_reader_ty *reader,
 
       remember_a_message (extract_reader->mlp, NULL,
                           desktop_unescape_string (value, is_list), false,
-                          null_context, key_pos,
+                          false, null_context, key_pos,
                           NULL, savable_comment, false);
     }
   savable_comment_reset ();
index 90a45c45563ed04eef81def05c3b3c53c70e5fce..c85739fe35685e1da580a8b1bea1c646a6b4e47a 100644 (file)
@@ -904,8 +904,8 @@ read_object (struct object *op, bool first_in_list, bool new_backquote_flag,
                 pos.file_name = logical_file_name;
                 pos.line_number = op->line_number_at_start;
                 remember_a_message (mlp, NULL, string_of_object (op), false,
-                                    null_context, &pos, NULL, savable_comment,
-                                    false);
+                                    false, null_context, &pos,
+                                    NULL, savable_comment, false);
               }
             last_non_comment_line = line_number;
             return;
index 8c0ee331f8289e62725df4ebd7cf782601d63866..64a7f2b6492800c5cfd809bda84d1b2af87c5c57 100644 (file)
@@ -1647,8 +1647,9 @@ extract_parenthesized (message_list_ty *mlp, token_type_ty terminator,
               {
                 char *string = mixed_string_contents (token.mixed_string);
                 mixed_string_free (token.mixed_string);
-                remember_a_message (mlp, NULL, string, true, inner_context,
-                                    &pos, NULL, token.comment, true);
+                remember_a_message (mlp, NULL, string, true, false,
+                                    inner_context, &pos,
+                                    NULL, token.comment, true);
               }
             else
               arglist_parser_remember (argparser, arg, token.mixed_string,
index 514fd30637ade0a028e402e1c73e142a36cf6eb8..4823b295c6e38b3349d754ac95e141b004d17e3b 100644 (file)
@@ -1661,8 +1661,9 @@ extract_balanced (message_list_ty *mlp,
               {
                 char *string = mixed_string_contents (token.mixed_string);
                 mixed_string_free (token.mixed_string);
-                remember_a_message (mlp, NULL, string, true, inner_context,
-                                    &pos, NULL, token.comment, true);
+                remember_a_message (mlp, NULL, string, true, false,
+                                    inner_context, &pos,
+                                    NULL, token.comment, true);
               }
             else
               arglist_parser_remember (argparser, arg, token.mixed_string,
index b516b84c7aa9818483b67bb77d93b23020569b31..d1ad681fc1dca1f5e3978272fb94bf1d86747260 100644 (file)
@@ -840,8 +840,8 @@ read_object (struct object *op, flag_context_ty outer_context)
                 pos.file_name = logical_file_name;
                 pos.line_number = op->line_number_at_start;
                 remember_a_message (mlp, NULL, string_of_object (op), false,
-                                    null_context, &pos, NULL, savable_comment,
-                                    false);
+                                    false, null_context, &pos,
+                                    NULL, savable_comment, false);
               }
             last_non_comment_line = line_number;
             return;
index 6dab490499ee55d9045e2a665818bc0a05dbaec4..a436f444c238ed7ca4deb173ffc6c2cbae248f65 100644 (file)
@@ -1200,7 +1200,7 @@ read_object (struct object *op, flag_context_ty outer_context)
                     pos.file_name = logical_file_name;
                     pos.line_number = op->line_number_at_start;
                     remember_a_message (mlp, NULL, string_of_object (op), false,
-                                        null_context, &pos,
+                                        false, null_context, &pos,
                                         NULL, savable_comment, false);
                   }
                 last_non_comment_line = line_number;
index 5aed25745a1d6697f913fc14fb8812feee37823c..25970fea949a12e9a53d98b4c11e15d960590424 100644 (file)
@@ -1151,8 +1151,9 @@ extract_balanced (message_list_ty *mlp, token_type_ty delim,
             pos.line_number = token.line_number;
 
             if (extract_all)
-              remember_a_message (mlp, NULL, token.string, false, inner_context,
-                                  &pos, NULL, token.comment, false);
+              remember_a_message (mlp, NULL, token.string, false, false,
+                                  inner_context, &pos,
+                                  NULL, token.comment, false);
             else
               {
                 mixed_string_ty *ms =
index 1517cb1178f504c3200f2bd134359e7489c3edfd..e16f9b60866f3b5a127884ae8277ffcef2a3b54c 100644 (file)
@@ -1590,8 +1590,8 @@ extract_variable (message_list_ty *mlp, token_ty *tp, int first)
                         pos.file_name = logical_file_name;
 
                         remember_a_message (mlp, NULL, xstrdup (t1->string),
-                                            true, context, &pos, NULL,
-                                            savable_comment, true);
+                                            true, false, context, &pos,
+                                            NULL, savable_comment, true);
                         free_token (t2);
                         free_token (t1);
                       }
@@ -2018,8 +2018,8 @@ interpolate_keywords (message_list_ty *mlp, const char *string, int lineno)
               buffer[bufpos] = '\0';
               token.string = xstrdup (buffer);
               extract_quotelike_pass3 (&token, EXIT_FAILURE);
-              remember_a_message (mlp, NULL, token.string, true, context, &pos,
-                                  NULL, savable_comment, true);
+              remember_a_message (mlp, NULL, token.string, true, false, context,
+                                  &pos, NULL, savable_comment, true);
               /* FALLTHROUGH */
             default:
               context = null_context;
@@ -3304,8 +3304,8 @@ extract_balanced (message_list_ty *mlp,
 
               pos.file_name = logical_file_name;
               pos.line_number = tp->line_number;
-              remember_a_message (mlp, NULL, string, true, inner_context, &pos,
-                                  NULL, tp->comment, true);
+              remember_a_message (mlp, NULL, string, true, false, inner_context,
+                                  &pos, NULL, tp->comment, true);
             }
           else if (!skip_until_comma)
             {
index de9b89f54447e9f67fb7a9ce113ba4c98809e782..cccb9dc2d29bbea10be733eec8cd8d91e2d1006a 100644 (file)
@@ -1,5 +1,5 @@
 /* xgettext PHP backend.
-   Copyright (C) 2001-2003, 2005-2010, 2014, 2018 Free Software Foundation, Inc.
+   Copyright (C) 2001-2003, 2005-2010, 2014, 2018-2019 Free Software Foundation, Inc.
 
    This file was written by Bruno Haible <bruno@clisp.org>, 2002.
 
@@ -1532,8 +1532,9 @@ extract_balanced (message_list_ty *mlp,
             pos.line_number = token.line_number;
 
             if (extract_all)
-              remember_a_message (mlp, NULL, token.string, false, inner_context,
-                                  &pos, NULL, token.comment, false);
+              remember_a_message (mlp, NULL, token.string, false, false,
+                                  inner_context, &pos,
+                                  NULL, token.comment, false);
             else
               {
                 mixed_string_ty *ms =
index 94e9930d6d60261a65424d033e93c4de01e03d6d..a27669eeccd4f97fa0f1882fa861fb409f4ed961 100644 (file)
@@ -1648,8 +1648,9 @@ extract_balanced (message_list_ty *mlp,
               {
                 char *string = mixed_string_contents (token.mixed_string);
                 mixed_string_free (token.mixed_string);
-                remember_a_message (mlp, NULL, string, true, inner_context,
-                                    &pos, NULL, token.comment, true);
+                remember_a_message (mlp, NULL, string, true, false,
+                                    inner_context, &pos,
+                                    NULL, token.comment, true);
               }
             else
               arglist_parser_remember (argparser, arg, token.mixed_string,
index d9705e11bf8984e11538d90d05a0fe945179595d..cde1ee6c024abc7c3c20868902e72d964363cb71 100644 (file)
@@ -1,5 +1,5 @@
 /* xgettext RST/RSJ backend.
-   Copyright (C) 2001-2003, 2005-2009, 2018 Free Software Foundation, Inc.
+   Copyright (C) 2001-2003, 2005-2009, 2018-2019 Free Software Foundation, Inc.
 
    This file was written by Bruno Haible <haible@clisp.cons.org>, 2001.
 
@@ -228,8 +228,8 @@ extract_rst (FILE *f,
       pos.file_name = location;
       pos.line_number = (size_t)(-1);
 
-      remember_a_message (mlp, NULL, msgid, false, null_context, &pos, NULL,
-                          NULL, false);
+      remember_a_message (mlp, NULL, msgid, false, false, null_context, &pos,
+                          NULL, NULL, false);
 
       /* Here c is the last read character: EOF or '\n'.  */
       if (c == EOF)
@@ -635,8 +635,9 @@ extract_rsj (FILE *f,
                       pos.file_name = location;
                       pos.line_number = (size_t)(-1);
 
-                      remember_a_message (mlp, NULL, msgid, true, null_context,
-                                          &pos, NULL, NULL, false);
+                      remember_a_message (mlp, NULL, msgid, true, false,
+                                          null_context, &pos,
+                                          NULL, NULL, false);
 
                       /* Parse a comma.  */
                       c = phase2_getc ();
index 075f46795b5ab7ec0167eb3759c5f2ce9cd64630..6f627b75eede5bf76a90dff77db7d2e87b671b47 100644 (file)
@@ -1332,8 +1332,8 @@ read_object (struct object *op, flag_context_ty outer_context)
                 pos.file_name = logical_file_name;
                 pos.line_number = op->line_number_at_start;
                 remember_a_message (mlp, NULL, string_of_object (op), false,
-                                    null_context, &pos, NULL, savable_comment,
-                                    false);
+                                    false, null_context, &pos,
+                                    NULL, savable_comment, false);
               }
             last_non_comment_line = line_number;
             return;
index 2d863aae5721bbb85ac35951f3cb58fbbcd116f5..ce8a864d4840079da3ce9f8058b2978666d06883 100644 (file)
@@ -1133,8 +1133,8 @@ read_word (struct word *wp, int looking_for, flag_context_ty context)
                       string.chars[string.charcount++] = (unsigned char) c;
                     }
                   remember_a_message (mlp, NULL, string_of_token (&string),
-                                      false, context, &pos, NULL,
-                                      savable_comment, false);
+                                      false, false, context, &pos,
+                                      NULL, savable_comment, false);
                   free_token (&string);
 
                   error_with_progname = false;
@@ -1302,8 +1302,8 @@ read_command (int looking_for, flag_context_ty outer_context)
               pos.file_name = logical_file_name;
               pos.line_number = inner.line_number_at_start;
               remember_a_message (mlp, NULL, string_of_word (&inner), false,
-                                  inner_context, &pos, NULL, savable_comment,
-                                  false);
+                                  false, inner_context, &pos,
+                                  NULL, savable_comment, false);
             }
         }
 
index 73c2b038d70c0aa74831011fa6343a4fa6674c90..1a2b60998e221294186a3e0fc32e99a2368a6978 100644 (file)
@@ -1,5 +1,5 @@
 /* xgettext Smalltalk backend.
-   Copyright (C) 2002-2003, 2005-2009, 2011, 2018 Free Software Foundation, Inc.
+   Copyright (C) 2002-2003, 2005-2009, 2011, 2018-2019 Free Software Foundation, Inc.
 
    This file was written by Bruno Haible <haible@clisp.cons.org>, 2002.
 
@@ -446,9 +446,18 @@ phase2_unget (token_ty *tp)
 
 /* 3. Combine "# string_literal" and "# symbol" to a single token.  */
 
+static token_ty phase3_pushback[1];
+static int phase3_pushback_length;
+
 static void
-x_smalltalk_lex (token_ty *tp)
+phase3_get (token_ty *tp)
 {
+  if (phase3_pushback_length)
+    {
+      *tp = phase3_pushback[--phase3_pushback_length];
+      return;
+    }
+
   phase2_get (tp);
   if (tp->type == token_type_uniq)
     {
@@ -466,6 +475,18 @@ x_smalltalk_lex (token_ty *tp)
     }
 }
 
+/* Supports only one pushback token.  */
+static void
+phase3_unget (token_ty *tp)
+{
+  if (tp->type != token_type_eof)
+    {
+      if (phase3_pushback_length == SIZEOF (phase3_pushback))
+        abort ();
+      phase3_pushback[phase3_pushback_length++] = *tp;
+    }
+}
+
 
 /* ========================= Extracting strings.  ========================== */
 
@@ -516,7 +537,7 @@ extract_smalltalk (FILE *f,
       {
         token_ty token;
 
-        x_smalltalk_lex (&token);
+        phase3_get (&token);
 
         switch (token.type)
           {
@@ -535,7 +556,7 @@ extract_smalltalk (FILE *f,
                 lex_pos_ty pos;
                 pos.file_name = logical_file_name;
                 pos.line_number = token.line_number;
-                remember_a_message (mlp, NULL, token.string, false,
+                remember_a_message (mlp, NULL, token.string, false, false,
                                     null_context, &pos, NULL, savable_comment,
                                     false);
                 state = 0;
@@ -544,11 +565,22 @@ extract_smalltalk (FILE *f,
             if (state == 3)
               {
                 lex_pos_ty pos;
+                token_ty token2;
+
                 pos.file_name = logical_file_name;
                 pos.line_number = token.line_number;
-                plural_mp = remember_a_message (mlp, NULL, token.string, false,
-                                                null_context, &pos,
-                                                NULL, savable_comment, false);
+
+                phase3_get (&token2);
+
+                plural_mp =
+                  remember_a_message (mlp, NULL, token.string, false,
+                                      token2.type == token_type_symbol
+                                      && strcmp (token.string, "plural:") == 0,
+                                      null_context, &pos,
+                                      NULL, savable_comment, false);
+
+                phase3_unget (&token2);
+
                 state = 4;
                 break;
               }
index 0c814cd0450a29dd8783b00858d4897cd1fabeb3..1be2bcbfa8b36e099c1be9d576a8ff204434c5c1 100644 (file)
@@ -889,7 +889,7 @@ read_command (int looking_for, flag_context_ty outer_context)
                 pos.file_name = logical_file_name;
                 pos.line_number = inner.line_number_at_start;
                 remember_a_message (mlp, NULL, string_of_word (&inner), false,
-                                    inner_context, &pos,
+                                    false, inner_context, &pos,
                                     NULL, savable_comment, false);
               }
           }
index 7bf0979a709a614a895c8707eb1ea3754c774a72..49e822d7adfacabf4428f9247bb6aaddb2803d5f 100644 (file)
@@ -1324,8 +1324,9 @@ extract_balanced (message_list_ty *mlp, token_type_ty delim,
               {
                 char *string = mixed_string_contents (token.mixed_string);
                 mixed_string_free (token.mixed_string);
-                remember_a_message (mlp, NULL, string, true, inner_context,
-                                    &pos, NULL, token.comment, false);
+                remember_a_message (mlp, NULL, string, true, false,
+                                    inner_context, &pos,
+                                    NULL, token.comment, false);
               }
             else
               {
index e27ba12d02d2fe362c9d6634754a879bec52c21f..51c4cb3b32295d111e26f202a017f215865ac0d4 100644 (file)
@@ -1,5 +1,5 @@
 /* xgettext YCP backend.
-   Copyright (C) 2001-2003, 2005-2009, 2011, 2018 Free Software Foundation, Inc.
+   Copyright (C) 2001-2003, 2005-2009, 2011, 2018-2019 Free Software Foundation, Inc.
 
    This file was written by Bruno Haible <haible@clisp.cons.org>, 2001.
 
@@ -581,9 +581,17 @@ phase5_unget (token_ty *tp)
 /* Concatenate adjacent string literals to form single string literals.
    (See libycp/src/parser.yy, rule 'string' vs. terminal 'STRING'.)  */
 
+static token_ty phase8_pushback[1];
+static int phase8_pushback_length;
+
 static void
 phase8_get (token_ty *tp)
 {
+  if (phase8_pushback_length)
+    {
+      *tp = phase8_pushback[--phase8_pushback_length];
+      return;
+    }
   phase5_get (tp);
   if (tp->type != token_type_string_literal)
     return;
@@ -605,6 +613,18 @@ phase8_get (token_ty *tp)
     }
 }
 
+/* Supports only one pushback token.  */
+static void
+phase8_unget (token_ty *tp)
+{
+  if (tp->type != token_type_eof)
+    {
+      if (phase8_pushback_length == SIZEOF (phase8_pushback))
+        abort ();
+      phase8_pushback[phase8_pushback_length++] = *tp;
+    }
+}
+
 
 /* ========================= Extracting strings.  ========================== */
 
@@ -680,9 +700,24 @@ extract_parenthesized (message_list_ty *mlp,
               if (plural_state == 0)
                 {
                   /* Seen an msgid.  */
-                  plural_mp = remember_a_message (mlp, NULL, token.string,
-                                                  false, inner_context, &pos,
-                                                  NULL, token.comment, false);
+                  token_ty token2;
+
+                  if (in_i18n)
+                    phase8_get (&token2);
+                  else
+                    phase5_get (&token2);
+
+                  plural_mp =
+                    remember_a_message (mlp, NULL, token.string, false,
+                                        token2.type == token_type_comma,
+                                        inner_context, &pos,
+                                        NULL, token.comment, false);
+
+                  if (in_i18n)
+                    phase8_unget (&token2);
+                  else
+                    phase5_unget (&token2);
+
                   plural_state = 1;
                   state = 2;
                 }
index a99dc5fc5d38ab7f2a82db8ba19ce85298a0cae1..d9795eb2d12834876ea28e1f121fb610a55b15e9 100644 (file)
@@ -1,6 +1,6 @@
 /* Resolving ambiguity of argument lists: Progressive parsing of an
    argument list, keeping track of all possibilities.
-   Copyright (C) 2001-2018 Free Software Foundation, Inc.
+   Copyright (C) 2001-2019 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -503,6 +503,7 @@ arglist_parser_done (struct arglist_parser *ap, int argnum)
             }
 
           mp = remember_a_message (ap->mlp, best_msgctxt, best_msgid, true,
+                                   best_msgid_plural != NULL,
                                    msgid_context,
                                    &best_cp->msgid_pos,
                                    NULL, best_cp->msgid_comment,
index b1938407cca641fb32298983234d70fd9fbe79d3..5b9d3577feca741f9478f96c7524e287f85f5e2d 100644 (file)
@@ -1,5 +1,5 @@
 /* Extracting a message.  Accumulating the message list.
-   Copyright (C) 2001-2018 Free Software Foundation, Inc.
+   Copyright (C) 2001-2019 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -136,7 +136,8 @@ and a mapping instead of a tuple for the arguments.\n"),
 
 message_ty *
 remember_a_message (message_list_ty *mlp, char *msgctxt, char *msgid,
-                    bool is_utf8, flag_context_ty context, lex_pos_ty *pos,
+                    bool is_utf8, bool pluralp, flag_context_ty context,
+                    lex_pos_ty *pos,
                     const char *extracted_comment,
                     refcounted_string_list_ty *comment, bool comment_is_utf8)
 {
@@ -202,6 +203,43 @@ meta information, not the empty string.\n")));
   mp = message_list_search (mlp, msgctxt, msgid);
   if (mp != NULL)
     {
+      if (pluralp != (mp->msgid_plural != NULL))
+        {
+          lex_pos_ty pos1;
+          lex_pos_ty pos2;
+          char buffer1[21];
+          char buffer2[21];
+
+          if (pluralp)
+            {
+              pos1 = mp->pos;
+              pos2 = *pos;
+            }
+          else
+            {
+              pos1 = *pos;
+              pos2 = mp->pos;
+            }
+
+          if (pos1.line_number == (size_t)(-1))
+            buffer1[0] = '\0';
+          else
+            sprintf (buffer1, ":%ld", (long) pos1.line_number);
+          if (pos2.line_number == (size_t)(-1))
+            buffer2[0] = '\0';
+          else
+            sprintf (buffer2, ":%ld", (long) pos2.line_number);
+          multiline_warning (xstrdup (_("warning: ")),
+                             xasprintf ("%s\n%s\n%s\n%s\n",
+                                        xasprintf (_("msgid '%s' is used without plural and with plural."),
+                                                   msgid),
+                                        xasprintf (_("%s%s: Here is the occurrence without plural."),
+                                                   pos1.file_name, buffer1),
+                                        xasprintf (_("%s%s: Here is the occurrence with plural."),
+                                                   pos2.file_name, buffer2),
+                                        xstrdup (_("Workaround: If the msgid is a sentence, change the wording of the sentence; otherwise, use contexts for disambiguation."))));
+        }
+
       if (msgctxt != NULL)
         free (msgctxt);
       free (msgid);
index 83ba4a6a4168d71aeb49f7ae56b05ef32c77cee3..8def094e7b2efa8b795f05785763db817f1484cd 100644 (file)
@@ -1,5 +1,5 @@
 /* Extracting a message.  Accumulating the message list.
-   Copyright (C) 2001-2018 Free Software Foundation, Inc.
+   Copyright (C) 2001-2019 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -37,6 +37,8 @@ extern "C" {
    MSGID must be a malloc()ed string; its ownership is passed to the callee.
    IS_UTF8 must be true if MSGCTXT and MSGID have already been converted to
    UTF-8.
+   PLURALP must be true if and only if a call to remember_a_message_plural will
+   follow.
    POS->file_name must be allocated with indefinite extent.
    EXTRACTED_COMMENT is a comment that needs to be copied into the POT file,
    or NULL.
@@ -49,6 +51,7 @@ extern message_ty *remember_a_message (message_list_ty *mlp,
                                        char *msgctxt,
                                        char *msgid,
                                        bool is_utf8,
+                                       bool pluralp,
                                        flag_context_ty context,
                                        lex_pos_ty *pos,
                                        const char *extracted_comment,
index 96dff8dac3e0c3e4a56b9b880e34553a878e6df8..e2e4525debfdad772a01596187ddb15114a3aa8a 100644 (file)
@@ -1804,7 +1804,7 @@ xgettext_its_extract_callback (message_list_ty *mlp,
   message = remember_a_message (mlp,
                                 msgctxt == NULL ? NULL : xstrdup (msgctxt),
                                 xstrdup (msgid),
-                                false,
+                                false, false,
                                 null_context, pos,
                                 extracted_comment, NULL, false);
 
index 53d6af7544a908c5ce0b754a711092e78c4c7751..b2bd779e41f018b2abd8c885f5cd02ed0f3eccf5 100644 (file)
@@ -77,7 +77,7 @@ TESTS = gettext-1 gettext-2 \
        recode-sr-latin-1 recode-sr-latin-2 \
        xgettext-2 xgettext-3 xgettext-4 xgettext-5 xgettext-6 \
        xgettext-7 xgettext-8 xgettext-9 xgettext-10 xgettext-11 xgettext-12 \
-       xgettext-13 xgettext-14 \
+       xgettext-13 xgettext-14 xgettext-15 \
        xgettext-appdata-1 \
        xgettext-awk-1 xgettext-awk-2 \
        xgettext-c-2 xgettext-c-3 xgettext-c-4 xgettext-c-5 xgettext-c-6 \
diff --git a/gettext-tools/tests/xgettext-15 b/gettext-tools/tests/xgettext-15
new file mode 100755 (executable)
index 0000000..355d91b
--- /dev/null
@@ -0,0 +1,55 @@
+#!/bin/sh
+. "${srcdir=.}/init.sh"; path_prepend_ . ../src
+
+# Test for a warning when the same msgid is used with and without msgid_plural.
+# <https://savannah.gnu.org/bugs/?35027>
+# <https://savannah.gnu.org/bugs/?56456>
+# <https://savannah.gnu.org/bugs/?56919>
+
+# Case when the message with plural appears first.
+
+cat <<\EOF > xg-test15-1.py
+ngettext("Language", "Languages", n)
+_("Language")
+EOF
+
+: ${XGETTEXT=xgettext}
+LANGUAGE= LC_ALL=C ${XGETTEXT} --omit-header --add-comments -d xg-test15-1.tmp xg-test15-1.py 2>xg-test15-1.err || Exit 1
+LC_ALL=C tr -d '\r' < xg-test15-1.tmp.po > xg-test15-1.po || Exit 1
+
+grep "is used without plural and with plural" xg-test15-1.err || Exit 1
+
+cat <<\EOF > xg-test15-1.ok
+#: xg-test15-1.py:1 xg-test15-1.py:2
+msgid "Language"
+msgid_plural "Languages"
+msgstr[0] ""
+msgstr[1] ""
+EOF
+
+: ${DIFF=diff}
+${DIFF} xg-test15-1.ok xg-test15-1.po || Exit 1
+
+# Case when the message without plural appears first.
+
+cat <<\EOF > xg-test15-2.py
+_("Language")
+ngettext("Language", "Languages", n)
+EOF
+
+: ${XGETTEXT=xgettext}
+LANGUAGE= LC_ALL=C ${XGETTEXT} --omit-header --add-comments -d xg-test15-2.tmp xg-test15-2.py 2>xg-test15-2.err || Exit 1
+LC_ALL=C tr -d '\r' < xg-test15-2.tmp.po > xg-test15-2.po || Exit 1
+
+grep "is used without plural and with plural" xg-test15-2.err || Exit 1
+
+cat <<\EOF > xg-test15-2.ok
+#: xg-test15-2.py:1 xg-test15-2.py:2
+msgid "Language"
+msgid_plural "Languages"
+msgstr[0] ""
+msgstr[1] ""
+EOF
+
+: ${DIFF=diff}
+${DIFF} xg-test15-2.ok xg-test15-2.po || Exit 1