mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-27 23:37:05 -05:00
fix: Various font loading issues and Weblate fuck ups
This commit is contained in:
@@ -13,6 +13,9 @@
|
||||
|
||||
EXPORT_MODULE namespace hex {
|
||||
|
||||
struct UnlocalizedString;
|
||||
using LanguageId = std::string;
|
||||
|
||||
namespace LocalizationManager {
|
||||
|
||||
struct PathEntry {
|
||||
@@ -21,25 +24,23 @@ EXPORT_MODULE namespace hex {
|
||||
};
|
||||
|
||||
struct LanguageDefinition {
|
||||
std::string id;
|
||||
LanguageId id;
|
||||
std::string name, nativeName;
|
||||
std::string flag;
|
||||
std::string filePath;
|
||||
std::string fallbackLanguageId;
|
||||
LanguageId fallbackLanguageId;
|
||||
|
||||
std::vector<PathEntry> languageFilePaths;
|
||||
};
|
||||
|
||||
void addLanguages(const std::string_view &languageList, std::function<std::string_view(const std::string &path)> callback);
|
||||
void setLanguage(const std::string &languageId);
|
||||
[[nodiscard]] const std::string& getSelectedLanguageId();
|
||||
[[nodiscard]] const std::string& get(const std::string &unlocalizedString);
|
||||
[[nodiscard]] const std::map<std::string, LanguageDefinition>& getLanguageDefinitions();
|
||||
void setLanguage(const LanguageId &languageId);
|
||||
[[nodiscard]] const LanguageId& getSelectedLanguageId();
|
||||
[[nodiscard]] const std::string& get(const LanguageId& languageId, const UnlocalizedString &unlocalizedString);
|
||||
[[nodiscard]] const std::map<LanguageId, LanguageDefinition>& getLanguageDefinitions();
|
||||
|
||||
}
|
||||
|
||||
struct UnlocalizedString;
|
||||
|
||||
class LangConst;
|
||||
|
||||
class Lang {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
@@ -11,9 +12,9 @@ namespace hex {
|
||||
|
||||
namespace {
|
||||
|
||||
AutoReset<std::map<std::string, LanguageDefinition>> s_languageDefinitions;
|
||||
AutoReset<std::map<LanguageId, LanguageDefinition>> s_languageDefinitions;
|
||||
AutoReset<std::unordered_map<std::size_t, std::string>> s_localizations;
|
||||
AutoReset<std::string> s_selectedLanguageId;
|
||||
AutoReset<LanguageId> s_selectedLanguageId;
|
||||
|
||||
}
|
||||
|
||||
@@ -40,44 +41,100 @@ namespace hex {
|
||||
definition.fallbackLanguageId = item["fallback"].get<std::string>();
|
||||
}
|
||||
|
||||
definition.languageFilePaths.emplace_back(PathEntry{ item["path"].get<std::string>(), std::move(callback) });
|
||||
const auto path = item["path"].get<std::string>();
|
||||
|
||||
definition.languageFilePaths.emplace_back(PathEntry{ path, callback });
|
||||
}
|
||||
}
|
||||
|
||||
static void populateLocalization(const std::string &languageId) {
|
||||
if (languageId.empty())
|
||||
return;
|
||||
static LanguageId findBestLanguageMatch(LanguageId languageId) {
|
||||
if (s_languageDefinitions->contains(languageId))
|
||||
return languageId;
|
||||
|
||||
log::debug("Populating localization for language: {}", languageId);
|
||||
if (const auto pos = languageId.find('_'); pos != std::string::npos) {
|
||||
// Turn language Ids like "en_US" into "en-US"
|
||||
languageId[pos] = '-';
|
||||
}
|
||||
|
||||
const auto &definition = (*s_languageDefinitions)[languageId];
|
||||
for (const auto &path : definition.languageFilePaths) {
|
||||
const auto translation = path.callback(path.path);
|
||||
const auto json = nlohmann::json::parse(translation);
|
||||
if (const auto pos = languageId.find('-'); pos != std::string::npos) {
|
||||
// Try to find a match with the language code without region
|
||||
languageId = languageId.substr(0, pos);
|
||||
|
||||
for (const auto &entry : json.items()) {
|
||||
auto value = entry.value().get<std::string>();
|
||||
if (value.empty())
|
||||
continue;
|
||||
|
||||
s_localizations->try_emplace(LangConst::hash(entry.key()), std::move(value));
|
||||
for (const auto &definition : *s_languageDefinitions) {
|
||||
if (definition.first.starts_with(languageId) || definition.first.starts_with(toLower(languageId))) {
|
||||
return definition.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
populateLocalization(definition.fallbackLanguageId);
|
||||
// Fall back to English if no better match was found
|
||||
return "en-US";
|
||||
}
|
||||
|
||||
void setLanguage(const std::string &languageId) {
|
||||
static void populateLocalization(LanguageId languageId, std::unordered_map<std::size_t, std::string> &localizations) {
|
||||
if (languageId.empty())
|
||||
return;
|
||||
|
||||
languageId = findBestLanguageMatch(languageId);
|
||||
|
||||
if (const auto it = s_languageDefinitions->find(languageId); it == s_languageDefinitions->end()) {
|
||||
log::error("No language definition found for language: {}", languageId);
|
||||
|
||||
constexpr static auto FallbackLanguageId = "en-US";
|
||||
if (languageId != FallbackLanguageId)
|
||||
populateLocalization(FallbackLanguageId, localizations);
|
||||
} else {
|
||||
const auto &definition = it->second;
|
||||
for (const auto &path : definition.languageFilePaths) {
|
||||
try {
|
||||
const auto translation = path.callback(path.path);
|
||||
const auto json = nlohmann::json::parse(translation);
|
||||
|
||||
for (const auto &entry : json.items()) {
|
||||
auto value = entry.value().get<std::string>();
|
||||
if (value.empty())
|
||||
continue;
|
||||
|
||||
localizations.try_emplace(LangConst::hash(entry.key()), std::move(value));
|
||||
}
|
||||
} catch (std::exception &e) {
|
||||
log::error("Failed to load localization file '{}': {}", path.path, e.what());
|
||||
}
|
||||
}
|
||||
|
||||
populateLocalization(definition.fallbackLanguageId, localizations);
|
||||
}
|
||||
}
|
||||
|
||||
void setLanguage(const LanguageId &languageId) {
|
||||
if (*s_selectedLanguageId == languageId)
|
||||
return;
|
||||
|
||||
s_localizations->clear();
|
||||
s_selectedLanguageId = languageId;
|
||||
|
||||
populateLocalization(languageId);
|
||||
populateLocalization(languageId, s_localizations);
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string& getSelectedLanguageId() {
|
||||
return *s_selectedLanguageId;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string& get(const LanguageId &languageId, const UnlocalizedString &unlocalizedString) {
|
||||
static AutoReset<LanguageId> currentLanguageId;
|
||||
static AutoReset<std::unordered_map<std::size_t, std::string>> loadedLocalization;
|
||||
static std::mutex mutex;
|
||||
|
||||
std::lock_guard lock(mutex);
|
||||
if (*currentLanguageId != languageId) {
|
||||
currentLanguageId = languageId;
|
||||
loadedLocalization->clear();
|
||||
populateLocalization(languageId, *loadedLocalization);
|
||||
}
|
||||
|
||||
return (*loadedLocalization)[LangConst::hash(unlocalizedString.get())];
|
||||
}
|
||||
|
||||
const std::map<std::string, LanguageDefinition>& getLanguageDefinitions() {
|
||||
return *s_languageDefinitions;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user