- 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
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:
- Directorio actual (desde donde se ejecuta el juego)
- 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.cppsoh/soh/Enhancements/randomizer/option_descriptions.cppTextos: ~1000+ Ejemplos: "Item Pool", "Logic", "Closed Forest", "Kakariko Gate", "Starting Age" Cómo se dibujan: Via macrosOPT_U8,OPT_BOOLque crean objetosOption, no pasan porAddWidget()Descripciones: Textos largos enoption_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 traducirsection.labelysidebarOrder - Usar claves estables basadas en índices (igual que widgets)
- Archivo:
soh/soh/SohGui/SohMenu.cpp
Paso 1.2: Tooltips de Widgets
- Agregar mapa
mOriginalTooltipsen 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
PreFuncde 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.reasonenMenuDrawItem()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
LanguageManageren el sistema deOption - 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
.jsonen la carpeta - ✅ Persistencia: El idioma seleccionado se guarda y se carga automáticamente al iniciar
- ⚠️ Ubicación de carpeta: La carpeta
lenguajesdebe 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.txtSohMenuSettings_hardcoded.txtSohMenuEnhancements_hardcoded.txtSohMenuRandomizer_hardcoded.txtSohMenuNetwork_hardcoded.txtSohMenuDevTools_hardcoded.txtSohMenuBar_hardcoded.txtResolutionEditor_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) |