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:
- 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. - 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ícitagettext()
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 unlocale
directorio. Todos esos catálogos más todos los catálogos que se encuentran enLOCALE_PATHS
(que siempre se incluyen) se fusionan en un catálogo. Predeterminado aNone
, lo que significa que todas las traducciones disponibles de todosINSTALLED_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 pori18n_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 correspondientefmt
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 comotrue
.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 aJavaScriptCatalog
pero devuelve una respuesta JSON.Consulte la documentación para
JavaScriptCatalog
para conocer los posibles valores y el uso de ladomain
ypackages
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 elmsgid
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
o
'msgstr' does not match'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
parámetro, como este:
djangojs
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
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”.
--version
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
odjangojs
. 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/
). losdjango
El dominio se utiliza para cadenas de traducción de plantillas y Python y se carga en los catálogos de traducción globales. losdjangojs
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 alrededorxgettext
ymsgfmt
. 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
, porqueLocaleMiddleware
hace uso de los datos de la sesión. Y debería venir antesCommonMiddleware
porqueCommonMiddleware
necesita un idioma activado para resolver la URL solicitada. - Si utiliza
CacheMiddleware
, ponerLocaleMiddleware
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 esdjango_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 tienede
disponible, Django usade
. -
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), configureLANGUAGES
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
oen-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 usegettext_lazy()
en lugar degettext()
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:
- Los directorios enumerados en
LOCALE_PATHS
tienen la mayor precedencia, y los que aparecen primero tienen mayor precedencia que los que aparecen después. - Luego, busca y usa si existe un
locale
directorio en cada una de las aplicaciones instaladas enumeradas enINSTALLED_APPS
. Los que aparecen primero tienen mayor precedencia que los que aparecen después. - 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
para hacer que el compilador procese todos los directorios en su
--settings=path.to.settingsLOCALE_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 conLANGUAGE_CODE
establecido en español y las cadenas originales escritas en ruso verán texto en ruso en lugar de español.