El libro de Django 1.0

18.1. Especificando cadenas de traducción en código Python

Las cadenas de traducción especifican "Este texto debería ser traducido." dichas cadenas pueden aparecer en tu código Python y en tus plantillas. Es tú responsabilidad marcar las cadenas traducibles; el sistema sólo puede traducir cadenas sobre las que está al tanto.

18.1.1. Funciones estándar de traducción

Las cadenas de traducción se especifican usando la función _(). (Si, el nombre de la función es el carácter guión bajo). Esta función está disponible globalmente (o sea como un componente incluido); no es necesario que lo importes.

En este ejemplo, el texto "Welcome to my site." está marcado como una cadena de traducción:

def my_view(request):
    output = _("Welcome to my site.")
    return HttpResponse(output)

La función django.utils.translation.gettext() es idéntica a _(). Este ejemplo es idéntico al anterior:

from django.utils.translation import gettext
def my_view(request):
    output = gettext("Welcome to my site.")
    return HttpResponse(output)

La mayoría de los desarrolladores prefiere usar _(), debido a que es más corta.

La traducción funciona también sobre valores computados. Este ejemplo es idéntico a los dos anteriores:

def my_view(request):
    words = ['Welcome', 'to', 'my', 'site.']
    output = _(' '.join(words))
    return HttpResponse(output)

La traducción funciona también sobre variables. De nuevo, este es otro ejemplo idéntico:

def my_view(request):
    sentence = 'Welcome to my site.'
    output = _(sentence)
    return HttpResponse(output)

(algo a tener en cuenta cuando se usan variables o valores computados, como se veía en los dos ejemplos previos, es que la utilidad de detección de cadenas de traducción de Django, make-messages.py, no será capaz de encontrar esas cadenas. Trataremos make-messages más adelante).

Las cadenas que le pasas a _() o gettext() pueden contener marcadores de posición (por placeholders), especificados con la sintaxis estándar de interpolación de cadenas con nombres, por ejemplo:

def my_view(request, n):
    output = _('%(name)s is my name.') % {'name': n}
    return HttpResponse(output)

Esta técnica permite que las traducciones específicas de cada idioma reordenen el texto de los marcadores de posición. Por ejemplo, una traducción al inglés podría ser Adrian is my name, mientras que una traducción al español podría ser Me llamo Adrian, con el marcador de posición (el nombre) ubicado a continuación del texto traducido y no antes del mismo.

Por esta razón, deberías usar interpolación de cadenas con nombres (por ejemplo %(name)s) en lugar de interpolación posicional (por ejemplo %s o %d). Si usas interpolación posicional las traducciones no serán capaces de reordenar el texto de los marcadores de posición.

18.1.2. Marcando cadenas como no-op

Usa la función django.utils.translation.gettext_noop() para marcar una cadena como una cadena de traducción sin realmente traducirla en ese momento. Las cadenas así marcadas no son traducidas sino hasta el último momento que sea posible.

Usa este enfoque si deseas tener cadenas constantes que deben ser almacenadas en el idioma original — tales como cadenas en una base de datos — pero que deben ser traducidas en el último momento posible, por ejemplo cuando la cadena es presentada al usuario.

18.1.3. Traducción perezosa

Usa la función django.utils.translation.gettext_lazy() para traducir cadenas en forma perezosa — cuando el valor es accedido en lugar de cuando se llama a la función gettext_lazy().

Por ejemplo, para marcar el atributo help_text de un campo como traducible, haz lo siguiente:

from django.utils.translation import gettext_lazy

class MyThing(models.Model):
    name = models.CharField(help_text=gettext_lazy('This is the help text'))

En este ejemplo, gettext_lazy() almacena una referencia perezosa a la cadena — no el verdadero texto traducido. La traducción en si misma se llevará a cabo cuando sea usada en un contexto de cadena, tal como el renderizado de una plantilla en el sitio de administración de Django.

Si no te gusta el nombre largo gettext_lazy puedes simplemente crear un alias _ (guión bajo) para el mismo, de la siguiente forma:

from django.utils.translation import gettext_lazy as _

class MyThing(models.Model):
    name = models.CharField(help_text=_('This is the help text'))

Usa siempre traducciones perezosas en modelos Django (de lo contrario no serán traducidos correctamente para cada usuario). Y es una buena idea agregar también traducciones de los nombres de campos y nombres de tablas. Esto significa escribir las opciones verbose_name y verbose_name_plural en forma explícita en la clase Meta:

from django.utils.translation import gettext_lazy as _

class MyThing(models.Model):
    name = models.CharField(_('name'), help_text=_('This is the help text'))
    class Meta:
        verbose_name = _('my thing')
        verbose_name_plural = _('mythings')

18.1.4. Pluralización

Usa la función django.utils.translation.ngettext() para especificar mensajes que tienen formas singular y plural distintas, por ejemplo:

from django.utils.translation import ngettext
def hello_world(request, count):
    page = ngettext(
        'there is %(count)d object',
        'there are %(count)d objects', count
    ) % {'count': count}
    return HttpResponse(page)

ngettext tiene tres argumentos: la cadena de traducción singular, la cadena de traducción plural y el número de objetos (el cual es pasado a los idiomas de traducción como la variable count).