Added Language setting and localization wrapper
This commit is contained in:
parent
a926b7b912
commit
bd5da4a36e
@ -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<const char*> 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;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
|
@ -3,6 +3,9 @@
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
#include <hex/helpers/lang.hpp>
|
||||
using namespace hex::lang_literals;
|
||||
|
||||
using u8 = std::uint8_t;
|
||||
using u16 = std::uint16_t;
|
||||
using u32 = std::uint32_t;
|
||||
|
36
plugins/libimhex/include/hex/helpers/lang.hpp
Normal file
36
plugins/libimhex/include/hex/helpers/lang.hpp
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
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<std::string, std::string>& getSupportedLanguages();
|
||||
|
||||
private:
|
||||
std::string m_unlocalizedString;
|
||||
};
|
||||
|
||||
namespace lang_literals {
|
||||
|
||||
LangEntry operator""_lang(const char *string, size_t) {
|
||||
return LangEntry(string);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -63,6 +63,7 @@ namespace hex {
|
||||
static u32 patternPaletteOffset;
|
||||
static std::string errorPopupMessage;
|
||||
static std::list<ImHexApi::Bookmarks::Entry> bookmarkEntries;
|
||||
static std::map<std::string, std::string> loadedLanguage;
|
||||
|
||||
static imgui_addons::ImGuiFileBrowser fileBrowser;
|
||||
static imgui_addons::ImGuiFileBrowser::DialogMode fileBrowserDialogMode;
|
||||
|
87
plugins/libimhex/source/helpers/lang.cpp
Normal file
87
plugins/libimhex/source/helpers/lang.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
#include "hex/helpers/lang.hpp"
|
||||
|
||||
#include "hex/helpers/shared_data.hpp"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
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<std::string, std::string>& LangEntry::getSupportedLanguages() {
|
||||
static std::map<std::string, std::string> 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<std::string>(), entry.path().stem().string() });
|
||||
} catch (std::exception &e) {}
|
||||
}
|
||||
}
|
||||
|
||||
return languages;
|
||||
}
|
||||
|
||||
}
|
@ -17,6 +17,7 @@ namespace hex {
|
||||
u32 SharedData::patternPaletteOffset;
|
||||
std::string SharedData::errorPopupMessage;
|
||||
std::list<ImHexApi::Bookmarks::Entry> SharedData::bookmarkEntries;
|
||||
std::map<std::string, std::string> SharedData::loadedLanguage;
|
||||
|
||||
imgui_addons::ImGuiFileBrowser SharedData::fileBrowser;
|
||||
imgui_addons::ImGuiFileBrowser::DialogMode SharedData::fileBrowserDialogMode;
|
||||
|
@ -1,3 +1,5 @@
|
||||
#include <hex.hpp>
|
||||
|
||||
#include "window.hpp"
|
||||
|
||||
#include <hex/api/content_registry.hpp>
|
||||
@ -51,7 +53,6 @@ int main(int argc, char **argv) {
|
||||
if (argc > 1)
|
||||
View::postEvent(Events::FileDropped, argv[1]);
|
||||
|
||||
window.initPlugins();
|
||||
window.loop();
|
||||
|
||||
|
||||
|
@ -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<const char*>("hello.world"_lang));
|
||||
glfwPollEvents();
|
||||
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
|
Loading…
Reference in New Issue
Block a user