Traducir Excel con Python y la API de ChatGPT (2026)
Guía paso a paso para traducir archivos Excel con openpyxl y la API de OpenAI: código completo y funcional, sin romper fórmulas ni formato.
Última actualización: junio de 2026 — probado con el SDK de Python de OpenAI v1.x y la API de Chat Completions.
Este tutorial usa la API de Chat Completions porque es sencilla y está ampliamente soportada. Para aplicaciones nuevas también puedes considerar la API de Responses de OpenAI y las salidas estructuradas.
Dos formas de traducir un archivo Excel
Antes de escribir una sola línea de código, conviene ser honesto sobre qué enfoque encaja realmente contigo:
- Escribir un script en Python (esta guía). Es lo mejor si quieres automatizar la traducción de muchos archivos, ejecutarla de forma programada o integrarla en una canalización mayor. Necesitarás una clave de API de OpenAI y algo de Python básico.
- Usar una herramienta lista para usar. Si solo necesitas traducir una hoja de cálculo ahora mismo —con gráficos, fórmulas y estilos preservados automáticamente—, subirla al traductor de Excel de Doc2Lang es más rápido y no requiere nada de código.
Esta guía se centra en el enfoque con Python y te ofrece código completo y funcional. También señalaremos exactamente dónde se complica la opción de hacerlo por tu cuenta, para que decidas con conocimiento de causa. Hay una comparación completa cerca del final.
Requisitos previos
Antes de empezar, necesitarás algunas cosas:
- Conocimientos básicos de Python. Este artículo incluye código. Saber algo de Python ayuda, pero explicaremos cada paso.
- Python instalado. Si aún no lo tienes, descárgalo desde el sitio web oficial.
- pip. Es lo que instala las bibliotecas de Python. Si tienes Python 3, casi seguro que ya tienes pip.
- Una clave de API de OpenAI. Créala en el panel de tu cuenta de OpenAI. La misma clave funciona con todos los modelos actuales (
gpt-4o,gpt-4o-mini, etc.). - Tu archivo de Excel. Ten listo el archivo
.xlsxque quieres traducir.
Configura tu clave de API como variable de entorno para que nunca quede dentro de tu código:
macOS / Linux:
export OPENAI_API_KEY="your_api_key_here"Windows PowerShell:
$env:OPENAI_API_KEY="your_api_key_here"Cómo está estructurado un archivo .xlsx (información opcional)
Cuando guardas una hoja de cálculo como .xlsx, en realidad estás empaquetando varios archivos dentro de un mismo contenedor. El formato se llama OpenXML. Si tienes curiosidad, puedes renombrar el archivo a .zip, descomprimirlo y mirar dentro:
xl/worksheets/— un archivo XML por hoja (sheet1.xml,sheet2.xml, …). Aquí es donde residen realmente tus filas, columnas y datos de celda.xl/styles.xml— todos los estilos del libro: qué celdas están en negrita, cuáles son azules, qué números tienen formato de moneda, etc.xl/sharedStrings.xml— para ahorrar espacio, Excel almacena cada cadena única una sola vez aquí y la referencia allí donde se utiliza. Si "Total" aparece 1000 veces, se guarda una sola vez.xl/workbook.xml— el índice: qué hojas existen, su orden y propiedades como la protección de hojas.
Bibliotecas como openpyxl te ocultan casi todo esto, pero entender la estructura ayuda cuando necesitas operaciones avanzadas o tienes que resolver algún problema.
Un archivo report.xlsx descomprimido: las hojas, las cadenas compartidas, los estilos y la estructura del libro son solo archivos XML dentro de un archivo zip.
Leer y escribir archivos Excel con openpyxl
openpyxl es una biblioteca de Python creada específicamente para leer y escribir archivos de Excel (.xlsx, .xlsm, .xltx, .xltm). Te permite trabajar directamente con hojas y celdas.
Conviene dejar algo claro de entrada: openpyxl es excelente para el trabajo a nivel de celda, pero no es un motor de diseño de Excel de fidelidad total. Las formas, algunas imágenes, los gráficos, las macros y el texto enriquecido dentro de una misma celda pueden no conservarse al abrir y volver a guardar un archivo. Para archivos .xlsm con macros, cárgalos con load_workbook(..., keep_vba=True) y guárdalos de nuevo como .xlsm; de lo contrario, las macros podrían perderse. Volveremos sobre estos límites al final.
1. Instalar openpyxl
pip install openpyxl2. Conceptos fundamentales
Algunos conceptos se corresponden directamente con openpyxl:
Workbook (libro) — un archivo de Excel en su conjunto.
from openpyxl import load_workbook
workbook = load_workbook(filename="sample.xlsx")Sheet (hoja) — un libro contiene una o varias hojas.
sheet = workbook.active # la hoja activa
another_sheet = workbook["Sheet2"] # una hoja por nombreCell (celda) — donde se cruzan una fila y una columna. Aquí es donde residen los datos.
cell_value = sheet["A1"].value # leer
sheet["B1"] = "Hello, Excel!" # escribirFilas y columnas — itera sobre ellas fácilmente:
for row in sheet.iter_rows(values_only=True):
for value in row:
print(value)Traducir texto con la API de OpenAI
Después de cargar tus datos con openpyxl, el siguiente paso es traducirlos con la API de OpenAI.
1. Instalar la biblioteca de Python de OpenAI
pip install openai2. Una función de traducción moderna (2026)
import os
from openai import OpenAI
# Lee la clave desde una variable de entorno: nunca la escribas directamente en tu script.
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
def translate_text(text, target_lang="Spanish"):
response = client.chat.completions.create(
model="gpt-4o-mini", # rápido y económico; usa "gpt-4o" para la mejor calidad
messages=[
{
"role": "system",
"content": (
f"You are a professional translator. Translate the user's text "
f"into {target_lang}. Return only the translation, with no extra commentary."
),
},
{"role": "user", "content": text},
],
)
return response.choices[0].message.content.strip()Atención: Muchos tutoriales antiguos usan
openai.ChatCompletion.create()conmodel="gpt-4". Esa sintaxis es del SDK anterior a la versión 1.0 y ya no funciona conopenai>=1.0. El código de arriba usa la interfaz actualclient.chat.completions.create(). Eligegpt-4o-minipara un coste y una velocidad bajos, ogpt-4ocuando necesites la máxima calidad de traducción.
3. Un primer intento ingenuo
El enfoque más habitual de los tutoriales es recorrer cada celda y sobrescribirla:
from openpyxl import load_workbook
workbook = load_workbook(filename="your_file.xlsx")
for sheet in workbook.worksheets:
for row in sheet.iter_rows():
for cell in row:
if isinstance(cell.value, str):
cell.value = translate_text(cell.value)
workbook.save("your_translated_file.xlsx")Esto funciona en una demo, pero tiene problemas reales con hojas de cálculo de verdad: hace una llamada a la API por celda (lento y caro), traduce las fórmulas y las rompe, y no tiene ninguna protección frente a los límites de velocidad. Vamos a corregir todo eso.
Cómo dejarlo listo para producción
1. No traduzcas las fórmulas
Si una celda contiene una fórmula como =SUM(A1:A10), traducirla corromperá la hoja de cálculo. Omite las fórmulas, las celdas vacías y los valores que no sean texto:
def is_translatable(cell):
# Omitir celdas vacías, números y celdas con fórmulas.
value = cell.value
return (
isinstance(value, str)
and value.strip() != ""
and cell.data_type != "f" # "f" = fórmula
)openpyxl solo reescribe cell.value, así que los formatos de número, las fuentes, los rellenos y casi todo el estilo permanecen intactos mientras dejes en paz las celdas que no sean de texto.
2. Almacena en caché las cadenas repetidas para reducir costes
Las hojas de cálculo repiten las mismas etiquetas constantemente ("Total", "Fecha", el nombre de un departamento). Traduce cada cadena única una sola vez:
cache = {}
def translate_cached(text, target_lang="Spanish"):
if text not in cache:
cache[text] = translate_text(text, target_lang)
return cache[text]En un informe típico, esto por sí solo puede reducir tus llamadas a la API —y tu factura— en una proporción enorme.
3. Agrupa las celdas en una sola petición
Una llamada a la API por celda es la mayor fuente de lentitud. En su lugar, envía muchas cadenas en una sola petición y pide al modelo que devuelva JSON para poder mapear los resultados de forma fiable:
import json
def translate_batch(texts, target_lang="Spanish"):
numbered = {str(i): t for i, t in enumerate(texts)}
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{
"role": "system",
"content": (
f"You are a professional translator. Translate each value in the "
f"JSON object into {target_lang}. Keep the same keys. "
f"Return only a JSON object."
),
},
{"role": "user", "content": json.dumps(numbered, ensure_ascii=False)},
],
response_format={"type": "json_object"},
)
result = json.loads(response.choices[0].message.content)
return [result[str(i)] for i in range(len(texts))]4. Reintenta ante los límites de velocidad (retroceso exponencial)
Cuando alcances un límite de velocidad, no falles: espera y vuelve a intentarlo, duplicando el retardo en cada ocasión:
import time
def with_retry(func, *args, retries=5, **kwargs):
for attempt in range(retries):
try:
return func(*args, **kwargs)
except Exception as e:
wait = 2 ** attempt
print(f"Error: {e}. Retrying in {wait}s...")
time.sleep(wait)
raise RuntimeError("Translation failed after several retries.")5. Maneja con seguridad los archivos no fiables
Si procesas archivos de Excel subidos por otras personas, protégete frente a XML malicioso. Instala defusedxml, que openpyxl usará automáticamente cuando esté presente, y valida el tamaño y el tipo del archivo antes de cargarlo:
pip install defusedxmlEsto es opcional para tus propios archivos, pero muy recomendable para cualquier archivo que no hayas creado tú mismo.
Script completo y funcional
Aquí tienes todo combinado en un único script que puedes copiar y ejecutar. Recopila las cadenas únicas, las traduce por lotes con reintentos, almacena los resultados en caché, omite las fórmulas y guarda en un archivo nuevo para que tu original quede a salvo.
import json
import os
import time
from openai import OpenAI
from openpyxl import load_workbook
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
TARGET_LANG = "Spanish"
MODEL = "gpt-4o-mini" # usa "gpt-4o" para mayor calidad
BATCH_SIZE = 40
def is_translatable(cell):
value = cell.value
return (
isinstance(value, str)
and value.strip() != ""
and cell.data_type != "f" # "f" = fórmula
)
def translate_batch(texts, target_lang=TARGET_LANG, retries=5):
numbered = {str(i): t for i, t in enumerate(texts)}
system = (
f"You are a professional translator. Translate each value in the JSON object "
f"into {target_lang}. Keep the same keys. Return only a JSON object."
)
for attempt in range(retries):
try:
response = client.chat.completions.create(
model=MODEL,
messages=[
{"role": "system", "content": system},
{"role": "user", "content": json.dumps(numbered, ensure_ascii=False)},
],
response_format={"type": "json_object"},
)
result = json.loads(response.choices[0].message.content)
return [result[str(i)] for i in range(len(texts))]
except Exception as e:
wait = 2 ** attempt
print(f"Error: {e}. Retrying in {wait}s...")
time.sleep(wait)
raise RuntimeError("Translation failed after several retries.")
# 1. Cargar el libro
workbook = load_workbook(filename="your_file.xlsx")
# 2. Recopilar todas las cadenas únicas y traducibles
unique_texts = set()
for sheet in workbook.worksheets:
for row in sheet.iter_rows():
for cell in row:
if is_translatable(cell):
unique_texts.add(cell.value)
unique_texts = list(unique_texts)
# 3. Traducir por lotes y construir una caché {original: traducción}
cache = {}
for start in range(0, len(unique_texts), BATCH_SIZE):
chunk = unique_texts[start:start + BATCH_SIZE]
cache.update(dict(zip(chunk, translate_batch(chunk))))
# 4. Escribir de vuelta las traducciones, sin tocar fórmulas ni estilos
for sheet in workbook.worksheets:
for row in sheet.iter_rows():
for cell in row:
if is_translatable(cell):
cell.value = cache[cell.value]
# 5. Guardar en un archivo nuevo
workbook.save("your_translated_file.xlsx")
print("Done!")Eso es un traductor completo y práctico en bastante menos de 100 líneas: rápido, seguro con las fórmulas y mucho más barato que la versión celda a celda.
Opcional: refuerzo para cargas de trabajo reales
El script de arriba ya es práctico. Para trabajos más grandes o recurrentes, hay tres salvaguardas más que ayudan.
No te tragues todas las excepciones. Reintentar ante cualquier excepción significa que una clave de API no válida o un nombre de modelo incorrecto también se reintentarán cinco veces. Reintenta solo ante los límites de velocidad y falla rápido en todo lo demás:
from openai import RateLimitError
def translate_batch(texts, target_lang=TARGET_LANG, retries=5):
numbered = {str(i): t for i, t in enumerate(texts)}
system = (
f"You are a professional translator. Translate each value in the JSON object "
f"into {target_lang}. Keep the same keys. Return only a JSON object."
)
for attempt in range(retries):
try:
response = client.chat.completions.create(
model=MODEL,
messages=[
{"role": "system", "content": system},
{"role": "user", "content": json.dumps(numbered, ensure_ascii=False)},
],
response_format={"type": "json_object"},
)
result = json.loads(response.choices[0].message.content)
missing = [str(i) for i in range(len(texts)) if str(i) not in result]
if missing:
raise ValueError(f"Missing translations for keys: {missing}")
return [result[str(i)] for i in range(len(texts))]
except RateLimitError:
wait = 2 ** attempt
print(f"Rate limited. Retrying in {wait}s...")
time.sleep(wait)
raise RuntimeError("Translation failed after several retries.")Esta versión también valida que el modelo haya devuelto todas las claves que se le pasaron, de modo que una respuesta truncada o malformada falla de forma evidente en lugar de descartar celdas en silencio.
Mantén el orden al eliminar duplicados. Usa una deduplicación ordenada en lugar de un conjunto, para que los registros y los mensajes de error sigan siendo predecibles:
# antes: unique_texts = list(unique_texts) con un set()
unique_texts = list(dict.fromkeys(collected_texts))Script en Python vs. Doc2Lang: ¿cuál deberías usar?
Escribir tu propio script es potente, pero tiene límites reales. Aquí va una comparación honesta:
| Python (manual) | Doc2Lang | |
|---|---|---|
| Formato y gráficos | Lo gestionas tú; se rompe con facilidad | Se preserva automáticamente |
| Fórmulas | Escribes tus propias condiciones para omitirlas | Se omiten automáticamente |
| Qué necesitas | Clave de API de OpenAI + programar | Solo subir el archivo |
| Ideal para | Desarrolladores que automatizan trabajos masivos o recurrentes | Cualquiera que necesite traducir un archivo ya |
Un informe financiero en inglés traducido al español por Doc2Lang: los gráficos de columnas y de líneas, las fórmulas, los formatos numéricos y los anchos de columna se conservan intactos (los nombres de las pestañas permanecen en el idioma original, sin traducir).
→ Prueba el traductor de Excel — sin clave de API, sin código.
La regla general: si quieres automatizar trabajos de traducción recurrentes, crea el script de arriba. Si solo necesitas traducir una hoja de cálculo ahora mismo sin escribir código, usa el traductor de Excel: súbelo, tradúcelo, descárgalo, con el formato intacto.
Guías relacionadas
- Traducir un archivo de Excel al inglés: la vía sin código y qué se conserva
- Automatizar la traducción de documentos de Word con Python y ChatGPT
- Traducción sencilla de PDF con Python y OpenAI
Preguntas frecuentes
¿Qué hago si recibo un error de límite de velocidad?
OpenAI aplica límites de velocidad según el nivel de tu cuenta. Usa el reintento con retroceso exponencial que se muestra arriba, reduce el tamaño del lote o sube el nivel de tu cuenta si procesas grandes volúmenes.
¿Cómo traduzco a varios idiomas a la vez?
Recorre una lista de idiomas de destino y ejecuta todo el proceso una vez por idioma, guardando cada resultado en su propio archivo (por ejemplo, report_es.xlsx, report_de.xlsx).
¿Usar la API de OpenAI cuesta dinero?
Sí. Pagas por los tokens utilizados. Almacenar en caché las cadenas repetidas y agrupar las peticiones (ambas cosas mostradas arriba) mantienen los costes bajos. gpt-4o-mini es muchísimo más barato que los modelos más grandes para la traducción cotidiana.
¿Esto preservará mi formato y mis fórmulas?
El script solo cambia los valores de las celdas de texto, así que los estilos básicos de celda —fuentes, rellenos, bordes, alineación y formatos de número— suelen conservarse, y las fórmulas se omiten. Sin embargo, openpyxl no es un motor de diseño de Excel de fidelidad total. Las macros, las formas, los gráficos, las imágenes, el texto enriquecido dentro de una misma celda y las funciones complejas del libro pueden no conservarse a la perfección. Para los archivos .xlsm, cárgalos con keep_vba=True y guárdalos de nuevo como .xlsm. Si el diseño perfecto al píxel te importa más que la automatización, una herramienta especializada gestiona estos casos automáticamente.
Conclusión
Con openpyxl y la API de OpenAI puedes crear un traductor de Excel rápido y seguro con las fórmulas en bastante menos de 100 líneas de código: una opción estupenda cuando necesitas automatizar la traducción a gran escala.
Si tu prioridad es preservar el diseño en lugar de automatizar, puede que una herramienta de traducción de Excel especializada encaje mejor: gestiona los gráficos, las formas y los estilos que openpyxl no puede.