does not yet correctly pass the format check.
+2001-12-06 Bruno Haible <bruno@clisp.org>
+
+ * format.h (struct formatstring_parser): Add 'noisy' argument to
+ 'check' field.
+ * format-c.c (format_check): Add 'noisy' argument.
+ * format-java.c (format_check): Likewise.
+ * format-lisp.c (format_check): Likewise.
+ * format-pascal.c (format_check): Likewise.
+ * format-python.c (format_check): Likewise.
+ * format-ycp.c (format_check): Likewise.
+ * msgfmt.c (check_pair): Pass noisy=true.
+ * message.c: Include format.h.
+ (msgfmt_check_pair_fails): New function.
+ (message_merge): Set fuzzy flag when adding a -format specifier that
+ needs the translator's attention.
+
2001-12-10 Bruno Haible <bruno@clisp.org>
* x-java.l (tailcmp): If s1 ends with s2, it must be either equal to
static void format_free PARAMS ((void *descr));
static int format_get_number_of_directives PARAMS ((void *descr));
static bool format_check PARAMS ((const lex_pos_ty *pos,
- void *msgid_descr, void *msgstr_descr));
+ void *msgid_descr, void *msgstr_descr,
+ bool noisy));
static int
}
static bool
-format_check (pos, msgid_descr, msgstr_descr)
+format_check (pos, msgid_descr, msgstr_descr, noisy)
const lex_pos_ty *pos;
void *msgid_descr;
void *msgstr_descr;
+ bool noisy;
{
struct spec *spec1 = (struct spec *) msgid_descr;
struct spec *spec2 = (struct spec *) msgstr_descr;
/* Check the argument types are the same. */
if (spec1->unnumbered_arg_count != spec2->unnumbered_arg_count)
{
- error_with_progname = false;
- error_at_line (0, 0, pos->file_name, pos->line_number,
- _("number of format specifications in 'msgid' and 'msgstr' does not match"));
- error_with_progname = true;
+ if (noisy)
+ {
+ error_with_progname = false;
+ error_at_line (0, 0, pos->file_name, pos->line_number,
+ _("number of format specifications in 'msgid' and 'msgstr' does not match"));
+ error_with_progname = true;
+ }
err = true;
}
else
for (i = 0; i < spec1->unnumbered_arg_count; i++)
if (spec1->unnumbered[i].type != spec2->unnumbered[i].type)
{
- error_with_progname = false;
- error_at_line (0, 0, pos->file_name, pos->line_number,
- _("format specifications in 'msgid' and 'msgstr' for argument %u are not the same"),
- i + 1);
- error_with_progname = true;
+ if (noisy)
+ {
+ error_with_progname = false;
+ error_at_line (0, 0, pos->file_name, pos->line_number,
+ _("format specifications in 'msgid' and 'msgstr' for argument %u are not the same"),
+ i + 1);
+ error_with_progname = true;
+ }
err = true;
}
static void format_free PARAMS ((void *descr));
static int format_get_number_of_directives PARAMS ((void *descr));
static bool format_check PARAMS ((const lex_pos_ty *pos,
- void *msgid_descr, void *msgstr_descr));
+ void *msgid_descr, void *msgstr_descr,
+ bool noisy));
/* Quote handling:
}
static bool
-format_check (pos, msgid_descr, msgstr_descr)
+format_check (pos, msgid_descr, msgstr_descr, noisy)
const lex_pos_ty *pos;
void *msgid_descr;
void *msgstr_descr;
+ bool noisy;
{
struct spec *spec1 = (struct spec *) msgid_descr;
struct spec *spec2 = (struct spec *) msgstr_descr;
if (cmp > 0)
{
- error_with_progname = false;
- error_at_line (0, 0, pos->file_name, pos->line_number,
- _("a format specification for argument {%u} doesn't exist in 'msgid'"),
- spec2->numbered[i].number);
- error_with_progname = true;
+ if (noisy)
+ {
+ error_with_progname = false;
+ error_at_line (0, 0, pos->file_name, pos->line_number,
+ _("a format specification for argument {%u} doesn't exist in 'msgid'"),
+ spec2->numbered[i].number);
+ error_with_progname = true;
+ }
err = true;
break;
}
else if (cmp < 0)
{
- error_with_progname = false;
- error_at_line (0, 0, pos->file_name, pos->line_number,
- _("a format specification for argument {%u} doesn't exist in 'msgstr'"),
- spec1->numbered[i].number);
- error_with_progname = true;
+ if (noisy)
+ {
+ error_with_progname = false;
+ error_at_line (0, 0, pos->file_name, pos->line_number,
+ _("a format specification for argument {%u} doesn't exist in 'msgstr'"),
+ spec1->numbered[i].number);
+ error_with_progname = true;
+ }
err = true;
break;
}
for (i = 0; i < spec2->numbered_arg_count; i++)
if (spec1->numbered[i].type != spec2->numbered[i].type)
{
- error_with_progname = false;
- error_at_line (0, 0, pos->file_name, pos->line_number,
- _("format specifications in 'msgid' and 'msgstr' for argument {%u} are not the same"),
- spec2->numbered[i].number);
- error_with_progname = true;
+ if (noisy)
+ {
+ error_with_progname = false;
+ error_at_line (0, 0, pos->file_name, pos->line_number,
+ _("format specifications in 'msgid' and 'msgstr' for argument {%u} are not the same"),
+ spec2->numbered[i].number);
+ error_with_progname = true;
+ }
err = true;
break;
}
static void format_free PARAMS ((void *descr));
static int format_get_number_of_directives PARAMS ((void *descr));
static bool format_check PARAMS ((const lex_pos_ty *pos,
- void *msgid_descr, void *msgstr_descr));
+ void *msgid_descr, void *msgstr_descr,
+ bool noisy));
/* ======================= Verify a format_arg_list ======================= */
}
static bool
-format_check (pos, msgid_descr, msgstr_descr)
+format_check (pos, msgid_descr, msgstr_descr, noisy)
const lex_pos_ty *pos;
void *msgid_descr;
void *msgstr_descr;
+ bool noisy;
{
struct spec *spec1 = (struct spec *) msgid_descr;
struct spec *spec2 = (struct spec *) msgstr_descr;
if (!equal_list (spec1->list, spec2->list))
{
- error_with_progname = false;
- error_at_line (0, 0, pos->file_name, pos->line_number,
- _("format specifications in 'msgid' and 'msgstr' are not equivalent"));
- error_with_progname = true;
+ if (noisy)
+ {
+ error_with_progname = false;
+ error_at_line (0, 0, pos->file_name, pos->line_number,
+ _("format specifications in 'msgid' and 'msgstr' are not equivalent"));
+ error_with_progname = true;
+ }
err = true;
}
static void format_free PARAMS ((void *descr));
static int format_get_number_of_directives PARAMS ((void *descr));
static bool format_check PARAMS ((const lex_pos_ty *pos,
- void *msgid_descr, void *msgstr_descr));
+ void *msgid_descr, void *msgstr_descr,
+ bool noisy));
static int
}
static bool
-format_check (pos, msgid_descr, msgstr_descr)
+format_check (pos, msgid_descr, msgstr_descr, noisy)
const lex_pos_ty *pos;
void *msgid_descr;
void *msgstr_descr;
+ bool noisy;
{
struct spec *spec1 = (struct spec *) msgid_descr;
struct spec *spec2 = (struct spec *) msgstr_descr;
if (cmp > 0)
{
- error_with_progname = false;
- error_at_line (0, 0, pos->file_name, pos->line_number,
- _("a format specification for argument {%u} doesn't exist in 'msgid'"),
- spec2->numbered[i].number);
- error_with_progname = true;
+ if (noisy)
+ {
+ error_with_progname = false;
+ error_at_line (0, 0, pos->file_name, pos->line_number,
+ _("a format specification for argument {%u} doesn't exist in 'msgid'"),
+ spec2->numbered[i].number);
+ error_with_progname = true;
+ }
err = true;
break;
}
else if (cmp < 0)
{
- error_with_progname = false;
- error_at_line (0, 0, pos->file_name, pos->line_number,
- _("a format specification for argument {%u} doesn't exist in 'msgstr'"),
- spec1->numbered[i].number);
- error_with_progname = true;
+ if (noisy)
+ {
+ error_with_progname = false;
+ error_at_line (0, 0, pos->file_name, pos->line_number,
+ _("a format specification for argument {%u} doesn't exist in 'msgstr'"),
+ spec1->numbered[i].number);
+ error_with_progname = true;
+ }
err = true;
break;
}
for (i = 0; i < spec2->numbered_arg_count; i++)
if (spec1->numbered[i].type != spec2->numbered[i].type)
{
- error_with_progname = false;
- error_at_line (0, 0, pos->file_name, pos->line_number,
- _("format specifications in 'msgid' and 'msgstr' for argument {%u} are not the same"),
- spec2->numbered[i].number);
- error_with_progname = true;
+ if (noisy)
+ {
+ error_with_progname = false;
+ error_at_line (0, 0, pos->file_name, pos->line_number,
+ _("format specifications in 'msgid' and 'msgstr' for argument {%u} are not the same"),
+ spec2->numbered[i].number);
+ error_with_progname = true;
+ }
err = true;
break;
}
static void format_free PARAMS ((void *descr));
static int format_get_number_of_directives PARAMS ((void *descr));
static bool format_check PARAMS ((const lex_pos_ty *pos,
- void *msgid_descr, void *msgstr_descr));
+ void *msgid_descr, void *msgstr_descr,
+ bool noisy));
static int
}
static bool
-format_check (pos, msgid_descr, msgstr_descr)
+format_check (pos, msgid_descr, msgstr_descr, noisy)
const lex_pos_ty *pos;
void *msgid_descr;
void *msgstr_descr;
+ bool noisy;
{
struct spec *spec1 = (struct spec *) msgid_descr;
struct spec *spec2 = (struct spec *) msgstr_descr;
if (spec1->named_arg_count > 0 && spec2->unnamed_arg_count > 0)
{
- error_with_progname = false;
- error_at_line (0, 0, pos->file_name, pos->line_number,
- _("format specifications in 'msgid' expect a mapping, those in 'msgstr' expect a tuple"));
- error_with_progname = true;
+ if (noisy)
+ {
+ error_with_progname = false;
+ error_at_line (0, 0, pos->file_name, pos->line_number,
+ _("format specifications in 'msgid' expect a mapping, those in 'msgstr' expect a tuple"));
+ error_with_progname = true;
+ }
err = true;
}
else if (spec1->unnamed_arg_count > 0 && spec2->named_arg_count > 0)
{
- error_with_progname = false;
- error_at_line (0, 0, pos->file_name, pos->line_number,
- _("format specifications in 'msgid' expect a tuple, those in 'msgstr' expect a mapping"));
- error_with_progname = true;
+ if (noisy)
+ {
+ error_with_progname = false;
+ error_at_line (0, 0, pos->file_name, pos->line_number,
+ _("format specifications in 'msgid' expect a tuple, those in 'msgstr' expect a mapping"));
+ error_with_progname = true;
+ }
err = true;
}
else
if (cmp > 0)
{
- error_with_progname = false;
- error_at_line (0, 0, pos->file_name, pos->line_number,
- _("a format specification for argument '%s' doesn't exist in 'msgid'"),
- spec2->named[i].name);
- error_with_progname = true;
+ if (noisy)
+ {
+ error_with_progname = false;
+ error_at_line (0, 0, pos->file_name, pos->line_number,
+ _("a format specification for argument '%s' doesn't exist in 'msgid'"),
+ spec2->named[i].name);
+ error_with_progname = true;
+ }
err = true;
break;
}
else if (cmp < 0)
{
- error_with_progname = false;
- error_at_line (0, 0, pos->file_name, pos->line_number,
- _("a format specification for argument '%s' doesn't exist in 'msgstr'"),
- spec1->named[i].name);
- error_with_progname = true;
+ if (noisy)
+ {
+ error_with_progname = false;
+ error_at_line (0, 0, pos->file_name, pos->line_number,
+ _("a format specification for argument '%s' doesn't exist in 'msgstr'"),
+ spec1->named[i].name);
+ error_with_progname = true;
+ }
err = true;
break;
}
for (i = 0; i < spec2->named_arg_count; i++)
if (spec1->named[i].type != spec2->named[i].type)
{
- error_with_progname = false;
- error_at_line (0, 0, pos->file_name, pos->line_number,
- _("format specifications in 'msgid' and 'msgstr' for argument '%s' are not the same"),
- spec2->named[i].name);
- error_with_progname = true;
+ if (noisy)
+ {
+ error_with_progname = false;
+ error_at_line (0, 0, pos->file_name, pos->line_number,
+ _("format specifications in 'msgid' and 'msgstr' for argument '%s' are not the same"),
+ spec2->named[i].name);
+ error_with_progname = true;
+ }
err = true;
break;
}
/* Check the argument types are the same. */
if (spec1->unnamed_arg_count != spec2->unnamed_arg_count)
{
- error_with_progname = false;
- error_at_line (0, 0, pos->file_name, pos->line_number,
- _("number of format specifications in 'msgid' and 'msgstr' does not match"));
- error_with_progname = true;
+ if (noisy)
+ {
+ error_with_progname = false;
+ error_at_line (0, 0, pos->file_name, pos->line_number,
+ _("number of format specifications in 'msgid' and 'msgstr' does not match"));
+ error_with_progname = true;
+ }
err = true;
}
else
for (i = 0; i < spec1->unnamed_arg_count; i++)
if (spec1->unnamed[i].type != spec2->unnamed[i].type)
{
- error_with_progname = false;
- error_at_line (0, 0, pos->file_name, pos->line_number,
- _("format specifications in 'msgid' and 'msgstr' for argument %u are not the same"),
- i + 1);
- error_with_progname = true;
+ if (noisy)
+ {
+ error_with_progname = false;
+ error_at_line (0, 0, pos->file_name, pos->line_number,
+ _("format specifications in 'msgid' and 'msgstr' for argument %u are not the same"),
+ i + 1);
+ error_with_progname = true;
+ }
err = true;
}
}
static void format_free PARAMS ((void *descr));
static int format_get_number_of_directives PARAMS ((void *descr));
static bool format_check PARAMS ((const lex_pos_ty *pos,
- void *msgid_descr, void *msgstr_descr));
+ void *msgid_descr, void *msgstr_descr,
+ bool noisy));
static void *
}
static bool
-format_check (pos, msgid_descr, msgstr_descr)
+format_check (pos, msgid_descr, msgstr_descr, noisy)
const lex_pos_ty *pos;
void *msgid_descr;
void *msgstr_descr;
+ bool noisy;
{
struct spec *spec1 = (struct spec *) msgid_descr;
struct spec *spec2 = (struct spec *) msgstr_descr;
if (arg_used1 != arg_used2)
{
- error_with_progname = false;
- error_at_line (0, 0, pos->file_name, pos->line_number,
- arg_used1
- ? _("a format specification for argument %u doesn't exist in 'msgstr'")
- : _("a format specification for argument %u doesn't exist in 'msgid'"),
- i + 1);
- error_with_progname = true;
+ if (noisy)
+ {
+ error_with_progname = false;
+ error_at_line (0, 0, pos->file_name, pos->line_number,
+ arg_used1
+ ? _("a format specification for argument %u doesn't exist in 'msgstr'")
+ : _("a format specification for argument %u doesn't exist in 'msgid'"),
+ i + 1);
+ error_with_progname = true;
+ }
err = true;
break;
}
#ifndef _FORMAT_H
#define _FORMAT_H
+#include <stdbool.h>
+
#include "pos.h" /* Get lex_pos_ty. */
#include "message.h" /* Get NFORMATS. */
error_with_progname = false;
error_at_line (0, 0, pos->file_name, pos->line_number, ...);
error_with_progname = true;
- and return true. Otherwise return false. */
- bool (*check) PARAMS ((const lex_pos_ty *pos, void *msgid_descr, void *msgstr_descr));
+ (but only if noisy=true) and return true. Otherwise return false. */
+ bool (*check) PARAMS ((const lex_pos_ty *pos, void *msgid_descr, void *msgstr_descr, bool noisy));
};
/* Format string parsers, each defined in its own file. */
#include "fstrcmp.h"
#include "hash.h"
+#include "format.h"
#include "xmalloc.h"
#include "strstr.h"
#include "system.h"
/* Prototypes for local functions. Needed to ensure compiler checking of
function argument counts despite of K&R C function definition syntax. */
+static bool msgfmt_check_pair_fails PARAMS ((const lex_pos_ty *pos,
+ const char *msgid,
+ const char *msgstr, size_t i));
static message_ty *message_list_search_fuzzy_inner PARAMS ((
message_list_ty *mlp, const char *msgid, double *best_weight_p));
}
+static bool
+msgfmt_check_pair_fails (pos, msgid, msgstr, i)
+ const lex_pos_ty *pos;
+ const char *msgid;
+ const char *msgstr;
+ size_t i;
+{
+ bool failure;
+ struct formatstring_parser *parser = formatstring_parsers[i];
+ void *msgid_descr = parser->parse (msgid);
+
+ if (msgid_descr != NULL)
+ {
+ void *msgstr_descr = parser->parse (msgstr);
+
+ if (msgstr_descr != NULL)
+ {
+ failure = parser->check (pos, msgid_descr, msgstr_descr, false);
+ parser->free (msgstr_descr);
+ }
+ else
+ failure = true;
+
+ parser->free (msgid_descr);
+ }
+ else
+ failure = false;
+
+ return failure;
+}
+
message_ty *
message_merge (def, ref)
message_ty *def;
from the reference message (such as format/no-format), others
come from the definition file (fuzzy or not). */
result->is_fuzzy = def->is_fuzzy;
+
for (i = 0; i < NFORMATS; i++)
- result->is_format[i] = ref->is_format[i];
+ {
+ result->is_format[i] = ref->is_format[i];
+
+ /* If the reference message is marked as being a format specifier,
+ but the definition message is not, we check if the resulting
+ message would pass "msgfmt -c". If yes, then all is fine. If
+ not, 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
+ && ref->msgid_plural == NULL
+ && possible_format_p (ref->is_format[i])
+ && !possible_format_p (def->is_format[i])
+ && msgfmt_check_pair_fails (&def->pos, ref->msgid, msgstr, i))
+ result->is_fuzzy = true;
+ }
+
result->do_wrap = ref->do_wrap;
/* Take the file position comments from the reference file, as they
if (msgstr_descr != NULL)
{
- if (parser->check (msgid_pos, msgid_descr, msgstr_descr))
+ if (parser->check (msgid_pos, msgid_descr, msgstr_descr,
+ true))
exit_status = EXIT_FAILURE;
parser->free (msgstr_descr);
+2001-12-06 Bruno Haible <bruno@clisp.org>
+
+ * msgmerge-20: New file.
+ * Makefile.am (TESTS): Add it.
+
2001-12-03 Bruno Haible <bruno@clisp.org>
* lang-java: Pass --omit-header --no-location to xgettext.
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-19 \
+ msgmerge-18 msgmerge-19 msgmerge-20 \
msgunfmt-1 \
msguniq-1 msguniq-2 msguniq-3 \
xgettext-1 xgettext-2 xgettext-3 xgettext-4 xgettext-5 xgettext-6 \
--- /dev/null
+#! /bin/sh
+
+# Test merging of a message which has c-format specified in ref.pot but not
+# in def.po.
+
+tmpfiles=""
+trap 'rm -fr $tmpfiles' 1 2 3 15
+
+tmpfiles="$tmpfiles mm-test20.po"
+cat <<EOF > mm-test20.po
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: cog_training 1.0\n"
+"POT-Creation-Date: 2001-04-29 22:40+0200\n"
+"PO-Revision-Date: 2001-04-29 21:19+02:00\n"
+"Last-Translator: Felix N. <xyz@zyx.uucp>\n"
+"Language-Team: German <de@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: foobar.c:11
+#, c-format
+msgid "file named %s"
+msgstr "Datei namens %s"
+
+#: foobar.c:12
+#, c-format
+msgid "directory named %s"
+msgstr "Verzeichnis namens %s"
+
+#: foobar.c:13
+msgid "result %s"
+msgstr "Ergebnis %s"
+
+#: foobar.c:14
+msgid "intermediate result %s"
+msgstr "Zwischenergebnis %d"
+
+#: foobar.c:15
+msgid "%age"
+msgstr "%-Satz"
+EOF
+
+tmpfiles="$tmpfiles mm-test20.pot"
+cat <<EOF > mm-test20.pot
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2001-04-30 18:51+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: foobar.c:21
+#, c-format
+msgid "file named %s"
+msgstr ""
+
+#: foobar.c:22
+msgid "directory named %s"
+msgstr ""
+
+#: foobar.c:23
+#, c-format
+msgid "result %s"
+msgstr ""
+
+#: foobar.c:24
+#, c-format
+msgid "intermediate result %s"
+msgstr ""
+
+#: foobar.c:25
+msgid "%age"
+msgstr ""
+EOF
+
+tmpfiles="$tmpfiles mm-test20.out"
+: ${MSGMERGE=msgmerge}
+${MSGMERGE} -q mm-test20.po mm-test20.pot -o mm-test20.out
+
+tmpfiles="$tmpfiles mm-test20.ok"
+cat <<EOF > mm-test20.ok
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR Free Software Foundation, Inc.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: cog_training 1.0\n"
+"POT-Creation-Date: 2001-04-30 18:51+0200\n"
+"PO-Revision-Date: 2001-04-29 21:19+02:00\n"
+"Last-Translator: Felix N. <xyz@zyx.uucp>\n"
+"Language-Team: German <de@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: foobar.c:21
+#, c-format
+msgid "file named %s"
+msgstr "Datei namens %s"
+
+#: foobar.c:22
+msgid "directory named %s"
+msgstr "Verzeichnis namens %s"
+
+#: foobar.c:23
+#, c-format
+msgid "result %s"
+msgstr "Ergebnis %s"
+
+#: foobar.c:24
+#, fuzzy, c-format
+msgid "intermediate result %s"
+msgstr "Zwischenergebnis %d"
+
+#: foobar.c:25
+msgid "%age"
+msgstr "%-Satz"
+EOF
+
+: ${DIFF=diff}
+${DIFF} mm-test20.ok mm-test20.out
+result=$?
+
+rm -fr $tmpfiles
+
+exit $result