← Volver al blog

StrawTraduction y el cómo funciona

devlogstrawberry-panicherramientas

Traducir un juego de PS2 no es copiar y pegar texto en un bloc de notas. Strawberry Panic! guarda sus textos en archivos binarios comprimidos con formatos propios de Sony, y su fuente japonesa no tiene tildes ni eñes. Para resolver todo esto creé StrawTraduction, un sistema completo con dos partes: una webapp para traducir y el módulo de build para reconstruir la ISO.

Interfaz principal

Interfaz de StrawTraduction

La webapp corre en http://0.0.0.0:8080 y ofrece un panel completo para gestionar la traducción.

Las dos partes del sistema

Webapp de traducción

Es una aplicación web hecha con Python + FastAPI + SQLite que permite:

  • Importar los textos del juego desde los archivos originales (Data.bin y SLPS_256.11)
  • Editar los diálogos en una interfaz con búsqueda full-text (FTS5), filtros por script y edición inline
  • Gestionar el progreso, exportar CSVs y controlar qué textos están traducidos, revisados o pendientes

La webapp guarda todo en una base de datos SQLite (translation_manager.db). Soporta interfaz en español e inglés, y permite configurar el idioma de destino independientemente del idioma de la UI.

Build / Reconstrucción de ISO

El módulo de build toma la base de datos con las traducciones y reconstruye la ISO del juego con los textos en español. Su trabajo:

  1. Lee translation_manager.db y detecta el idioma de destino y el mapa de glifos configurado
  2. Reconstruye los scripts de diálogo dentro de Data.bin respetando la estructura original
  3. Parchea los textos del ELF (SLPS_256.11) para menús, descripciones y modos de juego
  4. Genera la ISO final en work/Strawberry_translated.iso

¿Dónde guarda el juego los textos?

El juego reparte sus textos en dos archivos:

Archivo Qué contiene Codificación ¿Comprimido?
SLPS_256.11 (ELF) Menús, sistema, descripciones de personajes Shift-JIS No
Data.bin Diálogos del juego (escenas) UTF-16LE Sí (LZSS)

Data.bin es un contenedor con 27,411 archivos internos. De esos, 997 están comprimidos con LZSS (un algoritmo de compresión nativo de PS2) y solo 58 son scripts de diálogo con la firma que nos interesa. El resto requiere edición manual.


El truco de los glifos cirílicos

Este es probablemente el aspecto más ingenioso del sistema. La fuente japonesa del juego no tiene tildes, eñes ni signos de apertura (¡, ¿). No puedes simplemente escribir “á” porque el juego no sabe dibujarla.

La solución: tomar prestados caracteres cirílicos.

La fuente japonesa del PS2 sí incluye caracteres cirílicos (Г, Д, Е, Ж, И…). El sistema sustituye cada carácter español problemático por un carácter cirílico que sí existe en la fuente:

Carácter español Se reemplaza por Y PCSX2 dibuja…
á, Á Г (cirílico) Una textura que parece á
é, É Д Una textura que parece é
í, Í Е Una textura que parece í
ó, Ó Ж Una textura que parece ó
ú, Ü З Una textura que parece ú
ñ И Una textura que parece ñ
Ñ Й Una textura que parece Ñ
¡ К Una textura que parece ¡
¿ Л Una textura que parece ¿

Luego, mediante inyección de texturas de PCSX2, se reemplazan los glifos cirílicos por las versiones con tilde/eñe. El resultado: el texto se ve completamente en español aunque el juego crea que está dibujando caracteres cirílicos.

Este sistema también funciona para otros idiomas (polaco, alemán, francés) usando los 64 glifos cirílicos disponibles en la fuente, configurando un mapa personalizado desde la página de ajustes.


Cómo fluye la traducción

El proceso completo es:

  1. Extraer → La webapp lee Data.bin y SLPS_256.11, descomprime los scripts LZSS y carga los textos a la base de datos
  2. Traducir → Se editan los textos en la webapp, que guarda todo en text_entries con su estado
  3. Configurar → Se selecciona el idioma de destino y el mapa de glifos en la página de ajustes
  4. Build → El módulo de build lee la base de datos, aplica el mapa de glifos, reconstruye los binarios y genera la ISO
  5. Texturas → Se copian los PNG de Replacement/ a la carpeta de texturas de PCSX2 (textures/SLPS-25611/)

Detalles técnicos interesantes

Compresión LZSS de PS2

El algoritmo LZSS que usa el juego tiene una particularidad: su header mide 12 bytes, no 16 como muchas implementaciones asumen. Usar 16 bytes produce una diferencia de 6,905 bytes en la salida descomprimida y resulta en una pantalla negra al iniciar el juego.

La rareza del FAT

El size_field de cada archivo en la tabla FAT no indica el tamaño de ese archivo, sino el tamaño del archivo de la fila anterior. El tamaño real está en el size_field de la fila siguiente. El módulo datafat.py se encarga de interpretar esto correctamente.

Reconstrucción conservadora

El parcheador usa modo local-slack: reemplaza el texto traducido dentro del espacio de padding de ceros que ya existe en el archivo original, sin mover punteros. Esto evita romper referencias internas. Si una traducción no cabe (~150-230 bytes de margen), se marca como needs_shift y se omite.

Marcadores de pausa (@)

El carácter @ (y su variante japonesa ) es un marcador de click-pause: el texto se detiene y espera a que el jugador presione un botón. Debe conservarse en las mismas posiciones en la traducción.


Stack tecnológico

Capa Tecnología
Backend Python 3, FastAPI, Uvicorn
Base de datos SQLite + SQLAlchemy ORM + FTS5
Frontend Jinja2 + HTMX + Tailwind CSS
CLI / binarios Python stdlib + struct
Compresión LZSS nativo de PS2

Lo que falta

El sistema ya es completamente funcional, pero tiene limitaciones:

  • Solo 58 scripts son de tipo diálogo. Los otros ~939 requieren edición manual de .dec
  • Hace falta PCSX2 para el reemplazo de texturas (no funciona en hardware real sin modificar)
  • Las traducciones que exceden el padding local se omiten por ahora
  • La traducción del ELF es parcial (menús, descripciones)

Se sigue trabajando en mejorar estas áreas. La idea es que eventualmente el parche sea un solo archivo .xdelta que cualquiera pueda aplicar sin necesidad de herramientas adicionales.