Javascript i18n bug?

30 views
Skip to first unread message

Julien

unread,
Mar 21, 2008, 1:36:56 AM3/21/08
to Django users
Hi,

Instructions on the page http://www.djangoproject.com/documentation/i18n/#using-the-javascript-translation-catalog
suggest to use the function 'ungettext'.

However the script generated by the view
'django.views.i18n.javascript_catalog' has no function named
'ungettext'. Instead it has a function named 'ngettext'.

It's the first time I'm using that feature, so I'm not sure if that's
normal. Is that a bug or am I missing something?

Cheers,

Julien


FYI, the full content of the generated script:

/* gettext library */

var catalog = new Array();

function pluralidx(count) { return (count == 1) ? 0 : 1; }


function gettext(msgid) {
var value = catalog[msgid];
if (typeof(value) == 'undefined') {
return msgid;
} else {
return (typeof(value) == 'string') ? value : value[0];
}
}

function ngettext(singular, plural, count) {
value = catalog[singular];
if (typeof(value) == 'undefined') {
return (count == 1) ? singular : plural;
} else {
return value[pluralidx(count)];
}
}

function gettext_noop(msgid) { return msgid; }

function interpolate(fmt, obj, named) {
if (named) {
return fmt.replace(/%\(\w+\)s/g, function(match){return
String(obj[match.slice(2,-2)])});
} else {
return fmt.replace(/%s/g, function(match){return
String(obj.shift())});
}
}

Malcolm Tredinnick

unread,
Mar 21, 2008, 5:52:00 AM3/21/08
to django...@googlegroups.com

On Thu, 2008-03-20 at 22:36 -0700, Julien wrote:
> Hi,
>
> Instructions on the page http://www.djangoproject.com/documentation/i18n/#using-the-javascript-translation-catalog
> suggest to use the function 'ungettext'.
>
> However the script generated by the view
> 'django.views.i18n.javascript_catalog' has no function named
> 'ungettext'. Instead it has a function named 'ngettext'.
>
> It's the first time I'm using that feature, so I'm not sure if that's
> normal. Is that a bug or am I missing something?

Yeah, somebody's gotten a little bit excited there with
search-and-replace at some point. It should be ngettext(), not
ungettext().

Regards,
Malcolm

--
If you think nobody cares, try missing a couple of payments.
http://www.pointy-stick.com/blog/

Julien

unread,
Mar 21, 2008, 8:27:05 AM3/21/08
to Django users
Ok, that makes more sense now. Btw, I noticed another tiny bug in the
doc:

urlpatterns = patterns('',
(r'^jsi18n/(?P<packages>\S+?)/$,
'django.views.i18n.javascript_catalog'),
)

There's a missing quote after the dollar sign. Does all these things
deserve opening a ticket?

On Mar 21, 8:52 pm, Malcolm Tredinnick <malc...@pointy-stick.com>
wrote:
> On Thu, 2008-03-20 at 22:36 -0700, Julien wrote:
> > Hi,
>
> > Instructions on the pagehttp://www.djangoproject.com/documentation/i18n/#using-the-javascript...

Malcolm Tredinnick

unread,
Mar 21, 2008, 8:28:52 AM3/21/08
to django...@googlegroups.com

On Fri, 2008-03-21 at 05:27 -0700, Julien wrote:
> Ok, that makes more sense now. Btw, I noticed another tiny bug in the
> doc:
>
> urlpatterns = patterns('',
> (r'^jsi18n/(?P<packages>\S+?)/$,
> 'django.views.i18n.javascript_catalog'),
> )
>
> There's a missing quote after the dollar sign. Does all these things
> deserve opening a ticket?

Depends on whether you'd like them to be fixed or not. :-)

Malcolm

--
Tolkien is hobbit-forming.
http://www.pointy-stick.com/blog/

Julien

unread,
Mar 21, 2008, 8:37:29 AM3/21/08
to Django users
I've found another problem.

The javascript_catalog view generates the right catalog script:

var catalog = new Array();

function pluralidx(count) { return (count == 1) ? 0 : 1; }

catalog['You have %(count)s emails.'] = 'Vous avez %(count)s emails.';
catalog['You have 1 email.'] = 'Vous avez 1 email.';

function gettext(msgid) {
var value = catalog[msgid];
if (typeof(value) == 'undefined') {
return msgid;
} else {
return (typeof(value) == 'string') ? value : value[0];
}
}

function ngettext(singular, plural, count) {
value = catalog[singular];
if (typeof(value) == 'undefined') {
return (count == 1) ? singular : plural;
} else {
return value[pluralidx(count)];
}
}

function gettext_noop(msgid) { return msgid; }

function interpolate(fmt, obj, named) {
if (named) {
return fmt.replace(/%\(\w+\)s/g, function(match){return
String(obj[match.slice(2,-2)])});
} else {
return fmt.replace(/%s/g, function(match){return
String(obj.shift())});
}
}


Then, when I run the script:
$contact_header.html(interpolate(ngettext('You have 1 contact.', 'You
have %(count)s contacts.', contact_count), [contact_count]));

The right translation is fetched from the catalog, but only the first
letter is displayed, in this case the letter "V". This is because of
the "return value[pluralidx(count)]" statement in the ngettext
function, which returns the first (or the second if it's plural)
element of the string "value".

Again, is that a bug or am I misusing this feature?

Thanks!

Julien

Ramiro Morales

unread,
Mar 21, 2008, 7:11:21 PM3/21/08
to django...@googlegroups.com
On Fri, Mar 21, 2008 at 9:37 AM, Julien <jph...@gmail.com> wrote:
>
> I've found another problem.
>
> The javascript_catalog view generates the right catalog script:
>
>
> var catalog = new Array();
> [...]

> catalog['You have %(count)s emails.'] = 'Vous avez %(count)s emails.';
> catalog['You have 1 email.'] = 'Vous avez 1 email.';
> [...]

>
> Then, when I run the script:
> $contact_header.html(interpolate(ngettext('You have 1 contact.', 'You
> have %(count)s contacts.', contact_count), [contact_count]));
>
> [...]

>
> Again, is that a bug or am I misusing this feature?
>

I can't test this now but it seems you are mixing things

if you are going to do a named interpolation you should
use an array (or other JS data structure) that contains an element
named after the value you are using inside the literal

a = Array('count');
a('count') = 7;
a('name') = 'Dood';

interpolate(
ngettext('%(name)s: You have 1 contact.',
'You have %(count)s contacts. Go %(name)s!', a.count),
a)

You are using '%(count)s' but are passing [contact_count] as the 'named'
parameter to interpolate(), a totally unrelated name so there is no
interpolation possible.

Or if you don't need named interpolation at all (as your bare
contact_count variable seems
to indicate) just don't:

contact_count = 7;
ngettext('You have 1 contact.', 'You have %s contacts.', contact_count);

PS: Are you going to open the ticket with the two JS i18n doc fixes? I have a
mini-patch ready to submit.

Regards,

--
Ramiro Morales

Julien

unread,
Mar 21, 2008, 8:08:03 PM3/21/08
to Django users
Hi,

Thanks for that. It still doesn't work though...

I have got rid of the interpolation, and now I have:

$email_header.html(ngettext('You have %(count)s email.', 'You have %
(count)s emails.', email_count));

Also, I realised that I had misconfigured the .po file, which now
looks like this:

msgid "You have %(count)s email."
msgid_plural "You have %(count)s emails."
msgstr[0] "Vous avez %(count)s email."
msgstr[1] "Vous avez %(count)s emails."

Then, here's what the javascript_catalog view generates:

catalog['You have %(count)s email.'] = ['',''];
catalog['You have %(count)s email.'][0] = 'Vous avez %(count)s
email.';
catalog['You have %(count)s emails.'][1] = 'Vous avez %(count)s
emails.';

Now, we're almost there but there's still a problem. In the function
ngettext, the statement "return value[pluralidx(count)];" returns
null, because pluralidx(count) returns True or False instead of 1 or
0.

Indeed, pluralidx is defined as:

function pluralidx(n) {
return (n >= 1);
}

If it was like the following, I assumed it would work fine:

function pluralidx(n) {
return ((n >= 1)?1:0);
}

What do you think? Am I still misusing it?

Also, I was going to prepare a patch for the doc fixes. But if you
have a patch ready, please go for it. Thanks!

Julien

On Mar 22, 10:11 am, "Ramiro Morales" <cra...@gmail.com> wrote:

Julien

unread,
Mar 22, 2008, 9:08:04 AM3/22/08
to Django users
Hi there,

I debugged the generated javascript catalog and functions, and in
ngettext, the variable "value" is correct (an array with 2 cells: the
translated singular and plural), but the statement "return
value[pluralidx(count)]" returns null, simply because pluralidx itself
returns True of False.

Wouldn't the following be a more correct implementation of ngettext?

function ngettext(singular, plural, count) {
value = catalog[singular];
if (typeof(value) == 'undefined') {
return (count == 1) ? singular : plural;
} else {
return value[(pluralidx(count))?1:0];
}
}

What do you think?

Thanks a lot,

Julien

Ramiro Morales

unread,
Mar 22, 2008, 10:21:34 AM3/22/08
to django...@googlegroups.com
Julien,

On Sat, Mar 22, 2008 at 10:08 AM, Julien <jph...@gmail.com> wrote:
>
> Hi there,
>
> I debugged the generated javascript catalog and functions, and in
> ngettext, the variable "value" is correct (an array with 2 cells: the
> translated singular and plural), but the statement "return
> value[pluralidx(count)]" returns null, simply because pluralidx itself
> returns True of False.
>
> Wouldn't the following be a more correct implementation of ngettext?
>
>
> function ngettext(singular, plural, count) {
> value = catalog[singular];
> if (typeof(value) == 'undefined') {
> return (count == 1) ? singular : plural;
> } else {
> return value[(pluralidx(count))?1:0];
> }
> }
>
> What do you think?
>

This may be caused by the djangojs.po catalog of your
application/project missing
the Plural-Foms header, for example (for the the Argentinia spanish
django.po) it is:

"Plural-Forms: nplurals=2; plural=(n != 1);\n"

In fact now I see neither the django.po or the djangojs.po files of the Django
french traslation have that header.

(oops the djangojs.po for es_AR is also missing it :-))

I don't know if and which plural form formula does the french language use.
If so,and you happen to know or obtain it, try adding it to your
app/project .po files.

If the javascript_catalog() view doesn't detect a plural forms line in
your catalog
(line 156 of django/views/i18n.py) it uses a very basic one (the one
you are seeeing).

There is a [1]ticket opened a while ago about making the Django catalog handling
scripts copy the plural forms formula header from the Django .po files
to the app/project one when creating them.

Regards,

--
Ramiro Morales

PS: Just opened ticket #6859 with a patch for the doc innacuracies you
reported. Thanks.

1. http://code.djangoproject.com/ticket/6505

Julien

unread,
Mar 22, 2008, 8:00:06 PM3/22/08
to Django users
Hi,

In fact, I'm using my own po file, and the plural rule is exactly the
same one as you've mentioned above. So, I've changed the rule to:
"Plural-Forms: nplurals=2; plural=(n > 1)?1:0;\n"

And now the generated 'pluralidx' is as follows:
function pluralidx(n) {
return (n > 1)?1:0;
}

And ngettext now works fine.

Also, I've spotted another glitch in the doc, which I've reported in
the ticket you've opened: http://code.djangoproject.com/ticket/6859

Cheers!

Julien

Ramiro Morales

unread,
Mar 23, 2008, 4:24:48 PM3/23/08
to django...@googlegroups.com
Julien,

On Sat, Mar 22, 2008 at 9:00 PM, Julien <jph...@gmail.com> wrote:
>
> Hi,
>
> In fact, I'm using my own po file, and the plural rule is exactly the
> same one as you've mentioned above. So, I've changed the rule to:
> "Plural-Forms: nplurals=2; plural=(n > 1)?1:0;\n"

Glad to see it' working for you now. Sorry for trying to help
without grasping all the details.

I've tried to solve it in a similar way but at a different point to be safe in
the case an author of a (Django or app) djangojs.po catalog specifies

Plural-Forms: nplurals=2; plural=n>1;

instead of

Plural-Forms: nplurals=2; plural=n>1 ? 1 : 0;

because the first form (the one that relies on the "feature of C
expressions that boolean
expressions have to value zero or one.") is shown in the [1]official GNU gettext
documentation.

I've opened ticket #6864 with a patch attached. could you give it a try?.

>
> Also, I've spotted another glitch in the doc, which I've reported in
> the ticket you've opened: http://code.djangoproject.com/ticket/6859
>

I've updated the patch, do you think it's Ok?, thanks!.

Regards,

--
Ramiro Morales

1. http://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html#Plural-forms

Julien

unread,
Mar 23, 2008, 4:58:54 PM3/23/08
to Django users
Thanks Ramiro, both patches are great!
I've just left a small comment about the doc patch.

Regards,

Julien

On Mar 24, 7:24 am, "Ramiro Morales" <cra...@gmail.com> wrote:
> Julien,
>
> 1.http://www.gnu.org/software/gettext/manual/html_node/Plural-forms.htm...
Reply all
Reply to author
Forward
0 new messages