DEV Community

Cover image for How to translate MDN web docs to spanish.
Ifeanyi Chima
Ifeanyi Chima

Posted on

How to translate MDN web docs to spanish.

Good day, for the past 3 weeks I have been busy translating the popular documentation platform known as MDN web docs into the Spanish version, to help Spanish-speaking readers as it had been outdated for years with respect to the English version.

This has been part of my open-source journey. In this article, I want to talk about the process, to enable future contributors to seamlessly contribute one day.

Here are the rules to follow when trying to do the Spanish-translation work. Everything that I am going to write here is already mentioned inside of the rules.

Here is one rule to just bear in mind

is this text something a human reads (translate it) or something the code/interpreter looks up by exact name (leave it untouched)

File Paths

This is the most important one; File paths (bolded or inline) are never translated. It stays the same. Below, we will discuss the only thing that changes, which is en-US to es

English: docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Spanish: docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Front-matter

  • Final front-matter should only contain: title, slug, l10n.sourceCommit (plus short-title when the English file has one).
  • Remove page-type, sidebar, original_slug.
  • title (and short-title): translate to Spanish.
  • slug: never translate — left exactly as in English.
  • l10n.sourceCommit: set to the exact SHA given for that English source commit.

Links

External links: These are links point to external web pages and they should be left as is. For example: https://validator.w3.org/ or https://developer.flutterwave.com/docs/testing

Internal links: All the internal links that point to pages with in the MDN web docs website have to be changed from /en-US/ to /es/.

For example:

Original (English source):

/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
Enter fullscreen mode Exit fullscreen mode

This has to be changed to point to a spanish file now.

/es/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
Enter fullscreen mode Exit fullscreen mode

Link Text: (ONLY the visible label) gets translated when it's an internal MDN link.

For example

Original (English source):

[Object basics](/en-US/docs/Learn_web_development/Core/Scripting/Object_basics)
Enter fullscreen mode Exit fullscreen mode

We have to translate The link text "Object basics" to "Fundamentos de objetos"

Translated (Spanish):

[Fundamentos de objetos](/es/docs/Learn_web_development/Core/Scripting/Object_basics)
Enter fullscreen mode Exit fullscreen mode

Anchors: when you have an anchor like this, #heading_about_a_paragraph. Two things are involved:

  1. You need to check if that section that the anchor is referring to exists.
  2. If it exists, then you should translate it to Spanish #encabezado_sobre_un_párrafo

Bold / italics

  • Keep the bold/italic markers in the same place, only translate the text content.
  • Text content that were bold or italics in English stay bold or italics in Spanish.

Original (English source):

_this is supposed to be italic_ and **this is supposed to be bold**
Enter fullscreen mode Exit fullscreen mode

Translated (Spanish):

_esto se supone que debe estar en cursiva_ and **esto se supone que debe estar en negrita**
Enter fullscreen mode Exit fullscreen mode

Image(s)

  • Never copy images into the files/es/ folder because the build pulls them from the English folder automatically. Just leave the image file path as is

  • Only the alt text (the [...] part) gets translated; the filename or file path stays exactly as-is.

For example:

Original (English source)

![Prototype chain for myObject](myobject-prototype-chain.svg)
Enter fullscreen mode Exit fullscreen mode

Translated (Spanish)

![Cadena de prototipos para myObject](myobject-prototype-chain.svg)
Enter fullscreen mode Exit fullscreen mode

Callouts

  • In GitHub markdown, callouts such as [!NOTE] and [!WARNING] stay untranslated because translating them breaks the styled box.

  • ONLY the user-facing text content contained within the box gets translated.

For example,

Original (English source)

>[!NOTE]
> See also the [glossary entry on API](/en-US/docs/Glossary/API) for more information.
Enter fullscreen mode Exit fullscreen mode

Translated (Spanish)

>[!NOTE]
> Consulta también la [entrada del glosario sobre API](/es/docs/Glossary/API) para más información.
Enter fullscreen mode Exit fullscreen mode

Notice: [!NOTE] remains untouched

Code

Plain Code blocks: These are code blocks that contain only literal data: no comments, no prose mixed in so there's nothing to translate at all.

https://example.com/articles/
https://example.com/articles/23
https://example.com/articles/?page=2
Enter fullscreen mode Exit fullscreen mode

This stays exactly the same in the Spanish file — same URLs, same formatting, no changes whatsoever. There's no comment explaining anything and no prose sentence inside it.

name
age
city
greet
Enter fullscreen mode Exit fullscreen mode

These are actual JavaScript property names being listed for the reader to look at, not descriptive text, so translating "city" to "ciudad" or "age" to "edad" would misrepresent what the code actually contains.

HTML table structure:
Table tags (<table>, <tr>, <th>, etc.) stay exactly the same, only the visible text inside is translated.

For example:

Original (English source):

<table class="properties">
  <tbody>
    <tr>
      <th scope="row">Prerequisites</th>
      <td>
        A basic understanding of <a href="/en-US/docs/Learn_web_development/Core/Scripting">JavaScript basics</a>.
      </td>
    </tr>
    <tr>
      <th scope="row">Objective</th>
      <td>To understand JavaScript's prototype-based inheritance model.</td>
    </tr>
  </tbody>
</table>
Enter fullscreen mode Exit fullscreen mode

Translated (Spanish):

<table class="properties">
  <tbody>
    <tr>
      <th scope="row">Prerrequisitos</th>
      <td>
        Un entendimiento básico de <a href="/es/docs/Learn_web_development/Core/Scripting">los fundamentos de JavaScript</a>.
      </td>
    </tr>
    <tr>
      <th scope="row">Objetivo</th>
      <td>Comprender el modelo de herencia basado en prototipos de JavaScript.</td>
    </tr>
  </tbody>
</table>
Enter fullscreen mode Exit fullscreen mode

Kumascript macros {{...}}

  1. Macro names and their arguments (page paths) are never translated. The macro names such as (NextMenu, PreviousMenuNext) stay in English because they're internal MDN template functions, not prose.

  2. {{glossary("term")}}: if the English term doesn't naturally read well in Spanish, add a second argument with the translated display text — {{glossary("term", "término")}}. If the term is used as-is in Spanish (e.g. HTTP, JavaScript, Python), leave it with no second argument.

  3. Navigation macros ({{NextMenu(...)}}, {{PreviousMenuNext(...)}}) always left fully untouched whether in English or Spanish.

{{NextMenu("Learn_web_development/Core/Scripting/Object_prototypes", "Learn_web_development/Core/Scripting")}}

{{PreviousMenuNext("Learn_web_development/Core/Scripting/Object_prototypes", "Learn_web_development/Core/Scripting/Object_building_practice", "Learn_web_development/Core/Scripting")}}
Enter fullscreen mode Exit fullscreen mode

Headings

  • Translate headings to match the reference heading list given in the issue, using consistent verb style (gerund/imperative) across the doc. When you finish translating, review your work and make sure you have same headings, same order, same structure as the English source and Nothing is left untranslated

English (Original Source)

## Summary
## Basics: anatomy of a URL
## Scheme
## Authority
## Path to resource
## Parameters
## Anchor
## How to use URLs
## Absolute URLs vs. relative URLs
## URL usernames and passwords
## Semantic URLs
## See also
Enter fullscreen mode Exit fullscreen mode

Translated (Spanish)

## Resumen
## Conceptos básicos: anatomía de una URL
## Esquema
## Autoridad
## Ruta al recurso
## Parámetros
## Ancla
## Cómo utilizar las URL
## URL absolutas frente a URL relativas
## Nombres de usuario y contraseñas en las URL
## URL semánticas
## Véase también
Enter fullscreen mode Exit fullscreen mode
  • Watch for accented characters affecting auto-generated anchor targets (e.g. "Validación" becomes anchor validación_html, not validacion_html) because a missing accent in a link breaks the anchor.

Link: /es/docs/Learn_web_development/Core/Forms/Form_validation#validación_html

For example;

English (Original source)

## Validation HTML

Here's a small but easy-to-miss detail about headings and links. When MDN builds a page, it auto-generates an anchor ID for every heading by lowercasing the text and replacing spaces with underscores. The catch is that it keeps accented characters exactly as they are.
Enter fullscreen mode Exit fullscreen mode

Translated Spanish

## Validación HTML

Aquí hay un detalle pequeño pero fácil de pasar por alto sobre los encabezados y los enlaces. Cuando MDN construye una página, genera automáticamente un ancla para cada encabezado convirtiendo el texto a minúsculas y reemplazando los espacios con guiones bajos. La particularidad es que mantiene los caracteres acentuados exactamente como están.
Enter fullscreen mode Exit fullscreen mode

Comments

Comments inside of Code blocks

This has two (2) cases:

  • A comment that is explaining something to the user (reader) should be translated.
  • A comment that does not add any additional useful information should be discarded.

Useful comment(s)

A comment explaining something (translate it):
This comment is real prose explaining why the line exists or what it does. A Spanish-speaking reader benefits from having this translated

English (Original Source)

# Number of visits to this view, as counted in the session
num_visits = request.session.get('num_visits', 0)
Enter fullscreen mode Exit fullscreen mode

Translated (Spanish)

# Número de visitas a esta vista, contado en la sesión
num_visits = request.session.get('num_visits', 0)
Enter fullscreen mode Exit fullscreen mode

Throwaway comment(s)

Example 1

INSTALLED_APPS = [
    # ...
    'django.contrib.sessions',
]
Enter fullscreen mode Exit fullscreen mode

Here, # ... isn't explaining anything — it's just a visual placeholder telling the reader "there's more code here we're not showing." There's no real content to translate; translating ... doesn't mean anything different in Spanish. Best left as-is.

Example 2

const wheels = 'alloy'; // or comment
Enter fullscreen mode Exit fullscreen mode

This kind of comment is minor, vague, and doesn't add much context either way, so it's genuinely a coin-flip: leave it in English since it's a throwaway aside, or translate it for full consistency with the rest of the document.

Keywords, Variables, Functions:

DO NOT TRANSLATE ANY OF THESE

Variable names — e.g. numOfVisits, myCar, count

Function/method names — e.g. getPrototypeOf(), index()

Class names — e.g. Person, Author

Property/dictionary keys — e.g. city, wheels, my_car['wheels']

Exception names — e.g. KeyError

Boolean values (true, false): remain untranslated in both English and Spanish

English (Original Source)

// Uses 'toString()' by default, returns true
Enter fullscreen mode Exit fullscreen mode

Translated (Spanish)

// Usa 'toString()' por defecto, devuelve true
Enter fullscreen mode Exit fullscreen mode

Methods

Method names mentioned inside comments stay untouched.

English (Original Source)

// Calls 'getPrototypeOf()' to find the parent
Enter fullscreen mode Exit fullscreen mode

Translated (Spanish)

// Llama a 'getPrototypeOf()' para encontrar al padre
Enter fullscreen mode Exit fullscreen mode

Console.log()

There are two (2) incidents here:

  1. For literal strings printed to the user, you should translate it. An example is

English (Original Source):

console.log("Greetings from Madrid");
Enter fullscreen mode Exit fullscreen mode

Translated Spanish:

console.log("Saludos desde Madrid");
Enter fullscreen mode Exit fullscreen mode
  1. short/generic literal, here it's a judgment call, and the practical approach is to flag it for the reviewer

Example:

function greet() {
  console.log("hello!");
}
Enter fullscreen mode Exit fullscreen mode

Pluralization

If translating a word breaks a language feature (e.g. pluralization), adapt the word so the mechanism still works (e.g. "time" becomes "vece").

"time" plural form is "times" in English, but the literal spanish translation would be wrong (broken) spanish.

if we were to follow a literal translation of "time" into spanish "vez" literal plural translation "vezs" (which is wrong spanish)

"vez" correct plural form in spanish is "vece".

num_visits = 3, Here, pluralize looks at num_visits and, if it's more than 1, appends an "s" to whatever comes right before the template tag — turning "time" into "times".

English (Original Source)

You have visited this page {{ num_visits }} time{{ num_visits|pluralize }}.
Enter fullscreen mode Exit fullscreen mode

Adapted translation (mechanism still works):

Has visitado esta página {{ num_visits }} vece{{ num_visits|pluralize }}.
Enter fullscreen mode Exit fullscreen mode

More Information

  • Run Prettier on the finished file, when you are done translating.
npx prettier --write files/es/learn_web_development/core/scripting/object_prototypes/index.md
Enter fullscreen mode Exit fullscreen mode
  • Check for invisible/zero-width characters (e.g. using a script scanning for U+200B, U+200C, U+200D, U+FEFF)
import unicodedata
import sys

INVISIBLE_CHARS = (0x200B, 0x200C, 0x200D, 0xFEFF)

def check_file(path):
    with open(path, encoding="utf-8") as f:
        for line_number, line in enumerate(f, 1):
            found = [
                unicodedata.name(char, "?")
                for char in line
                if ord(char) in INVISIBLE_CHARS
            ]
            if found:
                print(line_number, found, repr(line[:40]))

if __name__ == "__main__":
    check_file(sys.argv[1])
Enter fullscreen mode Exit fullscreen mode

Thank you and please follow me.

Top comments (0)