From: Bruno Haible Date: Thu, 5 Oct 2006 11:24:13 +0000 (+0000) Subject: Extend the PO file syntax: Allow to store previous msgids. X-Git-Tag: 0.16.x-branchpoint~105 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=079e99c11d7a2b86935922f1247a9cd7a3ee20bf;p=thirdparty%2Fgettext.git Extend the PO file syntax: Allow to store previous msgids. --- diff --git a/NEWS b/NEWS index ace4acd5a..e4805b4c0 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,21 @@ Version 0.15.1 - October 2006 * Interoperability with automake-1.10. +* msgmerge has a new option --previous that has the effect of saving the + previous msgid of message when making them fuzzy. These previous msgids are + stored in the resulting PO file, using a pseudo-comment syntax like this: + + #, fuzzy + #| msgid "too many arguments" + msgid "too few arguments" + msgstr "trop d'arguments" + + The translator then only needs to compare the previous and the current + msgid ("too many arguments" and "too few arguments"), and infer which + parts of the translation she needs to change. + + msgattrib has a new option --clear-previous that removes these #| lines. + * msgmerge is faster now on CPUs with multiple execution units, if compiled with GCC 4.2 or newer. diff --git a/gettext-tools/doc/ChangeLog b/gettext-tools/doc/ChangeLog index 0d6a6d3b0..a43dac954 100644 --- a/gettext-tools/doc/ChangeLog +++ b/gettext-tools/doc/ChangeLog @@ -1,3 +1,9 @@ +2006-10-03 Bruno Haible + + * gettext.texi (PO Files): Document the "previous msgid" syntax. + * msgmerge.texi: Document the --previous option. + * msgattrib.texi: Document the --clear-previous option. + 2006-10-03 Bruno Haible * msgcmp.texi: Document --use-fuzzy and --use-untranslated options. diff --git a/gettext-tools/doc/gettext.texi b/gettext-tools/doc/gettext.texi index 25c85ce2d..feeecb51d 100644 --- a/gettext-tools/doc/gettext.texi +++ b/gettext-tools/doc/gettext.texi @@ -1147,6 +1147,7 @@ structure: #. @var{extracted-comments} #: @var{reference}@dots{} #, @var{flag}@dots{} +#| msgid @var{previous-untranslated-string} msgid @var{untranslated-string} msgstr @var{translated-string} @end example @@ -1180,7 +1181,10 @@ at the translator; these comments are called @var{extracted comments} because the @code{xgettext} program extracts them from the program's source code. Comment lines starting with @code{#:} contain references to the program's source code. Comment lines starting with @code{#,} contain -flags; more about these below. +flags; more about these below. Comment lines starting with @code{#|} +contain the previous untranslated string for which the translator gave +a translation. + All comments, of either kind, are optional. @kwindex msgid @@ -1372,6 +1376,8 @@ this: #. @var{extracted-comments} #: @var{reference}@dots{} #, @var{flag}@dots{} +#| msgctxt @var{previous-context} +#| msgid @var{previous-untranslated-string} msgctxt @var{context} msgid @var{untranslated-string} msgstr @var{translated-string} @@ -1394,6 +1400,8 @@ plural forms. #. @var{extracted-comments} #: @var{reference}@dots{} #, @var{flag}@dots{} +#| msgid @var{previous-untranslated-string-singular} +#| msgid_plural @var{previous-untranslated-string-plural} msgid @var{untranslated-string-singular} msgid_plural @var{untranslated-string-plural} msgstr[0] @var{translated-string-case-0} @@ -1415,6 +1423,11 @@ msgstr[1] "s'han trobat %d errors fatals" Here also, a @code{msgctxt} context can be specified before @code{msgid}, like above. +The @var{previous-untranslated-string} is optionally inserted by the +@code{msgmerge} program, at the same time when it marks a message fuzzy. +It helps the translator to see which changes were done by the developers +on the @var{untranslated-string}. + It happens that some lines, usually whitespace or comments, follow the very last entry of a PO file. Such lines are not part of any entry, and will be dropped when the PO file is processed by the tools, or may diff --git a/gettext-tools/doc/msgattrib.texi b/gettext-tools/doc/msgattrib.texi index 9baa603fb..596d6184f 100644 --- a/gettext-tools/doc/msgattrib.texi +++ b/gettext-tools/doc/msgattrib.texi @@ -122,6 +122,10 @@ Set all messages obsolete. @opindex --clear-obsolete@r{, @code{msgattrib} option} Set all messages non-obsolete. +@item --clear-previous +@opindex --clear-previous@r{, @code{msgattrib} option} +Remove the ``previous msgid'' (@samp{#|}) comments from all messages. + @item --only-file=@var{file} @opindex --only-file@r{, @code{msgattrib} option} Limit the attribute changes to entries that are listed in @var{file}. diff --git a/gettext-tools/doc/msgmerge.texi b/gettext-tools/doc/msgmerge.texi index 90dccd5b9..874ecae49 100644 --- a/gettext-tools/doc/msgmerge.texi +++ b/gettext-tools/doc/msgmerge.texi @@ -126,6 +126,11 @@ Apply @var{ref}.pot to each of the domains in @var{def}.po. @opindex --no-fuzzy-matching@r{, @code{msgmerge} option} Do not use fuzzy matching when an exact match is not found. This may speed up the operation considerably. + +@item --previous +@opindex --previous@r{, @code{msgmerge} option} +Keep the previous msgids of translated messages, marked with @samp{#|}, when +adding the fuzzy marker to such messages. @end table @subsection Input file syntax diff --git a/gettext-tools/src/ChangeLog b/gettext-tools/src/ChangeLog index fa3d520fb..d04f9c721 100644 --- a/gettext-tools/src/ChangeLog +++ b/gettext-tools/src/ChangeLog @@ -1,3 +1,79 @@ +2006-10-03 Bruno Haible + + * message.h (struct message_ty): New fields prev_msgctxt, prev_msgid, + prev_msgid_plural. + * message.c (message_alloc): Initialize the prev_msg* fields. + (message_free): Free the prev_msg* fields. + (message_copy): Copy the prev_msg* fields. + * msgl-ascii.c (is_ascii_message): Consider also the prev_msg* fields. + * msgl-cat.c (catenate_msgdomain_list): Copy the prev_msg* fields if + a message is copied, not merged. + * msgl-equal.c (message_equal): Consider also the prev_msg* fields. + * msgl-iconv.c (convert_prev_msgid): New function. + (iconv_message_list): Call it. + iconvable_prev_msgid): New function. + (is_message_list_iconvable): Call it. + + * po-lex.c (po_lex_previous): New variable. + (lex_start, lex_end): Reset it. + (keyword_p): Test it. New return values PREV_MSGID, PREV_MSGID_PLURAL, + PREV_MSGCTXT. + (po_gram_lex): Recognize #| and #~| syntax. New return value + PREV_STRING. + * po-gram-gen.y (do_callback_message): Add prev_msgctxt, prev_msgid, + prev_msgid_plural arguments. + (free_message_intro): New macro. + (PREV_MSGCTXT, PREV_MSGID, PREV_MSGID_PLURAL, PREV_STRING): New tokens. + (prev, message_intro): New structures. + (po_file): Renamed from msgfmt. + (message): Pass prev_* fields around. Call free_message_intro. + (message_intro, prev): New rules. + (msg_intro): Renamed from message_intro. + (prev_msg_intro, prev_msgid_pluralform, prev_string_list): New rules. + * read-po-abstract.h (struct abstract_po_reader_class_ty): Add + prev_msgctxt, prev_msgid, prev_msgid_plural arguments to the + 'directive_message' method. + (po_callback_message): Add prev_msgctxt, prev_msgid, + prev_msgid_plural arguments. + * read-po-abstract.c (call_directive_message, po_callback_message): Add + prev_msgctxt, prev_msgid, prev_msgid_plural arguments. + * read-po.h (struct default_po_reader_class_ty): Add prev_msgctxt, + prev_msgid, prev_msgid_plural arguments to the 'add_message' method. + (default_directive_message, default_add_message): Add prev_msgctxt, + prev_msgid, prev_msgid_plural arguments. + * read-po.c (call_add_message, default_directive_message, + default_add_message): Add prev_msgctxt, prev_msgid, prev_msgid_plural + arguments. + * read-properties.c (properties_parse): Update. + * read-stringtable.c (stringtable_parse): Update. + * xgettext.c (exclude_directive_message): Add prev_msgctxt, prev_msgid, + prev_msgid_plural arguments. + * x-po.c (extract_add_message): Add prev_msgctxt, prev_msgid, + prev_msgid_plural arguments. + + * write-po.c (wrap): Add extra_indent argument. + (message_print, message_print_obsolete): Print the prev_msgctxt, + prev_msgid, prev_msgid_plural fields. Compute an extra_indent. + + * msgmerge.c (keep_previous): New variable. + (long_options): Add --previous option. + (main): Handle it. + (usage): Document --previous option. + (message_merge): Add force_fuzzy argument. Set the new message's + prev_msg* fields. + (match_domain): Update. + * msgattrib.c (REMOVE_PREV): New enum item. + (long_options): Add --clear-previous option. + (main): Handle it. + (usage): Document --clear-previous option. + (process_message_list): Handle REMOVE_PREV. + * msgfmt.c (msgfmt_add_message): Add prev_msgctxt, prev_msgid, + prev_msgid_plural arguments. + * gettext-po.c (po_message_prev_msgctxt, po_message_set_prev_msgctxt, + po_message_prev_msgid, po_message_set_prev_msgid, + po_message_prev_msgid_plural, po_message_set_prev_msgid_plural): New + functions. + 2006-10-03 Bruno Haible * msgmerge.c (definitions_init): Fix initialization of fresh_lock. diff --git a/gettext-tools/src/gettext-po.c b/gettext-tools/src/gettext-po.c index b17ec5a94..597f14852 100644 --- a/gettext-tools/src/gettext-po.c +++ b/gettext-tools/src/gettext-po.c @@ -1,5 +1,5 @@ /* Public API for GNU gettext PO files. - Copyright (C) 2003-2005 Free Software Foundation, Inc. + Copyright (C) 2003-2006 Free Software Foundation, Inc. Written by Bruno Haible , 2003. This program is free software; you can redistribute it and/or modify @@ -906,6 +906,98 @@ po_message_add_filepos (po_message_t message, const char *file, size_t start_lin } +/* Return the previous context of a message, or NULL for none. */ + +const char * +po_message_prev_msgctxt (po_message_t message) +{ + message_ty *mp = (message_ty *) message; + + return mp->prev_msgctxt; +} + + +/* Change the previous context of a message. NULL is allowed. */ + +void +po_message_set_prev_msgctxt (po_message_t message, const char *prev_msgctxt) +{ + message_ty *mp = (message_ty *) message; + + if (prev_msgctxt != mp->prev_msgctxt) + { + char *old_prev_msgctxt = (char *) mp->prev_msgctxt; + + mp->prev_msgctxt = (prev_msgctxt != NULL ? xstrdup (prev_msgctxt) : NULL); + if (old_prev_msgctxt != NULL) + free (old_prev_msgctxt); + } +} + + +/* Return the previous msgid (untranslated English string) of a message, or + NULL for none. */ + +const char * +po_message_prev_msgid (po_message_t message) +{ + message_ty *mp = (message_ty *) message; + + return mp->prev_msgid; +} + + +/* Change the previous msgid (untranslated English string) of a message. + NULL is allowed. */ + +void +po_message_set_prev_msgid (po_message_t message, const char *prev_msgid) +{ + message_ty *mp = (message_ty *) message; + + if (prev_msgid != mp->prev_msgid) + { + char *old_prev_msgid = (char *) mp->prev_msgid; + + mp->prev_msgid = (prev_msgid != NULL ? xstrdup (prev_msgid) : NULL); + if (old_prev_msgid != NULL) + free (old_prev_msgid); + } +} + + +/* Return the previous msgid_plural (untranslated English plural string) of a + message, or NULL for none. */ + +const char * +po_message_prev_msgid_plural (po_message_t message) +{ + message_ty *mp = (message_ty *) message; + + return mp->prev_msgid_plural; +} + + +/* Change the previous msgid_plural (untranslated English plural string) of a + message. NULL is allowed. */ + +void +po_message_set_prev_msgid_plural (po_message_t message, const char *prev_msgid_plural) +{ + message_ty *mp = (message_ty *) message; + + if (prev_msgid_plural != mp->prev_msgid_plural) + { + char *old_prev_msgid_plural = (char *) mp->prev_msgid_plural; + + mp->prev_msgid_plural = + (prev_msgid_plural != NULL ? xstrdup (prev_msgid_plural) : NULL); + if (old_prev_msgid_plural != NULL) + free (old_prev_msgid_plural); + } +} + + /* Return true if the message is marked obsolete. */ int diff --git a/gettext-tools/src/message.c b/gettext-tools/src/message.c index bc6350e28..1bf045110 100644 --- a/gettext-tools/src/message.c +++ b/gettext-tools/src/message.c @@ -117,6 +117,9 @@ message_alloc (const char *msgctxt, for (i = 0; i < NFORMATS; i++) mp->is_format[i] = undecided; mp->do_wrap = undecided; + mp->prev_msgctxt = NULL; + mp->prev_msgid = NULL; + mp->prev_msgid_plural = NULL; mp->used = 0; mp->obsolete = false; return mp; @@ -140,6 +143,12 @@ message_free (message_ty *mp) free ((char *) mp->filepos[j].file_name); if (mp->filepos != NULL) free (mp->filepos); + if (mp->prev_msgctxt != NULL) + free ((char *) mp->prev_msgctxt); + if (mp->prev_msgid != NULL) + free ((char *) mp->prev_msgid); + if (mp->prev_msgid_plural != NULL) + free ((char *) mp->prev_msgid_plural); free (mp); } @@ -217,6 +226,12 @@ message_copy (message_ty *mp) lex_pos_ty *pp = &mp->filepos[j]; message_comment_filepos (result, pp->file_name, pp->line_number); } + result->prev_msgctxt = + (mp->prev_msgctxt != NULL ? xstrdup (mp->prev_msgctxt) : NULL); + result->prev_msgid = + (mp->prev_msgid != NULL ? xstrdup (mp->prev_msgid) : NULL); + result->prev_msgid_plural = + (mp->prev_msgid_plural != NULL ? xstrdup (mp->prev_msgid_plural) : NULL); return result; } diff --git a/gettext-tools/src/message.h b/gettext-tools/src/message.h index 5a0730172..1e04049ad 100644 --- a/gettext-tools/src/message.h +++ b/gettext-tools/src/message.h @@ -137,6 +137,12 @@ struct message_ty /* Do we want the string to be wrapped in the emitted PO file? */ enum is_wrap do_wrap; + /* The prev_msgctxt, prev_msgid and prev_msgid_plural strings appearing + before the message, if present. Generated by msgmerge. */ + const char *prev_msgctxt; + const char *prev_msgid; + const char *prev_msgid_plural; + /* If set the message is obsolete and while writing out it should be commented out. */ bool obsolete; diff --git a/gettext-tools/src/msgattrib.c b/gettext-tools/src/msgattrib.c index ad22c1b19..276ff098b 100644 --- a/gettext-tools/src/msgattrib.c +++ b/gettext-tools/src/msgattrib.c @@ -65,7 +65,8 @@ enum SET_FUZZY = 1 << 0, RESET_FUZZY = 1 << 1, SET_OBSOLETE = 1 << 2, - RESET_OBSOLETE = 1 << 3 + RESET_OBSOLETE = 1 << 3, + REMOVE_PREV = 1 << 4 }; static int to_change; @@ -75,6 +76,7 @@ static const struct option long_options[] = { "add-location", no_argument, &line_comment, 1 }, { "clear-fuzzy", no_argument, NULL, CHAR_MAX + 8 }, { "clear-obsolete", no_argument, NULL, CHAR_MAX + 10 }, + { "clear-previous", no_argument, NULL, CHAR_MAX + 18 }, { "directory", required_argument, NULL, 'D' }, { "escape", no_argument, NULL, 'E' }, { "force-po", no_argument, &force_po, 1 }, @@ -300,6 +302,10 @@ main (int argc, char **argv) message_print_syntax_stringtable (); break; + case CHAR_MAX + 18: /* --clear-previous */ + to_change |= REMOVE_PREV; + break; + default: usage (EXIT_FAILURE); /* NOTREACHED */ @@ -430,6 +436,8 @@ Attribute manipulation:\n")); printf (_("\ --clear-obsolete set all messages non-obsolete\n")); printf (_("\ + --clear-previous remove the \"previous msgid\" from all messages\n")); + printf (_("\ --only-file=FILE.po manipulate only entries listed in FILE.po\n")); printf (_("\ --ignore-file=FILE.po manipulate only entries not listed in FILE.po\n")); @@ -554,6 +562,12 @@ process_message_list (message_list_ty *mlp, mp->obsolete = true; if (to_change & RESET_OBSOLETE) mp->obsolete = false; + if (to_change & REMOVE_PREV) + { + mp->prev_msgctxt = NULL; + mp->prev_msgid = NULL; + mp->prev_msgid_plural = NULL; + } } } } diff --git a/gettext-tools/src/msgfmt.c b/gettext-tools/src/msgfmt.c index a181f71db..405e385f6 100644 --- a/gettext-tools/src/msgfmt.c +++ b/gettext-tools/src/msgfmt.c @@ -936,6 +936,9 @@ msgfmt_add_message (default_po_reader_ty *this, char *msgid_plural, char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos, + char *prev_msgctxt, + char *prev_msgid, + char *prev_msgid_plural, bool force_fuzzy, bool obsolete) { /* Check whether already a domain is specified. If not, use default @@ -951,7 +954,9 @@ msgfmt_add_message (default_po_reader_ty *this, /* Invoke superclass method. */ default_add_message (this, msgctxt, msgid, msgid_pos, msgid_plural, - msgstr, msgstr_len, msgstr_pos, force_fuzzy, obsolete); + msgstr, msgstr_len, msgstr_pos, + prev_msgctxt, prev_msgid, prev_msgid_plural, + force_fuzzy, obsolete); } diff --git a/gettext-tools/src/msgl-ascii.c b/gettext-tools/src/msgl-ascii.c index d1e4bd3ea..1ba53d8de 100644 --- a/gettext-tools/src/msgl-ascii.c +++ b/gettext-tools/src/msgl-ascii.c @@ -1,5 +1,5 @@ /* Message list test for ASCII character set. - Copyright (C) 2001-2002, 2005 Free Software Foundation, Inc. + Copyright (C) 2001-2002, 2005-2006 Free Software Foundation, Inc. Written by Bruno Haible , 2001. This program is free software; you can redistribute it and/or modify @@ -77,6 +77,14 @@ is_ascii_message (message_ty *mp) if (mp->msgctxt != NULL && !is_ascii_string (mp->msgctxt)) return false; + /* Likewise for the prev_* fields. */ + if (mp->prev_msgctxt != NULL && !is_ascii_string (mp->prev_msgctxt)) + return false; + if (mp->prev_msgid != NULL && !is_ascii_string (mp->prev_msgid)) + return false; + if (mp->prev_msgid_plural != NULL && !is_ascii_string (mp->prev_msgid_plural)) + return false; + return true; } diff --git a/gettext-tools/src/msgl-cat.c b/gettext-tools/src/msgl-cat.c index eed4a6e8a..241179cc1 100644 --- a/gettext-tools/src/msgl-cat.c +++ b/gettext-tools/src/msgl-cat.c @@ -524,6 +524,9 @@ UTF-8 encoded from the beginning, i.e. already in your source code files.\n"), for (i = 0; i < NFORMATS; i++) tmp->is_format[i] = mp->is_format[i]; tmp->do_wrap = mp->do_wrap; + tmp->prev_msgctxt = mp->prev_msgctxt; + tmp->prev_msgid = mp->prev_msgid; + tmp->prev_msgid_plural = mp->prev_msgid_plural; tmp->obsolete = mp->obsolete; } else if (msgcomm_mode) @@ -535,6 +538,9 @@ UTF-8 encoded from the beginning, i.e. already in your source code files.\n"), tmp->msgstr_len = mp->msgstr_len; tmp->pos = mp->pos; tmp->is_fuzzy = mp->is_fuzzy; + tmp->prev_msgctxt = mp->prev_msgctxt; + tmp->prev_msgid = mp->prev_msgid; + tmp->prev_msgid_plural = mp->prev_msgid_plural; } if (mp->comment && tmp->comment == NULL) for (i = 0; i < mp->comment->nitems; i++) @@ -588,6 +594,7 @@ UTF-8 encoded from the beginning, i.e. already in your source code files.\n"), tmp->is_format[i] = no; if (mp->do_wrap == no) tmp->do_wrap = no; + /* Don't fill tmp->prev_msgid in this case. */ if (!mp->obsolete) tmp->obsolete = false; } diff --git a/gettext-tools/src/msgl-equal.c b/gettext-tools/src/msgl-equal.c index 69a260252..3485709e0 100644 --- a/gettext-tools/src/msgl-equal.c +++ b/gettext-tools/src/msgl-equal.c @@ -1,5 +1,5 @@ /* Message list test for equality. - Copyright (C) 2001-2002, 2005 Free Software Foundation, Inc. + Copyright (C) 2001-2002, 2005-2006 Free Software Foundation, Inc. Written by Bruno Haible , 2001. This program is free software; you can redistribute it and/or modify @@ -181,6 +181,24 @@ message_equal (const message_ty *mp1, const message_ty *mp2, if (mp1->is_format[i] != mp2->is_format[i]) return false; + if (!(mp1->prev_msgctxt != NULL + ? mp2->prev_msgctxt != NULL + && strcmp (mp1->prev_msgctxt, mp2->prev_msgctxt) == 0 + : mp2->prev_msgctxt == NULL)) + return false; + + if (!(mp1->prev_msgid != NULL + ? mp2->prev_msgid != NULL + && strcmp (mp1->prev_msgid, mp2->prev_msgid) == 0 + : mp2->prev_msgid == NULL)) + return false; + + if (!(mp1->prev_msgid_plural != NULL + ? mp2->prev_msgid_plural != NULL + && strcmp (mp1->prev_msgid_plural, mp2->prev_msgid_plural) == 0 + : mp2->prev_msgid_plural == NULL)) + return false; + if (mp1->obsolete != mp2->obsolete) return false; diff --git a/gettext-tools/src/msgl-iconv.c b/gettext-tools/src/msgl-iconv.c index 61afda8e6..0a451c260 100644 --- a/gettext-tools/src/msgl-iconv.c +++ b/gettext-tools/src/msgl-iconv.c @@ -104,6 +104,18 @@ convert_string_list (iconv_t cd, string_list_ty *slp, slp->item[i] = convert_string (cd, slp->item[i], context); } +static void +convert_prev_msgid (iconv_t cd, message_ty *mp, + const struct conversion_context* context) +{ + if (mp->prev_msgctxt != NULL) + mp->prev_msgctxt = convert_string (cd, mp->prev_msgctxt, context); + if (mp->prev_msgid != NULL) + mp->prev_msgid = convert_string (cd, mp->prev_msgid, context); + if (mp->prev_msgid_plural != NULL) + mp->prev_msgid_plural = convert_string (cd, mp->prev_msgid_plural, context); +} + static void convert_msgid (iconv_t cd, message_ty *mp, const struct conversion_context* context) @@ -289,6 +301,7 @@ and iconv() does not support this conversion."), context.message = mp; convert_string_list (cd, mp->comment, &context); convert_string_list (cd, mp->comment_dot, &context); + convert_prev_msgid (cd, mp, &context); convert_msgid (cd, mp, &context); convert_msgstr (cd, mp, &context); } @@ -371,6 +384,21 @@ iconvable_string_list (iconv_t cd, string_list_ty *slp) return true; } +static bool +iconvable_prev_msgid (iconv_t cd, message_ty *mp) +{ + if (mp->prev_msgctxt != NULL) + if (!iconvable_string (cd, mp->prev_msgctxt)) + return false; + if (mp->prev_msgid != NULL) + if (!iconvable_string (cd, mp->prev_msgid)) + return false; + if (mp->msgid_plural != NULL) + if (!iconvable_string (cd, mp->prev_msgid_plural)) + return false; + return true; +} + static bool iconvable_msgid (iconv_t cd, message_ty *mp) { @@ -524,6 +552,7 @@ is_message_list_iconvable (message_list_ty *mlp, if (!(iconvable_string_list (cd, mp->comment) && iconvable_string_list (cd, mp->comment_dot) + && iconvable_prev_msgid (cd, mp) && iconvable_msgid (cd, mp) && iconvable_msgstr (cd, mp))) return false; diff --git a/gettext-tools/src/msgmerge.c b/gettext-tools/src/msgmerge.c index 117533871..12725879a 100644 --- a/gettext-tools/src/msgmerge.c +++ b/gettext-tools/src/msgmerge.c @@ -80,6 +80,9 @@ static bool multi_domain_mode = false; /* Determines whether to use fuzzy matching. */ static bool use_fuzzy_matching = true; +/* Determines whether to keep old msgids as previous msgids. */ +static bool keep_previous = false; + /* List of user-specified compendiums. */ static message_list_list_ty *compendiums; @@ -108,6 +111,7 @@ static const struct option long_options[] = { "no-location", no_argument, &line_comment, 0 }, { "no-wrap", no_argument, NULL, CHAR_MAX + 4 }, { "output-file", required_argument, NULL, 'o' }, + { "previous", no_argument, NULL, CHAR_MAX + 7 }, { "properties-input", no_argument, NULL, 'P' }, { "properties-output", no_argument, NULL, 'p' }, { "quiet", no_argument, NULL, 'q' }, @@ -293,6 +297,10 @@ main (int argc, char **argv) message_print_syntax_stringtable (); break; + case CHAR_MAX + 7: /* --previous */ + keep_previous = true; + break; + default: usage (EXIT_FAILURE); break; @@ -503,6 +511,8 @@ Operation modifiers:\n")); -m, --multi-domain apply ref.pot to each of the domains in def.po\n")); printf (_("\ -N, --no-fuzzy-matching do not use fuzzy matching\n")); + printf (_("\ + --previous keep previous msgids of translated messages\n")); printf ("\n"); printf (_("\ Input file syntax:\n")); @@ -758,10 +768,13 @@ msgfmt_check_pair_fails (const lex_pos_ty *pos, static message_ty * -message_merge (message_ty *def, message_ty *ref) +message_merge (message_ty *def, message_ty *ref, bool force_fuzzy) { const char *msgstr; size_t msgstr_len; + const char *prev_msgctxt; + const char *prev_msgid; + const char *prev_msgid_plural; message_ty *result; size_t j, i; @@ -968,11 +981,28 @@ message_merge (message_ty *def, message_ty *ref) msgstr = cp; msgstr_len = strlen (cp) + 1; + + prev_msgctxt = NULL; + prev_msgid = NULL; + prev_msgid_plural = NULL; } else { msgstr = def->msgstr; msgstr_len = def->msgstr_len; + + if (def->is_fuzzy) + { + prev_msgctxt = def->prev_msgctxt; + prev_msgid = def->prev_msgid; + prev_msgid_plural = def->prev_msgid_plural; + } + else + { + prev_msgctxt = def->msgctxt; + prev_msgid = def->msgid; + prev_msgid_plural = def->msgid_plural; + } } result = message_alloc (ref->msgctxt != NULL ? xstrdup (ref->msgctxt) : NULL, @@ -995,7 +1025,7 @@ message_merge (message_ty *def, message_ty *ref) /* The flags are mixed in a special way. Some informations come from the reference message (such as format/no-format), others come from the definition file (fuzzy or not). */ - result->is_fuzzy = def->is_fuzzy; + result->is_fuzzy = def->is_fuzzy | force_fuzzy; for (i = 0; i < NFORMATS; i++) { @@ -1018,6 +1048,21 @@ message_merge (message_ty *def, message_ty *ref) result->do_wrap = ref->do_wrap; + /* Insert previous msgid, commented out with "#|". + Do so only when --previous is specified, for backward compatibility. + Since the "previous msgid" represents the original msgid that led to + the current msgstr, + - we can omit it if the resulting message is not 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->is_fuzzy) + { + result->prev_msgctxt = prev_msgctxt; + result->prev_msgid = prev_msgid; + result->prev_msgid_plural = prev_msgid_plural; + } + /* Take the file position comments from the reference file, as they are generated by xgettext. Any in the definition file are old ones collected by previous runs of xgettext and msgmerge. */ @@ -1135,7 +1180,7 @@ match_domain (const char *fn1, const char *fn2, #: comments from the reference, take the # comments from the definition, take the msgstr from the definition. Add this merged entry to the output message list. */ - message_ty *mp = message_merge (defmsg, refmsg); + message_ty *mp = message_merge (defmsg, refmsg, false); message_list_append (resultmlp, mp); @@ -1168,9 +1213,7 @@ this message is used but not defined...")); #: comments from the reference, take the # comments from the definition, take the msgstr from the definition. Add this merged entry to the output message list. */ - mp = message_merge (defmsg, refmsg); - - mp->is_fuzzy = true; + mp = message_merge (defmsg, refmsg, true); message_list_append (resultmlp, mp); diff --git a/gettext-tools/src/po-gram-gen.y b/gettext-tools/src/po-gram-gen.y index 042db1100..145f27351 100644 --- a/gettext-tools/src/po-gram-gen.y +++ b/gettext-tools/src/po-gram-gen.y @@ -1,5 +1,5 @@ /* GNU gettext - internationalization aids - Copyright (C) 1995-1996, 1998, 2000-2001, 2003, 2005 Free Software Foundation, Inc. + Copyright (C) 1995-1996, 1998, 2000-2001, 2003, 2005-2006 Free Software Foundation, Inc. This file was written by Peter Miller @@ -97,6 +97,8 @@ static inline void do_callback_message (char *msgctxt, char *msgid, lex_pos_ty *msgid_pos, char *msgid_plural, char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos, + char *prev_msgctxt, + char *prev_msgid, char *prev_msgid_plural, bool obsolete) { /* Test for header entry. Ignore fuzziness of the header entry. */ @@ -106,14 +108,29 @@ do_callback_message (char *msgctxt, po_callback_message (msgctxt, msgid, msgid_pos, msgid_plural, msgstr, msgstr_len, msgstr_pos, + prev_msgctxt, prev_msgid, prev_msgid_plural, false, obsolete); } +#define free_message_intro(value) \ + if ((value).prev_ctxt != NULL) \ + free ((value).prev_ctxt); \ + if ((value).prev_id != NULL) \ + free ((value).prev_id); \ + if ((value).prev_id_plural != NULL) \ + free ((value).prev_id_plural); \ + if ((value).ctxt != NULL) \ + free ((value).ctxt); + %} %token COMMENT %token DOMAIN %token JUNK +%token PREV_MSGCTXT +%token PREV_MSGID +%token PREV_MSGID_PLURAL +%token PREV_STRING %token MSGCTXT %token MSGID %token MSGID_PLURAL @@ -129,27 +146,43 @@ do_callback_message (char *msgctxt, struct { string_list_ty stringlist; lex_pos_ty pos; bool obsolete; } stringlist; struct { long number; lex_pos_ty pos; bool obsolete; } number; struct { lex_pos_ty pos; bool obsolete; } pos; + struct { char *ctxt; char *id; char *id_plural; lex_pos_ty pos; bool obsolete; } prev; + struct { char *prev_ctxt; char *prev_id; char *prev_id_plural; char *ctxt; lex_pos_ty pos; bool obsolete; } message_intro; struct { struct msgstr_def rhs; lex_pos_ty pos; bool obsolete; } rhs; } -%type STRING COMMENT NAME message_intro msgid_pluralform -%type string_list +%type STRING PREV_STRING COMMENT NAME + msg_intro prev_msg_intro msgid_pluralform prev_msgid_pluralform +%type string_list prev_string_list %type NUMBER -%type DOMAIN MSGCTXT MSGID MSGID_PLURAL MSGSTR '[' ']' +%type DOMAIN + PREV_MSGCTXT PREV_MSGID PREV_MSGID_PLURAL + MSGCTXT MSGID MSGID_PLURAL MSGSTR '[' ']' +%type prev +%type message_intro %type pluralform pluralform_list %right MSGSTR %% -msgfmt +po_file : /* empty */ - | msgfmt comment - | msgfmt domain - | msgfmt message - | msgfmt error + | po_file comment + | po_file domain + | po_file message + | po_file error + ; + + +comment + : COMMENT + { + po_callback_comment_dispatcher ($1.string); + } ; + domain : DOMAIN STRING { @@ -157,6 +190,7 @@ domain } ; + message : message_intro string_list MSGSTR string_list { @@ -167,11 +201,14 @@ message check_obsolete ($1, $3); check_obsolete ($1, $4); if (!$1.obsolete || pass_obsolete_entries) - do_callback_message ($1.string, string2, &$1.pos, NULL, + do_callback_message ($1.ctxt, string2, &$1.pos, NULL, string4, strlen (string4) + 1, &$3.pos, + $1.prev_ctxt, + $1.prev_id, $1.prev_id_plural, $1.obsolete); else { + free_message_intro ($1); free (string2); free (string4); } @@ -184,11 +221,14 @@ message check_obsolete ($1, $3); check_obsolete ($1, $4); if (!$1.obsolete || pass_obsolete_entries) - do_callback_message ($1.string, string2, &$1.pos, $3.string, + do_callback_message ($1.ctxt, string2, &$1.pos, $3.string, $4.rhs.msgstr, $4.rhs.msgstr_len, &$4.pos, + $1.prev_ctxt, + $1.prev_id, $1.prev_id_plural, $1.obsolete); else { + free_message_intro ($1); free (string2); free ($3.string); free ($4.rhs.msgstr); @@ -199,6 +239,7 @@ message check_obsolete ($1, $2); check_obsolete ($1, $3); po_gram_error_at_line (&$1.pos, _("missing `msgstr[]' section")); + free_message_intro ($1); string_list_destroy (&$2.stringlist); free ($3.string); } @@ -207,6 +248,7 @@ message check_obsolete ($1, $2); check_obsolete ($1, $3); po_gram_error_at_line (&$1.pos, _("missing `msgid_plural' section")); + free_message_intro ($1); string_list_destroy (&$2.stringlist); free ($3.rhs.msgstr); } @@ -214,11 +256,59 @@ message { check_obsolete ($1, $2); po_gram_error_at_line (&$1.pos, _("missing `msgstr' section")); + free_message_intro ($1); string_list_destroy (&$2.stringlist); } ; + message_intro + : msg_intro + { + $$.prev_ctxt = NULL; + $$.prev_id = NULL; + $$.prev_id_plural = NULL; + $$.ctxt = $1.string; + $$.pos = $1.pos; + $$.obsolete = $1.obsolete; + } + | prev msg_intro + { + check_obsolete ($1, $2); + $$.prev_ctxt = $1.ctxt; + $$.prev_id = $1.id; + $$.prev_id_plural = $1.id_plural; + $$.ctxt = $2.string; + $$.pos = $2.pos; + $$.obsolete = $2.obsolete; + } + ; + + +prev + : prev_msg_intro prev_string_list + { + check_obsolete ($1, $2); + $$.ctxt = $1.string; + $$.id = string_list_concat_destroy (&$2.stringlist); + $$.id_plural = NULL; + $$.pos = $1.pos; + $$.obsolete = $1.obsolete; + } + | prev_msg_intro prev_string_list prev_msgid_pluralform + { + check_obsolete ($1, $2); + check_obsolete ($1, $3); + $$.ctxt = $1.string; + $$.id = string_list_concat_destroy (&$2.stringlist); + $$.id_plural = $3.string; + $$.pos = $1.pos; + $$.obsolete = $1.obsolete; + } + ; + + +msg_intro : MSGID { $$.string = NULL; @@ -235,6 +325,24 @@ message_intro } ; +prev_msg_intro + : PREV_MSGID + { + $$.string = NULL; + $$.pos = $1.pos; + $$.obsolete = $1.obsolete; + } + | PREV_MSGCTXT prev_string_list PREV_MSGID + { + check_obsolete ($1, $2); + check_obsolete ($1, $3); + $$.string = string_list_concat_destroy (&$2.stringlist); + $$.pos = $3.pos; + $$.obsolete = $3.obsolete; + } + ; + + msgid_pluralform : MSGID_PLURAL string_list { @@ -246,6 +354,17 @@ msgid_pluralform } ; +prev_msgid_pluralform + : PREV_MSGID_PLURAL prev_string_list + { + check_obsolete ($1, $2); + $$.string = string_list_concat_destroy (&$2.stringlist); + $$.pos = $1.pos; + $$.obsolete = $1.obsolete; + } + ; + + pluralform_list : pluralform { @@ -287,6 +406,7 @@ pluralform } ; + string_list : STRING { @@ -305,9 +425,20 @@ string_list } ; -comment - : COMMENT +prev_string_list + : PREV_STRING { - po_callback_comment_dispatcher ($1.string); + string_list_init (&$$.stringlist); + string_list_append (&$$.stringlist, $1.string); + $$.pos = $1.pos; + $$.obsolete = $1.obsolete; + } + | prev_string_list PREV_STRING + { + check_obsolete ($1, $2); + $$.stringlist = $1.stringlist; + string_list_append (&$$.stringlist, $2.string); + $$.pos = $1.pos; + $$.obsolete = $1.obsolete; } ; diff --git a/gettext-tools/src/po-lex.c b/gettext-tools/src/po-lex.c index c57786430..e806e9e88 100644 --- a/gettext-tools/src/po-lex.c +++ b/gettext-tools/src/po-lex.c @@ -602,6 +602,7 @@ mbfile_ungetc (const mbchar_t mbc, mbfile_t mbf) static mbfile_t mbf; unsigned int gram_max_allowed_errors = 20; static bool po_lex_obsolete; +static bool po_lex_previous; static bool pass_comments = false; bool pass_obsolete_entries = false; @@ -620,6 +621,7 @@ lex_start (FILE *fp, const char *real_filename, const char *logical_filename) gram_pos_column = 0; signal_eilseq = true; po_lex_obsolete = false; + po_lex_previous = false; po_lex_charset_init (); } @@ -633,6 +635,7 @@ lex_end () gram_pos_column = 0; signal_eilseq = false; po_lex_obsolete = false; + po_lex_previous = false; po_lex_charset_close (); } @@ -718,16 +721,29 @@ lex_ungetc (const mbchar_t mbc) static int keyword_p (const char *s) { - if (!strcmp (s, "domain")) - return DOMAIN; - if (!strcmp (s, "msgid")) - return MSGID; - if (!strcmp (s, "msgid_plural")) - return MSGID_PLURAL; - if (!strcmp (s, "msgstr")) - return MSGSTR; - if (!strcmp (s, "msgctxt")) - return MSGCTXT; + if (!po_lex_previous) + { + if (!strcmp (s, "domain")) + return DOMAIN; + if (!strcmp (s, "msgid")) + return MSGID; + if (!strcmp (s, "msgid_plural")) + return MSGID_PLURAL; + if (!strcmp (s, "msgstr")) + return MSGSTR; + if (!strcmp (s, "msgctxt")) + return MSGCTXT; + } + else + { + /* Inside a "#|" context, the keywords have a different meaning. */ + if (!strcmp (s, "msgid")) + return PREV_MSGID; + if (!strcmp (s, "msgid_plural")) + return PREV_MSGID_PLURAL; + if (!strcmp (s, "msgctxt")) + return PREV_MSGCTXT; + } po_gram_error_at_line (&gram_pos, _("keyword \"%s\" unknown"), s); return NAME; } @@ -866,6 +882,7 @@ po_gram_lex () { case '\n': po_lex_obsolete = false; + po_lex_previous = false; /* Ignore whitespace, not relevant for the grammar. */ break; @@ -886,6 +903,24 @@ po_gram_lex () characters are expected to be well formed. */ { po_lex_obsolete = true; + /* A pseudo-comment beginning with #~| denotes a previous + untranslated string in an obsolete entry. This does not + make much sense semantically, and is implemented here + for completeness only. */ + lex_getc (mbc); + if (mb_iseq (mbc, '|')) + po_lex_previous = true; + else + lex_ungetc (mbc); + break; + } + if (mb_iseq (mbc, '|')) + /* A pseudo-comment beginning with #| is found. This is + the previous untranslated string. We discard the "#|" + prefix, but change the keywords and string returns + accordingly. */ + { + po_lex_previous = true; break; } @@ -924,7 +959,7 @@ po_gram_lex () { /* We do this in separate loop because collecting large comments while they get not passed to the upper layers - is not very effective. */ + is not very efficient. */ while (!mb_iseof (mbc) && !mb_iseq (mbc, '\n')) lex_getc (mbc); po_lex_obsolete = false; @@ -979,7 +1014,7 @@ po_gram_lex () po_gram_lval.string.string = xstrdup (buf); po_gram_lval.string.pos = gram_pos; po_gram_lval.string.obsolete = po_lex_obsolete; - return STRING; + return (po_lex_previous ? PREV_STRING : STRING); case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': diff --git a/gettext-tools/src/read-po-abstract.c b/gettext-tools/src/read-po-abstract.c index b3c2790ca..c330b4d17 100644 --- a/gettext-tools/src/read-po-abstract.c +++ b/gettext-tools/src/read-po-abstract.c @@ -99,12 +99,18 @@ call_directive_message (abstract_po_reader_ty *pop, char *msgid_plural, char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos, + char *prev_msgctxt, + char *prev_msgid, + char *prev_msgid_plural, bool force_fuzzy, bool obsolete) { if (pop->methods->directive_message) pop->methods->directive_message (pop, msgctxt, msgid, msgid_pos, msgid_plural, msgstr, msgstr_len, msgstr_pos, + prev_msgctxt, + prev_msgid, + prev_msgid_plural, force_fuzzy, obsolete); } @@ -221,12 +227,16 @@ void po_callback_message (char *msgctxt, char *msgid, lex_pos_ty *msgid_pos, char *msgid_plural, char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos, + char *prev_msgctxt, + char *prev_msgid, + char *prev_msgid_plural, bool force_fuzzy, bool obsolete) { /* assert(callback_arg); */ call_directive_message (callback_arg, msgctxt, msgid, msgid_pos, msgid_plural, msgstr, msgstr_len, msgstr_pos, + prev_msgctxt, prev_msgid, prev_msgid_plural, force_fuzzy, obsolete); } diff --git a/gettext-tools/src/read-po-abstract.h b/gettext-tools/src/read-po-abstract.h index 8026bffd1..f3c9a323b 100644 --- a/gettext-tools/src/read-po-abstract.h +++ b/gettext-tools/src/read-po-abstract.h @@ -1,5 +1,5 @@ /* Reading PO files, abstract class. - Copyright (C) 1995-1996, 1998, 2000-2003, 2005 Free Software Foundation, Inc. + Copyright (C) 1995-1996, 1998, 2000-2003, 2005-2006 Free Software Foundation, Inc. This file was written by Peter Miller @@ -80,6 +80,8 @@ struct abstract_po_reader_class_ty char *msgid_plural, char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos, + char *prev_msgctxt, + char *prev_msgid, char *prev_msgid_plural, bool force_fuzzy, bool obsolete); /* What to do with a plain-vanilla comment - the expectation is that @@ -159,6 +161,8 @@ extern void po_callback_message (char *msgctxt, char *msgid_plural, char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos, + char *prev_msgctxt, + char *prev_msgid, char *prev_msgid_plural, bool force_fuzzy, bool obsolete); extern void po_callback_comment (const char *s); extern void po_callback_comment_dot (const char *s); diff --git a/gettext-tools/src/read-po.c b/gettext-tools/src/read-po.c index 4fea79b15..2ea14187d 100644 --- a/gettext-tools/src/read-po.c +++ b/gettext-tools/src/read-po.c @@ -1,5 +1,5 @@ /* Reading PO files. - Copyright (C) 1995-1998, 2000-2003, 2005 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2003, 2005-2006 Free Software Foundation, Inc. This file was written by Peter Miller This program is free software; you can redistribute it and/or modify @@ -54,6 +54,7 @@ call_add_message (struct default_po_reader_ty *this, char *msgctxt, char *msgid, lex_pos_ty *msgid_pos, char *msgid_plural, char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos, + char *prev_msgctxt, char *prev_msgid, char *prev_msgid_plural, bool force_fuzzy, bool obsolete) { default_po_reader_class_ty *methods = @@ -63,6 +64,7 @@ call_add_message (struct default_po_reader_ty *this, methods->add_message (this, msgctxt, msgid, msgid_pos, msgid_plural, msgstr, msgstr_len, msgstr_pos, + prev_msgctxt, prev_msgid, prev_msgid_plural, force_fuzzy, obsolete); } @@ -236,12 +238,16 @@ default_directive_message (abstract_po_reader_ty *that, char *msgid_plural, char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos, + char *prev_msgctxt, + char *prev_msgid, char *prev_msgid_plural, bool force_fuzzy, bool obsolete) { default_po_reader_ty *this = (default_po_reader_ty *) that; call_add_message (this, msgctxt, msgid, msgid_pos, msgid_plural, - msgstr, msgstr_len, msgstr_pos, force_fuzzy, obsolete); + msgstr, msgstr_len, msgstr_pos, + prev_msgctxt, prev_msgid, prev_msgid_plural, + force_fuzzy, obsolete); /* Prepare for next message. */ default_reset_comment_state (this); @@ -334,6 +340,9 @@ default_add_message (default_po_reader_ty *this, char *msgid_plural, char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos, + char *prev_msgctxt, + char *prev_msgid, + char *prev_msgid_plural, bool force_fuzzy, bool obsolete) { message_ty *mp; @@ -367,10 +376,18 @@ default_add_message (default_po_reader_ty *this, } /* We don't need the just constructed entries' parameter string (allocated in po-gram-gen.y). */ - free (msgstr); free (msgid); + if (msgid_plural != NULL) + free (msgid_plural); + free (msgstr); if (msgctxt != NULL) free (msgctxt); + if (prev_msgctxt != NULL) + free (prev_msgctxt); + if (prev_msgid != NULL) + free (prev_msgid); + if (prev_msgid_plural != NULL) + free (prev_msgid_plural); /* Add the accumulated comments to the message. */ default_copy_comment_state (this, mp); @@ -383,6 +400,9 @@ default_add_message (default_po_reader_ty *this, appropriate. */ mp = message_alloc (msgctxt, msgid, msgid_plural, msgstr, msgstr_len, msgstr_pos); + mp->prev_msgctxt = prev_msgctxt; + mp->prev_msgid = prev_msgid; + mp->prev_msgid_plural = prev_msgid_plural; mp->obsolete = obsolete; default_copy_comment_state (this, mp); if (force_fuzzy) diff --git a/gettext-tools/src/read-po.h b/gettext-tools/src/read-po.h index c1065a1c2..268de395b 100644 --- a/gettext-tools/src/read-po.h +++ b/gettext-tools/src/read-po.h @@ -1,5 +1,5 @@ /* Reading PO files. - Copyright (C) 1995-1998, 2000-2003, 2005 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2003, 2005-2006 Free Software Foundation, Inc. This file was written by Bruno Haible . This program is free software; you can redistribute it and/or modify @@ -59,6 +59,9 @@ struct default_po_reader_class_ty char *msgctxt, char *msgid, lex_pos_ty *msgid_pos, char *msgid_plural, char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos, + char *prev_msgctxt, + char *prev_msgid, + char *prev_msgid_plural, bool force_fuzzy, bool obsolete); /* How to modify a new message before adding it to the list. */ @@ -129,6 +132,9 @@ extern void default_directive_message (abstract_po_reader_ty *that, char *msgid_plural, char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos, + char *prev_msgctxt, + char *prev_msgid, + char *prev_msgid_plural, bool force_fuzzy, bool obsolete); extern void default_comment (abstract_po_reader_ty *that, const char *s); extern void default_comment_dot (abstract_po_reader_ty *that, const char *s); @@ -144,6 +150,9 @@ extern void default_add_message (default_po_reader_ty *this, char *msgid_plural, char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos, + char *prev_msgctxt, + char *prev_msgid, + char *prev_msgid_plural, bool force_fuzzy, bool obsolete); /* Allocate a fresh default_po_reader_ty (or derived class) instance and diff --git a/gettext-tools/src/read-properties.c b/gettext-tools/src/read-properties.c index c08839cb5..755627551 100644 --- a/gettext-tools/src/read-properties.c +++ b/gettext-tools/src/read-properties.c @@ -538,6 +538,7 @@ properties_parse (abstract_po_reader_ty *this, FILE *file, po_callback_message (NULL, msgid, &msgid_pos, NULL, msgstr, strlen (msgstr) + 1, &msgstr_pos, + NULL, NULL, NULL, force_fuzzy, false); } } diff --git a/gettext-tools/src/read-stringtable.c b/gettext-tools/src/read-stringtable.c index 1565ed397..1228f3c7f 100644 --- a/gettext-tools/src/read-stringtable.c +++ b/gettext-tools/src/read-stringtable.c @@ -881,6 +881,7 @@ stringtable_parse (abstract_po_reader_ty *pop, FILE *file, msgstr_pos = msgid_pos; po_callback_message (NULL, msgid, &msgid_pos, NULL, msgstr, strlen (msgstr) + 1, &msgstr_pos, + NULL, NULL, NULL, false, next_is_obsolete); } else if (c == '=') @@ -930,6 +931,7 @@ stringtable_parse (abstract_po_reader_ty *pop, FILE *file, /* A key/value pair. */ po_callback_message (NULL, msgid, &msgid_pos, NULL, msgstr, strlen (msgstr) + 1, &msgstr_pos, + NULL, NULL, NULL, false, next_is_obsolete); } else diff --git a/gettext-tools/src/write-po.c b/gettext-tools/src/write-po.c index 1c474de49..de35b7b9f 100644 --- a/gettext-tools/src/write-po.c +++ b/gettext-tools/src/write-po.c @@ -418,7 +418,7 @@ memcpy_small (void *dst, const void *src, size_t n) static void -wrap (const message_ty *mp, FILE *fp, const char *line_prefix, +wrap (const message_ty *mp, FILE *fp, const char *line_prefix, int extra_indent, const char *name, const char *value, enum is_wrap do_wrap, const char *charset) { @@ -711,7 +711,7 @@ internationalized messages should not contain the `\\%c' escape sequence"), See INDENT-S. */ startcol_after_break = (line_prefix ? strlen (line_prefix) : 0); if (indent) - startcol_after_break = (startcol_after_break + 8) & ~7; + startcol_after_break = (startcol_after_break + extra_indent + 8) & ~7; startcol_after_break++; /* The line width. Allow room for the closing quote character. */ @@ -728,14 +728,14 @@ internationalized messages should not contain the `\\%c' escape sequence"), { startcol += strlen (name); if (indent) - startcol = (startcol + 8) & ~7; + startcol = (startcol + extra_indent + 8) & ~7; else startcol++; } else { if (indent) - startcol = (startcol + 8) & ~7; + startcol = (startcol + extra_indent + 8) & ~7; } /* Allow room for the opening quote character. */ startcol++; @@ -772,13 +772,24 @@ internationalized messages should not contain the `\\%c' escape sequence"), if (first_line) { fputs (name, fp); - putc (indent ? '\t' : ' ', fp); + if (indent) + { + if (extra_indent > 0) + fwrite (" ", 1, extra_indent, fp); + putc ('\t', fp); + } + else + putc (' ', fp); first_line = false; } else { if (indent) - putc ('\t', fp); + { + if (extra_indent > 0) + fwrite (" ", 1, extra_indent, fp); + putc ('\t', fp); + } } /* Print the portion itself, with linebreaks where necessary. */ @@ -829,6 +840,8 @@ static void message_print (const message_ty *mp, FILE *fp, const char *charset, bool blank_line, bool debug) { + int extra_indent; + /* Separate messages with a blank line. Uniforum doesn't like blank lines, so use an empty comment (unless there already is one). */ if (blank_line && (!uniforum @@ -851,6 +864,20 @@ message_print (const message_ty *mp, FILE *fp, const char *charset, /* Print flag information in special comment. */ message_print_comment_flags (mp, fp, debug); + /* Print the previous msgid. This helps the translator when the msgid has + only slightly changed. */ + if (mp->prev_msgctxt != NULL) + wrap (mp, fp, "#| ", 0, "msgctxt", mp->prev_msgctxt, mp->do_wrap, charset); + if (mp->prev_msgid != NULL) + wrap (mp, fp, "#| ", 0, "msgid", mp->prev_msgid, mp->do_wrap, charset); + if (mp->prev_msgid_plural != NULL) + wrap (mp, fp, "#| ", 0, "msgid_plural", mp->prev_msgid_plural, mp->do_wrap, + charset); + extra_indent = (mp->prev_msgctxt != NULL || mp->prev_msgid != NULL + || mp->prev_msgid_plural != NULL + ? 3 + : 0); + /* Print each of the message components. Wrap them nicely so they are as readable as possible. If there is no recorded msgstr for this domain, emit an empty string. */ @@ -879,13 +906,16 @@ different from yours. Consider using a pure ASCII msgid instead.\n\ free (warning_message); } if (mp->msgctxt != NULL) - wrap (mp, fp, NULL, "msgctxt", mp->msgctxt, mp->do_wrap, charset); - wrap (mp, fp, NULL, "msgid", mp->msgid, mp->do_wrap, charset); + wrap (mp, fp, NULL, extra_indent, "msgctxt", mp->msgctxt, mp->do_wrap, + charset); + wrap (mp, fp, NULL, extra_indent, "msgid", mp->msgid, mp->do_wrap, charset); if (mp->msgid_plural != NULL) - wrap (mp, fp, NULL, "msgid_plural", mp->msgid_plural, mp->do_wrap, charset); + wrap (mp, fp, NULL, extra_indent, "msgid_plural", mp->msgid_plural, + mp->do_wrap, charset); if (mp->msgid_plural == NULL) - wrap (mp, fp, NULL, "msgstr", mp->msgstr, mp->do_wrap, charset); + wrap (mp, fp, NULL, extra_indent, "msgstr", mp->msgstr, mp->do_wrap, + charset); else { char prefix_buf[20]; @@ -897,7 +927,8 @@ different from yours. Consider using a pure ASCII msgid instead.\n\ p += strlen (p) + 1, i++) { sprintf (prefix_buf, "msgstr[%u]", i); - wrap (mp, fp, NULL, prefix_buf, p, mp->do_wrap, charset); + wrap (mp, fp, NULL, extra_indent, prefix_buf, p, mp->do_wrap, + charset); } } } @@ -907,6 +938,8 @@ static void message_print_obsolete (const message_ty *mp, FILE *fp, const char *charset, bool blank_line) { + int extra_indent; + /* If msgstr is the empty string we print nothing. */ if (mp->msgstr[0] == '\0') return; @@ -942,6 +975,20 @@ message_print_obsolete (const message_ty *mp, FILE *fp, const char *charset, putc ('\n', fp); } + /* Print the previous msgid. This helps the translator when the msgid has + only slightly changed. */ + if (mp->prev_msgctxt != NULL) + wrap (mp, fp, "#~| ", 0, "msgctxt", mp->prev_msgctxt, mp->do_wrap, charset); + if (mp->prev_msgid != NULL) + wrap (mp, fp, "#~| ", 0, "msgid", mp->prev_msgid, mp->do_wrap, charset); + if (mp->prev_msgid_plural != NULL) + wrap (mp, fp, "#~| ", 0, "msgid_plural", mp->prev_msgid_plural, mp->do_wrap, + charset); + extra_indent = (mp->prev_msgctxt != NULL || mp->prev_msgid != NULL + || mp->prev_msgid_plural != NULL + ? 1 + : 0); + /* Print each of the message components. Wrap them nicely so they are as readable as possible. */ if (mp->msgctxt != NULL && !is_ascii_string (mp->msgctxt) @@ -969,14 +1016,16 @@ different from yours. Consider using a pure ASCII msgid instead.\n\ free (warning_message); } if (mp->msgctxt != NULL) - wrap (mp, fp, "#~ ", "msgctxt", mp->msgctxt, mp->do_wrap, charset); - wrap (mp, fp, "#~ ", "msgid", mp->msgid, mp->do_wrap, charset); - if (mp->msgid_plural != NULL) - wrap (mp, fp, "#~ ", "msgid_plural", mp->msgid_plural, mp->do_wrap, + wrap (mp, fp, "#~ ", extra_indent, "msgctxt", mp->msgctxt, mp->do_wrap, charset); + wrap (mp, fp, "#~ ", extra_indent, "msgid", mp->msgid, mp->do_wrap, charset); + if (mp->msgid_plural != NULL) + wrap (mp, fp, "#~ ", extra_indent, "msgid_plural", mp->msgid_plural, + mp->do_wrap, charset); if (mp->msgid_plural == NULL) - wrap (mp, fp, "#~ ", "msgstr", mp->msgstr, mp->do_wrap, charset); + wrap (mp, fp, "#~ ", extra_indent, "msgstr", mp->msgstr, mp->do_wrap, + charset); else { char prefix_buf[20]; @@ -988,7 +1037,8 @@ different from yours. Consider using a pure ASCII msgid instead.\n\ p += strlen (p) + 1, i++) { sprintf (prefix_buf, "msgstr[%u]", i); - wrap (mp, fp, "#~ ", prefix_buf, p, mp->do_wrap, charset); + wrap (mp, fp, "#~ ", extra_indent, prefix_buf, p, mp->do_wrap, + charset); } } } diff --git a/gettext-tools/src/x-po.c b/gettext-tools/src/x-po.c index f57ab70b1..5db3af3f5 100644 --- a/gettext-tools/src/x-po.c +++ b/gettext-tools/src/x-po.c @@ -1,5 +1,5 @@ /* xgettext PO and JavaProperties backends. - Copyright (C) 1995-1998, 2000-2003, 2005 Free Software Foundation, Inc. + Copyright (C) 1995-1998, 2000-2003, 2005-2006 Free Software Foundation, Inc. This file was written by Peter Miller @@ -53,6 +53,9 @@ extract_add_message (default_po_reader_ty *this, char *msgid_plural, char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos, + char *prev_msgctxt, + char *prev_msgid, + char *prev_msgid_plural, bool force_fuzzy, bool obsolete) { /* See whether we shall exclude this message. */ @@ -87,13 +90,23 @@ extract_add_message (default_po_reader_ty *this, if (msgctxt != NULL) free (msgctxt); free (msgid); + if (msgid_plural != NULL) + free (msgid_plural); free (msgstr); + if (prev_msgctxt != NULL) + free (prev_msgctxt); + if (prev_msgid != NULL) + free (prev_msgid); + if (prev_msgid_plural != NULL) + free (prev_msgid_plural); return; } /* Invoke superclass method. */ default_add_message (this, msgctxt, msgid, msgid_pos, msgid_plural, - msgstr, msgstr_len, msgstr_pos, force_fuzzy, obsolete); + msgstr, msgstr_len, msgstr_pos, + prev_msgctxt, prev_msgid, prev_msgid_plural, + force_fuzzy, obsolete); } diff --git a/gettext-tools/src/xgettext.c b/gettext-tools/src/xgettext.c index aaabe8c49..6c0c81c24 100644 --- a/gettext-tools/src/xgettext.c +++ b/gettext-tools/src/xgettext.c @@ -914,6 +914,9 @@ exclude_directive_message (abstract_po_reader_ty *pop, char *msgid_plural, char *msgstr, size_t msgstr_len, lex_pos_ty *msgstr_pos, + char *prev_msgctxt, + char *prev_msgid, + char *prev_msgid_plural, bool force_fuzzy, bool obsolete) { message_ty *mp; diff --git a/gettext-tools/tests/ChangeLog b/gettext-tools/tests/ChangeLog index 9567ab7b7..459be674c 100644 --- a/gettext-tools/tests/ChangeLog +++ b/gettext-tools/tests/ChangeLog @@ -1,3 +1,17 @@ +2006-10-03 Bruno Haible + + * msgattrib-16: New file. + * msgattrib-17: New file. + * msgcat-15: New file. + * msgcat-16: New file. + * msgcmp-4: New file. + * msgcomm-26: New file. + * msgconv-6: New file. + * msgfmt-16: New file. + * msgmerge-19: New file. + * msguniq-6: New file. + * Makefile.am (TESTS): Add them. + 2006-10-03 Bruno Haible * msgmerge-18: Invoke msgcmp with options --use-fuzzy and diff --git a/gettext-tools/tests/Makefile.am b/gettext-tools/tests/Makefile.am index c74903db8..72dd48f5a 100644 --- a/gettext-tools/tests/Makefile.am +++ b/gettext-tools/tests/Makefile.am @@ -25,24 +25,27 @@ TESTS = gettext-1 gettext-2 gettext-3 gettext-4 gettext-5 gettext-6 gettext-7 \ msgattrib-1 msgattrib-2 msgattrib-3 msgattrib-4 msgattrib-5 \ msgattrib-6 msgattrib-7 msgattrib-8 msgattrib-9 msgattrib-10 \ msgattrib-11 msgattrib-12 msgattrib-13 msgattrib-14 msgattrib-15 \ + msgattrib-16 msgattrib-17 \ msgattrib-properties-1 \ msgcat-1 msgcat-2 msgcat-3 msgcat-4 msgcat-5 msgcat-6 msgcat-7 \ msgcat-8 msgcat-9 msgcat-10 msgcat-11 msgcat-12 msgcat-13 msgcat-14 \ + msgcat-15 msgcat-16 \ msgcat-properties-1 msgcat-properties-2 \ msgcat-stringtable-1 \ - msgcmp-1 msgcmp-2 msgcmp-3 \ + msgcmp-1 msgcmp-2 msgcmp-3 msgcmp-4 \ msgcomm-1 msgcomm-2 msgcomm-3 msgcomm-4 msgcomm-5 msgcomm-6 msgcomm-7 \ msgcomm-8 msgcomm-9 msgcomm-10 msgcomm-11 msgcomm-12 msgcomm-13 \ msgcomm-14 msgcomm-15 msgcomm-16 msgcomm-17 msgcomm-18 msgcomm-19 \ msgcomm-20 msgcomm-21 msgcomm-22 msgcomm-23 msgcomm-24 msgcomm-25 \ - msgconv-1 msgconv-2 msgconv-3 msgconv-4 msgconv-5 \ + msgcomm-26 \ + msgconv-1 msgconv-2 msgconv-3 msgconv-4 msgconv-5 msgconv-6 \ msgen-1 msgen-2 msgen-3 \ msgexec-1 msgexec-2 msgexec-3 msgexec-4 \ msgfilter-1 msgfilter-2 msgfilter-3 msgfilter-4 \ msgfilter-sr-latin-1 \ msgfmt-1 msgfmt-2 msgfmt-3 msgfmt-4 msgfmt-5 msgfmt-6 msgfmt-7 \ msgfmt-8 msgfmt-9 msgfmt-10 msgfmt-11 msgfmt-12 msgfmt-13 msgfmt-14 \ - msgfmt-15 \ + msgfmt-15 msgfmt-16 \ msgfmt-properties-1 \ msgfmt-qt-1 msgfmt-qt-2 \ msggrep-1 msggrep-2 msggrep-3 msggrep-4 msggrep-5 msggrep-6 msggrep-7 \ @@ -51,7 +54,7 @@ TESTS = gettext-1 gettext-2 gettext-3 gettext-4 gettext-5 gettext-6 gettext-7 \ 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-18 msgmerge-19 \ msgmerge-compendium-1 msgmerge-compendium-2 msgmerge-compendium-3 \ msgmerge-compendium-4 msgmerge-compendium-5 msgmerge-compendium-6 \ msgmerge-properties-1 msgmerge-properties-2 \ @@ -61,7 +64,7 @@ TESTS = gettext-1 gettext-2 gettext-3 gettext-4 gettext-5 gettext-6 gettext-7 \ msgunfmt-java-1 \ msgunfmt-properties-1 \ msgunfmt-tcl-1 \ - msguniq-1 msguniq-2 msguniq-3 msguniq-4 msguniq-5 \ + msguniq-1 msguniq-2 msguniq-3 msguniq-4 msguniq-5 msguniq-6 \ recode-sr-latin-1 recode-sr-latin-2 \ xgettext-1 xgettext-2 xgettext-3 xgettext-4 xgettext-5 xgettext-6 \ xgettext-7 xgettext-8 xgettext-9 \