| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- /*
- * 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 std::string & language, const TextIdentifier & UID, const std::string & localized)
- {
- std::lock_guard globalLock(globalTextMutex);
- assert(!modContext.empty());
- assert(!language.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()];
- entry.overrideLanguage = language;
- entry.overrideValue = localized;
- if (entry.modContext.empty())
- entry.modContext = modContext;
- }
- 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::deserialize(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)->deserialize(identifier);
- logGlobal->error("Unable to find localization for string '%s'", identifier.get());
- return identifier.get();
- }
- const auto & entry = stringsLocalizations.at(identifier.get());
- if (!entry.overrideValue.empty())
- return entry.overrideValue;
- return entry.baseValue;
- }
- void TextLocalizationContainer::registerString(const std::string & modContext, const TextIdentifier & UID, const std::string & localized, const std::string & language)
- {
- std::lock_guard globalLock(globalTextMutex);
- assert(!modContext.empty());
- assert(!Languages::getLanguageOptions(language).identifier.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); // registering already registered string?
- if(stringsLocalizations.count(UID.get()) > 0)
- {
- auto & value = stringsLocalizations[UID.get()];
- value.baseLanguage = language;
- value.baseValue = localized;
- }
- else
- {
- StringState value;
- value.baseLanguage = language;
- value.baseValue = localized;
- value.modContext = modContext;
- stringsLocalizations[UID.get()] = value;
- }
- }
- void TextLocalizationContainer::registerString(const std::string & modContext, const TextIdentifier & UID, const std::string & localized)
- {
- assert(!getModLanguage(modContext).empty());
- registerString(modContext, UID, localized, getModLanguage(modContext));
- }
- bool TextLocalizationContainer::validateTranslation(const std::string & language, const std::string & modContext, const JsonNode & config) const
- {
- std::lock_guard globalLock(globalTextMutex);
- bool allPresent = true;
- for(const auto & string : stringsLocalizations)
- {
- if (string.second.modContext != modContext)
- continue; // Not our mod
- if (string.second.overrideLanguage == language)
- continue; // Already translated
- if (string.second.baseLanguage == language && !string.second.baseValue.empty())
- continue; // Base string already uses our language
- if (string.second.baseLanguage.empty())
- continue; // String added in localization, not present in base language (e.g. maps/campaigns)
- if (config.Struct().count(string.first) > 0)
- continue;
- if (allPresent)
- logMod->warn("Translation into language '%s' in mod '%s' is incomplete! Missing lines:", language, modContext);
- std::string currentText;
- if (string.second.overrideValue.empty())
- currentText = string.second.baseValue;
- else
- currentText = string.second.overrideValue;
- logMod->warn(R"( "%s" : "%s",)", string.first, TextOperations::escapeString(currentText));
- allPresent = false;
- }
- bool allFound = true;
- // for(const auto & string : config.Struct())
- // {
- // if (stringsLocalizations.count(string.first) > 0)
- // continue;
- //
- // if (allFound)
- // logMod->warn("Translation into language '%s' in mod '%s' has unused lines:", language, modContext);
- //
- // logMod->warn(R"( "%s" : "%s",)", string.first, TextOperations::escapeString(string.second.String()));
- // allFound = false;
- // }
- return allPresent && allFound;
- }
- void TextLocalizationContainer::loadTranslationOverrides(const std::string & language, const std::string & modContext, const JsonNode & config)
- {
- for(const auto & node : config.Struct())
- registerStringOverride(modContext, language, 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.modContext;
- if (modName.find('.') != std::string::npos)
- modName = modName.substr(0, modName.find('.'));
- if (!entry.second.overrideValue.empty())
- textToWrite = entry.second.overrideValue;
- else
- textToWrite = entry.second.baseValue;
- 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.baseValue;
- if(!s.second.overrideValue.empty())
- dest.Struct()[s.first].String() = s.second.overrideValue;
- }
- }
- 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
|