Usando msgctxt: Añadiendo Contexto a las Traducciones de Gettext

Traduces la palabra inglesa "Book" al alemán, y tu traductor devuelve con confianza "Buch". Tres semanas después, llega un informe de error: el botón "Book a table" (Reservar una mesa) de tu formulario de reserva ahora dice "Buch a table" - el sustantivo, no el verbo. La palabra era correcta. Faltaba el contexto. Este es uno de los fallos silenciosos más comunes en la localización de software, y la solución ha existido en Gettext durante décadas: msgctxt.
Si alguna vez has entregado una traducción donde una única cadena en inglés era correcta en un lugar y un sinsentido en otro, has encontrado el problema de la ambigüedad. La misma palabra de origen se traduce de manera diferente según donde aparezca. Sin msgctxt, el traductor (humano o IA) no tiene forma de distinguir esos casos, porque todo lo que ve es la cadena desnuda msgid "Book". Esta guía explica cómo funciona msgctxt en Gettext, cómo marcar tu código fuente con _x() y _ex(), cómo aparece en tus archivos .po, y por qué una cadena de traducción consciente del contexto es la única forma fiable de traducir estas cadenas correctamente a gran escala.
El Problema de la Ambigüedad: Una Palabra, Muchos Significados
El lenguaje natural está lleno de palabras que se reducen a un único token en inglés pero se dividen en varias palabras en otros idiomas. El traductor solo ve la cadena de origen, por lo que cuando dos elementos de la interfaz de usuario no relacionados comparten la misma palabra en inglés, comparten el mismo msgid y Gettext los fusiona en una sola entrada.
Palabras Que Se Dividen en Diferentes Idiomas
Considera tres ejemplos clásicos:
- "Book" - el sustantivo (un objeto en un estante) versus el verbo ("Book a flight" - Reservar un vuelo). Alemán: Buch versus buchen.
- "Post" - publicar contenido versus enviar correo. Francés: publier versus courrier.
- "Order" - una secuencia/ordenación versus una compra. Español: orden versus pedido.
En inglés, tu código usa la misma cadena literal en ambos lugares:
// Somewhere in a library catalog screen
echo __( 'Book', 'mytextdomain' );
// Somewhere in a reservation form button
echo __( 'Book', 'mytextdomain' );
Cómo las Cadenas Idénticas se Colapsan en una Sola Entrada
Cuando ejecutas wp i18n make-pot o xgettext, ambas llamadas se colapsan en una única entrada .po:
#: catalog.php:42 reservation-form.php:88
msgid "Book"
msgstr ""
Hay exactamente un msgstr para rellenar. Elija lo que elija el traductor, una de las dos pantallas estará mal. El traductor no puede solucionar esto incluso si entiende el problema, porque el formato en sí no le permite proporcionar dos traducciones para un mismo msgid. La ambigüedad está inherente en los datos.
¿Qué es msgctxt y cómo desambigua?
msgctxt es una cadena de contexto adjunta a una entrada de traducción. La respuesta corta: añade una segunda clave junto a msgid, de modo que Gettext trata (contexto, msgid) como un par único. Dos entradas con el mismo msgid pero diferentes msgctxt se convierten en dos cadenas separadas y traducibles de forma independiente.
En el modelo de búsqueda de Gettext, una traducción normalmente se indexa solo por la cadena de origen. Con msgctxt, la clave se convierte en la combinación de contexto más origen. Ese es todo el mecanismo, y por eso funciona tan limpiamente: no estás cambiando el texto mostrado, solo la clave de búsqueda interna.
La Línea msgctxt en un Archivo .po
En un archivo .po, el contexto aparece en su propia línea, directamente encima del msgid:
#: catalog.php:42
msgctxt "noun"
msgid "Book"
msgstr "Buch"
#: reservation-form.php:88
msgctxt "verb"
msgid "Book"
msgstr "Reservieren"
Ahora hay dos entradas. Tienen valores msgid idénticos pero valores msgctxt distintos, por lo que cada una obtiene su propio msgstr. El catálogo muestra Buch; el botón de reserva muestra Reservieren. El tiempo de ejecución elige el correcto porque tu código le indicó qué contexto usar.
Compara esto con la versión de entrada única defectuosa anterior. La diferencia no es la calidad de la traducción, sino si el modelo de datos permite siquiera que exista la respuesta correcta.
Marcando Tu Código: _x() y _ex()
Para emitir msgctxt en tu plantilla .po, llamas a una función de traducción consciente del contexto en lugar de la simple. En WordPress, estas son _x() y su hermana que hace eco _ex(); en Gettext puro, se mapean a pgettext().
Eligiendo entre _x() y _ex()
La función simple __() toma la cadena y el dominio de texto. La variante de contexto inserta el contexto como el segundo argumento:
// Without context - ambiguous
__( 'Book', 'mytextdomain' );
// With context - the second argument is the msgctxt
_x( 'Book', 'noun', 'mytextdomain' ); // returns the translated string
_ex( 'Book', 'verb', 'mytextdomain' ); // echoes it directly
// Real-world disambiguation
_x( 'Post', 'verb: publish content', 'mytextdomain' );
_x( 'Post', 'noun: mail item', 'mytextdomain' );
_x( 'Order', 'sequence or sorting', 'mytextdomain' );
_x( 'Order', 'customer purchase', 'mytextdomain' );
El segundo argumento es la etiqueta de contexto. Nunca se muestra a tus usuarios; existe puramente para desambiguar, tanto para la búsqueda de Gettext como para quienquiera (o lo que sea) que esté realizando la traducción. Escribe los contextos como pistas cortas y descriptivas: 'sustantivo', 'verbo', 'etiqueta de botón', 'menú de administración'. Un contexto vago como '1' es técnicamente válido pero inútil para un traductor.
Cuando regeneras la plantilla, el extractor reconoce estas llamadas y emite la línea msgctxt. Herramientas como Poedit y otros editores PO luego agrupan las entradas visiblemente por contexto, de modo que un traductor humano ve inmediatamente que "Book (sustantivo)" y "Book (verbo)" son dos trabajos diferentes. Si aún estás configurando tu cadena de herramientas de extracción o luchando con cómo interactúan las variables con estas cadenas, nuestra guía sobre traducir archivos PO sin romper las variables de código cubre el flujo de trabajo circundante en profundidad.
Por Qué los Traductores Inexpertos – y Muchas Herramientas de IA – Se Equivocan en Esto
Aquí viene la parte incómoda. Añadir msgctxt a tu código fuente es necesario pero no suficiente. El contexto solo ayuda si quien realiza la traducción realmente lo lee.
El Modo de Fallo por Contexto Descartado
Un script de traducción por lotes ingenuo hace esto: itera sobre las entradas, toma cada msgid, lo envía a una API de traducción y escribe el resultado en msgstr. Nunca mira la línea msgctxt. Así, aunque hayas escrito cuidadosamente _x( 'Book', 'noun' ) y _x( 'Book', 'verb' ), el script envía dos solicitudes idénticas – "traducir Book" – y pega la misma respuesta en ambas. Todo tu esfuerzo de marcado se descarta en el último paso.
Muchas herramientas de traducción de IA de propósito general tienen el mismo punto ciego. Están diseñadas para traducir texto, y msgctxt son metadatos, no texto. Si la herramienta aplana tu archivo .po en una lista de cadenas antes de enviarlo al modelo, el contexto nunca llega al prompt del modelo. El modelo, al carecer de cualquier señal, recurre al sentido más estadísticamente común de la palabra – generalmente el sustantivo para "Book", el sentido de publicar para "Post" – y traduce incorrectamente de forma silenciosa el caso minoritario. No verás un error. Verás un informe de error de un usuario alemán semanas después.
Contexto y Plurales Comparten la Misma Causa Raíz
Aquí es también donde se cruzan el manejo de plurales y el contexto, porque ambos dependen de que la herramienta entienda la estructura de Gettext en lugar de tratar el archivo como texto plano. Si tus cadenas también implican formas basadas en conteo, la misma conciencia estructural es importante; lo desglosamos en comprendiendo los plurales de Gettext.
Cómo una Cadena de Traducción Consciente del Contexto Usa msgctxt
Una cadena de traducción que respeta msgctxt hace lo contrario que el script ingenuo. Analiza el archivo .po como datos estructurados, mantiene el contexto de cada entrada adjunto a su cadena de origen y pasa ese contexto a la IA como parte del prompt, para que el modelo sepa que está traduciendo "Book" específicamente como un verbo, no en abstracto.
El Contexto como una Señal de Primera Clase
Así es exactamente como SimplePoTranslate aborda el problema. Su IA consciente del contexto lee la línea msgctxt como una señal de primera clase: cuando dos entradas comparten un msgid pero difieren en contexto, se traducen como las cadenas distintas que realmente son, y la pista de contexto informa la elección de palabras del modelo. El resultado es que "Book (sustantivo)" se traduce como Buch mientras que "Book (verbo)" se traduce como buchen o reservieren – automáticamente, sin que tengas que corregir manualmente cada término ambiguo.
Igualmente importante, la cadena de traducción conserva la línea msgctxt en la salida. Una herramienta menos potente podría eliminar el contexto durante el proceso de ida y vuelta, colapsando silenciosamente tus dos entradas en una sola y reintroduciendo la ambigüedad en la siguiente fusión. El soporte completo de Gettext significa que el contexto sobrevive a la traducción, la compilación .mo y cualquier reimportación posterior, por lo que tu desambiguación es duradera, no un parche manual de una sola vez. Combinado con el Bloqueo de Sintaxis para marcadores de posición dentro de esas cadenas, obtienes traducciones que son contextualmente correctas y estructuralmente intactas.
Todavía eres el responsable de la decisión de marcado: solo tú sabes que un determinado "Book" es un verbo. Pero una vez que has anotado tu código fuente con _x() y _ex(), una cadena de traducción consciente del contexto convierte esa anotación en traducciones correctas en todos los idiomas de destino sin necesidad de supervisar cada cadena.
Conclusión
El problema de la ambigüedad –una palabra en inglés, muchos significados– no es una peculiaridad que puedas ignorar; es una característica estructural de cómo Gettext almacena las cadenas. La solución es msgctxt: anota las cadenas ambiguas en tu código fuente con _x() y _ex(), dales a cada ocurrencia una etiqueta de contexto clara y permite que Gettext indexe la traducción en el par (contexto, msgid). Esa parte depende de ti y lleva minutos.
La parte más difícil es asegurarse de que tu paso de traducción realmente respete ese contexto en lugar de desecharlo. Los scripts ingenuos y las herramientas de IA solo de texto descartan msgctxt y reintroducen el mismo error que intentabas prevenir. Una cadena de traducción consciente del contexto lee el contexto, traduce cada entrada desambiguada correctamente y lo preserva a través de la compilación y las reimportaciones.
¿Listo para dejar de enviar traducciones erróneas sin contexto? Prueba SimplePoTranslate gratis — no se requiere tarjeta de crédito. El nivel gratuito maneja archivos
.poy.potreales con soporte completo de contexto msgctxt, para que tus cadenas desambiguadas se traduzcan correctamente la primera vez.