Visión general

Para hacer que un proyecto de Django sea traducible, debe agregar una cantidad mínima de ganchos a su código y plantillas de Python. Estos ganchos se llaman cadenas de traducción. Le dicen a Django: “Este texto debe traducirse al idioma del usuario final, si hay una traducción de este texto disponible en ese idioma”. Es su responsabilidad marcar cadenas traducibles; el sistema solo puede traducir cadenas que conoce.

Luego, Django proporciona utilidades para extraer las cadenas de traducción en un archivo de mensaje. Este archivo es una forma conveniente para que los traductores proporcionen el equivalente de las cadenas de traducción en el idioma de destino. Una vez que los traductores hayan completado el archivo del mensaje, se debe compilar. Este proceso se basa en el conjunto de herramientas GNU gettext.

Una vez hecho esto, Django se encarga de traducir las aplicaciones web sobre la marcha en cada idioma disponible, de acuerdo con las preferencias de idioma de los usuarios.

Los ganchos de internacionalización de Django están activados de forma predeterminada, y eso significa que hay un poco de sobrecarga relacionada con i18n en ciertos lugares del marco. Si no usa la internacionalización, debe tomar los dos segundos para configurar USE_I18N = False en su archivo de configuración. Luego Django hará algunas optimizaciones para no cargar la maquinaria de internacionalización.

Nota

También hay un independiente pero relacionado USE_L10N configuración que controla si Django debe implementar la localización de formato. Ver Localización de formato para más detalles.

Nota

Asegúrese de haber activado la traducción para su proyecto (la forma más rápida es verificar si MIDDLEWARE incluye django.middleware.locale.LocaleMiddleware). Si aún no lo ha hecho, consulte Cómo descubre Django la preferencia de idioma.

Internacionalización: en código Python

Traducción estándar

Especifique una cadena de traducción mediante la función gettext(). Es una convención importar esto como un alias más corto, _, para ahorrar tipeo.

Nota

Biblioteca estándar de Python gettext instalación del módulo _() en el espacio de nombres global, como un alias para gettext(). En Django, hemos optado por no seguir esta práctica, por un par de razones:

  1. A veces, deberías usar gettext_lazy() como método de traducción predeterminado para un archivo en particular. Sin _() en el espacio de nombres global, el desarrollador tiene que pensar cuál es la función de traducción más apropiada.
  2. El carácter de subrayado (_) se utiliza para representar “el resultado anterior” en el shell interactivo de Python y en las pruebas de doctest. Instalando un global _() función causa interferencia. Importación explícita gettext() como _() evita este problema.

¿Qué funciones pueden tener un alias como _?

Por como xgettext (usado por makemessages) funciona, solo las funciones que toman un solo argumento de cadena se pueden importar como _:

  • gettext()
  • gettext_lazy()

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

from django.http import HttpResponse
from django.utils.translation import gettext as _

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

Puede codificar esto sin usar el alias. Este ejemplo es idéntico al anterior:

from django.http import HttpResponse
from django.utils.translation import gettext

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

La traducción funciona con valores calculados. 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 con variables. Nuevamente, aquí hay un ejemplo idéntico:

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

(La advertencia con el uso de variables o valores calculados, como en los dos ejemplos anteriores, es que la utilidad de detección de cadenas de traducción de Django, django-admin makemessages, no podrá encontrar estas cadenas. Más en makemessages más tarde.)

Las cuerdas a las que pasas _() o gettext() pueden tener marcadores de posición, especificados con la sintaxis de interpolación de cadenas con nombre estándar de Python. Ejemplo:

def my_view(request, m, d):
    output = _('Today is %(month)s %(day)s.') % {'month': m, 'day': d}
    return HttpResponse(output)

Esta técnica permite que las traducciones específicas del idioma reordenen el texto del marcador de posición. Por ejemplo, una traducción al inglés puede ser "Today is November 26.", mientras que una traducción al español puede ser "Hoy es 26 de noviembre." – con los marcadores de posición de mes y día intercambiados.

Por esta razón, debe utilizar la interpolación de cadenas con nombre (p. Ej., %(day)s) en lugar de interpolación posicional (p. ej., %s o %d) siempre que tenga más de un parámetro. Si utilizó la interpolación posicional, las traducciones no podrían reordenar el texto del marcador de posición.

Dado que la extracción de cuerdas la realiza el xgettext comando, solo las sintaxis admitidas por gettext son compatibles con Django. En particular, Python cuerdas f aún no son compatibles con xgettext, y las cadenas de plantillas de JavaScript necesitan gettext 0,21+.

Comentarios para traductores

Si desea dar pistas a los traductores sobre una cadena traducible, puede agregar un comentario con el prefijo Translators palabra clave en la línea que precede a la cadena, por ejemplo:

def my_view(request):
    # Translators: This message appears on the home page only
    output = gettext("Welcome to my site.")

El comentario aparecerá en el resultado .po archivo asociado con la construcción traducible que se encuentra debajo y también debe mostrarse en la mayoría de las herramientas de traducción.

Nota

Solo para completar, este es el fragmento correspondiente del resultado .po expediente:

#. Translators: This message appears on the home page only
# path/to/python/file.py:123
msgid "Welcome to my site."
msgstr ""

Esto también funciona en plantillas. Ver Comentarios para traductores en plantillas para más detalles.

Marcar cadenas como no operativas

Usa la función django.utils.translation.gettext_noop() para marcar una cadena como una cadena de traducción sin traducirla. Posteriormente, la cadena se traduce de una variable.

Use esto si tiene cadenas constantes que deben almacenarse en el idioma de origen porque se intercambian entre sistemas o usuarios, como cadenas en una base de datos, pero deben traducirse en el último momento posible, como cuando se presenta la cadena. al usuario.

Pluralización

Usa la función django.utils.translation.ngettext() para especificar mensajes pluralizados.

ngettext() toma tres argumentos: la cadena de traducción singular, la cadena de traducción plural y el número de objetos.

Esta función es útil cuando necesita que su aplicación Django sea localizable a idiomas donde el número y la complejidad de formas plurales es mayor que las dos formas utilizadas en inglés (‘objeto’ para el singular y ‘objetos’ para todos los casos donde count es diferente de uno, independientemente de su valor).

Por ejemplo:

from django.http import HttpResponse
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)

En este ejemplo, el número de objetos se pasa a los idiomas de traducción como el count variable.

Tenga en cuenta que la pluralización es complicada y funciona de manera diferente en cada idioma. Comparando count a 1 no siempre es la regla correcta. Este código parece sofisticado, pero producirá resultados incorrectos para algunos idiomas:

from django.utils.translation import ngettext
from myapp.models import Report

count = Report.objects.count()
if count == 1:
    name = Report._meta.verbose_name
else:
    name = Report._meta.verbose_name_plural

text = ngettext(
    'There is %(count)d %(name)s available.',
    'There are %(count)d %(name)s available.',
    count,
) % {
    'count': count,
    'name': name
}

No intente implementar su propia lógica singular o plural; no será correcto. En un caso como este, considere algo como lo siguiente:

text = ngettext(
    'There is %(count)d %(name)s object available.',
    'There are %(count)d %(name)s objects available.',
    count,
) % {
    'count': count,
    'name': Report._meta.verbose_name,
}

Nota

Cuando usas ngettext(), asegúrese de utilizar un solo nombre para cada variable extrapolada incluida en el literal. En los ejemplos anteriores, observe cómo usamos el name Variable de Python en ambas cadenas de traducción. Este ejemplo, además de ser incorrecto en algunos idiomas como se indicó anteriormente, fallaría:

text = ngettext(
    'There is %(count)d %(name)s available.',
    'There are %(count)d %(plural_name)s available.',
    count,
) % {
    'count': Report.objects.count(),
    'name': Report._meta.verbose_name,
    'plural_name': Report._meta.verbose_name_plural,
}

Obtendría un error al ejecutar django-admin
compilemessages
:

a format specification for argument 'name', as in 'msgstr[0]', doesn't exist in 'msgid'

Marcadores contextuales

A veces, las palabras tienen varios significados, como "May" en inglés, que se refiere al nombre de un mes y a un verbo. Para que los traductores puedan traducir estas palabras correctamente en diferentes contextos, puede utilizar el django.utils.translation.pgettext() función, o la django.utils.translation.npgettext() función si la cadena necesita pluralización. Ambos toman una cadena de contexto como primera variable.

En el resultado .po archivo, la cadena aparecerá tan a menudo como haya diferentes marcadores contextuales para la misma cadena (el contexto aparecerá en el msgctxt línea), permitiendo al traductor dar una traducción diferente para cada uno de ellos.

Por ejemplo:

from django.utils.translation import pgettext

month = pgettext("month name", "May")

o:

from django.db import models
from django.utils.translation import pgettext_lazy

class MyThing(models.Model):
    name = models.CharField(help_text=pgettext_lazy(
        'help text for MyThing model', 'This is the help text'))

aparecerá en el .po archivar como:

msgctxt "month name"
msgid "May"
msgstr ""

Los marcadores contextuales también son compatibles con translate y blocktranslate etiquetas de plantilla.

Traducción perezosa

Utilice las versiones perezosas de las funciones de traducción en django.utils.translation (fácilmente reconocible por el lazy sufijo en sus nombres) para traducir cadenas de forma perezosa, cuando se accede al valor en lugar de cuando se llaman.

Estas funciones almacenan una referencia perezosa a la cadena, no la traducción real. La traducción en sí se realizará cuando la cadena se utilice en un contexto de cadena, como en la representación de plantillas.

Esto es esencial cuando las llamadas a estas funciones se encuentran en rutas de código que se ejecutan en el momento de la carga del módulo.

Esto es algo que puede suceder fácilmente al definir modelos, formularios y formularios de modelo, porque Django los implementa de manera que sus campos son en realidad atributos de nivel de clase. Por esa razón, asegúrese de utilizar traducciones diferidas en los siguientes casos:

Campos y relaciones del modelo verbose_name y help_text valores de opción

Por ejemplo, para traducir el texto de ayuda del nombre campo en el siguiente modelo, haga lo siguiente:

from django.db import models
from django.utils.translation import gettext_lazy as _

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

Puede marcar nombres de ForeignKey, ManyToManyField o OneToOneField relación como traducible mediante el uso de su verbose_name opciones:

class MyThing(models.Model):
    kind = models.ForeignKey(
        ThingKind,
        on_delete=models.CASCADE,
        related_name='kinds',
        verbose_name=_('kind'),
    )

Como lo harías en verbose_name debe proporcionar un texto de nombre detallado en minúsculas para la relación, ya que Django lo pondrá automáticamente en mayúsculas cuando sea necesario.

Modelar valores de nombres detallados

Se recomienda proporcionar siempre explícitamente verbose_name y verbose_name_plural opciones en lugar de depender de la determinación alternativa centrada en el inglés y algo ingenua de los nombres detallados que realiza Django al observar el nombre de clase del modelo:

from django.db import models
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 = _('my things')

Métodos modelo description argumento a la @display decorador

Para los métodos de modelo, puede proporcionar traducciones a Django y al sitio de administración con el description argumento a la display() decorador:

from django.contrib import admin
from django.db import models
from django.utils.translation import gettext_lazy as _

class MyThing(models.Model):
    kind = models.ForeignKey(
        ThingKind,
        on_delete=models.CASCADE,
        related_name='kinds',
        verbose_name=_('kind'),
    )

    @admin.display(description=_('Is it a mouse?'))
    def is_mouse(self):
        return self.kind.type == MOUSE_TYPE

Trabajar con objetos de traducción diferidos

El resultado de un gettext_lazy() La llamada se puede usar siempre que use una cadena (una str object) en otro código Django, pero es posible que no funcione con código Python arbitrario. Por ejemplo, lo siguiente no funcionará porque el peticiones la biblioteca no maneja gettext_lazy objetos:

body = gettext_lazy("I u2764 Django")  # (Unicode :heart:)
requests.post('https://example.com/send', data={'body': body})

Puede evitar estos problemas lanzando gettext_lazy() objetos a cadenas de texto antes de pasarlos a código que no sea de Django:

requests.post('https://example.com/send', data={'body': str(body)})

Si no te gusta el largo gettext_lazy nombre, puede alias como _ (subrayado), así:

from django.db import models
from django.utils.translation import gettext_lazy as _

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

Utilizando gettext_lazy() y ngettext_lazy() marcar cadenas en modelos y funciones de utilidad es una operación común. Cuando trabaje con estos objetos en otra parte de su código, debe asegurarse de no convertirlos accidentalmente en cadenas, ya que deben convertirse lo más tarde posible (para que se aplique la configuración regional correcta). Esto requiere el uso de la función auxiliar que se describe a continuación.

Traducciones perezosas y plural

Cuando se usa la traducción diferida para una cadena plural (n[p]gettext_lazy), generalmente no conoce el number argumento en el momento de la definición de la cadena. Por lo tanto, está autorizado a pasar un nombre de clave en lugar de un número entero como number argumento. Luego number se buscará en el diccionario bajo esa clave durante la interpolación de cadenas. He aquí un ejemplo:

from django import forms
from django.core.exceptions import ValidationError
from django.utils.translation import ngettext_lazy

class MyForm(forms.Form):
    error_message = ngettext_lazy("You only provided %(num)d argument",
        "You only provided %(num)d arguments", 'num')

    def clean(self):
        # ...
        if error:
            raise ValidationError(self.error_message % {'num': number})

Si la cadena contiene exactamente un marcador de posición sin nombre, puede interpolar directamente con el number argumento:

class MyForm(forms.Form):
    error_message = ngettext_lazy(
        "You provided %d argument",
        "You provided %d arguments",
    )

    def clean(self):
        # ...
        if error:
            raise ValidationError(self.error_message % number)

Formateo de cadenas: format_lazy()

Python str.format() El método no funcionará cuando el format_string o cualquiera de los argumentos a str.format() contiene objetos de traducción perezosa. En su lugar, puede utilizar django.utils.text.format_lazy(), que crea un objeto perezoso que ejecuta el str.format() método solo cuando el resultado se incluye en una cadena. Por ejemplo:

from django.utils.text import format_lazy
from django.utils.translation import gettext_lazy
...
name = gettext_lazy('John Lennon')
instrument = gettext_lazy('guitar')
result = format_lazy('{name}: {instrument}', name=name, instrument=instrument)

En este caso, las traducciones perezosas en result solo se convertirá en cadenas cuando result en sí mismo se usa en una cadena (generalmente en el momento de la representación de la plantilla).

Otros usos de lazy en traducciones retrasadas

Para cualquier otro caso en el que desee retrasar la traducción, pero tenga que pasar la cadena traducible como argumento a otra función, puede envolver esta función dentro de una llamada perezosa usted mismo. Por ejemplo:

from django.utils.functional import lazy
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _

mark_safe_lazy = lazy(mark_safe, str)

Y luego más tarde:

lazy_string = mark_safe_lazy(_("<p>My <strong>string!</strong></p>"))

Nombres localizados de idiomas

get_language_info()

los get_language_info() La función proporciona información detallada sobre los idiomas:

>>> from django.utils.translation import activate, get_language_info
>>> activate('fr')
>>> li = get_language_info('de')
>>> print(li['name'], li['name_local'], li['name_translated'], li['bidi'])
German Deutsch Allemand False

los name, name_local, y name_translated Los atributos del diccionario contienen el nombre del idioma en inglés, en el idioma en sí y en su idioma activo actual, respectivamente. los bidi El atributo es Verdadero solo para lenguajes bidireccionales.

La fuente de la información del idioma es el django.conf.locale módulo. Se encuentra disponible un acceso similar a esta información para el código de plantilla. Vea abajo.

Internacionalización: en código de plantilla

Traducciones en Plantillas de Django utiliza dos etiquetas de plantilla y una sintaxis ligeramente diferente a la del código Python. Para que su plantilla acceda a estas etiquetas, coloque {% load i18n %} hacia la parte superior de su plantilla. Al igual que con todas las etiquetas de plantilla, esta etiqueta debe cargarse en todas las plantillas que utilizan traducciones, incluso aquellas plantillas que se extienden desde otras plantillas que ya han cargado el i18n etiqueta.

Advertencia

Las cadenas traducidas no se escaparán cuando se representen en una plantilla. Esto le permite incluir HTML en las traducciones, por ejemplo, para enfatizar, pero caracteres potencialmente peligrosos (p. Ej. ") también se mantendrá sin cambios.

translate etiqueta de plantilla

los {% translate %} La etiqueta de plantilla traduce una cadena constante (entre comillas simples o dobles) o contenido variable:

<title>{% translate "This is the title." %}</title>
<title>{% translate myvar %}</title>

Si el noop La opción está presente, la búsqueda de variables aún se lleva a cabo pero se omite la traducción. Esto es útil para “eliminar” contenido que requerirá traducción en el futuro:

<title>{% translate "myvar" noop %}</title>

Internamente, las traducciones en línea utilizan un gettext() llama.

En caso de que una plantilla var (myvar arriba) se pasa a la etiqueta, la etiqueta primero resolverá dicha variable en una cadena en tiempo de ejecución y luego buscará esa cadena en los catálogos de mensajes.

No es posible mezclar una variable de plantilla dentro de una cadena dentro de {% translate %}. Si sus traducciones requieren cadenas con variables (marcadores de posición), utilice {% blocktranslate %} en lugar de.

Si desea recuperar una cadena traducida sin mostrarla, puede usar la siguiente sintaxis:

{% translate "This is the title" as the_title %}

<title>{{ the_title }}</title>
<meta name="description" content="{{ the_title }}">

En la práctica, usará esto para obtener una cadena que pueda usar en varios lugares de una plantilla o para que pueda usar la salida como argumento para otras etiquetas o filtros de plantilla:

{% translate "starting point" as start %}
{% translate "end point" as end %}
{% translate "La Grande Boucle" as race %}

<h1>
  <a href="https://foroayuda.es/" title="{% blocktranslate %}Back to '{{ race }}' homepage{% endblocktranslate %}">{{ race }}</a>
</h1>
<p>
{% for stage in tour_stages %}
    {% cycle start end %}: {{ stage }}{% if forloop.counter|divisibleby:2 %}<br>{% else %}, {% endif %}
{% endfor %}
</p>

{% translate %} también apoya marcadores contextuales utilizando el context palabra clave:

{% translate "May" context "month name" %}

Cambiado en Django 3.1:

los trans se cambió el nombre de la etiqueta a translate. los trans La etiqueta todavía se admite como un alias para compatibilidad con versiones anteriores.

blocktranslate etiqueta de plantilla

Contrariamente a la translate etiqueta, la blocktranslate La etiqueta le permite marcar oraciones complejas que constan de literales y contenido variable para la traducción mediante el uso de marcadores de posición:

{% blocktranslate %}This string will have {{ value }} inside.{% endblocktranslate %}

Para traducir una expresión de plantilla, por ejemplo, acceder a atributos de objeto o usar filtros de plantilla, debe vincular la expresión a una variable local para usarla dentro del bloque de traducción. Ejemplos:

{% blocktranslate with amount=article.price %}
That will cost $ {{ amount }}.
{% endblocktranslate %}

{% blocktranslate with myvar=value|filter %}
This will have {{ myvar }} inside.
{% endblocktranslate %}

Puede utilizar varias expresiones dentro de una sola blocktranslate etiqueta:

{% blocktranslate with book_t=book|title author_t=author|title %}
This is {{ book_t }} by {{ author_t }}
{% endblocktranslate %}

Nota

El formato anterior más detallado todavía es compatible: {% blocktranslate with book|title as book_t and author|title as author_t %}

Otras etiquetas de bloque (por ejemplo {% for %} o {% if %}) no están permitidos dentro de un blocktranslate etiqueta.

Si falla la resolución de uno de los argumentos del bloque, blocktranslate volverá al idioma predeterminado desactivando el idioma actualmente activo temporalmente con el deactivate_all() función.

Esta etiqueta también proporciona pluralización. Para usarlo:

  • Designar y vincular un valor de contador con el nombre count. Este valor será el que se utilice para seleccionar la forma plural correcta.
  • Especifique las formas singular y plural separándolas con el {% plural %} etiqueta dentro de la {% blocktranslate %} y {% endblocktranslate %} etiquetas.

Un ejemplo:

{% blocktranslate count counter=list|length %}
There is only one {{ name }} object.
{% plural %}
There are {{ counter }} {{ name }} objects.
{% endblocktranslate %}

Un ejemplo más complejo:

{% blocktranslate with amount=article.price count years=i.length %}
That will cost $ {{ amount }} per year.
{% plural %}
That will cost $ {{ amount }} per {{ years }} years.
{% endblocktranslate %}

Cuando usa la función de pluralización y vincula valores a variables locales además del valor del contador, tenga en cuenta que el blocktranslate La construcción se convierte internamente en un ngettext llama. Esto significa lo mismo notas sobre las variables ngettext solicitar.

Las búsquedas inversas de URL no se pueden realizar dentro del blocktranslate y debe recuperarse (y almacenarse) de antemano:

{% url 'path.to.view' arg arg2 as the_url %}
{% blocktranslate %}
This is a URL: {{ the_url }}
{% endblocktranslate %}

Si desea recuperar una cadena traducida sin mostrarla, puede usar la siguiente sintaxis:

{% blocktranslate asvar the_title %}The title is {{ title }}.{% endblocktranslate %}
<title>{{ the_title }}</title>
<meta name="description" content="{{ the_title }}">

En la práctica, usará esto para obtener una cadena que pueda usar en varios lugares de una plantilla o para que pueda usar la salida como argumento para otras etiquetas o filtros de plantilla.

{% blocktranslate %} también apoya marcadores contextuales utilizando el context palabra clave:

{% blocktranslate with name=user.username context "greeting" %}Hi {{ name }}{% endblocktranslate %}

Otra característica {% blocktranslate %} apoya es el trimmed opción. Esta opción eliminará los caracteres de nueva línea del principio y el final del contenido de la {% blocktranslate %} etiqueta, reemplace cualquier espacio en blanco al principio y al final de una línea y combine todas las líneas en una usando un carácter de espacio para separarlas. Esto es muy útil para sangrar el contenido de un {% blocktranslate %} etiqueta sin que los caracteres de sangría terminen en la entrada correspondiente en el archivo PO, lo que facilita el proceso de traducción.

Por ejemplo, lo siguiente {% blocktranslate %} etiqueta:

{% blocktranslate trimmed %}
  First sentence.
  Second paragraph.
{% endblocktranslate %}

resultará en la entrada "First sentence. Second paragraph." en el archivo PO, en comparación con "n  First sentence.n  Second paragraph.n", Si el trimmed no se había especificado la opción.

Cambiado en Django 3.1:

los blocktrans se cambió el nombre de la etiqueta a blocktranslate. los blocktrans La etiqueta todavía se admite como un alias para compatibilidad con versiones anteriores.

Literales de cadena pasados ​​a etiquetas y filtros

Puede traducir los literales de cadena pasados ​​como argumentos a etiquetas y filtros mediante el uso familiar _() sintaxis:

{% some_tag _("Page not found") value|yesno:_("yes,no") %}

En este caso, tanto la etiqueta como el filtro verán la cadena traducida, por lo que no necesitan estar al tanto de las traducciones.

Nota

En este ejemplo, a la infraestructura de traducción se le pasará la cadena "yes,no", no las cadenas individuales "yes" y "no". La cadena traducida deberá contener la coma para que el código de análisis del filtro sepa cómo dividir los argumentos. Por ejemplo, un traductor de alemán podría traducir la cadena "yes,no" como "ja,nein" (manteniendo la coma intacta).

Comentarios para traductores en plantillas

Como con Código Python, estas notas para traductores se pueden especificar mediante comentarios, ya sea con la comment etiqueta:

{% comment %}Translators: View verb{% endcomment %}
{% translate "View" %}

{% comment %}Translators: Short intro blurb{% endcomment %}
<p>{% blocktranslate %}A multiline translatable
literal.{% endblocktranslate %}</p>

o con el {##} construcciones de comentarios de una línea:

{# Translators: Label of a button that triggers search #}
<button type="submit">{% translate "Go" %}</button>

{# Translators: This is a text of the base template #}
{% blocktranslate %}Ambiguous translatable block of text{% endblocktranslate %}

Nota

Solo para completar, estos son los fragmentos correspondientes del resultado .po expediente:

#. Translators: View verb
# path/to/template/file.html:10
msgid "View"
msgstr ""

#. Translators: Short intro blurb
# path/to/template/file.html:13
msgid ""
"A multiline translatable"
"literal."
msgstr ""

# ...

#. Translators: Label of a button that triggers search
# path/to/template/file.html:100
msgid "Go"
msgstr ""

#. Translators: This is a text of the base template
# path/to/template/file.html:103
msgid "Ambiguous translatable block of text"
msgstr ""

Cambio de idioma en plantillas

Si desea seleccionar un idioma dentro de una plantilla, puede utilizar el language etiqueta de plantilla:

{% load i18n %}

{% get_current_language as LANGUAGE_CODE %}
<!-- Current language: {{ LANGUAGE_CODE }} -->
<p>{% translate "Welcome to our page" %}</p>

{% language 'en' %}
    {% get_current_language as LANGUAGE_CODE %}
    <!-- Current language: {{ LANGUAGE_CODE }} -->
    <p>{% translate "Welcome to our page" %}</p>
{% endlanguage %}

Si bien la primera aparición de “Bienvenido a nuestra página” utiliza el idioma actual, la segunda siempre será en inglés.

Otras etiquetas

Estas etiquetas también requieren un {% load i18n %}.

get_available_languages

{% get_available_languages as LANGUAGES %} devuelve una lista de tuplas en la que el primer elemento es el Código de lenguaje y el segundo es el nombre del idioma (traducido a la configuración regional actualmente activa).

get_current_language

{% get_current_language as LANGUAGE_CODE %} devuelve el idioma preferido del usuario actual como una cadena. Ejemplo: en-us. Ver Cómo descubre Django la preferencia de idioma.

get_current_language_bidi

{% get_current_language_bidi as LANGUAGE_BIDI %} devuelve la dirección de la localidad actual. Si True, es un idioma de derecha a izquierda, por ejemplo, hebreo, árabe. Si False es un idioma de izquierda a derecha, por ejemplo, inglés, francés, alemán, etc.

i18n procesador de contexto

Si habilita el django.template.context_processors.i18n procesador de contexto, luego cada RequestContext tendrá acceso a LANGUAGES, LANGUAGE_CODE, y LANGUAGE_BIDI como se define arriba.

get_language_info

También puede recuperar información sobre cualquiera de los idiomas disponibles utilizando las etiquetas de plantilla y los filtros proporcionados. Para obtener información sobre un solo idioma, utilice el {% get_language_info %} etiqueta:

{% get_language_info for LANGUAGE_CODE as lang %}
{% get_language_info for "pl" as lang %}

A continuación, puede acceder a la información:

Language code: {{ lang.code }}<br>
Name of language: {{ lang.name_local }}<br>
Name in English: {{ lang.name }}<br>
Bi-directional: {{ lang.bidi }}
Name in the active language: {{ lang.name_translated }}

get_language_info_list

También puede utilizar el {% get_language_info_list %} etiqueta de plantilla para recuperar información para una lista de idiomas (por ejemplo, idiomas activos como se especifica en LANGUAGES). Ver la sección sobre la vista de redireccionamiento set_language para ver un ejemplo de cómo mostrar un selector de idioma usando {% get_language_info_list %}.

Además de LANGUAGES lista de estilos de tuplas, {% get_language_info_list %} admite listas de códigos de idioma. Si hace esto en su opinión:

context = {'available_languages': ['en', 'es', 'fr']}
return render(request, 'mytemplate.html', context)

puede iterar sobre esos idiomas en la plantilla:

{% get_language_info_list for available_languages as langs %}
{% for lang in langs %} ... {% endfor %}

Filtros de plantilla

También hay algunos filtros disponibles para mayor comodidad:

  • {{ LANGUAGE_CODE|language_name }} (“Alemán”)
  • {{ LANGUAGE_CODE|language_name_local }} (“Alemán”)
  • {{ LANGUAGE_CODE|language_bidi }} (Falso)
  • {{ LANGUAGE_CODE|language_name_translated }} (“Německy”, cuando el idioma activo es el checo)

Internacionalización: en código JavaScript

Agregar traducciones a JavaScript plantea algunos problemas:

  • El código JavaScript no tiene acceso a un gettext implementación.
  • El código JavaScript no tiene acceso a .po o .mo archivos; deben ser entregados por el servidor.
  • Los catálogos de traducción para JavaScript deben mantenerse lo más pequeños posible.

Django proporciona una solución integrada para estos problemas: pasa las traducciones a JavaScript, por lo que puede llamar gettext, etc., desde JavaScript.

La principal solución a estos problemas es la siguiente JavaScriptCatalog view, que genera una biblioteca de código JavaScript con funciones que imitan la gettext interfaz, además de una serie de cadenas de traducción.

los JavaScriptCatalog vista

class JavaScriptCatalog

Una vista que produce una biblioteca de código JavaScript con funciones que imitan la gettext interfaz, además de una serie de cadenas de traducción.

Atributos

domain

Dominio de traducción que contiene cadenas para agregar en la salida de la vista. Predeterminado a 'djangojs'.

packages

Una lista de application names entre las aplicaciones instaladas. Esas aplicaciones deben contener un locale directorio. Todos esos catálogos más todos los catálogos que se encuentran en LOCALE_PATHS (que siempre se incluyen) se fusionan en un catálogo. Predeterminado a None, lo que significa que todas las traducciones disponibles de todos INSTALLED_APPS se proporcionan en la salida de JavaScript.

Ejemplo con valores predeterminados:

from django.views.i18n import JavaScriptCatalog

urlpatterns = [
    path('jsi18n/', JavaScriptCatalog.as_view(), name="javascript-catalog"),
]

Ejemplo con paquetes personalizados:

urlpatterns = [
    path('jsi18n/myapp/',
         JavaScriptCatalog.as_view(packages=['your.app.label']),
         name="javascript-catalog"),
]

Si su URLconf raíz usa i18n_patterns(), JavaScriptCatalog también debe ser envuelto por i18n_patterns() para que el catálogo sea correcto generado.

Ejemplo con i18n_patterns():

from django.conf.urls.i18n import i18n_patterns

urlpatterns = i18n_patterns(
    path('jsi18n/', JavaScriptCatalog.as_view(), name="javascript-catalog"),
)

La precedencia de las traducciones es tal que los paquetes que aparecen más adelante en el packages Los argumentos tienen mayor precedencia que los que aparecen al principio. Esto es importante en el caso de traducciones contradictorias para el mismo literal.

Si usa más de uno JavaScriptCatalog vista en un sitio y algunos de ellos definen las mismas cadenas, las cadenas del catálogo que se cargó por última vez tienen prioridad.

Usar el catálogo de traducción de JavaScript

Para usar el catálogo, ingrese el script generado dinámicamente como este:

<script src="https://foroayuda.es/django/topics/i18n/{% url"javascript-catalog' %}"></script>

Utiliza la búsqueda inversa de URL para encontrar la URL de la vista de catálogo de JavaScript. Cuando se carga el catálogo, su código JavaScript puede utilizar los siguientes métodos:

  • gettext
  • ngettext
  • interpolate
  • get_format
  • gettext_noop
  • pgettext
  • npgettext
  • pluralidx

gettext

los gettext La función se comporta de manera similar a la estándar. gettext interfaz dentro de su código Python:

document.write(gettext('this is to be translated'));

ngettext

los ngettext La función proporciona una interfaz para pluralizar palabras y frases:

const objectCount = 1 // or 0, or 2, or 3, ...
const string = ngettext(
    'literal for the singular case',
    'literal for the plural case',
    objectCount
);

interpolate

los interpolate La función admite rellenar dinámicamente una cadena de formato. La sintaxis de interpolación se toma prestada de Python, por lo que interpolate La función admite interpolación posicional y con nombre:

  • Interpolación posicional: obj contiene un objeto de matriz de JavaScript cuyos valores de elementos se interpolan secuencialmente en su correspondiente fmt marcadores de posición en el mismo orden en que aparecen. Por ejemplo:

    const formats = ngettext(
      'There is %s object. Remaining: %s',
      'There are %s objects. Remaining: %s',
      11
    );
    const string = interpolate(formats, [11, 20]);
    // string is 'There are 11 objects. Remaining: 20'
    
  • Interpolación con nombre: este modo se selecciona pasando el booleano opcional named parámetro como true. obj contiene un objeto JavaScript o una matriz asociativa. Por ejemplo:

    const data = {
      count: 10,
      total: 50
    };
    
    const formats = ngettext(
        'Total: %(total)s, there is %(count)s object',
        'there are %(count)s of a total of %(total)s objects',
        data.count
    );
    const string = interpolate(formats, data, true);
    

Sin embargo, no debe exagerar con la interpolación de cadenas: esto sigue siendo JavaScript, por lo que el código tiene que hacer sustituciones repetidas de expresiones regulares. Esto no es tan rápido como la interpolación de cadenas en Python, así que guárdelo en aquellos casos en los que realmente lo necesite (por ejemplo, junto con ngettext para producir pluralizaciones adecuadas).

get_format

los get_format La función tiene acceso a la configuración de formato de i18n configurada y puede recuperar la cadena de formato para un nombre de configuración dado:

document.write(get_format('DATE_FORMAT'));
// 'N j, Y'

Tiene acceso a las siguientes configuraciones:

  • DATE_FORMAT
  • DATE_INPUT_FORMATS
  • DATETIME_FORMAT
  • DATETIME_INPUT_FORMATS
  • DECIMAL_SEPARATOR
  • FIRST_DAY_OF_WEEK
  • MONTH_DAY_FORMAT
  • NUMBER_GROUPING
  • SHORT_DATE_FORMAT
  • SHORT_DATETIME_FORMAT
  • THOUSAND_SEPARATOR
  • TIME_FORMAT
  • TIME_INPUT_FORMATS
  • YEAR_MONTH_FORMAT

Esto es útil para mantener la coherencia del formato con los valores representados por Python.

gettext_noop

Esto emula el gettext funciona pero no hace nada, devolviendo lo que se le pasa:

document.write(gettext_noop('this will not be translated'));

Esto es útil para eliminar partes del código que necesitarán traducción en el futuro.

pgettext

los pgettext La función se comporta como la variante de Python (pgettext()), proporcionando una palabra traducida contextualmente:

document.write(pgettext('month name', 'May'));

npgettext

los npgettext La función también se comporta como la variante de Python (npgettext()), proporcionando un pluralizado palabra traducida contextualmente:

document.write(npgettext('group', 'party', 1));
// party
document.write(npgettext('group', 'party', 2));
// parties

pluralidx

los pluralidx La función funciona de manera similar a la pluralize filtro de plantilla, determinando si un determinado count debe usar una forma plural de una palabra o no:

document.write(pluralidx(0));
// true
document.write(pluralidx(1));
// false
document.write(pluralidx(2));
// true

En el caso más simple, si no se necesita una pluralización personalizada, esto devuelve false para el entero 1 y true para todos los demás números.

Sin embargo, la pluralización no es tan simple en todos los idiomas. Si el idioma no admite la pluralización, se proporciona un valor vacío.

Además, si existen reglas complejas en torno a la pluralización, la vista de catálogo generará una expresión condicional. Esto evaluará a un true (debe pluralizar) o false (deberían no pluralizar) valor.

los JSONCatalog vista

class JSONCatalog

Para utilizar otra biblioteca del lado del cliente para manejar las traducciones, es posible que desee aprovechar la JSONCatalog vista. Es similar a JavaScriptCatalog pero devuelve una respuesta JSON.

Consulte la documentación para JavaScriptCatalog para conocer los posibles valores y el uso de la domain y packages atributos.

El formato de respuesta es el siguiente:

{
    "catalog": {
        # Translations catalog
    },
    "formats": {
        # Language formats for date, time, etc.
    },
    "plural": "..."  # Expression for plural forms, or null.
}

Nota sobre el rendimiento

Las diversas vistas de JavaScript / JSON i18n generan el catálogo desde .mo archivos en cada solicitud. Dado que su salida es constante, al menos para una versión determinada de un sitio, es un buen candidato para el almacenamiento en caché.

El almacenamiento en caché del lado del servidor reducirá la carga de la CPU. Se implementa fácilmente con cache_page() decorador. Para activar la invalidación de la caché cuando cambian las traducciones, proporcione un prefijo de clave dependiente de la versión, como se muestra en el siguiente ejemplo, o asigne la vista a una URL dependiente de la versión:

from django.views.decorators.cache import cache_page
from django.views.i18n import JavaScriptCatalog

# The value returned by get_version() must change when translations change.
urlpatterns = [
    path('jsi18n/',
         cache_page(86400, key_prefix='js18n-%s' % get_version())(JavaScriptCatalog.as_view()),
         name="javascript-catalog"),
]

El almacenamiento en caché del lado del cliente ahorrará ancho de banda y hará que su sitio se cargue más rápido. Si está usando ETags (ConditionalGetMiddleware), ya está cubierto. De lo contrario, puede aplicar decoradores condicionales. En el siguiente ejemplo, la caché se invalida cada vez que reinicia su servidor de aplicaciones:

from django.utils import timezone
from django.views.decorators.http import last_modified
from django.views.i18n import JavaScriptCatalog

last_modified_date = timezone.now()

urlpatterns = [
    path('jsi18n/',
         last_modified(lambda req, **kw: last_modified_date)(JavaScriptCatalog.as_view()),
         name="javascript-catalog"),
]

Incluso puede generar previamente el catálogo de JavaScript como parte de su procedimiento de implementación y servirlo como un archivo estático. Esta técnica radical se implementa en django-statici18n.

Internacionalización: en patrones de URL

Django proporciona dos mecanismos para internacionalizar los patrones de URL:

  • Agregar el prefijo de idioma a la raíz de los patrones de URL para que sea posible LocaleMiddleware para detectar el idioma a activar desde la URL solicitada.
  • Hacer que los patrones de URL sean traducibles a través del django.utils.translation.gettext_lazy() función.

Advertencia

El uso de cualquiera de estas funciones requiere que se establezca un idioma activo para cada solicitud; en otras palabras, necesitas tener django.middleware.locale.LocaleMiddleware en tus MIDDLEWARE configuración.

Prefijo de idioma en patrones de URL

i18n_patterns(*urls, prefix_default_language=True)

Esta función se puede utilizar en una URLconf raíz y Django antepondrá automáticamente el código de idioma activo actual a todos los patrones de URL definidos en i18n_patterns().

Configuración prefix_default_language para False elimina el prefijo del idioma predeterminado (LANGUAGE_CODE). Esto puede ser útil al agregar traducciones a un sitio existente para que las URL actuales no cambien.

Patrones de URL de ejemplo:

from django.conf.urls.i18n import i18n_patterns
from django.urls import include, path

from about import views as about_views
from news import views as news_views
from sitemap.views import sitemap

urlpatterns = [
    path('sitemap.xml', sitemap, name="sitemap-xml"),
]

news_patterns = ([
    path('', news_views.index, name="index"),
    path('category/<slug:slug>/', news_views.category, name="category"),
    path('<slug:slug>/', news_views.details, name="detail"),
], 'news')

urlpatterns += i18n_patterns(
    path('about/', about_views.main, name="about"),
    path('news/', include(news_patterns, namespace="news")),
)

Después de definir estos patrones de URL, Django agregará automáticamente el prefijo de idioma a los patrones de URL que fueron agregados por el i18n_patterns función. Ejemplo:

>>> from django.urls import reverse
>>> from django.utils.translation import activate

>>> activate('en')
>>> reverse('sitemap-xml')
'/sitemap.xml'
>>> reverse('news:index')
'/en/news/'

>>> activate('nl')
>>> reverse('news:detail', kwargs={'slug': 'news-slug'})
'/nl/news/news-slug/'

Con prefix_default_language=False y LANGUAGE_CODE='en', las URL serán:

>>> activate('en')
>>> reverse('news:index')
'/news/'

>>> activate('nl')
>>> reverse('news:index')
'/nl/news/'

Advertencia

i18n_patterns() solo se permite en una URLconf raíz. Usarlo dentro de una URLconf incluida arrojará un ImproperlyConfigured excepción.

Advertencia

Asegúrese de no tener patrones de URL sin prefijo que puedan colisionar con un prefijo de idioma agregado automáticamente.

Traducción de patrones de URL

Los patrones de URL también se pueden marcar como traducibles utilizando el gettext_lazy() función. Ejemplo:

from django.conf.urls.i18n import i18n_patterns
from django.urls import include, path
from django.utils.translation import gettext_lazy as _

from about import views as about_views
from news import views as news_views
from sitemaps.views import sitemap

urlpatterns = [
    path('sitemap.xml', sitemap, name="sitemap-xml"),
]

news_patterns = ([
    path('', news_views.index, name="index"),
    path(_('category/<slug:slug>/'), news_views.category, name="category"),
    path('<slug:slug>/', news_views.details, name="detail"),
], 'news')

urlpatterns += i18n_patterns(
    path(_('about/'), about_views.main, name="about"),
    path(_('news/'), include(news_patterns, namespace="news")),
)

Una vez que haya creado las traducciones, reverse() La función devolverá la URL en el idioma activo. Ejemplo:

>>> from django.urls import reverse
>>> from django.utils.translation import activate

>>> activate('en')
>>> reverse('news:category', kwargs={'slug': 'recent'})
'/en/news/category/recent/'

>>> activate('nl')
>>> reverse('news:category', kwargs={'slug': 'recent'})
'/nl/nieuws/categorie/recent/'

Advertencia

En la mayoría de los casos, es mejor usar las URL traducidas solo dentro de un bloque de patrones con prefijo de código de idioma (usando i18n_patterns()), para evitar la posibilidad de que una URL traducida de forma descuidada provoque una colisión con un patrón de URL no traducido.

Inversión en plantillas

Si las URL localizadas se invierten en las plantillas, siempre usan el idioma actual. Para enlazar a una URL en otro idioma, utilice el language etiqueta de plantilla. Habilita el idioma dado en la sección de plantilla adjunta:

{% load i18n %}

{% get_available_languages as languages %}

{% translate "View this category in:" %}
{% for lang_code, lang_name in languages %}
    {% language lang_code %}
    <a href="https://foroayuda.es/django/topics/i18n/{% url"category' slug=category.slug %}">{{ lang_name }}</a>
    {% endlanguage %}
{% endfor %}

los language La etiqueta espera el código de idioma como único argumento.

Localización: cómo crear archivos de idioma

Una vez que los literales de cadena de una aplicación se han etiquetado para su posterior traducción, es necesario escribir (u obtener) la propia traducción. Así es como funciona.

Archivos de mensajes

El primer paso es crear un archivo de mensaje por un nuevo idioma. Un archivo de mensaje es un archivo de texto sin formato, que representa un solo idioma, que contiene todas las cadenas de traducción disponibles y cómo deben representarse en el idioma dado. Los archivos de mensajes tienen un .po extensión de archivo.

Django viene con una herramienta, django-admin makemessages, que automatiza la creación y el mantenimiento de estos archivos.

Utilidades de Gettext

los makemessages comando (y compilemessages discutido más adelante) use comandos del conjunto de herramientas GNU gettext: xgettext, msgfmt, msgmerge y msguniq.

La versión mínima del gettext utilidades soportadas es 0.15.

Para crear o actualizar un archivo de mensaje, ejecute este comando:

django-admin makemessages -l de

…dónde de es el nombre de la configuración regional para el archivo de mensaje que desea crear. Por ejemplo, pt_BR para portugués brasileño, de_AT para alemán austriaco o id para indonesio.

El script debe ejecutarse desde uno de dos lugares:

  • El directorio raíz de su proyecto Django (el que contiene manage.py).
  • El directorio raíz de una de tus aplicaciones de Django.

La secuencia de comandos se ejecuta sobre el árbol de origen de su proyecto o el árbol de origen de su aplicación y extrae todas las cadenas marcadas para traducción (consulte Cómo Django descubre las traducciones y estar seguro LOCALE_PATHS está configurado correctamente). Crea (o actualiza) un archivo de mensaje en el directorio locale/LANG/LC_MESSAGES. En el de ejemplo, el archivo será locale/de/LC_MESSAGES/django.po.

Cuando corres makemessages desde el directorio raíz de su proyecto, las cadenas extraídas se distribuirán automáticamente a los archivos de mensajes correspondientes. Es decir, una cadena extraída de un archivo de una aplicación que contiene un locale directorio irá en un archivo de mensaje en ese directorio. Una cadena extraída de un archivo de una aplicación sin ningún locale El directorio irá en un archivo de mensaje debajo del directorio listado primero en LOCALE_PATHS o generará un error si LOCALE_PATHS esta vacio.

Por defecto django-admin makemessages examina cada archivo que tiene la .html, .txt o .py extensión de archivo. Si desea anular ese valor predeterminado, use el --extension o -e opción para especificar las extensiones de archivo a examinar:

django-admin makemessages -l de -e txt

Separe varias extensiones con comas y / o use -e o --extension varias veces:

django-admin makemessages -l de -e html,txt -e xml

Advertencia

Cuando crear archivos de mensajes a partir del código fuente de JavaScript necesitas usar el especial djangojs dominio, no -e js.

¿Utilizas plantillas Jinja2?

makemessages no comprende la sintaxis de las plantillas Jinja2. Para extraer cadenas de un proyecto que contiene plantillas Jinja2, use Extracción de mensajes de Babel en lugar de.

Aquí hay un ejemplo babel.cfg archivo de configuración:

# Extraction from Python source files
[python: **.py]

# Extraction from Jinja2 templates
[jinja2: **.jinja]
extensions = jinja2.ext.with_

¡Asegúrate de enumerar todas las extensiones que estás usando! De lo contrario, Babel no reconocerá las etiquetas definidas por estas extensiones e ignorará por completo las plantillas Jinja2 que las contengan.

Babel proporciona características similares a makemessages, puede reemplazarlo en general, y no depende de gettext. Para obtener más información, lea su documentación sobre trabajar con catálogos de mensajes.

¿Sin gettext?

Si no tienes el gettext utilidades instaladas, makemessages creará archivos vacíos. Si ese es el caso, instale el gettext utilidades o copie el archivo de mensajes en inglés (locale/en/LC_MESSAGES/django.po) si está disponible y utilícelo como punto de partida, que es un archivo de traducción vacío.

¿Trabaja en Windows?

Si está utilizando Windows y necesita instalar las utilidades gettext de GNU, makemessages obras, ver gettext en Windows para más información.

Cada .po El archivo contiene una pequeña cantidad de metadatos, como la información de contacto del responsable de la traducción, pero la mayor parte del archivo es una lista de mensajes – asignaciones entre las cadenas de traducción y el texto traducido real para el idioma en particular.

Por ejemplo, si su aplicación Django contiene una cadena de traducción para el texto "Welcome to my site.", al igual que:

_("Welcome to my site.")

…luego django-admin makemessages habrá creado un .po archivo que contiene el siguiente fragmento: un mensaje:

#: path/to/python/module.py:23
msgid "Welcome to my site."
msgstr ""

Una explicación rápida:

  • msgid es la cadena de traducción, que aparece en la fuente. No lo cambie.
  • msgstr es donde pones la traducción específica del idioma. Comienza vacío, por lo que es su responsabilidad cambiarlo. Asegúrese de mantener las citas alrededor de su traducción.
  • Para su comodidad, cada mensaje incluye, en forma de una línea de comentario con el prefijo # y ubicado sobre el msgid línea, el nombre de archivo y el número de línea de la que se obtuvo la cadena de traducción.

Los mensajes largos son un caso especial. Allí, la primera cuerda directamente después de la msgstr (o msgid) es una cadena vacía. Luego, el contenido en sí se escribirá en las siguientes líneas como una cadena por línea. Esas cadenas se concatenan directamente. No olvide los espacios finales dentro de las cadenas; de lo contrario, se unirán sin espacios en blanco.

Cuidado con tu juego de caracteres

Debido a la forma en que gettext las herramientas funcionan internamente y, como queremos permitir cadenas de código fuente no ASCII en el núcleo de Django y en sus aplicaciones, debe utilice UTF-8 como codificación para sus archivos PO (el valor predeterminado cuando se crean archivos PO). Esto significa que todos usarán la misma codificación, lo cual es importante cuando Django procesa los archivos PO.

Entradas borrosas

makemessages a veces genera entradas de traducción marcadas como borrosas, por ejemplo, cuando las traducciones se infieren de cadenas traducidas previamente. Por defecto, las entradas difusas son no procesado por compilemessages.

Para volver a examinar todo el código fuente y las plantillas para las nuevas cadenas de traducción y actualizar todos los archivos de mensajes para todos idiomas, ejecute esto:

django-admin makemessages -a

Compilar archivos de mensajes

Después de crear su archivo de mensaje, y cada vez que realice cambios en él, deberá compilarlo en una forma más eficiente, para que lo use gettext. Haz esto con el django-admin compilemessages utilidad.

Esta herramienta funciona con todos los disponibles. .po archivos y crea .mo archivos, que son archivos binarios optimizados para su uso por gettext. En el mismo directorio desde el que ejecutó django-admin makemessages, correr django-admin compilemessages como esto:

django-admin compilemessages

Eso es todo. Sus traducciones están listas para su uso.

¿Trabaja en Windows?

Si está utilizando Windows y necesita instalar las utilidades gettext de GNU, django-admin compilemessages obras ver gettext en Windows para más información.

Archivos .po: Codificación y uso de BOM.

Django solo admite .po archivos codificados en UTF-8 y sin ninguna lista de materiales (marca de orden de bytes), por lo que si su editor de texto agrega dichas marcas al principio de los archivos de forma predeterminada, deberá volver a configurarlo.

Solución de problemas: gettext() detecta incorrectamente python-format en cadenas con signos de porcentaje

En algunos casos, como cadenas con un signo de porcentaje seguido de un espacio y un tipo de conversión de cadena (p.ej _("10% interest")), gettext() marca incorrectamente cadenas con python-format.

Si intenta compilar archivos de mensajes con cadenas marcadas incorrectamente, obtendrá un mensaje de error como number of format specifications in 'msgid' and
'msgstr' does not match
o 'msgstr' is not a valid Python format string,
unlike 'msgid'
.

Para solucionar esto, puede escapar de los signos de porcentaje agregando un segundo signo de porcentaje:

from django.utils.translation import gettext as _
output = _("10%% interest")

O puedes usar no-python-format para que todos los signos de porcentaje se traten como literales:

# xgettext:no-python-format
output = _("10% interest")

Crear archivos de mensajes a partir del código fuente de JavaScript

Usted crea y actualiza los archivos de mensajes de la misma manera que los otros archivos de mensajes de Django, con el django-admin makemessages herramienta. La única diferencia es que necesita especificar explícitamente lo que en el lenguaje de gettext se conoce como dominio, en este caso el djangojs dominio, proporcionando un -d
djangojs
parámetro, como este:

django-admin makemessages -d djangojs -l de

Esto crearía o actualizaría el archivo de mensaje de JavaScript para alemán. Después de actualizar los archivos de mensajes, ejecute django-admin compilemessages de la misma manera que lo hace con los archivos de mensajes normales de Django.

gettext en Windows

Esto solo es necesario para las personas que desean extraer ID de mensajes o compilar archivos de mensajes (.po). El trabajo de traducción en sí implica la edición de archivos existentes de este tipo, pero si desea crear sus propios archivos de mensajes, o desea probar o compilar un archivo de mensajes modificado, descargue un instalador binario precompilado.

También puede utilizar gettext binarios que haya obtenido en otro lugar, siempre que el xgettext --version El comando funciona correctamente. No intente utilizar las utilidades de traducción de Django con un gettext paquete si el comando xgettext
--version
ingresado en un símbolo del sistema de Windows provoca una ventana emergente que dice “xgettext.exe ha generado errores y será cerrado por Windows”.

Personalizando el makemessages mando

Si desea pasar parámetros adicionales a xgettext, necesitas crear un personalizado makemessages comando y anular su xgettext_options atributo:

from django.core.management.commands import makemessages

class Command(makemessages.Command):
    xgettext_options = makemessages.Command.xgettext_options + ['--keyword=mytrans']

Si necesita más flexibilidad, también puede agregar un nuevo argumento a su makemessages mando:

from django.core.management.commands import makemessages

class Command(makemessages.Command):

    def add_arguments(self, parser):
        super().add_arguments(parser)
        parser.add_argument(
            '--extra-keyword',
            dest="xgettext_keywords",
            action='append',
        )

    def handle(self, *args, **options):
        xgettext_keywords = options.pop('xgettext_keywords')
        if xgettext_keywords:
            self.xgettext_options = (
                makemessages.Command.xgettext_options[:] +
                ['--keyword=%s' % kwd for kwd in xgettext_keywords]
            )
        super().handle(*args, **options)

Diverso

los set_language redireccionar vista

set_language(request)

Para su comodidad, Django viene con una vista, django.views.i18n.set_language(), que establece la preferencia de idioma de un usuario y lo redirecciona a una URL determinada o, de forma predeterminada, vuelve a la página anterior.

Active esta vista agregando la siguiente línea a su URLconf:

path('i18n/', include('django.conf.urls.i18n')),

(Tenga en cuenta que este ejemplo hace que la vista esté disponible en /i18n/setlang/.)

Advertencia

Asegúrese de no incluir la URL anterior en i18n_patterns() – debe ser independiente del idioma para funcionar correctamente.

La vista espera ser llamada a través del POST método, con un language conjunto de parámetros en la solicitud. Si el soporte de sesión está habilitado, la vista guarda la elección de idioma en la sesión del usuario. También guarda la elección del idioma en una cookie que se denomina django_language por defecto. (El nombre se puede cambiar a través del LANGUAGE_COOKIE_NAME configuración.)

Después de establecer la elección del idioma, Django busca un next parámetro en el POST o GET datos. Si se encuentra y Django la considera una URL segura (es decir, no apunta a un host diferente y usa un esquema seguro), se realizará una redirección a esa URL. De lo contrario, Django puede recurrir a redirigir al usuario a la URL desde el Referer encabezado o, si no está configurado, a /, dependiendo de la naturaleza de la solicitud:

  • Si la solicitud acepta contenido HTML (según su Accept Encabezado HTTP), la reserva siempre se realizará.
  • Si la solicitud no acepta HTML, la reserva se realizará solo si el next se configuró el parámetro. De lo contrario, se devolverá un código de estado 204 (Sin contenido).

Cambiado en Django 3.1:

En versiones anteriores, la distinción para el respaldo se basa en si el X-Requested-With el encabezado se establece en el valor XMLHttpRequest. Esto lo establece jQuery ajax() método.

A continuación, se muestra un código de plantilla HTML de ejemplo:

{% load i18n %}

<form action="https://foroayuda.es/django/topics/i18n/{% url"set_language' %}" method="post">{% csrf_token %}
    <input name="next" type="hidden" value="{{ redirect_to }}">
    <select name="language">
        {% get_current_language as LANGUAGE_CODE %}
        {% get_available_languages as LANGUAGES %}
        {% get_language_info_list for LANGUAGES as languages %}
        {% for language in languages %}
            <option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected{% endif %}>
                {{ language.name_local }} ({{ language.code }})
            </option>
        {% endfor %}
    </select>
    <input type="submit" value="Go">
</form>

En este ejemplo, Django busca la URL de la página a la que se redirigirá al usuario en el redirect_to variable de contexto.

Establecer explícitamente el idioma activo

Es posible que desee establecer explícitamente el idioma activo para la sesión actual. Quizás la preferencia de idioma de un usuario se recupera de otro sistema, por ejemplo. Ya te han presentado django.utils.translation.activate(). Eso se aplica solo al hilo actual. Para conservar el idioma durante toda la sesión en una cookie, configure el LANGUAGE_COOKIE_NAME cookie en la respuesta:

from django.conf import settings
from django.http import HttpResponse
from django.utils import translation
user_language="fr"
translation.activate(user_language)
response = HttpResponse(...)
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, user_language)

Por lo general, querrá usar ambos: django.utils.translation.activate() cambia el idioma de este hilo y la configuración de la cookie hace que esta preferencia persista en solicitudes futuras.

Usar traducciones fuera de vistas y plantillas

Si bien Django proporciona un amplio conjunto de herramientas i18n para usar en vistas y plantillas, no restringe el uso al código específico de Django. Los mecanismos de traducción de Django se pueden usar para traducir textos arbitrarios a cualquier idioma que sea compatible con Django (siempre que exista un catálogo de traducción apropiado, por supuesto). Puede cargar un catálogo de traducción, activarlo y traducir el texto al idioma que elija, pero recuerde volver al idioma original, ya que la activación de un catálogo de traducción se realiza por subproceso y dicho cambio afectará el código que se ejecuta en el mismo subproceso. .

Por ejemplo:

from django.utils import translation

def welcome_translated(language):
    cur_language = translation.get_language()
    try:
        translation.activate(language)
        text = translation.gettext('welcome')
    finally:
        translation.activate(cur_language)
    return text

Llamar a esta función con el valor 'de' Te regalaré "Willkommen", independientemente de LANGUAGE_CODE e idioma establecido por middleware.

Las funciones de especial interés son django.utils.translation.get_language() que devuelve el idioma utilizado en el hilo actual, django.utils.translation.activate() que activa un catálogo de traducción para el hilo actual, y django.utils.translation.check_for_language() que comprueba si el idioma dado es compatible con Django.

Para ayudar a escribir código más conciso, también hay un administrador de contexto django.utils.translation.override() que almacena el idioma actual al entrar y lo restaura al salir. Con él, el ejemplo anterior se convierte en:

from django.utils import translation

def welcome_translated(language):
    with translation.override(language):
        return translation.gettext('welcome')

Cookie de idioma

Se pueden usar varias configuraciones para ajustar las opciones de cookies de idioma:

  • LANGUAGE_COOKIE_NAME
  • LANGUAGE_COOKIE_AGE
  • LANGUAGE_COOKIE_DOMAIN
  • LANGUAGE_COOKIE_HTTPONLY
  • LANGUAGE_COOKIE_PATH
  • LANGUAGE_COOKIE_SAMESITE
  • LANGUAGE_COOKIE_SECURE

Notas de implementación

Especialidades de la traducción de Django

La maquinaria de traducción de Django utiliza el estándar gettext módulo que viene con Python. Si usted sabe gettext, puede notar estas especialidades en la forma en que Django hace la traducción:

  • El dominio de cadena es django o djangojs. Este dominio de cadena se usa para diferenciar entre diferentes programas que almacenan sus datos en una biblioteca de archivos de mensajes común (generalmente /usr/share/locale/). los django El dominio se utiliza para cadenas de traducción de plantillas y Python y se carga en los catálogos de traducción globales. los djangojs El dominio solo se usa para catálogos de traducción de JavaScript para asegurarse de que sean lo más pequeños posible.
  • Django no usa xgettext solo. Utiliza envoltorios de Python alrededor xgettext y msgfmt. Esto es principalmente por conveniencia.

Cómo descubre Django la preferencia de idioma

Una vez que haya preparado sus traducciones, o si desea utilizar las traducciones que vienen con Django, deberá activar la traducción para su aplicación.

Detrás de escena, Django tiene un modelo muy flexible para decidir qué idioma se debe usar: en toda la instalación, para un usuario en particular o ambos.

Para establecer una preferencia de idioma para toda la instalación, configure LANGUAGE_CODE. Django usa este idioma como traducción predeterminada: el último intento si no se encuentra una traducción que coincida mejor a través de uno de los métodos empleados por el middleware de configuración regional (ver más abajo).

Si todo lo que desea es ejecutar Django con su idioma nativo, todo lo que necesita hacer es configurar LANGUAGE_CODE y asegúrese de que el correspondiente archivos de mensajes y sus versiones compiladas (.mo) existe.

Si desea que cada usuario individual especifique qué idioma prefiere, también debe usar el LocaleMiddleware. LocaleMiddleware habilita la selección de idioma en función de los datos de la solicitud. Personaliza el contenido para cada usuario.

Usar LocaleMiddleware, agregar 'django.middleware.locale.LocaleMiddleware' para usted MIDDLEWARE configuración. Debido a que el orden del middleware es importante, siga estas pautas:

  • Asegúrese de que sea uno de los primeros middleware instalados.
  • Debería venir después SessionMiddleware, porque LocaleMiddleware hace uso de los datos de la sesión. Y debería venir antes CommonMiddleware porque CommonMiddleware necesita un idioma activado para resolver la URL solicitada.
  • Si utiliza CacheMiddleware, poner LocaleMiddleware después de.

Por ejemplo, tu MIDDLEWARE podría verse así:

MIDDLEWARE = [
   'django.contrib.sessions.middleware.SessionMiddleware',
   'django.middleware.locale.LocaleMiddleware',
   'django.middleware.common.CommonMiddleware',
]

(Para obtener más información sobre middleware, consulte la documentación de middleware.)

LocaleMiddleware intenta determinar la preferencia de idioma del usuario siguiendo este algoritmo:

  • Primero, busca el prefijo de idioma en la URL solicitada. Esto solo se realiza cuando está utilizando el i18n_patterns función en su URLconf raíz. Ver Internacionalización: en patrones de URL para obtener más información sobre el prefijo de idioma y cómo internacionalizar los patrones de URL.
  • De no ser así, busca una galleta.

    El nombre de la cookie utilizada lo establece el LANGUAGE_COOKIE_NAME configuración. (El nombre predeterminado es django_language.)

  • Si eso falla, mira el Accept-Language Encabezado HTTP. Este encabezado es enviado por su navegador y le dice al servidor qué idioma (s) prefiere, en orden por prioridad. Django prueba cada idioma en el encabezado hasta que encuentra uno con traducciones disponibles.
  • De no ser así, utiliza el método global LANGUAGE_CODE configuración.

Notas:

  • En cada uno de estos lugares, se espera que la preferencia de idioma esté en el estándar formato de idioma, como una cuerda. Por ejemplo, el portugués brasileño es pt-br.
  • Si un idioma base está disponible pero el sub-idioma especificado no lo está, Django usa el idioma base. Por ejemplo, si un usuario especifica de-at (Alemán austriaco) pero Django solo tiene de disponible, Django usa de.
  • Solo los idiomas enumerados en el LANGUAGES se puede seleccionar el ajuste. Si desea restringir la selección de idioma a un subconjunto de idiomas proporcionados (porque su aplicación no proporciona todos esos idiomas), configure LANGUAGES a una lista de idiomas. Por ejemplo:

    LANGUAGES = [
        ('de', _('German')),
        ('en', _('English')),
    ]
    

    Este ejemplo restringe los idiomas que están disponibles para la selección automática a alemán e inglés (y cualquier sub-idioma, como de-ch o en-us).

  • Si define un personalizado LANGUAGES configuración, como se explica en la viñeta anterior, puede marcar los nombres de los idiomas como cadenas de traducción, pero use gettext_lazy() en lugar de gettext() para evitar una importación circular.

    Aquí hay un archivo de configuración de muestra:

    from django.utils.translation import gettext_lazy as _
    
    LANGUAGES = [
        ('de', _('German')),
        ('en', _('English')),
    ]
    

Una vez LocaleMiddleware determina la preferencia del usuario, hace que esta preferencia esté disponible como request.LANGUAGE_CODE para cada HttpRequest. No dude en leer este valor en su código de vista. He aquí un ejemplo:

from django.http import HttpResponse

def hello_world(request, count):
    if request.LANGUAGE_CODE == 'de-at':
        return HttpResponse("You prefer to read Austrian German.")
    else:
        return HttpResponse("You prefer to read another language.")

Tenga en cuenta que, con la traducción estática (sin middleware), el idioma está en settings.LANGUAGE_CODE, mientras que con la traducción dinámica (middleware), está en request.LANGUAGE_CODE.

Cómo Django descubre las traducciones

En tiempo de ejecución, Django crea un catálogo unificado en memoria de traducciones de literales. Para lograrlo, busca traducciones siguiendo este algoritmo con respecto al orden en el que examina las diferentes rutas de archivo para cargar el compilado. archivos de mensajes (.mo) y la precedencia de múltiples traducciones para el mismo literal:

  1. Los directorios enumerados en LOCALE_PATHS tienen la mayor precedencia, y los que aparecen primero tienen mayor precedencia que los que aparecen después.
  2. Luego, busca y usa si existe un locale directorio en cada una de las aplicaciones instaladas enumeradas en INSTALLED_APPS. Los que aparecen primero tienen mayor precedencia que los que aparecen después.
  3. Finalmente, la traducción base proporcionada por Django en django/conf/locale se utiliza como alternativa.

Ver también

Las traducciones de los literales incluidos en los activos de JavaScript se buscan siguiendo un algoritmo similar pero no idéntico. Ver JavaScriptCatalog para más detalles.

También puedes poner archivos de formato personalizado en el LOCALE_PATHS directorios si también estableces FORMAT_MODULE_PATH.

En todos los casos, se espera que el nombre del directorio que contiene la traducción se nombre usando nombre de la configuración regional notación. P.ej de, pt_BR, es_AR, etc. Las cadenas no traducidas para las variantes lingüísticas territoriales utilizan las traducciones del idioma genérico. Por ejemplo, sin traducir pt_BR uso de cadenas pt traducciones.

De esta forma, puede escribir aplicaciones que incluyan sus propias traducciones y puede anular las traducciones base en su proyecto. O puede crear un gran proyecto a partir de varias aplicaciones y poner todas las traducciones en un gran archivo de mensaje común específico para el proyecto que está redactando. La decisión es tuya.

Todos los repositorios de archivos de mensajes están estructurados de la misma manera. Son:

  • Todas las rutas enumeradas en LOCALE_PATHS en su archivo de configuración se buscan <language>/LC_MESSAGES/django.(po|mo)
  • $APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo)
  • $PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo)

Para crear archivos de mensajes, utilice el django-admin makemessages herramienta. Y usas django-admin compilemessages para producir el binario .mo archivos que son utilizados por gettext.

También puedes correr django-admin compilemessages
--settings=path.to.settings
para hacer que el compilador procese todos los directorios en su LOCALE_PATHS configuración.

Usar un idioma base que no sea el inglés

Django asume que las cadenas originales de un proyecto traducible están escritas en inglés. Puede elegir otro idioma, pero debe tener en cuenta ciertas limitaciones:

  • gettext solo proporciona dos formas plurales para los mensajes originales, por lo que también deberá proporcionar una traducción para que el idioma base incluya todas las formas plurales si las reglas del plural para el idioma base son diferentes del inglés.
  • Cuando se activa una variante en inglés y faltan cadenas en inglés, el idioma de reserva no será el LANGUAGE_CODE del proyecto, pero las cadenas originales. Por ejemplo, un usuario de inglés que visita un sitio con LANGUAGE_CODE establecido en español y las cadenas originales escritas en ruso verán texto en ruso en lugar de español.