diff --git a/src/cheatmenu.cpp b/src/cheatmenu.cpp index d21ca31..5300a0c 100644 --- a/src/cheatmenu.cpp +++ b/src/cheatmenu.cpp @@ -179,6 +179,7 @@ CheatMenu::CheatMenu() m_fMenuSize.y = gConfig.GetValue("window.sizeY", screen::GetScreenHeight() / 1.2f); srand(CTimer::m_snTimeInMilliseconds); + Locale::Init("CheatMenu/locale/"); Events::processScriptsEvent += []() { if (!BY_GAME(FrontEndMenuManager.m_bMenuActive, FrontendMenuManager.m_bMenuVisible, FrontEndMenuManager.m_bMenuActive)) diff --git a/src/json.cpp b/src/json.cpp index aa1c581..95f19ea 100644 --- a/src/json.cpp +++ b/src/json.cpp @@ -1,14 +1,17 @@ #include "pch.h" #include "json.h" -CJson::CJson(const char* name) +CJson::CJson(const char* name, bool pathPredefined) { if (name == "" || !std::filesystem::is_directory(PLUGIN_PATH((char*)"CheatMenu"))) { return; } - m_FilePath = PLUGIN_PATH((char*)"/CheatMenu/json/") + std::string(name) + ".json"; + if (!pathPredefined) + { + m_FilePath = PLUGIN_PATH((char*)"/CheatMenu/json/") + std::string(name) + ".json"; + } if (std::filesystem::exists(m_FilePath)) { diff --git a/src/json.h b/src/json.h index cf430e2..40df9c2 100644 --- a/src/json.h +++ b/src/json.h @@ -47,8 +47,7 @@ public: } } - template <> - std::string GetValue(std::string&& key, std::string&& defaultVal) + std::string GetValueStr(const std::string& key, const std::string& defaultVal) { try { @@ -119,5 +118,5 @@ public: Saves json data to disk */ void WriteToDisk(); - CJson(const char* text = ""); + CJson(const char* text, bool pathPredefined = false); }; diff --git a/src/locale.cpp b/src/locale.cpp new file mode 100644 index 0000000..2ada4e5 --- /dev/null +++ b/src/locale.cpp @@ -0,0 +1,91 @@ +#include "pch.h" +#include "locale.h" +#include + +Locale::eReturnCodes Locale::Init(const char* path) +{ + std::string localePath = path; + if (localePath.back() != '/') + { + localePath += '/'; + } + +#ifdef _GTA_ + m_path = PLUGIN_PATH((char*)localePath.c_str()); +#else + m_path = localePath; +#endif + + if (!std::filesystem::exists(m_path)) + { +#ifdef _GTA_ + gLog << "Locale directory doesn't exist" << std::endl; +#endif + return eReturnCodes::DIR_NOT_FOUND; + } + + + /* + Get the list of available languages + We won't load them here, we'll load them when we need them + */ +#ifdef _GTA_ + gLog << "Loading languages..." << std::endl; +#endif + for (auto& entry : std::filesystem::directory_iterator(m_path)) + { + if (entry.path().extension() == ".json") + { +#ifdef _GTA_ + gLog << "Found locale: " << entry.path().stem().string() << std::endl; +#endif + m_locales.push_back(entry.path().stem().string()); + } + } + + if (sizeof(m_locales) == 0) + { +#ifdef _GTA_ + gLog << "No language files found" << std::endl; +#endif + return eReturnCodes::NO_LOCALE_FOUND; + } + + return eReturnCodes::SUCCESS; +} + +std::vector& Locale::GetLocaleList() +{ + return m_locales; +} + +std::string Locale::GetText(std::string&& key, std::string&& defaultValue) +{ + if (m_pJson == nullptr) + { + return defaultValue; + } + + return m_pJson->GetValueStr(key, defaultValue); +} + +Locale::eReturnCodes Locale::SetLocale(int index) +{ + if(m_pJson) + { + delete m_pJson; + m_pJson = nullptr; + } + + if (index < 0 || index >= m_locales.size()) + { + return eReturnCodes::INVALID_INDEX; + } + + std::string localeFile = m_locales[index]; + localeFile += ".json"; + std::string localePath = m_path + localeFile; + m_pJson = new CJson(localePath.c_str()); + return eReturnCodes::SUCCESS; +} + diff --git a/src/locale.h b/src/locale.h new file mode 100644 index 0000000..b7f5ae6 --- /dev/null +++ b/src/locale.h @@ -0,0 +1,57 @@ +#pragma once +#include +#include +#include "json.h" + +/* + A custom i18n library + Loads strings from a json file + Requires the CJson class +*/ +class Locale +{ +private: + static inline std::vector m_locales; + static inline std::string m_path; + static inline CJson *m_pJson = nullptr; + +public: + + enum class eReturnCodes + { + DIR_NOT_FOUND = 0, // Failed to find the language directory + NO_LOCALE_FOUND = 1, // Failed to find language files + INVALID_INDEX = 2, // Invalid langauge index for GetLocaleList() + SUCCESS = 3, + }; + + Locale() = delete; + Locale(Locale const&) = delete; + void operator=(Locale const&) = delete; + + /* + Loads json files from the locale directory + Calling it multiple times will unload previous data + */ + static eReturnCodes Init(const char* path); + + // Returns a vector of available languages + static std::vector& GetLocaleList(); + + /* + Returns the string for the given key for the language specified + If the key is not found, returns the defaultValue + + You need to call SetLanguage once before calling this function + By default, the language is set to "en" + */ + static std::string GetText(std::string&& key, std::string&& defaultValue); + + /* + Sets the language to use + If the language is not found, the default language is used + + index is the index of the language in the GetLocaleList() list + */ + static eReturnCodes SetLocale(int index); +}; \ No newline at end of file diff --git a/src/menu.cpp b/src/menu.cpp index f340358..2f70e78 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -350,21 +350,37 @@ void Menu::ProcessCommands() void Menu::ShowPage() { - ImGui::Spacing(); - if (ImGui::Button("Reset config", ImVec2(Ui::GetSize(2)))) - { - gConfig.m_Data.clear(); - SetHelpMessage("Config has been reset. Restart the game for it to take effect.", false, false, false); - } - ImGui::SameLine(); - if (ImGui::Button("Reset size", ImVec2(Ui::GetSize(2)))) - { - CheatMenu::ResetMenuSize(); - } - - ImGui::Spacing(); if (ImGui::BeginTabBar("Menu", ImGuiTabBarFlags_NoTooltip + ImGuiTabBarFlags_FittingPolicyScroll)) { + if (ImGui::BeginTabItem("Config")) + { + ImGui::Spacing(); + if (ImGui::Button("Reset config", ImVec2(Ui::GetSize(2)))) + { + gConfig.m_Data.clear(); + SetHelpMessage("Config has been reset. Restart the game for it to take effect.", false, false, false); + } + ImGui::SameLine(); + if (ImGui::Button("Reset size", ImVec2(Ui::GetSize(2)))) + { + CheatMenu::ResetMenuSize(); + } + ImGui::Spacing(); + + static int selected = 0; + if (Ui::ListBox("Language", Locale::GetLocaleList(), selected)) + { + if (Locale::SetLocale(selected) == Locale::eReturnCodes::SUCCESS) + { + SetHelpMessage(Locale::GetText("Menu.LanguageChangeSuccess", "Language changed successfully!").c_str(), false, false, false); + } + else + { + SetHelpMessage(Locale::GetText("Menu.LanguageChangeFailed", "Failed to change language").c_str(), false, false, false); + } + } + ImGui::EndTabItem(); + } if (ImGui::BeginTabItem("Overlay")) { ImGui::Spacing(); diff --git a/src/pch.cpp b/src/pch.cpp index 6bc32aa..9155456 100644 --- a/src/pch.cpp +++ b/src/pch.cpp @@ -1,5 +1,7 @@ #include "pch.h" CJson gConfig = CJson("config"); +eRenderer gRenderer = Render_Unknown; +std::ofstream gLog = std::ofstream("CheatMenu.log"); Hotkey aimSkinChanger; Hotkey freeCam; diff --git a/src/pch.h b/src/pch.h index afb786b..e003ba0 100644 --- a/src/pch.h +++ b/src/pch.h @@ -6,6 +6,7 @@ #define DISCORD_INVITE "https://discord.gg/ZzW7kmf" #define GITHUB_LINK "https://github.com/user-grinch/Cheat-Menu" #define IMGUI_DEFINE_MATH_OPERATORS +#define _GTA_ #ifdef GTASA #define BY_GAME(sa, vc, iii) sa @@ -73,6 +74,7 @@ #include "vkeys.h" #include "resourcestore.h" #include "fontmgr.h" +#include "locale.h" using namespace plugin; @@ -83,10 +85,8 @@ enum eRenderer Render_Unknown }; -static eRenderer gRenderer = Render_Unknown; -static std::ofstream gLog = std::ofstream("CheatMenu.log"); -// why doesn't this work? -// inline CJson gConfig = CJson("config"); +extern eRenderer gRenderer; +extern std::ofstream gLog; extern CJson gConfig; // Fix function clashes