After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 328988 - translatable string conflict: "second"
translatable string conflict: "second"
Status: RESOLVED FIXED
Product: evolution
Classification: Applications
Component: Calendar
2.6.x (obsolete)
Other All
: Normal trivial
: ---
Assigned To: evolution-calendar-maintainers
Evolution QA team
Depends on:
Blocks: 327508
 
 
Reported: 2006-01-28 17:21 UTC by Changwoo Ryu
Modified: 2013-09-13 00:52 UTC
See Also:
GNOME target: ---
GNOME version: 2.13/2.14


Attachments
proposed additional patch with gettext context (2.66 KB, patch)
2006-02-12 12:05 UTC, Theppitak Karoonboonyanan
none Details | Review
proposed fix (3.84 KB, patch)
2006-02-13 01:44 UTC, Karsten Bräckelmann
none Details | Review
proposed patch using ngettext and Q_() (6.00 KB, patch)
2006-02-13 10:02 UTC, Theppitak Karoonboonyanan
none Details | Review
more polished patch (6.03 KB, patch)
2006-02-13 15:09 UTC, Theppitak Karoonboonyanan
reviewed Details | Review
rewritten calculate_time() + using Q_() (9.10 KB, patch)
2006-02-13 18:21 UTC, Theppitak Karoonboonyanan
none Details | Review
Simplified patch (7.97 KB, patch)
2006-02-27 06:41 UTC, Theppitak Karoonboonyanan
reviewed Details | Review
Updated patch, without string freeze breaking (5.55 KB, patch)
2006-02-28 15:07 UTC, Theppitak Karoonboonyanan
committed Details | Review

Description Changwoo Ryu 2006-01-28 17:21:35 UTC
Please describe the problem:
In recurrence-page.c, "second" means "2nd".  

	static const char *options[] = {
		N_("first"),
		N_("second"),
		N_("third"),
		N_("fourth"),
		N_("last")
	};

But in misc.c and util.c, "second" is used for time..  

			str = g_strdup_printf (_("(%d %s %d %s)"), minutes, ngettext(_("minute"),
_("minutes"), minutes), seconds, ngettext(_("second"), _("seconds"), seconds));

These "second"s should be distinguished or translators couldn't translate them
correctly.


Steps to reproduce:
1. 
2. 
3. 


Actual results:


Expected results:


Does this happen every time?


Other information:
Comment 1 Karsten Bräckelmann 2006-01-28 18:05:19 UTC
Confirming. Adding appropriate keywords.
Comment 4 Theppitak Karoonboonyanan 2006-02-12 10:08:19 UTC
While translator comments are pretty much appreciated,
I don't think the problem is really solved. Translators still cannot
provide different translations for different meanings, as they still
share the same msgid entry. Maybe, gettext context helps?

Please re-open the bug.
Comment 5 Theppitak Karoonboonyanan 2006-02-12 12:05:31 UTC
Created attachment 59175 [details] [review]
proposed additional patch with gettext context
Comment 6 André Klapper 2006-02-12 12:22:31 UTC
reopening as per comment 4.
Comment 7 Karsten Bräckelmann 2006-02-12 19:53:48 UTC
Agreed to Theppitak in comment 4. Actaully, I just came across this and was about to propose the very same. :)

The patch looks good to me. Unfortunetaly I lack the gettext experience to actually approve the patch.
Comment 8 Karsten Bräckelmann 2006-02-13 00:49:29 UTC
Ah, nope. As discused on IRC, when using prefixes we need to use Q_() rather than _(). Probably going to fix this in a few...
Comment 9 Karsten Bräckelmann 2006-02-13 01:44:54 UTC
Created attachment 59222 [details] [review]
proposed fix

use prefixes and Q_()
Comment 10 James Henstridge 2006-02-13 01:59:01 UTC
Comment on attachment 59222 [details] [review]
proposed fix

>Index: gui/misc.c
>===================================================================
>RCS file: /cvs/gnome/evolution/calendar/gui/misc.c,v
>retrieving revision 1.7
>diff -p -u -r1.7 misc.c
>--- gui/misc.c	11 Feb 2006 19:14:49 -0000	1.7
>+++ gui/misc.c	13 Feb 2006 01:42:17 -0000
>@@ -109,7 +109,7 @@ calculate_time (time_t start, time_t end
> 		seconds = difference % 60;
> 		if (seconds)
> 		/* TRANSLATORS: here, "second" is the time division (like "minute"), not the ordinal number (like "third") */
>-			str = g_strdup_printf (_("(%d %s %d %s)"), minutes, ngettext(_("minute"), _("minutes"), minutes), seconds, ngettext(_("second"), _("seconds"), seconds));
>+			str = g_strdup_printf (_("(%d %s %d %s)"), minutes, ngettext(_("minute"), _("minutes"), minutes), seconds, ngettext(Q_("time|second"), _("seconds"), seconds));
> 		else 
> 			str = g_strdup_printf (_("(%d %s)"), minutes, ngettext(_("minute"), _("minutes"), minutes));

The ngettext() usage in this function looks incorrect both before and after this patch.  The arguments to ngettext() should not be marked for translation to begin with (it is the "minute"/"minutes" pair that is used as a key when looking up the translation).

It is possible that if they weren't marked, that this would not be an issue ...


>Index: gui/alarm-notify/util.c
>===================================================================
>RCS file: /cvs/gnome/evolution/calendar/gui/alarm-notify/util.c,v
>retrieving revision 1.7
>diff -p -u -r1.7 util.c
>--- gui/alarm-notify/util.c	11 Feb 2006 19:14:49 -0000	1.7
>+++ gui/alarm-notify/util.c	13 Feb 2006 01:42:17 -0000

The same issue applies here.

>Index: gui/dialogs/recurrence-page.c
>===================================================================
>RCS file: /cvs/gnome/evolution/calendar/gui/dialogs/recurrence-page.c,v
>retrieving revision 1.77
>diff -p -u -r1.77 recurrence-page.c
>--- gui/dialogs/recurrence-page.c	12 Feb 2006 21:53:32 -0000	1.77
>+++ gui/dialogs/recurrence-page.c	13 Feb 2006 01:42:17 -0000
>@@ -995,7 +995,7 @@ make_recur_month_num_menu (int month_ind
> 		 * (dropdown menu options are in [square brackets]). This means that after 'second', either the string 'day' or 
> 		 * the name of a week day (like 'Monday' or 'Friday') always follow.
> 		 */
>-		N_("second"),
>+		N_("ordinal|second"),
> 		/* TRANSLATORS: Entire string is for example: This appointment recurs/Every [x] month(s) on the [third] [Monday] [forever]'
> 		 * (dropdown menu options are in [square brackets]). This means that after 'third', either the string 'day' or 
> 		 * the name of a week day (like 'Monday' or 'Friday') always follow.
>@@ -1021,7 +1021,7 @@ make_recur_month_num_menu (int month_ind
> 
> 	/* Relation */
> 	for (i = 0; i < sizeof (options) / sizeof (options[0]); i++) {
>-		item = gtk_menu_item_new_with_label (_(options[i]));
>+		item = gtk_menu_item_new_with_label (Q_(options[i]));
> 		gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
> 		gtk_widget_show (item);
> 	}

This change looks good, although it might be worth adding the same context to the other strings.
Comment 11 Karsten Bräckelmann 2006-02-13 02:27:17 UTC
So we don't need _() inside negttext...

There is a bunch of other usage of the same broken code. Plus, there are kind of duplicated strings marked for translation. Like "minutes" and "%s minutes".

I am so not going to fix this tonight...
Comment 12 James Henstridge 2006-02-13 02:42:47 UTC
For reference, you can tell if the ngettext() call has been extracted correctly by looking at the PO file template.

If you see an entry like this, then the string is being handled correctly:
  msgid "minute"
  msgid_plural "minutes"
  msgstr[0] ""
  msgstr[1] ""

If they are being treated as separate translations, you'd see:
  msgid "minute"
  msgstr ""

  msgid "minutes"
  msgstr ""

Note that while the second case works okay for languages with the same plural rules as English, it is not enough for other languages (which might have more than two plural forms).
Comment 13 Theppitak Karoonboonyanan 2006-02-13 10:02:59 UTC
Created attachment 59246 [details] [review]
proposed patch using ngettext and Q_()

I totally agree with using ngettext(). My first patch was so quick and dirty indeed.

So, I propose another patch based on what suggested here. Note that context is still required for the ordinal case.
Comment 14 Theppitak Karoonboonyanan 2006-02-13 15:09:06 UTC
Created attachment 59265 [details] [review]
more polished patch

As guenther suggested on IRC, I have prepared an improved patch which further unifies the translations of the plural forms.
Comment 15 Karsten Bräckelmann 2006-02-13 15:16:43 UTC
That last patch looks good to me by a quick glimpse. :)  Obsoletes my patch.
Comment 16 James Henstridge 2006-02-13 15:32:24 UTC
Actually, there is a reason to prefer "%u minutes" as a translatable string over "minutes".  With the former, the translator can reorder the words in the phrase (which is important for some languages).
Comment 17 Theppitak Karoonboonyanan 2006-02-13 15:48:19 UTC
In that case, _(" %u %s") in the front still provides the possibility?
Comment 18 James Henstridge 2006-02-13 15:52:49 UTC
It is possible if you use C99 format string extensions to reorder the arguments, but it is nicer not to have to rely on that if possible, since it isn't supported on all platforms yet.

It is worth noting that a translatable string like "%u %s" would almost definitely need some context ...
Comment 19 Theppitak Karoonboonyanan 2006-02-13 16:17:24 UTC
Hmm.. That means the code in if (difference > 60 && difference < 3600) ... 
case also needs to be changed. And, with the "%d" or "%u", with or without 
leading space, that would result in many combinations.

To minimize duplicated strings to translate, wouldn't it be better to 
prepare the "%u second(s)", "%u minute(s)" and "%u hour(s)" fragments separately 
without the leading space concern, and then combine them afterwards case by case?
Comment 20 André Klapper 2006-02-13 17:45:13 UTC
I am definitely not qualified to comment on that, therefore reassigning.
Comment 21 Theppitak Karoonboonyanan 2006-02-13 18:21:22 UTC
Created attachment 59279 [details] [review]
rewritten calculate_time() + using Q_()

In this patch, calculate_time() is rewritten as shown below
(without new strings introduced, as necessary strings are
already in POT):

char *
calculate_time (time_t start, time_t end)
{
        time_t difference = end - start;
        char *str;
        int   hours, minutes;
        char *s_hours = NULL, *s_minutes = NULL, *s_seconds = NULL;

        if (difference >= 3600) {
                hours = difference / 3600;
                difference %= 3600;

                s_hours = g_strdup_printf (ngettext("%d hour", "%d hours", hours), hours);
        }
        if (difference >= 60) {
                minutes = difference / 60;
                difference %= 60;

                s_minutes = g_strdup_printf (ngettext("%d minute", "%d minutes", minutes), minutes);
        }
        /* TRANSLATORS: here, "second" is the time division (like "minute"), not the ordinal number (like "third") */
        s_seconds = g_strdup_printf (ngettext("%d second", "%d seconds", difference), (int)difference);

        if (s_hours) {
                if (s_minutes)  {
                        if (s_seconds) {
                                str = g_strconcat ("(", s_hours,
                                                   " ", s_minutes,
                                                   " ", s_seconds, ")", NULL);
                        } else {
                                str = g_strconcat ("(", s_hours,
                                                   " ", s_minutes, ")", NULL);
                        }
                } else {
                        if (s_seconds) {
                                str = g_strconcat ("(", s_hours,
                                                   " ", s_seconds, ")", NULL);
                        } else {
                                str = g_strconcat ("(", s_hours, ")", NULL);
                        }
                }
        } else {
                if (s_minutes)  {
                        if (s_seconds) {
                                str = g_strconcat ("(", s_minutes,
                                                   " ", s_seconds, ")", NULL);
                        } else {
                                str = g_strconcat ("(", s_minutes, ")", NULL);
                        }
                } else {
                        str = g_strconcat ("(", s_seconds, ")", NULL);
                }
        }

        g_free (s_hours);
        g_free (s_minutes);
        g_free (s_seconds);

        return g_strchug(str);
}
Comment 22 Theppitak Karoonboonyanan 2006-02-13 18:29:36 UTC
As a notice, this still breaks string freeze, anyway, in the prefixed strings part.
Comment 23 André Klapper 2006-02-26 15:24:16 UTC
*ping*
anyone qualified (james? ;-) willing to review thep's patch?
thanks very much in advance...
Comment 24 James Henstridge 2006-02-27 03:55:23 UTC
The code looks like it uses ngettext() correctly, but I have a few comments on the code changes themselves.

For a start, the code for putting together the time components looks more complicated than it needs to be.  How about something like this:

  char *times[4] = { NULL, };
  int i = 0

  if (has_hour) {
      times[i++] = g_strdup_printf(ngettext("%d hour", ...
  }
  if (has_minute) {
      times[i++] = g_strdup_printf(ngettext("%d minute", ...
  }
  if (has_second) {
      times[i++] = g_strdup_printf(ngettext("%d second", ...
  }

  joined = g_strjoin(" ", times);
  str = g_strconcat("(", joined, ")", NULL);

  for (i = 0; times[i] != NULL; i++)
      g_free(times[i]);
  g_free(joined);

This is easier to understand, and doesn't lead to a combinatorial explosion when assembling the time quantities.

Secondly, this code appears to be duplicated almost exactly in the two places.  Is there a place this code could be placed to make it useful to both parts of Evolution?

Lastly, it would be good to decide how 0 seconds should be handled.  With the pseudo-code I listed above, you'd probably get "()" for 0 seconds.  It would be good to make the function return "(0 seconds)" or similar in this case.
Comment 25 Theppitak Karoonboonyanan 2006-02-27 06:41:27 UTC
Created attachment 60207 [details] [review]
Simplified patch

Thank you for the review. I have simplified the patch as you suggested.
For the case of 0 seconds, I have added a check in my patch so that the 
text is generated only if no hours nor minutes texts are generated before.
(In previous patch, it always generates, to guarantee the calculated
string not to be empty. But that's too loose for cases like 60 seconds.)

I won't touch the refactoring for now. I don't think I know the source
tree well enough.
Comment 26 James Henstridge 2006-02-27 08:39:30 UTC
Comment on attachment 60207 [details] [review]
Simplified patch

Looks great.  The only change I'd make now is to remove the g_strchug() call at the end of the function.

The string shouldn't ever end up with leading whitespace, so there should be no reason to trim it.

I guess you just need the sign off from one of the Evo developers now.
Comment 27 Theppitak Karoonboonyanan 2006-02-28 15:07:32 UTC
Created attachment 60321 [details] [review]
Updated patch, without string freeze breaking

g_strchug() removed as noticed.

Another notice is that the "ordinal|" prefixes are now unnecessary,
as the "second" strings are now totally removed from time calculation.
So, this bug could be fixed without breaking string freeze!
Comment 28 James Henstridge 2006-02-28 15:28:13 UTC
That is pretty lucky that the plural form translations exist in calendar/gui/e-alarm-list.c.

I'd expect the translators to be in favour of this patch then, since they'd fall into one of the following two categories:
 * they translate "second" to the same thing in both ordinal and time based
   contexts, so the change doesn't affect them.
 * "second" should be translated differently by context, so their translation
   was incorrect before this patch but shouldn't be any less correct with the
   patch.

Good work, Theppitak.
Comment 29 Theppitak Karoonboonyanan 2006-03-01 05:32:58 UTC
So, can I commit it?
Comment 30 André Klapper 2006-03-01 11:14:51 UTC
srag will take care of this so we get this in before 2.6
Comment 31 André Klapper 2006-03-03 14:16:40 UTC
srag: *poke*.
Comment 32 Srinivasa Ragavan 2006-03-06 09:35:05 UTC
Committed to HEAD. Thanks for your patch.