Files
Shiip-of-Hakinian-Espanol/PLAN_TRADUCCION.md
nickpons666 25bbd8f7f6
Some checks failed
generate-builds / generate-soh-otr (push) Has been cancelled
generate-builds / build-macos (push) Has been cancelled
generate-builds / build-linux (push) Has been cancelled
generate-builds / build-windows (push) Has been cancelled
feat: Add Spanish translation system (LanguageManager, Espanol.json ~950 strings, UI selector)
- LanguageManager.h/cpp: Dynamic language loading from JSON files
- Espanol.json: ~950 translations extracted from all menu files
- SohMenu.cpp/h: Widget name translation with stable index-based keys
- SohMenuSettings.cpp: Dynamic language selector with persistence
- Localization.h/cpp: Stub for compilation compatibility
- PLAN_TRADUCCION.md: Complete implementation plan with analysis
2026-04-03 15:11:17 -06:00

16 KiB

Plan de Implementación del Sistema de Traducción

Objetivo

Crear un sistema de traducción dinámico que permita cargar idiomas desde archivos JSON externos sin modificar los textos hardcodeados existentes. Los textos en el código permanecen en inglés como fallback por defecto.


1. Funcionamiento Clave

1.1 Comportamiento

  • Sin carpeta de idiomas: El juego funciona exactamente como ahora con los textos hardcodeados en inglés
  • Con carpeta de idiomas: Cuando el usuario selecciona un idioma, se carga el JSON y se traducen los textos disponibles
  • Fallback: Si una traducción no existe en el JSON, se usa el texto hardcodeado (inglés)
  • Persistencia: El idioma seleccionado se guarda en la configuración y se carga automáticamente al iniciar

1.2 Carpeta de Idiomas (opcional)

/lenguajes/
  ├── Espanol.json
  ├── Portugues.json
  └── (otros idiomas).json

Nota: No se requiere English.json porque el inglés ya está hardcodeado en el código.


2. Archivos Creados

Archivo Descripción
soh/soh/SohGui/LanguageManager.h Header del manager de idiomas
soh/soh/SohGui/LanguageManager.cpp Implementación del manager
lenguajes/Espanol.json Traducción español (~950 claves)
soh/soh/Localization.h Stub para compatibilidad de compilación
soh/soh/Localization.cpp Stub para compatibilidad de compilación

3. Archivos Modificados (Implementación Base)

Archivo Cambios
soh/soh/SohGui/SohMenuSettings.cpp Agregar selector de idioma dinámico + carga automática al inicio
soh/soh/SohGui/SohMenu.cpp Aplicar traducción automática en DrawElement() con almacenamiento de nombres originales
soh/soh/SohGui/SohMenu.h Agregar mapa de nombres originales y tooltips originales

4. Ubicación de la Carpeta de Idiomas

4.1 Ubicaciones Buscadas

El sistema busca la carpeta lenguajes en este orden:

  1. Directorio actual (desde donde se ejecuta el juego)
  2. Directorio de datos de la app (~/.local/share/com.shipofharkinian.soh/)

4.2 Cómo colocar los archivos

# Opción 1: Copiar junto al ejecutable (después de compilar)
cp -r lenguajes build-cmake/soh/

# Opción 2: En el directorio de datos de la app
# Linux: ~/.local/share/com.shipofharkinian.soh/lenguajes/

5. Formato de Archivos JSON

5.1 Estructura del JSON

{
  "language": "Español",
  "strings": {
    "Settings": "Configuración",
    "Enabled": "Activado",
    "Disabled": "Desactivado"
  }
}

5.2 Espanol.json (Completo)

Actualmente incluye ~950 traducciones extraídas automáticamente de todos los archivos del menú.


6. Implementación del LanguageManager

6.1 LanguageManager.h

class LanguageManager {
public:
    static LanguageManager& Instance();
    
    void Init();
    void LoadLanguage(const std::string& languageName);
    std::string GetString(const std::string& key);
    std::vector<std::string> GetAvailableLanguages();
    std::string GetCurrentLanguage();
    bool IsTranslationLoaded();
    
private:
    std::string currentLanguage;
    std::map<std::string, std::string> translations;
    bool translationLoaded;
    
    void ScanLanguageFiles();
    bool LoadJsonFile(const std::string& path);
    std::string GetLanguagesDirectory();
};

6.2 Lógica de Funcionamiento

std::string LanguageManager::GetString(const std::string& key) {
    if (!translationLoaded || translations.empty()) {
        return key;
    }
    auto it = translations.find(key);
    if (it != translations.end()) {
        return it->second;
    }
    return key; // Fallback al texto original
}

7. Estado Actual de la Implementación

Completado

  • LanguageManager.h/cpp - Carga de idiomas desde JSON
  • Selector de idioma dinámico en Settings (usa CVar integer para el índice)
  • Traducción automática de nombres de widgets en DrawElement()
  • Almacenamiento de nombres originales con claves estables (sección|sidebar|columna|índice)
  • Persistencia del idioma seleccionado
  • Espanol.json con ~950 traducciones
  • Compilación exitosa y funcional

Pendiente - Fase 1: Menú Completo (Riesgo Bajo-Medio)

  • Headers del menú principal (Settings, Enhancements, Randomizer, Network, Dev Tools)
  • Labels de sidebars (General, Audio, Graphics, Controls, etc.)
  • Tooltips de widgets (mensajes al pasar el mouse)
  • Opciones de combobox (temas, filtros de textura, etc.)
  • Mensajes de estado (disabled tooltips, mensajes de error)
  • Custom widgets que usan ImGui directo
  • Editor de resolución (labels de presets, textos de configuración)
  • Textos del sistema base de búsqueda (Search Results, Clear Search, No results found)
  • Botones del header (Quit SoH, Reset, Close Menu)
  • Nombres de botones N64 en UIWidgets (Modifier 1, Modifier 2)
  • Textos dinámicos en PreFunc (Connecting..., Connected, etc.)

Pendiente - Fase 2: Randomizer (Riesgo Alto)

  • Opciones del randomizer (settings.cpp - macros OPT_U8, OPT_BOOL)
  • Descripciones de opciones (option_descriptions.cpp)
  • Nombres de grupos de opciones (OptionGroup::SubGroup)
  • Textos custom del menú randomizer (ImGui directo)
  • Nombres de tricks y descripciones
  • Nombres de áreas
  • Textos del Plandomizer (Locations, Items, etc.)

8. Análisis Completo de Textos por Categoría

Categoría 1: SohMenu.cpp - Mensajes de Estado

Archivo: soh/soh/SohGui/SohMenu.cpp Textos: ~14 mensajes de disabledMap Ejemplos: "Disabling VSync not supported", "Debug Mode is Disabled", "Frame Advance is Disabled" Cómo se dibujan: Se concatenan en Menu::MenuDrawItem() como tooltips de widgets deshabilitados Tipo: const char* en struct disabledInfo Riesgo: BAJO

Categoría 2: SohMenuSettings.cpp - Widgets de Settings

Archivo: soh/soh/SohGui/SohMenuSettings.cpp Textos: ~200 (nombres de widgets, tooltips, opciones de combobox) Ejemplos de combobox options: "Small", "Normal", "Large" (ImGui Scale), "Red", "Dark Red", "Orange" (temas), "Three-Point", "Linear", "None" (filtro textura) Ejemplos de tooltips: "Changes the Theme of the Menu Widgets.", "Allows controller navigation of the port menu..." Cómo se dibujan: Via AddWidget().Tooltip("...") y .ComboMap(mapa) Tipo: Tooltips como std::string en WidgetOptions, combobox como std::map<int32_t, const char*> Riesgo: MEDIO

Categoría 3: SohMenuEnhancements.cpp - Widgets de Enhancements

Archivo: soh/soh/SohGui/SohMenuEnhancements.cpp Textos: ~500+ (nombres, tooltips, opciones de combobox, disabledTooltips) Ejemplos de combobox options: "Vanilla", "Faster Run", "Faster + Longer Jump" (Bunny Hood), "Plentiful", "Balanced", "Scarce", "Minimal" (Item Pool del randomizer) Ejemplos de tooltips: Textos largos de varias líneas explicando cada mejora Cómo se dibujan: Mismo patrón que Settings Riesgo: MEDIO-ALTO (volumen grande)

Categoría 4: SohMenuRandomizer.cpp - Widgets de Randomizer

Archivo: soh/soh/SohGui/SohMenuRandomizer.cpp Textos: ~100 + datos del motor del randomizer Ejemplos: "Seed Entry", "Generate Randomizer", "Filter (inc,-exc)", "Disable All", "Enable All" Cómo se dibujan: Mix de AddWidget() y custom widgets con ImGui directo (ImGui::Text(), ImGui::Button(), ImGui::BeginTable()) Datos del randomizer: Nombres de ubicaciones, tricks, áreas vienen de Rando::StaticData, TrickSetting, Option Riesgo: ALTO (datos del randomizer pueden afectar compatibilidad con seeds)

Categoría 5: SohMenuNetwork.cpp - Widgets de Network

Archivo: soh/soh/SohGui/SohMenuNetwork.cpp Textos: ~30 Ejemplos: "Host & Port", "Enable##Sail", "Connecting...##Sail", "About Crowd Control" Cómo se dibujan: Mix de AddWidget() y textos ImGui directo Riesgo: BAJO

Categoría 6: SohMenuDevTools.cpp - Widgets de Dev Tools

Archivo: soh/soh/SohGui/SohMenuDevTools.cpp Textos: ~50 Ejemplos: "Debug Mode", "Frame Advance", "Log Level", "Trace", "Debug", "Info", "Warn" Riesgo: BAJO (herramientas de desarrollo, prioridad baja)

Categoría 7: Menu.cpp - Sistema Base del Menú

Archivo: soh/soh/SohGui/Menu.cpp Textos: ~20 Ejemplos: "This setting is disabled because: \n", "Search Results", "Clear Search", "No results found", "Quit SoH", "Reset", "Close Menu (Esc)" Cómo se dibujan: Directamente en MenuDrawItem() con llamadas ImGui Riesgo: MEDIO (textos del sistema core)

Categoría 8: UIWidgets.cpp - Widgets UI

Archivo: soh/soh/SohGui/UIWidgets.cpp Textos: ~15 Ejemplos: "Modifier 1", "Modifier 2", "Remove this button from the combination", "Resets this color to its default value" Cómo se dibujan: En BtnSelector() y Color Picker Riesgo: BAJO-MEDIO

Categoría 9: ResolutionEditor.cpp - Editor de Resolución

Archivo: soh/soh/SohGui/ResolutionEditor.cpp Textos: ~40 Ejemplos: "Off", "Custom", "Original (4:3)", "Widescreen (16:9)", "Pixel Perfect Mode", "Integer Scaling Settings" Cómo se dibujan: Mix de AddWidget() y ResolutionCustomWidget() con ImGui directo Riesgo: MEDIO

Categoría 10: Randomizer Settings - Opciones del Randomizer

Archivos:

  • soh/soh/Enhancements/randomizer/settings.cpp
  • soh/soh/Enhancements/randomizer/option_descriptions.cpp Textos: ~1000+ Ejemplos: "Item Pool", "Logic", "Closed Forest", "Kakariko Gate", "Starting Age" Cómo se dibujan: Via macros OPT_U8, OPT_BOOL que crean objetos Option, no pasan por AddWidget() Descripciones: Textos largos en option_descriptions.cpp (~836 líneas) Grupos: OptionGroup::SubGroup("Logic Options", ...), OptionGroup::SubGroup("Logical Tricks", ...) Riesgo: MUY ALTO (puede romper compatibilidad con seeds, spoiler logs, herramientas externas)

Categoría 11: SohMenu.h - Idiomas del Juego

Archivo: soh/soh/SohGui/SohMenu.h Textos: 4 ("English", "German", "French", "Japanese") Riesgo: MUY BAJO (nombres propios de idiomas)


9. Plan de Implementación Gradual (Opción C)

Fase 1: Menú Completo (sin Randomizer)

Objetivo: Traducir todo el menú principal ~700 textos adicionales Riesgo: Medio Tiempo estimado: Moderado

Paso 1.1: Headers y Sidebars

  • Modificar DrawElement() para traducir section.label y sidebarOrder
  • Usar claves estables basadas en índices (igual que widgets)
  • Archivo: soh/soh/SohGui/SohMenu.cpp

Paso 1.2: Tooltips de Widgets

  • Agregar mapa mOriginalTooltips en SohMenu.h
  • Guardar tooltips originales con claves de índice
  • Traducir en DrawElement() antes de dibujar
  • Archivos: SohMenu.h, SohMenu.cpp

Paso 1.3: Opciones de Combobox

  • Traducir en PreFunc de cada widget combobox
  • Usar mapas estáticos con traducción dinámica
  • Archivos: SohMenuSettings.cpp, SohMenuEnhancements.cpp, etc.

Paso 1.4: Mensajes de Estado (disabledMap)

  • Traducir disabledInfo.reason en MenuDrawItem() al concatenar
  • Archivo: soh/soh/SohGui/Menu.cpp

Paso 1.5: Textos del Sistema Base

  • Traducir textos de búsqueda, botones del header, diálogos de confirmación
  • Archivo: soh/soh/SohGui/Menu.cpp

Paso 1.6: Custom Widgets

  • Envolver textos ImGui directo con LanguageManager::Instance().GetString()
  • Archivos: SohMenuNetwork.cpp, SohMenuDevTools.cpp, ResolutionEditor.cpp

Paso 1.7: UIWidgets

  • Traducir labels de botones (Modifier 1, Modifier 2) y tooltips de Color Picker
  • Archivo: soh/soh/SohGui/UIWidgets.cpp

Fase 2: Randomizer (requiere diseño cuidadoso)

Objetivo: Traducir opciones del randomizer ~1000+ textos Riesgo: Alto Consideraciones:

  • Los nombres de opciones se usan como keys en mapas y serialización
  • Puede afectar compatibilidad con seeds existentes y spoiler logs
  • Los nombres de tricks son parte de la cultura del speedrunning
  • Se necesita evaluar si traducir solo display names o también keys internas

Paso 2.1: Opciones del Randomizer

  • Integrar LanguageManager en el sistema de Option
  • Traducir GetName() al renderizar, NO al crear la opción
  • Archivo: soh/soh/Enhancements/randomizer/settings.cpp

Paso 2.2: Descripciones de Opciones

  • Traducir mOptionDescriptions[] al mostrar
  • Archivo: soh/soh/Enhancements/randomizer/option_descriptions.cpp

Paso 2.3: Grupos de Opciones

  • Traducir nombres de OptionGroup::SubGroup() al renderizar
  • Archivo: soh/soh/Enhancements/randomizer/settings.cpp

Paso 2.4: Custom Widgets del Randomizer

  • Traducir textos ImGui directo en el menú del randomizer
  • Archivo: soh/soh/SohGui/SohMenuRandomizer.cpp

Paso 2.5: Tricks y Áreas (opcional, bajo demanda)

  • Traducir nombres de tricks y áreas
  • Evaluar impacto en la comunidad de speedrunning
  • Archivos: soh/soh/Enhancements/randomizer/3drando/tricks.cpp, etc.

10. Notas Importantes

  • Textos hardcodeados permanecen: El código no se modifica, los textos en inglés quedan como están
  • Sin carpeta de idiomas funciona igual: Si no existe la carpeta, el juego funciona exactamente como antes
  • Fallback automático: Si falta una traducción, se muestra el texto original
  • Selector dinámico: Los nombres de idiomas vienen de los archivos JSON, no están hardcodeados
  • Fácil agregar idiomas: Solo hay que crear un nuevo archivo .json en la carpeta
  • Persistencia: El idioma seleccionado se guarda y se carga automáticamente al iniciar
  • ⚠️ Ubicación de carpeta: La carpeta lenguajes debe estar junto al ejecutable o en el directorio de datos de la app
  • ⚠️ Claves estables: Los nombres de widgets se traducen usando claves basadas en índices para evitar corrupción al cambiar idioma

11. Cómo Compilar y Ejecutar

# 1. Compilar el proyecto
cmake -H. -Bbuild-cmake -GNinja
cmake --build build-cmake -j$(nproc)

# 2. Copiar carpeta de idiomas junto al ejecutable
cp -r lenguajes build-cmake/soh/

# 3. Ejecutar desde la raíz del proyecto
./build-cmake/soh/soh.elf

12. Resumen de Dificultad por Categoría

Categoría Textos Dificultad Riesgo
Headers y Sidebars ~30 Media Medio
Tooltips del menú ~400 Media Medio
Opciones de combobox ~150 Media Medio
Mensajes de estado ~30 Baja Bajo
Custom widgets ~80 Media Medio
Editor de resolución ~40 Media Medio
Sistema base (búsqueda, botones) ~20 Media Medio
UIWidgets ~15 Baja Bajo
Opciones del Randomizer ~1000+ Muy Alta Muy Alto
Tricks y Áreas ~100+ Muy Alta Muy Alto

13. Archivos de Referencia con Textos Hardcodeados

SohGui (ya analizados)

  • SohMenu_hardcoded.txt
  • SohMenuSettings_hardcoded.txt
  • SohMenuEnhancements_hardcoded.txt
  • SohMenuRandomizer_hardcoded.txt
  • SohMenuNetwork_hardcoded.txt
  • SohMenuDevTools_hardcoded.txt
  • SohMenuBar_hardcoded.txt
  • ResolutionEditor_hardcoded.txt

14. Diferencias con el Plan Anterior

Aspecto Plan Anterior Plan Actual
English.json Obligatorio No necesario (hardcodeado es fallback)
Reemplazo de textos Sí, en todos los archivos No, solo agregar función GetString
Archivos a modificar 8+ archivos 2 archivos (SohMenuSettings.cpp, SohMenu.cpp)
Funcionamiento sin carpeta Requiere English.json Funciona igual que antes
Stub Localization No previsto Necesario para compilar
Persistencia de idioma No implementada Guardado y cargado automáticamente
Strings en selector Implementación con problemas Solucionado con map estático
Traducción de tooltips No previsto Implementado con claves estables
Headers y Sidebars No previsto Pendiente (Fase 1)
Randomizer No previsto Pendiente (Fase 2, requiere diseño)