123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- /*
- * TextLocalizationContainer.cpp, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
- #include "StdInc.h"
- #include "TextLocalizationContainer.h"
- #include "texts/CGeneralTextHandler.h"
- #include "Languages.h"
- #include "TextOperations.h"
- #include "../VCMI_Lib.h"
- #include "../json/JsonNode.h"
- #include "../modding/CModHandler.h"
- VCMI_LIB_NAMESPACE_BEGIN
- std::recursive_mutex TextLocalizationContainer::globalTextMutex;
- void TextLocalizationContainer::registerStringOverride(const std::string & modContext, const TextIdentifier & UID, const std::string & localized)
- {
- std::lock_guard globalLock(globalTextMutex);
- assert(!modContext.empty());
- // NOTE: implicitly creates entry, intended - strings added by maps, campaigns, vcmi and potentially - UI mods are not registered anywhere at the moment
- auto & entry = stringsLocalizations[UID.get()];
- // load string override only in following cases:
- // a) string was not modified in another mod (e.g. rebalance mod gave skill new description)
- // b) this string override is defined in the same mod as one that provided modified version of this string
- if (entry.identifierModContext == entry.baseStringModContext || modContext == entry.baseStringModContext)
- {
- entry.translatedText = localized;
- if (entry.identifierModContext.empty())
- {
- entry.identifierModContext = modContext;
- entry.baseStringModContext = modContext;
- }
- }
- else
- {
- logGlobal->debug("Skipping translation override for string %s: changed in a different mod", UID.get());
- }
- }
- void TextLocalizationContainer::addSubContainer(const TextLocalizationContainer & container)
- {
- std::lock_guard globalLock(globalTextMutex);
- assert(!vstd::contains(subContainers, &container));
- subContainers.push_back(&container);
- }
- void TextLocalizationContainer::removeSubContainer(const TextLocalizationContainer & container)
- {
- std::lock_guard globalLock(globalTextMutex);
- assert(vstd::contains(subContainers, &container));
- subContainers.erase(std::remove(subContainers.begin(), subContainers.end(), &container), subContainers.end());
- }
- const std::string & TextLocalizationContainer::translateString(const TextIdentifier & identifier) const
- {
- std::lock_guard globalLock(globalTextMutex);
- if(stringsLocalizations.count(identifier.get()) == 0)
- {
- for(auto containerIter = subContainers.rbegin(); containerIter != subContainers.rend(); ++containerIter)
- if((*containerIter)->identifierExists(identifier))
- return (*containerIter)->translateString(identifier);
- logGlobal->error("Unable to find localization for string '%s'", identifier.get());
- return identifier.get();
- }
- const auto & entry = stringsLocalizations.at(identifier.get());
- return entry.translatedText;
- }
- void TextLocalizationContainer::registerString(const std::string & modContext, const TextIdentifier & inputUID, const JsonNode & localized)
- {
- assert(localized.isNull() || !localized.getModScope().empty());
- assert(localized.isNull() || !getModLanguage(localized.getModScope()).empty());
- if (localized.isNull())
- registerString(modContext, modContext, inputUID, localized.String());
- else
- registerString(modContext, localized.getModScope(), inputUID, localized.String());
- }
- void TextLocalizationContainer::registerString(const std::string & modContext, const TextIdentifier & UID, const std::string & localized)
- {
- registerString(modContext, modContext, UID, localized);
- }
- void TextLocalizationContainer::registerString(const std::string & identifierModContext, const std::string & localizedStringModContext, const TextIdentifier & UID, const std::string & localized)
- {
- std::lock_guard globalLock(globalTextMutex);
- assert(!identifierModContext.empty());
- assert(!localizedStringModContext.empty());
- assert(UID.get().find("..") == std::string::npos); // invalid identifier - there is section that was evaluated to empty string
- assert(stringsLocalizations.count(UID.get()) == 0 || boost::algorithm::starts_with(UID.get(), "map")); // registering already registered string?
- if(stringsLocalizations.count(UID.get()) > 0)
- {
- auto & value = stringsLocalizations[UID.get()];
- value.translatedText = localized;
- value.identifierModContext = identifierModContext;
- value.baseStringModContext = localizedStringModContext;
- }
- else
- {
- StringState value;
- value.translatedText = localized;
- value.identifierModContext = identifierModContext;
- value.baseStringModContext = localizedStringModContext;
- stringsLocalizations[UID.get()] = value;
- }
- }
- void TextLocalizationContainer::loadTranslationOverrides(const std::string & modContext, const JsonNode & config)
- {
- for(const auto & node : config.Struct())
- registerStringOverride(modContext, node.first, node.second.String());
- }
- bool TextLocalizationContainer::identifierExists(const TextIdentifier & UID) const
- {
- std::lock_guard globalLock(globalTextMutex);
- return stringsLocalizations.count(UID.get());
- }
- void TextLocalizationContainer::exportAllTexts(std::map<std::string, std::map<std::string, std::string>> & storage) const
- {
- std::lock_guard globalLock(globalTextMutex);
- for (auto const & subContainer : subContainers)
- subContainer->exportAllTexts(storage);
- for (auto const & entry : stringsLocalizations)
- {
- std::string textToWrite;
- std::string modName = entry.second.baseStringModContext;
- if (entry.second.baseStringModContext == entry.second.identifierModContext)
- {
- if (modName.find('.') != std::string::npos)
- modName = modName.substr(0, modName.find('.'));
- }
- boost::range::replace(modName, '.', '_');
- textToWrite = entry.second.translatedText;
- if (!textToWrite.empty())
- storage[modName][entry.first] = textToWrite;
- }
- }
- std::string TextLocalizationContainer::getModLanguage(const std::string & modContext)
- {
- if (modContext == "core")
- return CGeneralTextHandler::getInstalledLanguage();
- return VLC->modh->getModLanguage(modContext);
- }
- void TextLocalizationContainer::jsonSerialize(JsonNode & dest) const
- {
- std::lock_guard globalLock(globalTextMutex);
- for(auto & s : stringsLocalizations)
- dest.Struct()[s.first].String() = s.second.translatedText;
- }
- TextContainerRegistrable::TextContainerRegistrable()
- {
- VLC->generaltexth->addSubContainer(*this);
- }
- TextContainerRegistrable::~TextContainerRegistrable()
- {
- VLC->generaltexth->removeSubContainer(*this);
- }
- TextContainerRegistrable::TextContainerRegistrable(const TextContainerRegistrable & other)
- : TextLocalizationContainer(other)
- {
- VLC->generaltexth->addSubContainer(*this);
- }
- TextContainerRegistrable::TextContainerRegistrable(TextContainerRegistrable && other) noexcept
- :TextLocalizationContainer(other)
- {
- VLC->generaltexth->addSubContainer(*this);
- }
- VCMI_LIB_NAMESPACE_END
|