Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
Making verbose_name(_plural) more i18n-friendly (ticket #11688)
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  5 messages - Collapse all  -  Translate all to Translated (View all originals)
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
Ramiro Morales  
View profile  
 More options Nov 28 2011, 5:49 am
From: Ramiro Morales <cra...@gmail.com>
Date: Mon, 28 Nov 2011 07:49:26 -0300
Local: Mon, Nov 28 2011 5:49 am
Subject: Making verbose_name(_plural) more i18n-friendly (ticket #11688)
Hi fellow translators,

I've been working that new-feature ticket starting with an idea Jannis
Leidel had posted in a GitHb [0]Gist some months ago and would like to
get some feedback from developers with real i18n experience about this
first iteration of a [1]patch for it.

Solving this would allow Django to support in a better way translation
of model names to a wider range of locales and could help with ticket
[2]#14844 by providing a base infrastructure for fixing it.

A brief description of the user-facing part of the proposed
implementation:

NOTE: The names are up for replacement in case they are too ugly too
generic or too prone to clash with existing code. I myself have renamed
them twice already (fortunately it is mostly a mass search and replace
operation).

It is composed of two parts:

Part 1:
=======

A new, optional

  @classmethod
  def verbose_names(cls, count=1)

that can be implemented by the programmer in her model. It is in charge
of returning the verbose name corresponding to /count/ model instances.

This means:

* The now deprecated Meta.verbose_name and Meta.verbose_name_plural
  options have been promoted from the Meta inner class to the model
  scope itself.

* Singular and plural forms treatment is unified by delegating in this
  single method the job of returning them based on the value of
  the /count/ parameter. Plural forms aren't limited to two (singular
  case plus one plural form) as in English and most western European
  languages.

Simple example for audience group #1: Authors of apps whose users use
and will always use one locale (e.g. English) so they set USE_I18N=False
and don't need to care for i18n::

 1 class DjangoMascot(models.Model):
 2     ...
 3
 4     @classmethod
 5     def verbose_names(cls, count=1):
 6         if count == 1:
 7             return 'flying pony'
 8         else:
 9             return 'flying ponies'

verbose_names() can ignore one or more values of /count/ and implement
returning a valid verbose name only for certain values of such argument.
In that case Django will make sure default fallback values are provided
to consumers (see description of the public API in Part 2 and backward
compatibility sections below), e.g.::

 1 class Poll(models.Model):
 2     ...
 3
 4     # Developer didn't provide a verbose_names() classmethod.
 5     # Django provided fallbacks means 'poll' and 'polls'
 6     # will be returned when Poll.get_verbose_name(1) and
 7     # Poll.get_verbose_name(<any values different from 1>) are
 8     # called, respectively.

Other example::

 1 class FirewallPolicy(models.Model):
 2     ...
 3
 4     @classmethod
 5     def verbose_names(cls, count=1):
 6         if count != 1:
 7             return 'firewall policies'
 8         # Django provided fallback means 'firewall policy'
 9         # will be returned when FirewallPolicy.get_verbose_name(1)
10         # is called

Example for audience group #2: Authors of i18n-aware apps and that
because of that use USE_I18N=True and functions from
django.utils.translation:

What currently is expressed in this fashion::

 1 from django.utils.translation import ugettext_lazy as _
 2
 3 class Library(models.Model):
 4     city_name = models.CharField(max_length=30)
 5
 6     class Meta
 7         verbose_name = _('llbrary')
 8         verbose_name_plural = _('llbraries')

Will need to be converted to this::

 1 from django.utils.translation import ungettext_lazy
 2
 3 class Library(models.Model):
 4     city_name = models.CharField(max_length=30)
 5
 6     @classmethod
 7     def verbose_names(cls, count=1):
 8         return ungettext_lazy('llbrary', 'libraries', count)

The fact that we can use ungettext_lazy() means that the gettext PO
catalog entries for this model will change from::

#: foo/models.py:7
msgid "library"
msgstr "<translation of 'library'>"

#: foo/models.py:8
msgid "libraries"
msgstr "<translation of 'libraries'>"

To this::

#: foo/models.py:8
msgid "library"
msgid_plural "libraries"
msgstr[0] "<translation of 'library' with plural form #1>"
...
msgstr[n] "<translation of 'library' with plural form #n+1>"

This is semantically more complete and will allow locales with more than
two plural forms to have better translations of phrases that involve
arbitrary quantities of Django models. E.g. Polish (pl) has three plural
forms and Irish (ga) has five.

Part 2:
=======

A django.db.Model.get_verbose_name(cls, count=1): classmethod that
provides a published API to obtain different flavors of verbose names of
the model at hand.

It is always available so it is always possible to get verbose
names of any model. This method isolates code that needs to get human
readable representations of model names from the particularities of
the verbose_names() model method described in Part 1, if any.

This method will seldomly be overridden by developers if at all. It's
implemented in the base Model class and contains the logic for backward
compatibility and to cope with the possible behaviors of user-provided
verbose_names().

All internal uses in Django itself have been converted to use this API.
Previously this was implemented by reading
<Model class>._meta.verbose_name and
<Model class>._meta.verbose_name_plural

Backward compatibility
----------------------

Backward compatibility has been implemented in a way such that:

 o The presence of a verbose_names() classmethod in a model definition
   has precedence over the Meta.verbose_name and
   Meta.verbose_name_plural options

 o Also, these options get their values from internal calls to this
   method to preserve compatibility with other apps/code that will keep
   using them during a transition period.

 o The fallback get_verbose_name() return values in case the developer
   doesn't implement verbose_names() (or implements it partially) in a
   given model are the same Django has us accustomed to when we didn't
   specify Meta.verbose_name and/or Meta.verbose_name_plural i.e.:

   * CamelCase -> 'camel case' transformation for the singular case

   * Singular verbose name + 's' for the plural case.

Deprecation process
-------------------

As implemented in the patch, currently PendingDeprecationWarning is
raised (one needs to specify the -Wall command line switch to the Python
interpreter to see them) when:

* Meta.verbose_name or Meta.verbose_name_plural are specified
  in a model definition

* Model._meta.verbose_name or Model._meta.verbose_name_plural
  are accessed (read) (implementation note: They've been converted
  into properties)

In Django 1.4+1 the warnings will be changed to DeprecationWarning

Starting with Django 1.4+2 Meta.verbose_name and
Meta.verbose_name_plural will be ignored.

(Open) questions/Things that could be changed
---------------------------------------------

* Is it ok to add (class)method's to Model?, there is the possibility
  of name clash with equally named existing attributes/method names in
  user models.

* Should we make verbose_names() count argument not have a default value
  (=1) and so make it mandatory to specify a value of model quantity?

* Why are these classmethods? Because there isn't anything in these
  methods that might make them depend on a given model instance
  characteristics to do their job and because many uses from other parts
  of Django don't have a model instance at hand but rather the model
  class.

* Further, maybe actually there is even no need to them be classmethods
  and we can make them staticmethods?

* Can we drop the setter in the now properties _meta Option verbose_name
  and verbose_name_plural? This would effectively convert them in
  read-only options because we never officially supported modification
  of these options at runtime.

Patch status
------------

Patch is in good shape, has documentation changes and tests although
I plan to expand them more.

Any kind of feedback is welcome!

0. https://gist.github.com/2000f763e15c260c0666
1. https://code.djangoproject.com/attachment/ticket/11688/11688-verbose_...
2. https://code.djangoproject.com/ticket/14844

Regards,

--
Ramiro Morales


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Vladimir Macek  
View profile  
 More options Nov 28 2011, 7:36 am
From: Vladimir Macek <ma...@sandbox.cz>
Date: Mon, 28 Nov 2011 13:36:58 +0100
Local: Mon, Nov 28 2011 7:36 am
Subject: Re: Making verbose_name(_plural) more i18n-friendly (ticket #11688)
On 28.11.2011 11:49, Ramiro Morales wrote:

> Any kind of feedback is welcome!

Wonderful! Thanks for making verbose_names's really plural friendly!

--
:  Vladimir Macek  :  http://macek.sandbox.cz  :  +420 608 978 164
:  UNIX && Dev || Training  :  Python, Django  :  GPG key 1F059424


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Sergiy Kuzmenko  
View profile  
 More options Nov 28 2011, 7:45 pm
From: Sergiy Kuzmenko <s.kuzme...@gmail.com>
Date: Mon, 28 Nov 2011 19:45:22 -0500
Local: Mon, Nov 28 2011 7:45 pm
Subject: Re: Making verbose_name(_plural) more i18n-friendly (ticket #11688)

My two cents:

1. Plural translation should output a fully translated phrase, e.g.:
ungettext('%(count)d poll', '%(count)d polls, count) % {'count': count, }
instead of noun alone, as in:
ungettext_lazy('poll', 'polls', count)

The advantage is that we provide translators with a complete translation
string and thus there is no need to do stitching in the template with a
specific word order in mind. Numeral + noun is not the universally
acceptable word order [1].

2. I'm not very clear why we need both verbose_names and get_verbose_name.
If get_verbose_name is going to be the published interface we probably
don't need additional class methods, do we?

[1] http://wals.info/chapter/89

Thanks


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Ramiro Morales  
View profile  
 More options Nov 30 2011, 10:41 am
From: Ramiro Morales <cra...@gmail.com>
Date: Wed, 30 Nov 2011 12:41:55 -0300
Local: Wed, Nov 30 2011 10:41 am
Subject: Re: Making verbose_name(_plural) more i18n-friendly (ticket #11688)

On Mon, Nov 28, 2011 at 9:45 PM, Sergiy Kuzmenko <s.kuzme...@gmail.com> wrote:
> My two cents:

> 1. Plural translation should output a fully translated phrase, e.g.:
> ungettext('%(count)d poll', '%(count)d polls, count) % {'count': count, }
> instead of noun alone, as in:
> ungettext_lazy('poll', 'polls', count)

I think we all agree with this, i.e having full phrases being marked up
for translation is better than composing phrases with translated
fragments.

Problem is that the replacement for `Meta.verbose_name` and
`Meta.verbose_name_plural` we finally come up with also needs to:

* Maintain backward compatibility

* Not change verbose names behavior when i18n isn't being used. IMHO
  disrupting the workflow native English developers (especially
  English-speaking Django core developers) use (and the results
  they get) the least possible this is particularly important to
  increase the chances of a proposed fix being finally committed.)

* Simply accept the fact that bare human readable model verbose
  names are also needed and very useful in many contexts. I believe that
  if for some UI work one needs the 'Poll' literal (or its translation)
  and instead one gets '1 Poll' it would be surprising to say the
  least, not matter what locale is in effect.

So, making the implementation to always execute something like

  ungettext('%(count)d poll', '%(count)d polls, count) % {'count': count, }

isn't the right thing to do either. At least with this particular API.

By the way, there is a piece of code in the admin app that after the patch
looks like this (`changecount` is the int variable that contains the number of
model instances involved)::

    name = force_unicode(model.get_verbose_name(changecount))
    msg = ungettext("%(count)s %(name)s was changed successfully.",
                    "%(count)s %(name)s were changed successfully.",
                    changecount) % {'count': changecount,
                                    'name': name}
    self.message_user(request, msg)

Here, we aren't using full phrase translation but we still are setting
things up in way so a) Translators can reorder the words, they just need
to keep in mind that the 'name' var will contain the right verbose name
for the plural form in use and b) Final users are shown correct model
verbose names in all locales.

(Having said this, I have been doing some work to see how a fix for
[1]#14844 -- "Getting the ``blocktrans` template tag to select the right
plural model verbose name for every locale" would look like, based on
the work for this ticket and at the same time to validate the proposed
implementation. Will attach my WIP patch to that ticket and post a
follow-up email to this thread with some further findings and thoughts
because they are related to this kind of problems.)

> The advantage is that we provide translators with a complete translation
> string and thus there is no need to do stitching in the template with a
> specific word order in mind. Numeral + noun is not the universally
> acceptable word order [1].

> [1] http://wals.info/chapter/89

Wow that links is a very good resource, thanks for sharing it.

> 2. I'm not very clear why we need both verbose_names and get_verbose_name.
> If get_verbose_name is going to be the published interface we probably don't
> need additional class methods, do we?

This is also related to the three constraints I mentioned above.

In fact my initial plan (reflected in the first patch) was to make
get_verbose_name() effectively a published interface but for consumers
that need model verbose name literals.

We need it to always exist because we need that it always returns
something more or less sane (be it what the model developer implemented
with the non-mandatory verbose_names() method or one of the backward
compatibility fallbacks)

(Remember that the developer that creates a model has the freedom to
provide or not a verbose_names() method, and to make it return
values for any subset of the plural forms. This freedom is needed to
mirror the one the developer has when using Meta.verbose_name and
Meta.verbose_name_plural.)

But in further discussion with Jannis Leidel via IRC we decided to not
leave get_verbose_name() at the model level and make it a method of the
still non-public inner `_meta` Options instance (possibly postponing its
publication until `_meta` gets officially documented). So, code that
needs to consume model verbose names need to stop using
`<Model class>._name._verbose_name*` and call `<Model
class>._name.get_verbose_name()`
instead.

I've changed this in a [2]second version of the patch I've just attached
to the ticket.

Thanks for reviewing and commenting.

1. https://code.djangoproject.com/ticket/14844
2. https://code.djangoproject.com/attachment/ticket/11688/11688-verbose_...

--
Ramiro Morales


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Sergiy Kuzmenko  
View profile  
 More options Nov 30 2011, 10:48 pm
From: Sergiy Kuzmenko <s.kuzme...@gmail.com>
Date: Wed, 30 Nov 2011 22:48:35 -0500
Local: Wed, Nov 30 2011 10:48 pm
Subject: Re: Making verbose_name(_plural) more i18n-friendly (ticket #11688)

These are good and valid points to which I agree. However, in the context
of software localization there are two distinct usages for plural:

1. Unquantified plurals (i.e. some unknown qty greater than 1). This is
used in model listing on the admin site landing page.
2. Quantified plurals (e.g., 4 cows). This is used in admin messages and
admin paginator.

For languages with multiple plural forms, quantified plural without
quantifier is rather meaningless.

With this in mind maybe we can leave Meta.verbose_name_plural as is for the
sake of backward compatibility as well as for getting unquantified plural
form of the model. And introduce a new method for getting quantified
plurals only as I outlined earlier:

ungettext('%(count)d poll', '%(count)d polls, count) % {'count': count, }

(Unless there is an additional reason to get rid of Meta options.)

> By the way, there is a piece of code in the admin app that after the patch
> looks like this (`changecount` is the int variable that contains the
> number of
> model instances involved)::

>    name = force_unicode(model.get_verbose_name(changecount))
>    msg = ungettext("%(count)s %(name)s was changed successfully.",
>                    "%(count)s %(name)s were changed successfully.",
>                    changecount) % {'count': changecount,
>                                    'name': name}
>    self.message_user(request, msg)

Here, we aren't using full phrase translation but we still are setting

> things up in way so a) Translators can reorder the words, they just need
> to keep in mind that the 'name' var will contain the right verbose name
> for the plural form in use and b) Final users are shown correct model
> verbose names in all locales.

The problem with current implementation: it does not work well for
languages with multiple plural form because the form of %(name)s depends on
the count. The proposed change will resolve this problem. But to achieve a
correct plural translation we essentially need 2 translation call:

1) to get the correct plural form the model based on the quantifier
2) to get the resulting translation into "%(count)s %(name)s" string which
I think can be somewhat confusing to translators

Lastly, regardless of what we agree upon there probably should be a new tag
or filter to get pluralized model names in templates, because AFAIK there
is no way to call a model method with an argument directly.

Thanks


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
End of messages
« Back to Discussions « Newer topic     Older topic »