afegit suport multiidioma
afegida traducció al valencià
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "core/input/input.hpp" // Para Input, InputAction, Input::DO_NOT_ALLOW_REPEAT
|
||||
#include "core/locale/locale.hpp" // Para Locale
|
||||
#include "core/rendering/screen.hpp" // Para Screen
|
||||
#include "game/options.hpp" // Para Options, options, OptionsVideo, Section
|
||||
#include "game/scene_manager.hpp" // Para SceneManager
|
||||
@@ -27,7 +28,7 @@ namespace GlobalInputs {
|
||||
if (stringInVector(Notifier::get()->getCodes(), CODE)) {
|
||||
SceneManager::current = SceneManager::Scene::TITLE;
|
||||
} else {
|
||||
Notifier::get()->show({CODE}, Notifier::Style::DEFAULT, -1, true, CODE);
|
||||
Notifier::get()->show({Locale::get()->get("ui.press_again_menu")}, Notifier::Style::DEFAULT, -1, true, CODE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -47,7 +48,7 @@ namespace GlobalInputs {
|
||||
if (stringInVector(Notifier::get()->getCodes(), CODE)) {
|
||||
SceneManager::current = SceneManager::Scene::QUIT;
|
||||
} else {
|
||||
Notifier::get()->show({CODE}, Notifier::Style::DEFAULT, -1, true, CODE);
|
||||
Notifier::get()->show({Locale::get()->get("ui.press_again_exit")}, Notifier::Style::DEFAULT, -1, true, CODE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,58 +72,58 @@ namespace GlobalInputs {
|
||||
|
||||
void handleToggleBorder() {
|
||||
Screen::get()->toggleBorder();
|
||||
Notifier::get()->show({"BORDER " + std::string(Options::video.border.enabled ? "ENABLED" : "DISABLED")});
|
||||
Notifier::get()->show({Locale::get()->get(Options::video.border.enabled ? "ui.border_enabled" : "ui.border_disabled")});
|
||||
}
|
||||
|
||||
void handleToggleVideoMode() {
|
||||
Screen::get()->toggleVideoMode();
|
||||
Notifier::get()->show({"FULLSCREEN " + std::string(static_cast<int>(Options::video.fullscreen) == 0 ? "DISABLED" : "ENABLED")});
|
||||
Notifier::get()->show({Locale::get()->get(static_cast<int>(Options::video.fullscreen) == 0 ? "ui.fullscreen_disabled" : "ui.fullscreen_enabled")});
|
||||
}
|
||||
|
||||
void handleDecWindowZoom() {
|
||||
if (Screen::get()->decWindowZoom()) {
|
||||
Notifier::get()->show({"WINDOW ZOOM x" + std::to_string(Options::window.zoom)});
|
||||
Notifier::get()->show({Locale::get()->get("ui.window_zoom") + std::to_string(Options::window.zoom)});
|
||||
}
|
||||
}
|
||||
|
||||
void handleIncWindowZoom() {
|
||||
if (Screen::get()->incWindowZoom()) {
|
||||
Notifier::get()->show({"WINDOW ZOOM x" + std::to_string(Options::window.zoom)});
|
||||
Notifier::get()->show({Locale::get()->get("ui.window_zoom") + std::to_string(Options::window.zoom)});
|
||||
}
|
||||
}
|
||||
|
||||
void handleTogglePostFX() {
|
||||
Screen::get()->togglePostFX();
|
||||
Notifier::get()->show({"POSTFX " + std::string(Options::video.postfx ? "ENABLED" : "DISABLED")});
|
||||
Notifier::get()->show({Locale::get()->get(Options::video.postfx ? "ui.postfx_enabled" : "ui.postfx_disabled")});
|
||||
}
|
||||
|
||||
void handleNextPostFXPreset() {
|
||||
if (!Options::postfx_presets.empty()) {
|
||||
Options::current_postfx_preset = (Options::current_postfx_preset + 1) % static_cast<int>(Options::postfx_presets.size());
|
||||
Screen::get()->reloadPostFX();
|
||||
Notifier::get()->show({"POSTFX " + Options::postfx_presets[static_cast<size_t>(Options::current_postfx_preset)].name});
|
||||
Notifier::get()->show({Locale::get()->get("ui.postfx") + " " + Options::postfx_presets[static_cast<size_t>(Options::current_postfx_preset)].name});
|
||||
}
|
||||
}
|
||||
|
||||
void handleNextPalette() {
|
||||
Screen::get()->nextPalette();
|
||||
Notifier::get()->show({"PALETTE " + Options::video.palette});
|
||||
Notifier::get()->show({Locale::get()->get("ui.palette") + " " + Options::video.palette});
|
||||
}
|
||||
|
||||
void handlePreviousPalette() {
|
||||
Screen::get()->previousPalette();
|
||||
Notifier::get()->show({"PALETTE " + Options::video.palette});
|
||||
Notifier::get()->show({Locale::get()->get("ui.palette") + " " + Options::video.palette});
|
||||
}
|
||||
|
||||
void handleToggleIntegerScale() {
|
||||
Screen::get()->toggleIntegerScale();
|
||||
Screen::get()->setVideoMode(Options::video.fullscreen);
|
||||
Notifier::get()->show({"INTEGER SCALE " + std::string(Options::video.integer_scale ? "ENABLED" : "DISABLED")});
|
||||
Notifier::get()->show({Locale::get()->get(Options::video.integer_scale ? "ui.integer_scale_enabled" : "ui.integer_scale_disabled")});
|
||||
}
|
||||
|
||||
void handleToggleVSync() {
|
||||
Screen::get()->toggleVSync();
|
||||
Notifier::get()->show({"V-SYNC " + std::string(Options::video.vertical_sync ? "ENABLED" : "DISABLED")});
|
||||
Notifier::get()->show({Locale::get()->get(Options::video.vertical_sync ? "ui.vsync_enabled" : "ui.vsync_disabled")});
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
90
source/core/locale/locale.cpp
Normal file
90
source/core/locale/locale.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
#include "core/locale/locale.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "external/fkyaml_node.hpp" // Para fkyaml::node
|
||||
#include "game/options.hpp" // Para Options::console
|
||||
|
||||
// [SINGLETON]
|
||||
Locale* Locale::locale_ = nullptr;
|
||||
|
||||
// [SINGLETON] Crea el objeto con esta función estática
|
||||
void Locale::init(const std::string& file_path) {
|
||||
Locale::locale_ = new Locale();
|
||||
Locale::locale_->loadFromFile(file_path);
|
||||
}
|
||||
|
||||
// [SINGLETON] Destruye el objeto con esta función estática
|
||||
void Locale::destroy() {
|
||||
delete Locale::locale_;
|
||||
Locale::locale_ = nullptr;
|
||||
}
|
||||
|
||||
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||
auto Locale::get() -> Locale* {
|
||||
return Locale::locale_;
|
||||
}
|
||||
|
||||
// Devuelve la traducción de la clave o la clave como fallback
|
||||
auto Locale::get(const std::string& key) const -> std::string {
|
||||
auto it = strings_.find(key);
|
||||
if (it != strings_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
if (Options::console) {
|
||||
std::cerr << "Locale: clave no encontrada: " << key << '\n';
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
// Aplana un nodo YAML de forma recursiva: {a: {b: "val"}} -> {"a.b" -> "val"}
|
||||
void Locale::flatten(const void* node_ptr, const std::string& prefix) {
|
||||
const auto& node = *static_cast<const fkyaml::node*>(node_ptr);
|
||||
|
||||
for (auto itr = node.begin(); itr != node.end(); ++itr) {
|
||||
const std::string KEY = prefix.empty()
|
||||
? itr.key().get_value<std::string>()
|
||||
: prefix + "." + itr.key().get_value<std::string>();
|
||||
|
||||
const auto& value = itr.value();
|
||||
if (value.is_mapping()) {
|
||||
flatten(&value, KEY);
|
||||
} else if (value.is_string()) {
|
||||
strings_[KEY] = value.get_value<std::string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Carga las traducciones desde el fichero YAML indicado
|
||||
void Locale::loadFromFile(const std::string& file_path) {
|
||||
if (file_path.empty()) {
|
||||
if (Options::console) {
|
||||
std::cerr << "Locale: ruta de fichero vacía, sin traducciones cargadas\n";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
std::ifstream file(file_path);
|
||||
if (!file.is_open()) {
|
||||
if (Options::console) {
|
||||
std::cerr << "Locale: no se puede abrir " << file_path << '\n';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
auto yaml = fkyaml::node::deserialize(file);
|
||||
flatten(&yaml, "");
|
||||
|
||||
if (Options::console) {
|
||||
std::cout << "Locale: " << strings_.size() << " traducciones cargadas desde " << file_path << '\n';
|
||||
}
|
||||
} catch (const fkyaml::exception& e) {
|
||||
if (Options::console) {
|
||||
std::cerr << "Locale: error al parsear YAML: " << e.what() << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
26
source/core/locale/locale.hpp
Normal file
26
source/core/locale/locale.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
// Clase Locale: gestiona las traducciones del juego (singleton)
|
||||
// Las traducciones se cargan desde un fichero YAML en el inicio.
|
||||
// No se permite cambio de idioma en caliente.
|
||||
class Locale {
|
||||
public:
|
||||
static void init(const std::string& file_path); // Crea e inicializa el singleton
|
||||
static void destroy(); // Destruye el singleton
|
||||
static auto get() -> Locale*; // Devuelve el singleton
|
||||
|
||||
// Devuelve la traducción de la clave dada.
|
||||
// Si la clave no existe, devuelve la propia clave como fallback.
|
||||
[[nodiscard]] auto get(const std::string& key) const -> std::string;
|
||||
|
||||
private:
|
||||
Locale() = default;
|
||||
void loadFromFile(const std::string& file_path);
|
||||
void flatten(const void* node_ptr, const std::string& prefix); // Aplana nodos YAML anidados
|
||||
|
||||
static Locale* locale_;
|
||||
std::unordered_map<std::string, std::string> strings_;
|
||||
};
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "core/audio/audio.hpp" // Para Audio
|
||||
#include "core/input/input.hpp" // Para Input, InputAction
|
||||
#include "core/locale/locale.hpp" // Para Locale
|
||||
#include "core/rendering/screen.hpp" // Para Screen
|
||||
#include "core/resources/resource_cache.hpp" // Para Resource
|
||||
#include "core/resources/resource_helper.hpp" // Para ResourceHelper
|
||||
@@ -162,6 +163,14 @@ Director::Director(std::vector<std::string> const& args) {
|
||||
|
||||
std::cout << "\n"; // Fin de inicialización de sistemas
|
||||
|
||||
// Inicializa el sistema de localización (antes de Cheevos que usa textos traducidos)
|
||||
#ifdef RELEASE_BUILD
|
||||
std::string locale_path = executable_path_ + PREFIX + "/data/locale/" + Options::language + ".yaml";
|
||||
Locale::init(locale_path);
|
||||
#else
|
||||
Locale::init(Resource::List::get()->get(Options::language + ".yaml"));
|
||||
#endif
|
||||
|
||||
// Special handling for cheevos.bin - also needs filesystem path
|
||||
#ifdef RELEASE_BUILD
|
||||
std::string cheevos_path = system_folder_ + "/cheevos.bin";
|
||||
@@ -177,6 +186,7 @@ Director::~Director() {
|
||||
|
||||
// Destruye los singletones
|
||||
Cheevos::destroy();
|
||||
Locale::destroy();
|
||||
#ifdef _DEBUG
|
||||
Debug::destroy();
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user