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

397 lines
16 KiB
Markdown

# 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
```bash
# 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
```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
```cpp
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
```cpp
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
- [x] LanguageManager.h/cpp - Carga de idiomas desde JSON
- [x] Selector de idioma dinámico en Settings (usa CVar integer para el índice)
- [x] Traducción automática de nombres de widgets en DrawElement()
- [x] Almacenamiento de nombres originales con claves estables (sección|sidebar|columna|índice)
- [x] Persistencia del idioma seleccionado
- [x] Espanol.json con ~950 traducciones
- [x] 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
```bash
# 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) |