diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 409f530d0b..ab0e8f3137 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -777,6 +777,18 @@ void OMW::Engine::prepareEngine() mEnvironment.setWorldModel(mWorld->getWorldModel()); mEnvironment.setWorldScene(mWorld->getWorldScene()); + const MWWorld::Store* gmst = &mWorld->getStore().get(); + mL10nManager->setGmstLoader([gmst](std::string_view gmstName) { + const ESM::GameSetting* res = gmst->search(gmstName); + if (res && res->mValue.getType() == ESM::VT_String) + return res->mValue.getString(); + else + { + Log(Debug::Error) << "GMST " << gmstName << " not found"; + return std::string("GMST:") + std::string(gmstName); + } + }); + mWindowManager->setStore(mWorld->getStore()); mWindowManager->initUI(); diff --git a/apps/openmw_test_suite/lua/test_l10n.cpp b/apps/openmw_test_suite/lua/test_l10n.cpp index 79f126df86..835492f13c 100644 --- a/apps/openmw_test_suite/lua/test_l10n.cpp +++ b/apps/openmw_test_suite/lua/test_l10n.cpp @@ -87,7 +87,7 @@ you_have_arrows: "Arrows count: {count}" internal::CaptureStdout(); l10n::Manager l10nManager(mVFS.get()); l10nManager.setPreferredLocales({ "de", "en" }); - EXPECT_THAT(internal::GetCapturedStdout(), "Preferred locales: de en\n"); + EXPECT_THAT(internal::GetCapturedStdout(), "Preferred locales: gmst de en\n"); l["l10n"] = LuaUtil::initL10nLoader(l, &l10nManager); @@ -114,7 +114,7 @@ you_have_arrows: "Arrows count: {count}" internal::CaptureStdout(); l10nManager.setPreferredLocales({ "en", "de" }); EXPECT_THAT(internal::GetCapturedStdout(), - "Preferred locales: en de\n" + "Preferred locales: gmst en de\n" "Language file \"l10n/Test1/en.yaml\" is enabled\n" "Language file \"l10n/Test1/de.yaml\" is enabled\n" "Language file \"l10n/Test2/en.yaml\" is enabled\n"); @@ -152,7 +152,7 @@ you_have_arrows: "Arrows count: {count}" internal::CaptureStdout(); l10nManager.setPreferredLocales({ "en-GB-oed", "de" }); EXPECT_THAT(internal::GetCapturedStdout(), - "Preferred locales: en_GB_OED de\n" + "Preferred locales: gmst en_GB_OED de\n" "Language file \"l10n/Test1/en.yaml\" is enabled\n" "Language file \"l10n/Test1/de.yaml\" is enabled\n" "Language file \"l10n/Test2/en.yaml\" is enabled\n"); diff --git a/components/l10n/manager.cpp b/components/l10n/manager.cpp index 3b6db4f774..333f1205c3 100644 --- a/components/l10n/manager.cpp +++ b/components/l10n/manager.cpp @@ -12,6 +12,7 @@ namespace l10n void Manager::setPreferredLocales(const std::vector& langs) { mPreferredLocales.clear(); + mPreferredLocales.push_back(icu::Locale("gmst")); std::set langSet; for (const auto& lang : langs) { @@ -90,6 +91,7 @@ namespace l10n throw std::runtime_error(std::string("Invalid l10n context name: ") + contextName); icu::Locale fallbackLocale(fallbackLocaleName.c_str()); std::shared_ptr ctx = std::make_shared(mPreferredLocales, fallbackLocale); + ctx->setGmstLoader(mGmstLoader); updateContext(contextName, *ctx); mCache.emplace(key, ctx); return ctx; diff --git a/components/l10n/manager.hpp b/components/l10n/manager.hpp index a75ccb3f9b..272009b68e 100644 --- a/components/l10n/manager.hpp +++ b/components/l10n/manager.hpp @@ -24,6 +24,7 @@ namespace l10n void dropCache() { mCache.clear(); } void setPreferredLocales(const std::vector& locales); const std::vector& getPreferredLocales() const { return mPreferredLocales; } + void setGmstLoader(std::function fn) { mGmstLoader = std::move(fn); } std::shared_ptr getContext( const std::string& contextName, const std::string& fallbackLocale = "en"); @@ -35,6 +36,7 @@ namespace l10n const VFS::Manager* mVFS; std::vector mPreferredLocales; std::map, std::shared_ptr> mCache; + std::function mGmstLoader; }; } diff --git a/components/l10n/messagebundles.cpp b/components/l10n/messagebundles.cpp index 75f0c325fe..4656116487 100644 --- a/components/l10n/messagebundles.cpp +++ b/components/l10n/messagebundles.cpp @@ -72,6 +72,7 @@ namespace l10n { YAML::Node data = YAML::Load(input); std::string localeName = lang.getName(); + const icu::Locale& langOrEn = localeName == "gmst" ? icu::Locale::getEnglish() : lang; for (const auto& it : data) { const auto key = it.first.as(); @@ -79,7 +80,7 @@ namespace l10n icu::UnicodeString pattern = icu::UnicodeString::fromUTF8(icu::StringPiece(value.data(), value.size())); icu::ErrorCode status; UParseError parseError; - icu::MessageFormat message(pattern, lang, parseError, status); + icu::MessageFormat message(pattern, langOrEn, parseError, status); if (checkSuccess(status, std::string("Failed to create message ") + key + " for locale " + lang.getName(), parseError)) { @@ -120,6 +121,20 @@ namespace l10n return formatMessage(key, argNames, argValues); } + static std::string loadGmst( + const std::function gmstLoader, const icu::MessageFormat* message) + { + icu::UnicodeString gmstNameUnicode; + std::string gmstName; + icu::ErrorCode success; + message->format(nullptr, nullptr, 0, gmstNameUnicode, success); + gmstNameUnicode.toUTF8String(gmstName); + if (gmstLoader) + return gmstLoader(gmstName); + else + return "GMST:" + gmstName; + } + std::string MessageBundles::formatMessage(std::string_view key, const std::vector& argNames, const std::vector& args) const { @@ -132,7 +147,11 @@ namespace l10n { message = findMessage(key, loc); if (message) + { + if (loc == "gmst") + return loadGmst(mGmstLoader, message); break; + } } // If no requested locales included the message, try the fallback locale if (!message) diff --git a/components/l10n/messagebundles.hpp b/components/l10n/messagebundles.hpp index d25000d8ab..f3e8f9db19 100644 --- a/components/l10n/messagebundles.hpp +++ b/components/l10n/messagebundles.hpp @@ -1,6 +1,7 @@ #ifndef COMPONENTS_L10N_MESSAGEBUNDLES_H #define COMPONENTS_L10N_MESSAGEBUNDLES_H +#include #include #include #include @@ -42,6 +43,7 @@ namespace l10n void load(std::istream& input, const icu::Locale& lang, const std::string& path); bool isLoaded(const icu::Locale& loc) const { return mBundles.find(loc.getName()) != mBundles.end(); } const icu::Locale& getFallbackLocale() const { return mFallbackLocale; } + void setGmstLoader(std::function fn) { mGmstLoader = std::move(fn); } private: // icu::Locale isn't hashable (or comparable), so we use the string form instead, which is canonicalized @@ -49,6 +51,7 @@ namespace l10n const icu::Locale mFallbackLocale; std::vector mPreferredLocaleStrings; std::vector mPreferredLocales; + std::function mGmstLoader; const icu::MessageFormat* findMessage(std::string_view key, const std::string& localeName) const; };