Manejo multilingüe en Django: Evitar que "Polish" se convierta en "polaco" (Marcadores contextuales)
Cuando se implementa el soporte multilingüe (i18n) de manera adecuada, es común encontrarse con situaciones como:
- Un botón con “Polish” (refinar la UI) se traduce como “polaco”
- El componente de selección de fechas muestra “May” que se traduce como un nombre propio en algunos idiomas
- El menú presenta “Book” solo como “libro”, sin la opción de “reservar”
La causa es sencilla:
Las computadoras no comprenden el contexto. Si dos cadenas son idénticas, se tratan como la misma.
En este artículo, utilizaremos los Marcadores contextuales de Django para mantener el código fuente intacto y asignar traducciones distintas a la misma cadena.
¿Por qué ocurre esto? Funcionamiento básico de gettext
El sistema de traducción de Django se basa en GNU gettext. Su lógica es muy simple:
- Texto original →
msgid - Texto traducido →
msgstr - Si
msgides idéntico, siempre se usa el mismomsgstr
# django.po
msgid "Polish"
msgstr "polaco"
Una vez que se crea esta asociación, cualquier aparición de “Polish” en el proyecto usará la misma traducción. Por eso, los dos usos de “Polish” (verbo y nombre de idioma) no se distinguen.
Para evitarlo, algunos desarrolladores modifican el código fuente:
<!-- Código a evitar -->
{% trans "Polish (verb)" %}
{% trans "Polish (language)" %}
Aunque la traducción sea correcta, el texto visible para el usuario se vuelve extraño y la reutilización se complica.
Lo que buscamos es:
- Mantener la cadena original
"Polish" - Añadir una explicación de su significado en el contexto
Los Marcadores contextuales son la solución.
Solución en plantillas: {% translate %} + context
En las plantillas de Django, el tag {% translate %} (o su versión antigua {% trans %}) acepta la opción context para diferenciar la misma cadena según su uso.
1) Código original (colisión)
{% load i18n %}
<button>{% translate "Polish" %}</button>
<span>{% translate "Polish" %}</span>
En el archivo .po, ambas líneas comparten msgid "Polish", por lo que solo se puede traducir una vez.
2) Código mejorado (con contexto)
{% load i18n %}
<button>
{% translate "Polish" context "verb: to refine UI" %}
</button>
<span>
{% translate "Polish" context "language name" %}
</span>
Puntos clave:
- El texto después de
contextno se muestra al usuario. - Es información meta para el sistema de traducción y los traductores.
- Se recomienda usar descripciones breves y claras.
3) También funciona con {% blocktranslate %}
Para frases largas, se puede usar {% blocktranslate %} con context.
{% load i18n %}
{% blocktranslate context "greeting message" with username=user.username %}
Hello {{ username }}
{% endblocktranslate %}
Esto permite reutilizar la misma frase con diferentes contextos.
Solución en código Python: pgettext
En vistas, modelos, formularios y demás código Python, se utilizan las funciones de la familia pgettext.
pgettext(context, message)pgettext_lazy(context, message)– evaluación diferidanpgettext(context, singular, plural, number)– plural + contexto
1) Ejemplo básico
from django.utils.translation import pgettext
def my_view(request):
# 1. Mes "May"
month = pgettext("month name", "May")
# 2. Nombre propio "May"
person = pgettext("person name", "May")
# 3. Verbo modal "may"
verb = pgettext("auxiliary verb", "may")
Aunque el msgid sea el mismo, el context permite distintas traducciones.
2) Uso de pgettext_lazy en modelos
from django.db import models
from django.utils.translation import pgettext_lazy
class Order(models.Model):
type = models.CharField(
verbose_name=pgettext_lazy("order model field", "Order type"),
max_length=20,
)
STATUS_CHOICES = [
("open", pgettext_lazy("order status", "Open")),
("opened", pgettext_lazy("log action", "Open")),
]
status = models.CharField(
max_length=20,
choices=STATUS_CHOICES,
)
3) Manejo de plurales con npgettext
from django.utils.translation import npgettext
def get_notification(count):
return npgettext(
"user notification",
"You have %(count)d message",
"You have %(count)d messages",
count
) % {"count": count}
¿Cómo se ve en el archivo .po?
Después de usar context, el comando de extracción añade msgctxt.
python manage.py makemessages -l ko
El archivo .po resultante:
# django.po
# 1) "Polish" = verbo de refinar la UI
msgctxt "verb: to refine UI"
msgid "Polish"
msgstr "refinar"
# 2) "Polish" = idioma
msgctxt "language name"
msgid "Polish"
msgstr "polaco"
Aunque msgid sea idéntico, el msgctxt diferencia las entradas, lo que facilita la traducción y la gestión.
Consejos para crear buenos contextos
El contexto no se muestra al usuario, pero es la pista más valiosa para el traductor.
1) Describir el rol en la UI
"button label""menu item""tooltip""error message""form field label"
2) Añadir el concepto cuando sea necesario
"File"→"file menu item","uploaded file object""Order"→"e-commerce order","sorting order"
3) No incluir la traducción en el contexto
El contexto debe ser breve y en el idioma original (usualmente inglés).
Cuándo usar marcadores contextuales
Considera usar context/pgettext cuando:
- La cadena es corta (1–2 palabras) y aparece en varios lugares.
- Se reutiliza con significados distintos (ej. "Open", "Book").
- Los traductores no tienen acceso a la pantalla.
Resumen

- Django asigna una única traducción a cada
msgid. - Los homónimos como "Polish", "May", "Book" suelen causar conflictos.
- No cambies la cadena original; usa
{% translate "…" context "…" %}en plantillas ypgettext/pgettext_lazy/npgettexten Python. - Así, el archivo
.potendrámsgctxt, permitiendo distintas traducciones y mejorando la calidad y mantenibilidad.
En la era del soporte multilingüe, los marcadores contextuales son una herramienta esencial para los desarrolladores de Django.
Artículos relacionados