diff --git a/lib/libimhex/include/hex/api/localization_manager.hpp b/lib/libimhex/include/hex/api/localization_manager.hpp index 1551b8801..104e444e5 100644 --- a/lib/libimhex/include/hex/api/localization_manager.hpp +++ b/lib/libimhex/include/hex/api/localization_manager.hpp @@ -1,11 +1,14 @@ #pragma once +#include + #include #include #include #include #include +#include namespace hex { @@ -22,8 +25,10 @@ namespace hex { }; namespace impl { + void setFallbackLanguage(const std::string &language); void resetLanguageStrings(); + } void loadLanguage(const std::string &language); @@ -32,6 +37,7 @@ namespace hex { [[nodiscard]] const std::map &getSupportedLanguages(); [[nodiscard]] const std::string &getFallbackLanguage(); [[nodiscard]] const std::string &getSelectedLanguage(); + } struct UnlocalizedString; @@ -47,10 +53,30 @@ namespace hex { [[nodiscard]] operator std::string_view() const; [[nodiscard]] operator const char *() const; - [[nodiscard]] const std::string &get() const; + const std::string &get() const; + + constexpr static size_t hash(std::string_view string){ + constexpr u64 p = 131; + constexpr u64 m = std::numeric_limits::max() - 4; // Largest 32 bit prime + u64 total = 0; + u64 currentMultiplier = 1; + + for (char c : string) { + total = (total + currentMultiplier * c) % m; + currentMultiplier = (currentMultiplier * p) % m; + } + + return total; + } private: - std::string m_unlocalizedString; + constexpr explicit Lang(std::size_t hash) : m_entryHash(hash) {} + + template + friend consteval Lang operator""_lang(); + + private: + std::size_t m_entryHash; }; [[nodiscard]] std::string operator+(const std::string &&left, const Lang &&right); @@ -61,14 +87,16 @@ namespace hex { [[nodiscard]] std::string operator+(const Lang &&left, const char *right); [[nodiscard]] std::string operator+(const Lang &&left, const Lang &&right); - [[nodiscard]] inline Lang operator""_lang(const char *string, size_t) { - return Lang(string); + template + [[nodiscard]] consteval Lang operator""_lang() { + return Lang(Lang::hash(String.value.data())); } struct UnlocalizedString { public: UnlocalizedString() = default; + UnlocalizedString(auto && arg) : m_unlocalizedString(std::forward(arg)) { static_assert(!std::same_as, Lang>, "Expected a unlocalized name, got a localized one!"); } @@ -107,4 +135,4 @@ namespace hex { return entry.get(); } -} \ No newline at end of file +} diff --git a/lib/libimhex/source/api/localization_manager.cpp b/lib/libimhex/source/api/localization_manager.cpp index 2d9b05764..4d58d4ff7 100644 --- a/lib/libimhex/source/api/localization_manager.cpp +++ b/lib/libimhex/source/api/localization_manager.cpp @@ -10,7 +10,7 @@ namespace hex { AutoReset s_fallbackLanguage; AutoReset s_selectedLanguage; - AutoReset> s_currStrings; + AutoReset> s_currStrings; } @@ -41,6 +41,21 @@ namespace hex { return m_entries; } + static void loadLanguageDefinitions(const std::vector &definitions) { + for (const auto &definition : definitions) { + const auto &entries = definition.getEntries(); + if (entries.empty()) + continue; + + for (const auto &[key, value] : entries) { + if (value.empty()) + continue; + + s_currStrings->emplace(Lang::hash(key), value); + } + } + } + void loadLanguage(const std::string &language) { auto &definitions = ContentRegistry::Language::impl::getLanguageDefinitions(); @@ -49,14 +64,10 @@ namespace hex { s_currStrings->clear(); - for (const auto &definition : definitions.at(language)) - s_currStrings->insert(definition.getEntries().begin(), definition.getEntries().end()); + loadLanguageDefinitions(definitions.at(language)); const auto& fallbackLanguage = getFallbackLanguage(); - if (language != fallbackLanguage && definitions.contains(fallbackLanguage)) { - for (const auto &definition : definitions.at(fallbackLanguage)) - s_currStrings->insert(definition.getEntries().begin(), definition.getEntries().end()); - } + loadLanguageDefinitions(definitions.at(fallbackLanguage)); s_selectedLanguage = language; } @@ -98,11 +109,10 @@ namespace hex { } - Lang::Lang(const char *unlocalizedString) : m_unlocalizedString(unlocalizedString) { } - Lang::Lang(const std::string &unlocalizedString) : m_unlocalizedString(unlocalizedString) { } - Lang::Lang(const UnlocalizedString &unlocalizedString) : m_unlocalizedString(unlocalizedString.get()) { } - Lang::Lang(std::string_view unlocalizedString) : m_unlocalizedString(unlocalizedString) { } - + Lang::Lang(const char *unlocalizedString) : m_entryHash(hash(unlocalizedString)) { } + Lang::Lang(const std::string &unlocalizedString) : m_entryHash(hash(unlocalizedString)) { } + Lang::Lang(const UnlocalizedString &unlocalizedString) : m_entryHash(hash(unlocalizedString.get())) { } + Lang::Lang(std::string_view unlocalizedString) : m_entryHash(hash(unlocalizedString)) { } Lang::operator std::string() const { return get(); @@ -116,6 +126,18 @@ namespace hex { return get().c_str(); } + const std::string &Lang::get() const { + const auto &lang = *LocalizationManager::s_currStrings; + + auto it = lang.find(m_entryHash); + if (it == lang.end()) { + static const std::string invalidString = "[ !!! INVALID LANGUAGE STRING !!! ]"; + return invalidString; + } else { + return it->second; + } + } + std::string operator+(const std::string &&left, const Lang &&right) { return left + static_cast(right); } @@ -144,12 +166,4 @@ namespace hex { return static_cast(left) + right; } - const std::string &Lang::get() const { - auto &lang = LocalizationManager::s_currStrings; - if (lang->contains(m_unlocalizedString)) - return lang->at(m_unlocalizedString); - else - return m_unlocalizedString; - } - } \ No newline at end of file