# 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 {#sec-aff43a618865} 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 `msgid` es idéntico, siempre se usa el mismo `msgstr` ```po # 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: ```html {% 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` {#sec-e28151952ba2} 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) {#sec-40afc992a96b} ```html {% load i18n %} {% translate "Polish" %} ``` 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) {#sec-4fa05f04b9d3} ```html {% load i18n %} {% translate "Polish" context "language name" %} ``` Puntos clave: * El texto después de `context` no 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 %}` {#sec-c2a9f27dea01} Para frases largas, se puede usar `{% blocktranslate %}` con `context`. ```html {% 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` {#sec-3a9a008d3f99} 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 diferida * `npgettext(context, singular, plural, number)` – plural + contexto ### 1) Ejemplo básico {#sec-27f89a09cea2} ```python 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 {#sec-11832a96275e} ```python 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` {#sec-ed84f3cf8d15} ```python 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`? {#sec-fb610023c81a} Después de usar `context`, el comando de extracción añade `msgctxt`. ```bash python manage.py makemessages -l ko ``` El archivo `.po` resultante: ```po # 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 {#sec-df37b35ab408} El contexto no se muestra al usuario, pero es la pista más valiosa para el traductor. ### 1) Describir el *rol* en la UI {#sec-9dfe29490c86} * `"button label"` * `"menu item"` * `"tooltip"` * `"error message"` * `"form field label"` ### 2) Añadir el *concepto* cuando sea necesario {#sec-135dce4b280b} * `"File"` → `"file menu item"`, `"uploaded file object"` * `"Order"` → `"e-commerce order"`, `"sorting order"` ### 3) No incluir la traducción en el contexto {#sec-9197b1a38f27} El contexto debe ser breve y en el idioma original (usualmente inglés). --- ## Cuándo usar marcadores contextuales {#sec-58e84d2a2b4c} Considera usar `context`/`pgettext` cuando: 1. La cadena es corta (1–2 palabras) y aparece en varios lugares. 2. Se reutiliza con significados distintos (ej. "Open", "Book"). 3. Los traductores no tienen acceso a la pantalla. --- ## Resumen {#sec-8cc5759d0812} ![Desenfoque de un desarrollador con homónimos](/media/editor_temp/6/14112b82-d049-4b32-9275-02429e9305c0.png) * 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 y `pgettext`/`pgettext_lazy`/`npgettext` en Python. * Así, el archivo `.po` tendrá `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** - [Django: Diferencia entre gettext y gettext_lazy](/whitedec/2026/1/5/django-gettext-vs-gettext-lazy/) - [Problemas al usar gettext_lazy como clave JSON y cómo solucionarlos](/whitedec/2025/4/26/gettext-lazy-json-key-problem-solution/)