- Add LanguageManager integration to Plandomizer.cpp, randomizer_check_tracker.cpp, randomizer_item_tracker.cpp, and randomizer_entrance_tracker.cpp - Add ~100 new translation keys to Espanol.json for Randomizer UI - Include lenguajes folder in AppImage/DEB packaging via CMakeLists.txt - Update PLAN_TRADUCCION.md with Randomizer translation status and packaging info
372 lines
13 KiB
Markdown
372 lines
13 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 bleiben 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 (~250 claves) |
|
|
| `soh/soh/Localization.h` | Stub para compatibilidad de compilación |
|
|
| `soh/soh/Localization.cpp` | Stub para compatibilidad de compilación |
|
|
|
|
---
|
|
|
|
## 3. Archivos Modificados
|
|
|
|
| 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 AddWidget |
|
|
| `soh/soh/Enhancements/randomizer/Plandomizer.cpp` | Traducir textos de UI con LanguageManager |
|
|
| `soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp` | Traducir textos de UI con LanguageManager |
|
|
| `soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp` | Traducir textos de UI con LanguageManager |
|
|
| `soh/soh/Enhancements/randomizer/randomizer_entrance_tracker.cpp` | Traducir textos de UI con LanguageManager |
|
|
| `CMakeLists.txt` | Incluir carpeta `lenguajes` en AppImage/DEB |
|
|
|
|
---
|
|
|
|
## 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/
|
|
```
|
|
|
|
### 4.3 Empaquetado en AppImage/DEB
|
|
La carpeta `lenguajes` se incluye automáticamente en los paquetes AppImage y DEB gracias a la directiva de instalación en `CMakeLists.txt`:
|
|
|
|
```cmake
|
|
install(DIRECTORY "${CMAKE_SOURCE_DIR}/lenguajes/" DESTINATION ./lenguajes COMPONENT ship OPTIONAL)
|
|
```
|
|
|
|
Esto significa que al generar un AppImage con `cpack`, la carpeta `lenguajes` con todos los archivos `.json` se incluirá automáticamente dentro del paquete, sin necesidad de copiarla manualmente. El flag `OPTIONAL` evita errores de compilación si la carpeta no existe.
|
|
|
|
---
|
|
|
|
## 5. Formato de Archivos JSON
|
|
|
|
### 5.1 Estructura del JSON
|
|
```json
|
|
{
|
|
"language": "Español",
|
|
"strings": {
|
|
"Settings": "Configuración",
|
|
"Enhancements": "Mejoras",
|
|
"Randomizer": "Randomizer",
|
|
"Network": "Red",
|
|
"Dev Tools": "Herramientas de Desarrollo",
|
|
"Enabled": "Activado",
|
|
"Disabled": "Desactivado",
|
|
"Apply": "Aplicar",
|
|
"Cancel": "Cancelar"
|
|
}
|
|
}
|
|
```
|
|
|
|
### 5.2 Espanol.json (Completo)
|
|
Ya incluye ~250 traducciones para los menús principales:
|
|
- Settings (General, Graphics, Audio, Controls, etc.)
|
|
- Enhancements
|
|
- Randomizer
|
|
- Network
|
|
- Dev Tools
|
|
|
|
---
|
|
|
|
## 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) {
|
|
// Si no hay traducción cargada, retorna el texto hardcodeado (ingles)
|
|
if (!translationLoaded || translations.empty()) {
|
|
return key;
|
|
}
|
|
|
|
// Busca la traducción
|
|
auto it = translations.find(key);
|
|
if (it != translations.end()) {
|
|
return it->second;
|
|
}
|
|
|
|
// Si no encuentra la traducción, retorna el texto hardcodeado
|
|
return key;
|
|
}
|
|
```
|
|
|
|
### 6.3 Funcionalidades Principales
|
|
|
|
1. **Escaneo de idiomas**: Al iniciar, escanea la carpeta `/lenguajes/` y detecta archivos `.json`
|
|
2. **Carga bajo demanda**: Solo carga el JSON cuando el usuario selecciona un idioma
|
|
3. **Fallback seguro**: Si no existe la traducción, retorna el texto hardcodeado
|
|
4. **Selector dinámico**: Genera opciones basadas en archivos encontrados (sin hardcodear nombres)
|
|
5. **Búsqueda dual**: Busca primero en directorio actual, luego en directorio de datos
|
|
6. **Persistencia**: Guarda el idioma seleccionado en CVAR y lo carga al iniciar
|
|
|
|
---
|
|
|
|
## 7. Ejemplo de Uso en el Código
|
|
|
|
### 7.1 Sin cambios en el código existente
|
|
Los textos hardcodeados permanecen exactamente igual:
|
|
|
|
```cpp
|
|
// El código queda igual, NO se cambia a L("key")
|
|
AddWidget(path, "Settings", WIDGET_SEPARATOR_TEXT);
|
|
AddWidget(path, "Language", WIDGET_CVAR_COMBOBOX);
|
|
AddWidget(path, "Enabled", WIDGET_CVAR_CHECKBOX);
|
|
```
|
|
|
|
### 7.2 La traducción se aplica automáticamente
|
|
En `SohMenu.cpp`, método `AddWidget`:
|
|
|
|
```cpp
|
|
SidebarEntry& entry = sidebar.at(pathInfo.sidebarName);
|
|
std::string translatedName = LanguageManager::Instance().GetString(widgetName);
|
|
entry.columnWidgets.at(column).push_back({ .name = translatedName, .type = widgetType });
|
|
WidgetInfo& widget = entry.columnWidgets.at(column).back();
|
|
```
|
|
|
|
### 7.3 Cómo funciona
|
|
- Los textos en el código bleiben en inglés
|
|
- La función `GetString()` se llama al momento de mostrar el texto
|
|
- Si hay una traducción cargada y existe la clave, retorna la traducción
|
|
- Si no hay traducción o no existe la clave, retorna el texto original (hardcodeado)
|
|
|
|
---
|
|
|
|
## 8. Selector de Idioma
|
|
|
|
### 8.1 Ubicación
|
|
En `SohMenuSettings.cpp` dentro del menú de configuración, sección "Languages"
|
|
|
|
### 8.2 Comportamiento
|
|
- Muestra todos los archivos `.json` encontrados en `/lenguajes/`
|
|
- El nombre del archivo (sin extensión) se muestra en el selector
|
|
- Al seleccionar un idioma, carga el archivo JSON correspondiente
|
|
- Por defecto (sin acción del usuario), funciona con textos hardcodeados
|
|
- Incluye opción "None" para desactivar traducciones
|
|
- **El idioma seleccionado se guarda y se carga automáticamente al iniciar el juego**
|
|
|
|
### 8.3 Widget implementado
|
|
```cpp
|
|
// Variables estáticas para mantener los strings vivos
|
|
static std::map<int32_t, std::string> uiLanguageOptionsStr = { };
|
|
static std::map<int32_t, const char*> uiLanguageOptions = { };
|
|
|
|
// Inicialización con carga automática del idioma guardado
|
|
static void InitUILanguages() {
|
|
LanguageManager::Instance().Init();
|
|
uiLanguageOptionsStr.clear();
|
|
uiLanguageOptions.clear();
|
|
|
|
uiLanguageOptionsStr[0] = "None";
|
|
uiLanguageOptions[0] = "None";
|
|
|
|
int32_t idx = 1;
|
|
for (const auto& lang : LanguageManager::Instance().GetAvailableLanguages()) {
|
|
if (!lang.empty()) {
|
|
uiLanguageOptionsStr[idx] = lang;
|
|
uiLanguageOptions[idx] = uiLanguageOptionsStr[idx].c_str();
|
|
idx++;
|
|
}
|
|
}
|
|
|
|
// Cargar idioma guardado automáticamente
|
|
int32_t savedLang = CVarGetInteger(CVAR_SETTING("UILanguage"), 0);
|
|
if (savedLang > 0 && savedLang < (int32_t)LanguageManager::Instance().GetAvailableLanguages().size() + 1) {
|
|
std::string langName = LanguageManager::Instance().GetAvailableLanguages()[savedLang - 1];
|
|
LanguageManager::Instance().LoadLanguage(langName);
|
|
}
|
|
}
|
|
|
|
// Widget del selector
|
|
AddWidget(path, "UI Translation", WIDGET_CVAR_COMBOBOX)
|
|
.CVar(CVAR_SETTING("UILanguage"))
|
|
.Callback([](WidgetInfo& info) {
|
|
// Guarda y carga el idioma seleccionado
|
|
})
|
|
.Options(ComboboxOptions()
|
|
.ComboMap(uiLanguageOptions)
|
|
.Tooltip("Select the UI translation language..."));
|
|
```
|
|
|
|
---
|
|
|
|
## 9. Proceso de Implementación (Completado)
|
|
|
|
### Fase 1: Fundamentos ✅
|
|
1. Crear `LanguageManager.h/cpp`
|
|
2. Crear estructura de carpetas `/lenguajes/`
|
|
|
|
### Fase 2: Integración ✅
|
|
3. Modificar `SohMenuSettings.cpp` para agregar selector de idioma dinámico
|
|
4. Modificar `SohMenu.cpp` para aplicar traducción automática
|
|
5. Crear `Localization.h/cpp` (stubs para compilación)
|
|
6. **Corregir problema de strings temporales** (usar map estático para mantener strings vivos)
|
|
7. **Agregar carga automática del idioma guardado al iniciar**
|
|
|
|
### Fase 3: Pruebas ✅
|
|
8. Crear `Espanol.json` de prueba
|
|
9. Probar cambio de idioma
|
|
10. Corregir rutas de búsqueda
|
|
11. Verificar persistencia del idioma seleccionado
|
|
|
|
---
|
|
|
|
## 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
|
|
|
|
---
|
|
|
|
## 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. Estado de Implementación ✅ COMPLETADO
|
|
|
|
### Implementación Base ✅
|
|
- [x] LanguageManager.h/cpp - Carga de idiomas desde JSON
|
|
- [x] Selector de idioma dinámico en Settings
|
|
- [x] Aplicación automática de traducciones en AddWidget
|
|
- [x] Persistencia del idioma seleccionado (guardado/cargado al inicio)
|
|
- [x] Traducciones para menús principales (Settings, Enhancements, Randomizer, Network, DevTools)
|
|
- [x] Fix de strings temporales en dropdowns
|
|
- [x] Fix de compilación en Menu.cpp (SohGui::LanguageManager)
|
|
- [x] Compilación exitosa
|
|
|
|
### Traducción del Randomizer ✅
|
|
- [x] Plandomizer.cpp - Textos de UI traducidos (tablas, popups, tooltips, tabs)
|
|
- [x] randomizer_check_tracker.cpp - Textos de UI traducidos (checkboxes, botones, búsqueda, settings)
|
|
- [x] randomizer_item_tracker.cpp - Textos de UI traducidos (settings table, checks counter)
|
|
- [x] randomizer_entrance_tracker.cpp - Textos de UI traducidos (sort, group, legend, tooltips)
|
|
- [x] Claves de traducción añadidas a Espanol.json (~100 nuevas claves)
|
|
|
|
### Pendientes / Mejoras Futuras
|
|
- [ ] Agregar más traducciones al JSON (actualmente ~350+ claves)
|
|
- [ ] Crear archivo Portugues.json
|
|
- [ ] Posibilidad de recargar traducciones en tiempo real sin cerrar el juego
|
|
|
|
---
|
|
|
|
## 13. Mejoras al Plandomizer (Randomizer)
|
|
|
|
### 13.1 Filtro de Items en Locations
|
|
Agregadas nuevas funcionalidades en la pestaña Locations:
|
|
|
|
| Feature | Descripción |
|
|
|---------|-------------|
|
|
| **Campo de búsqueda** | Escribe el nombre de un item y presiona Enter para seleccionarlo |
|
|
| **Botón A-Z** | Ordena la lista de items alfabéticamente |
|
|
| **Limpiar** | El botón "Clear Item Filter" ahora también limpia el campo de búsqueda |
|
|
|
|
### 13.2 Archivos Modificados
|
|
- `soh/soh/Enhancements/randomizer/Plandomizer.cpp`
|
|
|
|
---
|
|
|
|
## 15. 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`
|
|
|
|
---
|
|
|
|
## 15. 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 |
|