- 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
397 lines
16 KiB
Markdown
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) |
|