# Internacionalización en Django: evitar colisiones de significado con marcadores contextuales Cuando se implementa bien el soporte multilingüe (i18n), es habitual encontrarse con situaciones como estas: * Un botón con **“Polish”** (en el sentido de “pulir” o “refinar”) acaba traducido como **“polaco”**. * En un selector de fechas, **“May”** puede traducirse como un **nombre propio** en algunos idiomas. * El ítem de menú **“Book”** se traduce solo como **“libro”** y no como **“reservar”**. La causa es sencilla: > Las computadoras no entienden el *contexto*. > Si dos cadenas son idénticas, se tratan como la misma. En este artículo veremos cómo usar los **marcadores contextuales** de Django para mantener el texto fuente intacto y, aun así, asignar traducciones distintas a una misma cadena. --- ## ¿Por qué ocurre esto? Comportamiento básico de gettext {#sec-aff43a618865} El sistema de traducción de Django se apoya en **GNU gettext**, que funciona con reglas muy simples: * Cadena fuente → `msgid` * Traducción → `msgstr` * **Si `msgid` es el mismo, se reutiliza el mismo `msgstr`** ```po # django.po msgid "Polish" msgstr "polaco" ``` Una vez creada esa asociación en el `.po`, cualquier aparición de `"Polish"` usará la misma traducción, aunque el sentido sea distinto. Por eso no se distinguen estos dos usos: * `"Polish"` = verbo (pulir / refinar) * `"Polish"` = nombre de idioma o gentilicio Para evitarlo, a veces se modifica el texto fuente: ```html {% trans "Polish (verb)" %} {% trans "Polish (language)" %} ``` Aunque “funcione”, el texto visible se vuelve artificial y se pierde reutilización. Lo que queremos es: * Mantener la cadena fuente **"Polish"** * Añadir una pista externa sobre el significado en ese punto Ahí entran los **marcadores contextuales**. --- ## Solución en plantillas: `{% translate %}` + `context` {#sec-e28151952ba2} En plantillas de Django, el tag `{% translate %}` (o el antiguo `{% trans %}`) admite la opción `context` para diferenciar cadenas idénticas según su uso. ### 1) Código original (colisión) {#sec-40afc992a96b} ```html {% load i18n %} {% translate "Polish" %} ``` En el `.po` ambas entradas quedan como `msgid "Polish"`, así que solo puede existir una traducción. ### 2) Código mejorado (con contexto) {#sec-4fa05f04b9d3} ```html {% load i18n %} {% translate "Polish" context "language name" %} ``` Puntos clave: * El texto de `context` **no se muestra al usuario**. * Es metainformación para el sistema y para quienes traducen. * Conviene que sea breve y específico (por ejemplo: `"button text"`, `"menu item"`, `"language name"`). ### 3) También con `{% blocktranslate %}` {#sec-c2a9f27dea01} En frases más largas, `context` también funciona con `{% blocktranslate %}`: ```html {% load i18n %} {% blocktranslate context "greeting message" with username=user.username %} Hello {{ username }} {% endblocktranslate %} ``` Así puedes reutilizar estructuras de frase sin perder el significado por falta de contexto. --- ## Solución en código Python: `pgettext` {#sec-3a9a008d3f99} En código Python (vistas, modelos, formularios), en lugar de `gettext` se usa la familia `pgettext`: * `pgettext(context, message)` * `pgettext_lazy(context, message)` – evaluación diferida (por ejemplo, en modelos) * `npgettext(context, singular, plural, number)` – plural + contexto ### 1) Ejemplo básico {#sec-27f89a09cea2} ```python from django.utils.translation import pgettext def my_view(request): month = pgettext("month name", "May") person = pgettext("person name", "May") verb = pgettext("auxiliary verb", "may") ``` Aunque el `msgid` sea el mismo, el `context` permite traducciones distintas. ### 2) `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) ``` Con esto, una misma cadena puede traducirse de forma distinta según sea “estado” o “acción”. ### 3) 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} Tras extraer mensajes, el `.po` incluirá `msgctxt` para las cadenas con contexto: ```bash python manage.py makemessages -l ``` ```po # django.po msgctxt "verb: to refine UI" msgid "Polish" msgstr "pulir" msgctxt "language name" msgid "Polish" msgstr "polaco" ``` Aunque `msgid` sea idéntico, `msgctxt` separa las entradas y las herramientas de traducción las gestionan por separado. --- ## Consejos para escribir buenos contextos {#sec-df37b35ab408} El contexto no se ve en pantalla, pero suele ser la pista más útil para traducir bien. * **Describe el rol**: `"button label"`, `"menu item"`, `"tooltip"`, `"error message"`, `"form field label"`. * **Aclara el concepto** cuando haga falta: `"File"` → `"file menu item"` / `"uploaded file object"`. * **No metas la traducción en el contexto**: debe ser una descripción breve en el idioma fuente (normalmente inglés). --- ## Cuándo usar marcadores contextuales {#sec-58e84d2a2b4c} Suele ser buena idea usar `context`/`pgettext` cuando: 1. La cadena es corta (1–2 palabras). 2. Se reutiliza con significados distintos en la UI. 3. Quien traduce no ve la interfaz (plataformas de traducción o entrega de `.po`). --- ## Resumen {#sec-8cc5759d0812} ![Desenfoque de un desarrollador con homónimos](/media/editor_temp/6/14112b82-d049-4b32-9275-02429e9305c0.png) * Django asocia por defecto una única traducción a cada `msgid`. * Palabras ambiguas como `"Polish"`, `"May"` o `"Book"` generan colisiones. * En vez de cambiar el texto fuente, añade contexto: * Templates: `{% translate "…" context "…" %}` * Python: `pgettext`, `pgettext_lazy`, `npgettext` * El `.po` incorpora `msgctxt`, lo que permite traducciones distintas y mejora la mantenibilidad. En proyectos multilingües, los marcadores contextuales son una herramienta clave para mantener el código limpio y las traducciones coherentes. --- **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/)