Localización de MDN en español

September 11, 2026 · View on GitHub

Guía para colaborar traduciendo y manteniendo el contenido de MDN Web Docs al español.

Antes de empezar, lee la guía oficial de contribución.

Tabla de contenido


¿Por dónde empezar?

Si no sabes por dónde comenzar, revisa los issues con la etiqueta l10n-es. Allí publicamos documentos que necesitan traducción nueva, actualización o revisión. Comenta en el issue que te interese para evitar duplicar esfuerzos.


Tipos de contribución que preferimos

No todas las contribuciones aportan el mismo valor al lector. Estas son nuestras preferencias para que planifiques tu PR:

🥇 Preferido: actualización completa de un documento

Un PR que traduce o actualiza una página entera para que coincida con la fuente en inglés más reciente (incluido el l10n.sourceCommit). Este tipo de cambios cierra issues como los listados en l10n-es y reduce la deuda de traducción.

✅ También bienvenido: correcciones pequeñas

Arreglar acentos, tildes, erratas o una frase mal traducida es una excelente puerta de entrada para quien está conociendo el proyecto. Estos PRs se aceptan y se revisan con el mismo cuidado.

Si es tu primera contribución, siéntete libre de empezar con un cambio pequeño: nos importa más que te integres a la comunidad que el tamaño del PR. Eso sí, procura no abrir varios PRs minúsculos sobre el mismo archivo en días consecutivos; si detectas varios problemas en una misma página, agrúpalos en un único PR.


Abrir un Pull Request

Tienes dos maneras de contribuir. Elige la que te sea más cómoda.

Opción A: Desde GitHub (sin instalar nada)

Ideal para erratas, traducciones cortas o cambios en un solo archivo. Todo el flujo vive en el navegador, no necesitas clonar el repositorio.

  1. Entra al archivo que quieres modificar dentro de files/es/.
  2. Pulsa el ícono de lápiz (Edit this file) en la parte superior derecha. GitHub te ofrecerá crear un fork automáticamente, acepta.
  3. Edita el contenido directamente en el navegador.
  4. Al terminar, en la parte inferior rellena el mensaje de commit (añade el sufijo [es]) y pulsa Propose changes.
  5. GitHub abrirá la pantalla de Compare & pull request. Completa el título/descripción y envía el PR hacia mdn/translated-content:main.

Opción B: Desde tu computadora (recomendada para cambios grandes)

Necesaria si vas a traducir páginas extensas, actualizar varios archivos o ejecutar los linters localmente.

Tutorial en video: https://youtu.be/pFeW0vUYbkg

Requisitos

  • Node.js >= 24 (ver .nvmrc y .tool-versions).
  • npm (la versión exacta se define en el campo packageManager de package.json; npm install la respeta automáticamente con corepack habilitado).
  • Recomendamos un gestor de versiones de Node: mise, fnm o nvm. Cualquiera de ellos leerá .nvmrc o .tool-versions automáticamente.

No necesitas levantar un servidor local para traducir: el bot genera una URL de previsualización en cada PR. npm install sólo hace falta si quieres correr los linters (npm run lint:md, npm run fix:md) antes de enviar el cambio.

Pasos

  1. Haz fork de https://github.com/mdn/translated-content a tu cuenta de GitHub.

  2. Clona tu fork:

    git clone git@github.com:TU_USUARIO/translated-content.git
    cd translated-content
    

    ⏳ El repositorio es grande (varios GB de historia). El primer clone puede tardar varios minutos dependiendo de tu conexión. Ten paciencia, sólo hay que hacerlo una vez.

  3. Crea una rama descriptiva:

    git switch -c fix-issue-123
    
  4. Realiza los cambios necesarios.

  5. Agrega y confirma los archivos:

    git add files/es/ruta/al/archivo.md
    git rm  files/es/archivo-obsoleto.html   # si corresponde
    git commit -m "Corrige error 123 [es]"
    

    El sufijo [es] en el mensaje ayuda a identificar PRs en español.

  6. Publica la rama y abre el Pull Request:

    git push -u origin fix-issue-123
    
  7. Abre https://github.com/TU_USUARIO/translated-content y crea el PR hacia mdn/translated-content:main.

Ejemplo en video: https://youtu.be/pFeW0vUYbkg


Traducir un documento

  1. Ubica la versión en inglés dentro de mdn/content/files/en-us/. Ejemplo: files/en-us/web/javascript/reference/global_objects/array/index.md.

  2. Busca la versión en español en mdn/translated-content/files/es/.

    • Si no existe, créalo en formato Markdown respetando la misma ruta del original.
    • Si el archivo existe en formato HTML, conviértelo a Markdown.
  3. Traduce manteniendo intacto lo siguiente:

    • Identificadores del código (APIs, propiedades, métodos, variables, funciones).
      • Los nombres propios de APIs conservan su forma en inglés: no se traducen ni se reordenan. Escribe Canvas API, WebVR API, WebXR Device API, no «API Canvas» ni «API WebXR Device». El artículo en español va delante del nombre completo: «la Canvas API quedó obsoleta».
    • Macros de Kumascript como {{domxref(...)}}, {{jsxref(...)}}, {{Glossary(...)}}.
    • Bloques de código: sólo traduce comentarios y cadenas dirigidas al usuario final.
    • Enlaces externos (GitHub, web.dev, etc.).
  4. Cambia los enlaces internos de /en-US/ a /es/.

    ¿Por qué /es/ aunque la página no exista en español? Por coherencia de idioma del proyecto, no por un respaldo automático: si files/es/…/index.md no existe, la URL /es/docs/… devuelve 404. MDN no sirve el artículo completo en inglés como sustituto de una página en español inexistente, y tampoco rellena con inglés las secciones que falten dentro de una página ya traducida: el texto en inglés que se ve en una traducción parcial está escrito en el propio archivo de files/es/. Aun así, el enlace debe escribirse en /es/: es la convención del proyecto, y así queda correcto automáticamente en cuanto la página destino se traduzca.

    Por eso la regla general es: usa siempre /es/ en los enlaces internos absolutos de MDN, sin excepción. No conserves /en-US/ "para que funcione": un enlace en /en-US/ saca al lector del contexto de su idioma preferido, incluso si la traducción sí existe.

    Anclas (#fragmento): deben coincidir con un encabezado real de la página destino en español

    Cuando un enlace incluye un fragmento (#), la ancla debe coincidir con el ID de un encabezado que exista en la página en español (asumiendo que la página ya está traducida; si no lo está, aplica la regla anterior del error 404). Un fragmento que no coincide con ningún ID no rompe el enlace (el navegador simplemente lo ignora y carga la página desde el inicio), pero deja al lector en la parte superior en lugar de la sección esperada.

    CasoQué hacer con la ancla
    La página destino está traducidaUsa el ID del encabezado traducido: #compatibilidad_con_navegadores
    La página destino no está traducidaQuita el fragmento y deja solo el enlace a la página; agrégalo cuando se traduzca
    Enlace dentro de la misma páginaUsa el ID del encabezado traducido de este archivo

    Ejemplo del problema frecuente: dado el enlace en inglés /en-US/docs/Web/API/Fetch_API#browser_compatibility, al traducir, cambiar solo el prefijo (/es/docs/Web/API/Fetch_API#browser_compatibility) deja una ancla en inglés que no existe en la página en español, donde ese encabezado se renderiza como #compatibilidad_con_navegadores. En sentido contrario, copiar una ancla ya traducida hacia una página que aún no tiene traducción al español tampoco funciona.

    La solución es verificar antes de escribir la ancla:

    • ¿Existe files/es/…/Fetch_API/index.md con ese encabezado ya traducido? → usa la ancla en español.
    • ¿No existe la página en español? → deja solo /es/docs/Web/API/Fetch_API, sin fragmento.
    • ¿Existe la página pero esa sección puntual aún no está traducida? → usa el ID tal como aparece renderizado actualmente en la página en español (puede seguir en inglés).

    Para los enlaces dentro de la misma página ([ver más](#cómo_funciona)), la ancla debe coincidir con el ID generado por el encabezado traducido. Si tradujiste ## How it works como ## Cómo funciona, el enlace debe ser #cómo_funciona.

    Cómo verificar el ID real de un encabezado: la forma exacta en que un encabezado se convierte en ID (si conserva tildes, mayúsculas, guiones bajos, etc.) depende de la versión actual del motor de build (Rari), así que no conviene deducirlo a mano. Para confirmarlo, levanta el sitio localmente:

    # Desde tu clon de mdn/content, con CONTENT_TRANSLATED_ROOT apuntando a translated-content
    cd /ruta/a/content
    npm start
    

    Abre la página en http://localhost:5042/es/docs/..., inspecciona el encabezado con las herramientas de desarrollo del navegador y copia el id real generado por el build. Ese es el único valor confiable; no lo derives manualmente del texto del encabezado.

  5. Revisa el front-matter YAML (title, slug, l10n.sourceCommit) como se describe en la siguiente sección.


Imágenes y otros archivos

Regla corta: no copies a files/es/ las imágenes que ya existen en mdn/content.

Cuando una página en español referencia una imagen que sólo existe en la carpeta en inglés, el build resuelve automáticamente el src hacia la ruta de en-US. Basta con conservar en el Markdown la misma referencia relativa que usa el original:

![Descripción de la imagen traducida al español](default-vite.png)

Y el HTML publicado en la página en español queda así:

<img
  src="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_getting_started/default-vite.png"
  alt="Descripción de la imagen traducida al español" />

Es decir: traduce el texto del alt, pero no subas el archivo binario.

¿Por qué no duplicarlas?

  • Tamaño del repositorio. Git no puede calcular diferencias (diff) sobre un .png o un .jpg: cada commit que toque el archivo suma su peso completo al historial, para siempre.
  • Desincronización silenciosa. Si la imagen en inglés se actualiza o se renombra, la copia en español queda obsoleta sin que nada falle en CI. Es un problema real: la versión anterior de Primeros pasos en React seguía mostrando una captura de create-react-app mucho después de que el original en inglés cambiara a Vite.
  • No aporta nada. Una copia idéntica byte por byte se renderiza exactamente igual que la referencia al original.

De hecho, en todo files/es/ hay apenas un puñado de imágenes, y casi todas son capturas propias que no existen en inglés.

¿Cuándo sí se agrega una imagen a files/es/?

Sólo cuando el contenido de la imagen es específico del idioma, por ejemplo:

  • Una captura de pantalla de una interfaz en español (el navegador, un formulario, un panel de herramientas de desarrollo).
  • Un diagrama cuyas etiquetas están en inglés en el original y aportan al lector verlas en español.

En ese caso, colócala en la misma carpeta del documento (files/es/<ruta>/mi-imagen.png), usa el mismo nombre de archivo que el original para que sea evidente qué está reemplazando, y comprímela antes de subirla:

# Desde tu clon de mdn/content
npm run filecheck ../translated-content/files/es/<ruta>/mi-imagen.png --save-compression

Cómo verificar cómo quedó resuelta una imagen

Cualquier página de MDN expone su HTML ya renderizado en index.json, lo que permite comprobar el src final sin levantar el sitio:

curl -sL "https://developer.mozilla.org/es/docs/<Slug>/index.json" | grep -oE '<img[^>]{0,140}'

Si el resultado apunta a /en-US/..., el respaldo funcionó correctamente y no hace falta hacer nada más.

Note

Antes de agregar una imagen nueva, revisa el repositorio mdn/shared-assets: funciona como biblioteca de recursos compartidos y quizá ya exista algo que puedas reutilizar. Los detalles generales están en Cómo agregar imágenes y medios.


Mantener el l10n.sourceCommit al día

Cada archivo traducido debe incluir un front-matter YAML como este:

---
title: Título traducido
slug: Ruta/Original/En/Ingles
l10n:
  sourceCommit: <SHA del commit en mdn/content>
---

Qué es l10n.sourceCommit

Es el SHA del commit de mdn/content cuyo contenido en inglés refleja exactamente lo traducido. Sirve para detectar qué cambios en la fuente aún no se han trasladado al español.

Reglas del front-matter

  • Solo debe incluir: title, short-title (únicamente si está presente en el archivo en inglés), slug y l10n.sourceCommit.
  • No incluir page-type, browser-compat, tags, sidebar ni original_slug.
  • El slug debe ser idéntico al del archivo en inglés.

Cómo obtener el SHA correcto

Usa el SHA del último commit que modificó el archivo en inglés:

# Dentro de tu clon actualizado de mdn/content, en la rama main
git log -n 1 --format=%H -- files/en-us/ruta/al/archivo.md

O con la API de GitHub:

gh api "repos/mdn/content/commits?path=files/en-us/ruta/al/archivo.md&per_page=1" --jq '.[0].sha'

Copia el SHA completo (40 caracteres) y pégalo en el campo sourceCommit.

Cuándo actualizarlo

  • Al crear una traducción nueva, apunta al SHA más reciente de la página en inglés.
  • Al sincronizar con cambios posteriores del inglés, actualiza el SHA al del commit que acabas de incorporar.
  • Si no trasladaste todos los cambios, conserva el SHA anterior hasta completar la sincronización.

Convención de traducciones

La comunidad de español sugiere las siguientes convenciones.

Términos técnicos

Término en inglésTraducción al español
Event listenerDetector de eventos
Event handlerManejador de eventos
See alsoVéase también
SpecificationsEspecificaciones
Browser compatibilityCompatibilidad con navegadores
WarningAdvertencia
NoteNota
CalloutObservación
ExamplesEjemplos
SyntaxSintaxis
ParametersParámetros
Return valueValor de retorno
ExceptionsExcepciones
Instance propertiesPropiedades de instancia
Instance methodsMétodos de instancia
Static propertiesPropiedades estáticas
Static methodsMétodos estáticos
EventsEventos
ValueValor
Event typeTipo de evento
DescriptionDescripción
ConstructorConstructor
HTMLHTML (sin traducir)
JavaScriptJavaScript (sin traducir)
FrameworkFramework (sin traducir)

Marcadores en línea

InglésEspañol
**Note:****Nota:**
**Warning:****Advertencia:**
**Callout:****Observación:**

Formato matemático

ExpresiónCómo escribirlo
252^5

Macros de glosario

Cuando en inglés aparece {{Glossary("TLD")}} y el término natural en español no coincide, agrega el segundo argumento traducido:

{{Glossary("TLD", "Dominio de primer nivel")}}

Excepción: si la frase en español ya explica el término justo después del macro (por ejemplo, {{Glossary("TLD")}} (Top-Level Domain) Dominio de primer nivel), deja el macro con un solo argumento para evitar duplicar el texto renderizado.

Elegir el macro de referencia correcto

Cada macro de referencia construye la URL sobre un subárbol fijo de la documentación. Si eliges el equivocado, el enlace apunta a una página que no existe, o que sólo funciona por una redirección, y nada en el PR lo delata: la macro se renderiza igual y el CI pasa en verde.

MacroEnlaza aÚsalo para
{{domxref("X")}}/es/docs/Web/API/XInterfaces, métodos, propiedades y eventos de las APIs web
{{jsxref("X")}}/es/docs/Web/JavaScript/Reference/…/XObjetos globales y sintaxis de JavaScript
{{cssxref("X")}}/es/docs/Web/CSS/Reference/…/XPropiedades, tipos de valor, funciones y pseudoclases CSS
{{HTMLElement("X")}}/es/docs/Web/HTML/Reference/Elements/XElementos HTML
{{httpheader("X")}}/es/docs/Web/HTTP/Reference/Headers/XCabeceras HTTP
{{SVGElement("X")}}/es/docs/Web/SVG/Reference/Element/XElementos SVG
{{SVGAttr("X")}}/es/docs/Web/SVG/Reference/Attribute/XAtributos SVG
{{Glossary("X", "texto")}}/es/docs/Glossary/XTérminos del glosario

Los argumentos no son iguales en todas. Esto se presta a error porque la forma se parece:

  • domxref, jsxref, cssxref, HTMLElement y httpheader aceptan (página, texto a mostrar, ancla).
  • Glossary acepta sólo (término, texto a mostrar), sin ancla. Un tercer argumento no hace nada.
  • SVGElement y SVGAttr aceptan sólo el nombre; no tienen parámetro de texto a mostrar.

El error más frecuente es usar domxref para tipos de JavaScript. Aparecen en las páginas de APIs web, así que es natural tratarlos como parte del DOM, pero sus páginas viven en la referencia de JavaScript. /es/docs/Web/API/DOMString devuelve un 404; Web/API/Boolean, Web/API/Promise y Web/API/USVString responden 200 sólo porque redirigen a la referencia de JavaScript, es decir, el enlace funciona por accidente y con un salto de más.

Los tipos de WebIDL además no se enlazan con su propio nombre, porque no tienen página propia: se enlazan al tipo de JavaScript que representan, y el texto mostrado cambia con ellos.

En la fuente en inglésQué usar
DOMString, USVString, ByteString, CSSOMString{{jsxref("String")}}
ArrayBufferView{{jsxref("TypedArray")}}
Boolean, Promise, Number, JSON, ArrayBuffer, Float32Array, Uint8Array{{jsxref("…")}} con el mismo nombre

Si necesitas conservar el nombre traducido en el texto visible, va como segundo argumento y la página sigue siendo la inglesa: {{jsxref("Promise", "Promesa")}}.

Para un macro que no esté en la tabla, la fuente autorizada es rari, el motor que renderiza MDN hoy: cada macro es un archivo en crates/rari-doc/src/templ/templs/, y ahí están tanto la ruta base como los argumentos que acepta. Por ejemplo, links/svgattr.rs declara svgattr(name: String), que es de donde sale que sólo admita un argumento.

Conviene saber que kumascript/macros/ en Yari ya no es la implementación que se usa al renderizar, aunque los archivos sigan ahí. Por ejemplo, HTMLElement.ejs construye Web/HTML/Element/, mientras que la página publicada enlaza a Web/HTML/Reference/Elements/. Si consultas Yari para resolver una duda sobre macros, puedes acabar con una ruta que no coincide con la real.

Estilo de escritura

Tuteo (tú) en lugar de usted

Usa la forma de (tuteo) cuando te dirijas directamente al lector. MDN español adoptó el tuteo como convención moderna: "abre el archivo", "asegúrate de incluir", "puedes omitir". Evita el ustedeo ("abra el archivo", "asegúrese de incluir").

Esta convención adapta al español la guía de estilo general de MDN, que recomienda una redacción directa (voz activa) y cercana (tono conversacional). La fórmula estandarizada en español combina: voz activa + tuteo (implícito) + modo imperativo.

El imperativo hace innecesario el pronombre "tú". Al conjugar en segunda persona, el sujeto queda implícito:

  • ❌ Redundante: "Tú haz clic aquí."
  • ✅ Imperativo natural: "Haz clic aquí."

Alterna con construcciones impersonales o pasivas para suavizar el tono. Acumular órdenes seguidas puede sonar rígido; intercalar frases descriptivas mantiene la fluidez:

  • ❌ Demasiado imperativo: "Registra tu correo. Verifica tu contraseña."
  • ✅ Balance fluido: "Registra tu correo. Una vez que tu cuenta sea verificada, podrás ingresar."

Bloques de aviso GFM (GitHub Flavored Markdown)

Los bloques de aviso con sintaxis GFM deben conservar la palabra clave en inglés. Son: [!NOTE], [!WARNING], [!CALLOUT]. Rari/Yari solo los renderiza como cajas con estilo si están escritos exactamente así. Si los traduces ([!Nota], [!Advertencia]), se muestran como una cita simple sin formato especial.

<!-- Correcto -->

> [!NOTE]
> Este comportamiento cambió en Firefox 130.

<!-- Incorrecto — se renderiza como blockquote sin estilos -->

> [!Nota]
> Este comportamiento cambió en Firefox 130.

El texto dentro del bloque sí debe ir en español.

Nombres de macros (mayúsculas importan)

Rari/Yari distingue mayúsculas en los nombres de macro. Usa exactamente la capitalización del archivo en inglés:

  • {{Deprecated_Header}}, no {{deprecated_header}}
  • {{SeeCompatTable}}, no {{seecompattable}}
  • {{Non-standard_Header}}, no {{non-standard_header}}

Notas pendientes (TODO)

A veces, al traducir, queda una duda que no se puede resolver en el momento: un ancla cuyo destino todavía no existe en español, o un término sin equivalente acordado. Para esos casos usamos un marcador en el propio archivo, con este formato exacto:

<!-- TODO(l10n-es): enlace sin ancla; #compatibilidad_con_navegadores depende de que se sincronice Web/API/Fetch_API -->

El prefijo TODO(l10n-es) no es decorativo. Buscar sólo TODO en files/es/ no es fiable: también encuentra la palabra española TODOS (Elimina el contorno de TODOS los enlaces) y títulos de enlaces en inglés (A simple TODO list using HTML5 IndexedDB). Con el prefijo, un solo comando da el inventario completo del locale:

grep -rn 'TODO(l10n-es)' files/es/

Antes de dejar un marcador, intenta resolver la duda

La mayoría se responden en el momento, y un marcador resuelto vale más que un marcador registrado. Para el caso más común, un ancla, hay cuatro escenarios y sólo uno termina en TODO:

  1. El fragmento apunta a un identificador técnico. No se traduce, así que no hay nada que esperar: corrige el enlace con el ancla en inglés y sigue. Los encabezados en prosa sí cambian (#deprecated#obsoleto), pero un identificador no: #display-p3 convive con srgb, oklab y rec2020, son valores de la función CSS color() y sobreviven igual a la traducción.
  2. La página destino ya está traducida. Usa el id que renderiza hoy esa página, que puede seguir en inglés si esa sección concreta aún no se tradujo. No lo deduzcas de memoria: compruébalo contra la página real (ver la sección de anclas más arriba).
  3. Un PR abierto ya crea ese id. Pasa a menudo cuando alguien traduce dos páginas relacionadas: no hace falta marcador ni issue, sólo apuntar al ancla que ese PR va a crear y decir en la conversación del PR cuál de los dos se fusiona primero.
  4. La página destino no existe en español, o existe pero está desactualizada y no tiene esa sección. Este sí es el caso del marcador. Ver abajo.

Si la duda depende de otra página

Deja el enlace sin el fragmento (un ancla que no coincide con nada deja al lector arriba de la página, igual que si no hubiera ancla), agrega el marcador, y abre el issue sobre la página destino, no sobre la que lleva el marcador: un issue para traducir o sincronizar Web/API/Fetch_API, listando en su cuerpo los enlaces que están esperando.

El sentido importa. Nadie que vaya a traducir una página busca antes qué otras páginas le enlazan, así que un issue abierto sobre el archivo que lleva el marcador se quedaría dormido exactamente igual que el marcador. Puesto en la página destino, agrupa varios marcadores en un solo issue y le pone la lista de arreglos delante a quien puede resolverlos.

Dos límites

  • Los marcadores se publican. Los comentarios HTML llegan al HTML renderizado. No se ven al leer, pero quedan en el código fuente de la página publicada. Por eso el marcador debe ser breve y describir la duda concreta, no ser un apunte personal.
  • Un TODO no es para contenido sin traducir. Si a una sección le falta el texto, eso no es una duda pendiente sino una traducción incompleta, y el camino es una sub-tarea de sincronización de esa página. Marcadores como <!-- TODO: add content --> o !!TODO!! dejados en medio de la prosa acaban publicándose y se leen como un error en la página.

Arreglar "flaws" (defectos)

Al ejecutar npm start en tu clon de mdn/content puedes previsualizar localmente los cambios. La misma previsualización está disponible en la URL que genera el bot al abrir un PR. En ambas vistas, la parte superior del documento muestra los flaws detectados automáticamente (enlaces rotos, macros mal usadas, etc.). Muchos se pueden corregir con un clic o aplicando una sugerencia.


Charla con nosotros


Enlaces relevantes

Despliega para ver recursos adicionales

Más información en la discusión general de la comunidad de español.