Skip Menu |

This queue is for tickets about the libintl-perl CPAN distribution.

Report information
The Basics
Id: 46471
Status: resolved
Priority: 0/
Queue: libintl-perl

People
Owner: GUIDO [...] cpan.org
Requestors: user42 [...] zip.com.au
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: N__() in scalar context
Date: Sat, 30 May 2009 01:09:57 +1000
To: bug-libintl-perl [...] rt.cpan.org
From: Kevin Ryde <user42 [...] zip.com.au>
With libintl-perl 0.18 and i386 debian perl 5.10.0 the program foo.pl below prints 1 where I hoped it would print true message It'd be good if a call to N__() with one arg in scalar context returned that arg. I see the SYNOPSIS section of Locale::TextDomain shows N__ with two args, my @plurals = (N__ ("One world", "{num} worlds"), N__ ("1 file", "%d files")); so I suppose in array context it should continue to return all args in case someone has cut and pasted from there. Perhaps N__n() is intended though, or if all of N__ N__n N__xn etc are aliases anyway then it doesn't matter which.
use strict; use warnings; use Locale::TextDomain; my $message = (2+2 == 4 ? N__('true message') : N__('false message')); print $message,"\n";
On Fri May 29 11:10:30 2009, user42@zip.com.au wrote: Show quoted text
> ... > It'd be good if a call to N__() with one arg in scalar context returned > that arg.
Yes, confirmed. The function is prototyped, so it can actually not be called with more than one arg. Anyway, both in scalar and array context, the argument should be returned, for practical reasons. Show quoted text
> I see the SYNOPSIS section of Locale::TextDomain shows N__ with two > args, > > my @plurals = (N__ ("One world", "{num} worlds"), > N__ ("1 file", "%d files")); > > so I suppose in array context it should continue to return all args in > case someone has cut and pasted from there. Perhaps N__n() is intended > though, or if all of N__ N__n N__xn etc are aliases anyway then it > doesn't matter which.
Yes N__n() was meant. However, all N__[np]+ functions that take more than one argument are tricky. What should be returned? Their purpose is to postpone actual translation, typically because they are called to early, and the user locale is not yet set. Let's look at N__n(). In array context, it is pretty obvious, that the caller wants all three arguments. And in scalar context? If somebody uses these functions in scalar context, it is probably a bug. Say for example, somebody really writes: my $message = N__n("One world", "{num} worlds", 3); Both strings are marked and will appear in one entry in the po file, but in this case (count is 3), the first string is effectively discarded inside the script. If you later really want the translation, you have to write it again. And either it will be found again by xgettext, or you write something really braindamaged like: my $count = int rand 10; my $void = N__n("One world", "{num} worlds", $count; my $sg = "One world"; my $pl = "{num} worlds"; POSIX::setlocale (LC_ALL, ''); my $non_void = N__n($sg, $pl, $count); Well, pretty esoteric. I will change the implementation of implementation of N__(), although it is actually a little inconsistent. But for convenience it makes sense.
Subject: Re: [rt.cpan.org #46471] N__() in scalar context
Date: Sat, 30 May 2009 02:57:19 +1000
To: bug-libintl-perl [...] rt.cpan.org
From: Kevin Ryde <user42 [...] zip.com.au>
"GUIDO via RT" <bug-libintl-perl@rt.cpan.org> writes: Show quoted text
> > The function is prototyped
Is it? I see __() prototyped, but is N__ the same? Show quoted text
> However, all N__[np]+ functions that take more than one argument are > tricky. What should be returned?
Oh, umm, yes. Show quoted text
> my $message = N__n("One world", "{num} worlds", 3);
Maybe return the two messages, and don't have a number until later. my @message = (N__n("File", "Files")); # and later ... print ngettext(@message, $count); Does that sound likely? That's how it is now is it? Or equally well with a constant of the two returned strings, if that looked better or worse. use constant MESSAGE_N => N__n("File", "Files"); ... print ngettext(MESSAGE_N, $count); Show quoted text
> my $void = N__n("One world", "{num} worlds", $count; > my $sg = "One world"; > my $pl = "{num} worlds";
Oh, well, I suppose the aim of whatever return value(s) would be to help you not write the strings twice. But I haven't struck a case myself yet where I needed to conditionalize or select a plural form :-).
On Fri May 29 12:57:46 2009, user42@zip.com.au wrote: Show quoted text
> "GUIDO via RT" <bug-libintl-perl@rt.cpan.org> writes:
> > > > The function is prototyped
> > Is it? I see __() prototyped, but is N__ the same?
You're right, I forgot that. Show quoted text
> > my $message = N__n("One world", "{num} worlds", 3);
> > Maybe return the two messages, and don't have a number until later. > > my @message = (N__n("File", "Files")); > > # and later ... > print ngettext(@message, $count); > > Does that sound likely? That's how it is now is it?
It will not work because __n() resp. ngettext() is prototyped. Show quoted text
> Or equally well with a constant of the two returned strings, if that > looked better or worse. > > use constant MESSAGE_N => N__n("File", "Files"); > ... > print ngettext(MESSAGE_N, $count);
Hm, I think it is cleaner to just return whatever you stuffed into the function. In order to accomadate the prototype of __n()/ngettext(), you have to unroll the list anyway: print __n(CONST->[0], CONST->[1], $count); Show quoted text
> Oh, well, I suppose the aim of whatever return value(s) would be to help > you not write the strings twice. But I haven't struck a case myself yet > where I needed to conditionalize or select a plural form :-).
Yes, barely needed, and that's why I hope that I can break compatibility here without later being flamed. ;-)
Subject: Re: [rt.cpan.org #46471] N__() in scalar context
Date: Sun, 31 May 2009 10:22:54 +1000
To: bug-libintl-perl [...] rt.cpan.org
From: Kevin Ryde <user42 [...] zip.com.au>
"GUIDO via RT" <bug-libintl-perl@rt.cpan.org> writes: Show quoted text
> > It will not work because __n() resp. ngettext() is prototyped.
Ah. Another reason prototypes should be banned :-) Or rather a bit of syntactic sugar on one-arg funcs, but multi-arg always seems doubtful. Show quoted text
> print __n(CONST->[0], CONST->[1], $count);
Or rather I suppose with a list constant it's print __n((CONST)[0], (CONST)[1], $count); or maybe easier to side-step the prototype print &ngettext(MSG_N, $count); Either way I suppose the count arg belongs in the ngettext, not the N__n, if the point of N__n is that it's only for marking strings, ie. much earlier than the translation lookup. You could think about taking it out of the POD of N__n and N__np.
On Sat May 30 20:24:10 2009, user42@zip.com.au wrote: Show quoted text
> "GUIDO via RT" <bug-libintl-perl@rt.cpan.org> writes:
> > > > It will not work because __n() resp. ngettext() is prototyped.
> > Ah. Another reason prototypes should be banned :-) Or rather a bit of > syntactic sugar on one-arg funcs, but multi-arg always seems doubtful.
I wanted to be able to write things like this: print __"Hello world!", "\n"; You need prototypes for that. Show quoted text
> Either way I suppose the count arg belongs in the ngettext, not the > N__n, if the point of N__n is that it's only for marking strings, > ie. much earlier than the translation lookup. You could think about > taking it out of the POD of N__n and N__np.
I thought about a consistent way, how I could explain how the N__[np]+ functions work. IMHO, the closest resemblance to the C (preprocessor) macro N_() is to define that the functions are always a complete noop, so that these things work as if you had omitted the intermediate call to the noop functions: &__(N__("Hello world!")); &__n(N__n("Hello world!", "Hello worlds!", $count)); &__p(N__p("Menu|File|", "Open")); # etc. Additional magic like discarding arguments would spoil the concept and make it even less understandable. You have a point, sure, but i kind of like the transparent approach better.
Subject: Re: [rt.cpan.org #46471] N__() in scalar context
Date: Tue, 02 Jun 2009 06:56:11 +1000
To: bug-libintl-perl [...] rt.cpan.org
From: Kevin Ryde <user42 [...] zip.com.au>
"GUIDO via RT" <bug-libintl-perl@rt.cpan.org> writes: Show quoted text
> > print __"Hello world!", "\n";
I've been happy with parens like print __('Hello'), "\n"; because I wanted to use single quotes and since __'Hello' doesn't work, of course the ' being the old package part separator. You could think about a note on the latter under the __ docs, explaining why __"" is good (and how the prototype helps) but __'' can't be used. Show quoted text
> &__n(N__n("Hello world!", "Hello worlds!", $count));
That's the one I suspect the messages would be in the N__n and the count outside, ie. &__n(N__n("Hello world!", "Hello worlds!"), $count); I guess both work, as long as it's nice and clear N__n does nothing except return all its args.
Fixed in libintl-perl 1.19.