diff --git a/plugins/builtin/source/content/settings_entries.cpp b/plugins/builtin/source/content/settings_entries.cpp index 8c681030c..f98b67ae6 100644 --- a/plugins/builtin/source/content/settings_entries.cpp +++ b/plugins/builtin/source/content/settings_entries.cpp @@ -4,6 +4,56 @@ namespace hex::plugin::builtin { void registerSettings() { + ContentRegistry::Settings::add("Interface", "Color theme", 0, [](nlohmann::json &setting) { + static int selection = setting; + if (ImGui::Combo("##color_theme", &selection, "Dark\0Light\0Classic\0")) { + setting = selection; + return true; + } + + return false; + }); + + ContentRegistry::Settings::add("Interface", "Language", "en-US", [](nlohmann::json &setting) { + auto &languages = LangEntry::getSupportedLanguages(); + + static int selection = [&]() -> int { + u16 index = 0; + for (auto &[languageName, languageFile] : languages){ + if (languageFile == setting) + return index; + index++; + } + + return 0; + }(); + + static auto languageNames = [&]() { + std::vector result; + for (auto &[languageName, languageFile] : languages) + result.push_back(languageName.c_str()); + + return result; + }(); + + + if (ImGui::Combo("##language", &selection, languageNames.data(), languageNames.size())) { + + u16 index = 0; + for (auto &[languageName, languageFile] : languages){ + if (selection == index) { + setting = languageFile; + break; + } + index++; + } + + return true; + } + + return false; + }); + } } \ No newline at end of file diff --git a/plugins/libimhex/CMakeLists.txt b/plugins/libimhex/CMakeLists.txt index 57b18d09a..9c202db6b 100644 --- a/plugins/libimhex/CMakeLists.txt +++ b/plugins/libimhex/CMakeLists.txt @@ -23,6 +23,7 @@ add_library(libimhex SHARED source/helpers/utils.cpp source/helpers/shared_data.cpp source/helpers/crypto.cpp + source/helpers/lang.cpp source/lang/pattern_language.cpp source/lang/preprocessor.cpp diff --git a/plugins/libimhex/include/hex.hpp b/plugins/libimhex/include/hex.hpp index 1a53abcd9..d2039cb3b 100644 --- a/plugins/libimhex/include/hex.hpp +++ b/plugins/libimhex/include/hex.hpp @@ -3,6 +3,9 @@ #include #include +#include +using namespace hex::lang_literals; + using u8 = std::uint8_t; using u16 = std::uint16_t; using u32 = std::uint32_t; diff --git a/plugins/libimhex/include/hex/helpers/lang.hpp b/plugins/libimhex/include/hex/helpers/lang.hpp new file mode 100644 index 000000000..868272260 --- /dev/null +++ b/plugins/libimhex/include/hex/helpers/lang.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include + +namespace hex { + + class LangEntry { + public: + LangEntry(const char *unlocalizedString); + + operator std::string() const; + operator std::string_view() const; + operator const char*() const; + + std::string_view get() const; + + static void loadLanguage(std::string_view language); + static const std::map& getSupportedLanguages(); + + private: + std::string m_unlocalizedString; + }; + + namespace lang_literals { + + LangEntry operator""_lang(const char *string, size_t) { + return LangEntry(string); + } + + } + + + +} \ No newline at end of file diff --git a/plugins/libimhex/include/hex/helpers/shared_data.hpp b/plugins/libimhex/include/hex/helpers/shared_data.hpp index 7bddff038..b4d23a2ef 100644 --- a/plugins/libimhex/include/hex/helpers/shared_data.hpp +++ b/plugins/libimhex/include/hex/helpers/shared_data.hpp @@ -63,6 +63,7 @@ namespace hex { static u32 patternPaletteOffset; static std::string errorPopupMessage; static std::list bookmarkEntries; + static std::map loadedLanguage; static imgui_addons::ImGuiFileBrowser fileBrowser; static imgui_addons::ImGuiFileBrowser::DialogMode fileBrowserDialogMode; diff --git a/plugins/libimhex/source/helpers/lang.cpp b/plugins/libimhex/source/helpers/lang.cpp new file mode 100644 index 000000000..43f8c55aa --- /dev/null +++ b/plugins/libimhex/source/helpers/lang.cpp @@ -0,0 +1,87 @@ +#include "hex/helpers/lang.hpp" + +#include "hex/helpers/shared_data.hpp" + +#include +#include +#include + +namespace hex { + + LangEntry::LangEntry(const char *unlocalizedString) : m_unlocalizedString(unlocalizedString) { } + + LangEntry::operator std::string() const { + return std::string(get()); + } + + LangEntry::operator std::string_view() const { + return get(); + } + + LangEntry::operator const char*() const { + return get().data(); + } + + std::string_view LangEntry::get() const { + auto &lang = SharedData::loadedLanguage; + if (lang.find(this->m_unlocalizedString) != lang.end()) + return lang[this->m_unlocalizedString]; + else + return this->m_unlocalizedString; + } + + void LangEntry::loadLanguage(std::string_view language) { + SharedData::loadedLanguage.clear(); + + bool isDefaultLanguage = language == "en-US"; + + try { + std::ifstream languageFile("lang/" + std::string(language) + ".json"); + nlohmann::json languageJson; + + if (!languageFile.is_open() && !isDefaultLanguage) + languageFile.open("lang/en-US.json"); + + languageFile >> languageJson; + + for (auto &[unlocalizedString, localizedString] : languageJson["lang"].items()) + SharedData::loadedLanguage.insert({ unlocalizedString, localizedString }); + + if (!isDefaultLanguage) { + languageFile.open("lang/en-US.json"); + if (!languageFile.good()) + return; + + languageFile >> languageJson; + + for (auto &[unlocalizedString, localizedString] : languageJson["lang"].items()) + SharedData::loadedLanguage.insert({ unlocalizedString, localizedString }); + } + } catch (std::exception &e) { + printf("Language load error: %s\n", e.what()); + + if (!isDefaultLanguage) + loadLanguage("en-US"); + } + + } + + const std::map& LangEntry::getSupportedLanguages() { + static std::map languages; + + if (languages.empty()) { + for (auto &entry : std::filesystem::directory_iterator("lang")) { + try { + std::ifstream file(entry.path()); + nlohmann::json json; + file >> json; + + languages.insert({ json["name"].get(), entry.path().stem().string() }); + } catch (std::exception &e) {} + } + } + + return languages; + } + +} \ No newline at end of file diff --git a/plugins/libimhex/source/helpers/shared_data.cpp b/plugins/libimhex/source/helpers/shared_data.cpp index a941a0adc..13859eaf2 100644 --- a/plugins/libimhex/source/helpers/shared_data.cpp +++ b/plugins/libimhex/source/helpers/shared_data.cpp @@ -17,6 +17,7 @@ namespace hex { u32 SharedData::patternPaletteOffset; std::string SharedData::errorPopupMessage; std::list SharedData::bookmarkEntries; + std::map SharedData::loadedLanguage; imgui_addons::ImGuiFileBrowser SharedData::fileBrowser; imgui_addons::ImGuiFileBrowser::DialogMode SharedData::fileBrowserDialogMode; diff --git a/source/main.cpp b/source/main.cpp index 2b2334f0d..f630a0c86 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,3 +1,5 @@ +#include + #include "window.hpp" #include @@ -51,7 +53,6 @@ int main(int argc, char **argv) { if (argc > 1) View::postEvent(Events::FileDropped, argv[1]); - window.initPlugins(); window.loop(); diff --git a/source/window.cpp b/source/window.cpp index a7f72b33c..becc3afec 100644 --- a/source/window.cpp +++ b/source/window.cpp @@ -51,33 +51,32 @@ namespace hex { this->initGLFW(); this->initImGui(); - - ContentRegistry::Settings::add("Interface", "Color theme", 0, [](nlohmann::json &setting) { - static int selection = setting; - if (ImGui::Combo("##nolabel", &selection, "Dark\0Light\0Classic\0")) { - setting = selection; - return true; - } - - return false; - }); + this->initPlugins(); ImGui::GetStyle().Colors[ImGuiCol_DockingEmptyBg] = ImGui::GetStyle().Colors[ImGuiCol_WindowBg]; EventManager::subscribe(Events::SettingsChanged, this, [](auto) -> std::any { - int theme = ContentRegistry::Settings::getSettingsData()["Interface"]["Color theme"]; - switch (theme) { - default: - case 0: /* Dark theme */ - ImGui::StyleColorsDark(); - break; - case 1: /* Light theme */ - ImGui::StyleColorsLight(); - break; - case 2: /* Classic theme */ - ImGui::StyleColorsClassic(); - break; + + { + int theme = ContentRegistry::Settings::getSettingsData()["Interface"]["Color theme"]; + switch (theme) { + default: + case 0: /* Dark theme */ + ImGui::StyleColorsDark(); + break; + case 1: /* Light theme */ + ImGui::StyleColorsLight(); + break; + case 2: /* Classic theme */ + ImGui::StyleColorsClassic(); + break; + } + ImGui::GetStyle().Colors[ImGuiCol_DockingEmptyBg] = ImGui::GetStyle().Colors[ImGuiCol_WindowBg]; + } + + { + std::string language = ContentRegistry::Settings::getSettingsData()["Interface"]["Language"]; + LangEntry::loadLanguage(language); } - ImGui::GetStyle().Colors[ImGuiCol_DockingEmptyBg] = ImGui::GetStyle().Colors[ImGuiCol_WindowBg]; return { }; }); @@ -201,6 +200,7 @@ namespace hex { } void Window::frameBegin() { + printf("%s\n", static_cast("hello.world"_lang)); glfwPollEvents(); ImGui_ImplOpenGL3_NewFrame();