diff --git a/lib/CArtHandler.cpp b/lib/CArtHandler.cpp index 5b3f82a0d..07b83dec3 100644 --- a/lib/CArtHandler.cpp +++ b/lib/CArtHandler.cpp @@ -431,9 +431,9 @@ std::shared_ptr CArtHandler::loadFromJson(const std::string & scope, const JsonNode & text = node["text"]; - VLC->generaltexth->registerString(scope, art->getNameTextID(), text["name"].String()); - VLC->generaltexth->registerString(scope, art->getDescriptionTextID(), text["description"].String()); - VLC->generaltexth->registerString(scope, art->getEventTextID(), text["event"].String()); + VLC->generaltexth->registerString(scope, art->getNameTextID(), text["name"]); + VLC->generaltexth->registerString(scope, art->getDescriptionTextID(), text["description"]); + VLC->generaltexth->registerString(scope, art->getEventTextID(), text["event"]); const JsonNode & graphics = node["graphics"]; art->image = graphics["image"].String(); diff --git a/lib/CBonusTypeHandler.cpp b/lib/CBonusTypeHandler.cpp index 799bf2632..666f4e86e 100644 --- a/lib/CBonusTypeHandler.cpp +++ b/lib/CBonusTypeHandler.cpp @@ -240,8 +240,8 @@ void CBonusTypeHandler::loadItem(const JsonNode & source, CBonusType & dest, con if (!dest.hidden) { - VLC->generaltexth->registerString( "vcmi", dest.getNameTextID(), source["name"].String()); - VLC->generaltexth->registerString( "vcmi", dest.getDescriptionTextID(), source["description"].String()); + VLC->generaltexth->registerString( "vcmi", dest.getNameTextID(), source["name"]); + VLC->generaltexth->registerString( "vcmi", dest.getDescriptionTextID(), source["description"]); } const JsonNode & graphics = source["graphics"]; diff --git a/lib/CCreatureHandler.cpp b/lib/CCreatureHandler.cpp index 546aed9b7..f34608fd2 100644 --- a/lib/CCreatureHandler.cpp +++ b/lib/CCreatureHandler.cpp @@ -617,9 +617,9 @@ std::shared_ptr CCreatureHandler::loadFromJson(const std::string & sc cre->cost = ResourceSet(node["cost"]); - VLC->generaltexth->registerString(scope, cre->getNameSingularTextID(), node["name"]["singular"].String()); - VLC->generaltexth->registerString(scope, cre->getNamePluralTextID(), node["name"]["plural"].String()); - VLC->generaltexth->registerString(scope, cre->getDescriptionTextID(), node["description"].String()); + VLC->generaltexth->registerString(scope, cre->getNameSingularTextID(), node["name"]["singular"]); + VLC->generaltexth->registerString(scope, cre->getNamePluralTextID(), node["name"]["plural"]); + VLC->generaltexth->registerString(scope, cre->getDescriptionTextID(), node["description"]); cre->addBonus(node["hitPoints"].Integer(), BonusType::STACK_HEALTH); cre->addBonus(node["speed"].Integer(), BonusType::STACKS_SPEED); diff --git a/lib/CHeroHandler.cpp b/lib/CHeroHandler.cpp index 991cbbff2..820f8404d 100644 --- a/lib/CHeroHandler.cpp +++ b/lib/CHeroHandler.cpp @@ -459,11 +459,11 @@ std::shared_ptr CHeroHandler::loadFromJson(const std::string & scope, con hero->onlyOnWaterMap = node["onlyOnWaterMap"].Bool(); hero->onlyOnMapWithoutWater = node["onlyOnMapWithoutWater"].Bool(); - VLC->generaltexth->registerString(scope, hero->getNameTextID(), node["texts"]["name"].String()); - VLC->generaltexth->registerString(scope, hero->getBiographyTextID(), node["texts"]["biography"].String()); - VLC->generaltexth->registerString(scope, hero->getSpecialtyNameTextID(), node["texts"]["specialty"]["name"].String()); - VLC->generaltexth->registerString(scope, hero->getSpecialtyTooltipTextID(), node["texts"]["specialty"]["tooltip"].String()); - VLC->generaltexth->registerString(scope, hero->getSpecialtyDescriptionTextID(), node["texts"]["specialty"]["description"].String()); + VLC->generaltexth->registerString(scope, hero->getNameTextID(), node["texts"]["name"]); + VLC->generaltexth->registerString(scope, hero->getBiographyTextID(), node["texts"]["biography"]); + VLC->generaltexth->registerString(scope, hero->getSpecialtyNameTextID(), node["texts"]["specialty"]["name"]); + VLC->generaltexth->registerString(scope, hero->getSpecialtyTooltipTextID(), node["texts"]["specialty"]["tooltip"]); + VLC->generaltexth->registerString(scope, hero->getSpecialtyDescriptionTextID(), node["texts"]["specialty"]["description"]); hero->iconSpecSmall = node["images"]["specialtySmall"].String(); hero->iconSpecLarge = node["images"]["specialtyLarge"].String(); diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 12901cd6d..87cad05bc 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -212,7 +212,7 @@ std::shared_ptr CSkillHandler::loadFromJson(const std::string & scope, c skill->onlyOnWaterMap = json["onlyOnWaterMap"].Bool(); - VLC->generaltexth->registerString(scope, skill->getNameTextID(), json["name"].String()); + VLC->generaltexth->registerString(scope, skill->getNameTextID(), json["name"]); switch(json["gainChance"].getType()) { case JsonNode::JsonType::DATA_INTEGER: @@ -237,7 +237,7 @@ std::shared_ptr CSkillHandler::loadFromJson(const std::string & scope, c skill->addNewBonus(bonus, level); } CSkill::LevelInfo & skillAtLevel = skill->at(level); - VLC->generaltexth->registerString(scope, skill->getDescriptionTextID(level), levelNode["description"].String()); + VLC->generaltexth->registerString(scope, skill->getDescriptionTextID(level), levelNode["description"]); skillAtLevel.iconSmall = levelNode["images"]["small"].String(); skillAtLevel.iconMedium = levelNode["images"]["medium"].String(); skillAtLevel.iconLarge = levelNode["images"]["large"].String(); diff --git a/lib/RiverHandler.cpp b/lib/RiverHandler.cpp index 0a117e6f8..c903b18e3 100644 --- a/lib/RiverHandler.cpp +++ b/lib/RiverHandler.cpp @@ -50,7 +50,7 @@ std::shared_ptr RiverTypeHandler::loadFromJson( info->paletteAnimation.push_back(element); } - VLC->generaltexth->registerString(scope, info->getNameTextID(), json["text"].String()); + VLC->generaltexth->registerString(scope, info->getNameTextID(), json["text"]); return info; } diff --git a/lib/RoadHandler.cpp b/lib/RoadHandler.cpp index aed58730f..0d82d9da6 100644 --- a/lib/RoadHandler.cpp +++ b/lib/RoadHandler.cpp @@ -41,7 +41,7 @@ std::shared_ptr RoadTypeHandler::loadFromJson( info->shortIdentifier = json["shortIdentifier"].String(); info->movementCost = json["moveCost"].Integer(); - VLC->generaltexth->registerString(scope,info->getNameTextID(), json["text"].String()); + VLC->generaltexth->registerString(scope,info->getNameTextID(), json["text"]); return info; } diff --git a/lib/TerrainHandler.cpp b/lib/TerrainHandler.cpp index 6b2e81aef..f3431394a 100644 --- a/lib/TerrainHandler.cpp +++ b/lib/TerrainHandler.cpp @@ -45,7 +45,7 @@ std::shared_ptr TerrainTypeHandler::loadFromJson( const std::string info->transitionRequired = json["transitionRequired"].Bool(); info->terrainViewPatterns = json["terrainViewPatterns"].String(); - VLC->generaltexth->registerString(scope, info->getNameTextID(), json["text"].String()); + VLC->generaltexth->registerString(scope, info->getNameTextID(), json["text"]); const JsonVector & unblockedVec = json["minimapUnblocked"].Vector(); info->minimapUnblocked = diff --git a/lib/entities/faction/CTownHandler.cpp b/lib/entities/faction/CTownHandler.cpp index 036c2f6ef..3ed640afc 100644 --- a/lib/entities/faction/CTownHandler.cpp +++ b/lib/entities/faction/CTownHandler.cpp @@ -292,8 +292,8 @@ void CTownHandler::loadBuilding(CTown * town, const std::string & stringID, cons ret->modScope = source.getModScope(); ret->town = town; - VLC->generaltexth->registerString(source.getModScope(), ret->getNameTextID(), source["name"].String()); - VLC->generaltexth->registerString(source.getModScope(), ret->getDescriptionTextID(), source["description"].String()); + VLC->generaltexth->registerString(source.getModScope(), ret->getNameTextID(), source["name"]); + VLC->generaltexth->registerString(source.getModScope(), ret->getDescriptionTextID(), source["description"]); ret->subId = vstd::find_or(MappedKeys::SPECIAL_BUILDINGS, source["type"].String(), BuildingSubID::NONE); ret->resources = TResources(source["cost"]); @@ -603,7 +603,7 @@ void CTownHandler::loadTown(CTown * town, const JsonNode & source) town->namesCount = 0; for(const auto & name : source["names"].Vector()) { - VLC->generaltexth->registerString(town->faction->modScope, town->getRandomNameTextID(town->namesCount), name.String()); + VLC->generaltexth->registerString(town->faction->modScope, town->getRandomNameTextID(town->namesCount), name); town->namesCount += 1; } @@ -718,8 +718,8 @@ std::shared_ptr CTownHandler::loadFromJson(const std::string & scope, faction->modScope = scope; faction->identifier = identifier; - VLC->generaltexth->registerString(scope, faction->getNameTextID(), source["name"].String()); - VLC->generaltexth->registerString(scope, faction->getDescriptionTextID(), source["description"].String()); + VLC->generaltexth->registerString(scope, faction->getNameTextID(), source["name"]); + VLC->generaltexth->registerString(scope, faction->getDescriptionTextID(), source["description"]); faction->creatureBg120 = ImagePath::fromJson(source["creatureBackground"]["120px"]); faction->creatureBg130 = ImagePath::fromJson(source["creatureBackground"]["130px"]); diff --git a/lib/mapObjectConstructors/CBankInstanceConstructor.cpp b/lib/mapObjectConstructors/CBankInstanceConstructor.cpp index c35a2cf28..71abc90b0 100644 --- a/lib/mapObjectConstructors/CBankInstanceConstructor.cpp +++ b/lib/mapObjectConstructors/CBankInstanceConstructor.cpp @@ -28,7 +28,7 @@ void CBankInstanceConstructor::initTypeData(const JsonNode & input) if (input.Struct().count("name") == 0) logMod->warn("Bank %s missing name!", getJsonKey()); - VLC->generaltexth->registerString(input.getModScope(), getNameTextID(), input["name"].String()); + VLC->generaltexth->registerString(input.getModScope(), getNameTextID(), input["name"]); levels = input["levels"].Vector(); bankResetDuration = static_cast(input["resetDuration"].Float()); diff --git a/lib/mapObjectConstructors/CObjectClassesHandler.cpp b/lib/mapObjectConstructors/CObjectClassesHandler.cpp index e45332abb..de28a4a0f 100644 --- a/lib/mapObjectConstructors/CObjectClassesHandler.cpp +++ b/lib/mapObjectConstructors/CObjectClassesHandler.cpp @@ -278,7 +278,7 @@ std::unique_ptr CObjectClassesHandler::loadFromJson(const std::stri newObject->base = json["base"]; newObject->id = index; - VLC->generaltexth->registerString(scope, newObject->getNameTextID(), json["name"].String()); + VLC->generaltexth->registerString(scope, newObject->getNameTextID(), json["name"]); newObject->objectTypeHandlers.resize(json["lastReservedIndex"].Float() + 1); diff --git a/lib/mapObjectConstructors/CRewardableConstructor.cpp b/lib/mapObjectConstructors/CRewardableConstructor.cpp index 80d842a47..20375961a 100644 --- a/lib/mapObjectConstructors/CRewardableConstructor.cpp +++ b/lib/mapObjectConstructors/CRewardableConstructor.cpp @@ -23,7 +23,7 @@ void CRewardableConstructor::initTypeData(const JsonNode & config) blockVisit = config["blockedVisitable"].Bool(); if (!config["name"].isNull()) - VLC->generaltexth->registerString( config.getModScope(), getNameTextID(), config["name"].String()); + VLC->generaltexth->registerString( config.getModScope(), getNameTextID(), config["name"]); JsonUtils::validate(config, "vcmi:rewardable", getJsonKey()); diff --git a/lib/mapObjectConstructors/DwellingInstanceConstructor.cpp b/lib/mapObjectConstructors/DwellingInstanceConstructor.cpp index 609a57efb..24fb98a72 100644 --- a/lib/mapObjectConstructors/DwellingInstanceConstructor.cpp +++ b/lib/mapObjectConstructors/DwellingInstanceConstructor.cpp @@ -29,7 +29,7 @@ void DwellingInstanceConstructor::initTypeData(const JsonNode & input) if (input.Struct().count("name") == 0) logMod->warn("Dwelling %s missing name!", getJsonKey()); - VLC->generaltexth->registerString( input.getModScope(), getNameTextID(), input["name"].String()); + VLC->generaltexth->registerString( input.getModScope(), getNameTextID(), input["name"]); const JsonVector & levels = input["creatures"].Vector(); const auto totalLevels = levels.size(); diff --git a/lib/modding/CModHandler.cpp b/lib/modding/CModHandler.cpp index 8d20639f2..f5eccc700 100644 --- a/lib/modding/CModHandler.cpp +++ b/lib/modding/CModHandler.cpp @@ -401,33 +401,6 @@ CModVersion CModHandler::getModVersion(TModID modName) const return {}; } -bool CModHandler::validateTranslations(TModID modName) const -{ - bool result = true; - const auto & mod = allMods.at(modName); - - { - auto fileList = mod.config["translations"].convertTo >(); - JsonNode json = JsonUtils::assembleFromFiles(fileList); - result |= VLC->generaltexth->validateTranslation(mod.baseLanguage, modName, json); - } - - for(const auto & language : Languages::getLanguageList()) - { - if (mod.config[language.identifier].isNull()) - continue; - - if (mod.config[language.identifier]["skipValidation"].Bool()) - continue; - - auto fileList = mod.config[language.identifier]["translations"].convertTo >(); - JsonNode json = JsonUtils::assembleFromFiles(fileList); - result |= VLC->generaltexth->validateTranslation(language.identifier, modName, json); - } - - return result; -} - void CModHandler::loadTranslation(const TModID & modName) { const auto & mod = allMods[modName]; @@ -441,8 +414,8 @@ void CModHandler::loadTranslation(const TModID & modName) JsonNode baseTranslation = JsonUtils::assembleFromFiles(baseTranslationList); JsonNode extraTranslation = JsonUtils::assembleFromFiles(extraTranslationList); - VLC->generaltexth->loadTranslationOverrides(modBaseLanguage, modName, baseTranslation); - VLC->generaltexth->loadTranslationOverrides(preferredLanguage, modName, extraTranslation); + VLC->generaltexth->loadTranslationOverrides(modName, baseTranslation); + VLC->generaltexth->loadTranslationOverrides(modName, extraTranslation); } void CModHandler::load() @@ -480,12 +453,6 @@ void CModHandler::load() for(const TModID & modName : activeMods) loadTranslation(modName); -#if 0 - for(const TModID & modName : activeMods) - if (!validateTranslations(modName)) - allMods[modName].validation = CModInfo::FAILED; -#endif - logMod->info("\tLoading mod data: %d ms", timer.getDiff()); VLC->creh->loadCrExpMod(); VLC->identifiersHandler->finalize(); diff --git a/lib/modding/CModHandler.h b/lib/modding/CModHandler.h index f88e1fe26..358483c22 100644 --- a/lib/modding/CModHandler.h +++ b/lib/modding/CModHandler.h @@ -49,8 +49,6 @@ class DLL_LINKAGE CModHandler final : boost::noncopyable void loadOneMod(std::string modName, const std::string & parent, const JsonNode & modSettings, bool enableMods); void loadTranslation(const TModID & modName); - bool validateTranslations(TModID modName) const; - CModVersion getModVersion(TModID modName) const; public: diff --git a/lib/rewardable/Info.cpp b/lib/rewardable/Info.cpp index 04512886f..8c8d321de 100644 --- a/lib/rewardable/Info.cpp +++ b/lib/rewardable/Info.cpp @@ -76,7 +76,7 @@ void Rewardable::Info::init(const JsonNode & objectConfig, const std::string & o auto loadString = [&](const JsonNode & entry, const TextIdentifier & textID){ if (entry.isString() && !entry.String().empty() && entry.String()[0] != '@') - VLC->generaltexth->registerString(entry.getModScope(), textID, entry.String()); + VLC->generaltexth->registerString(entry.getModScope(), textID, entry); }; parameters = objectConfig; diff --git a/lib/spells/CSpellHandler.cpp b/lib/spells/CSpellHandler.cpp index 454c8080d..a96fed944 100644 --- a/lib/spells/CSpellHandler.cpp +++ b/lib/spells/CSpellHandler.cpp @@ -783,7 +783,7 @@ std::shared_ptr CSpellHandler::loadFromJson(const std::string & scope, c spell->combat = type == "combat"; } - VLC->generaltexth->registerString(scope, spell->getNameTextID(), json["name"].String()); + VLC->generaltexth->registerString(scope, spell->getNameTextID(), json["name"]); logMod->trace("%s: loading spell %s", __FUNCTION__, spell->getNameTranslated()); @@ -1005,7 +1005,7 @@ std::shared_ptr CSpellHandler::loadFromJson(const std::string & scope, c const si32 levelPower = levelObject.power = static_cast(levelNode["power"].Integer()); if (!spell->isCreatureAbility()) - VLC->generaltexth->registerString(scope, spell->getDescriptionTextID(levelIndex), levelNode["description"].String()); + VLC->generaltexth->registerString(scope, spell->getDescriptionTextID(levelIndex), levelNode["description"]); levelObject.cost = static_cast(levelNode["cost"].Integer()); levelObject.AIValue = static_cast(levelNode["aiValue"].Integer()); diff --git a/lib/texts/TextLocalizationContainer.cpp b/lib/texts/TextLocalizationContainer.cpp index 4a210ede3..17f5d905a 100644 --- a/lib/texts/TextLocalizationContainer.cpp +++ b/lib/texts/TextLocalizationContainer.cpp @@ -22,17 +22,15 @@ 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) +void TextLocalizationContainer::registerStringOverride(const std::string & modContext, 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; @@ -76,6 +74,15 @@ const std::string & TextLocalizationContainer::deserialize(const TextIdentifier return entry.baseValue; } +void TextLocalizationContainer::registerString(const std::string & modContext, const TextIdentifier & inputUID, const JsonNode & localized) +{ + assert(!localized.getModScope().empty()); + assert(!getModLanguage(localized.getModScope()).empty()); + + std::lock_guard globalLock(globalTextMutex); + registerString(modContext, inputUID, localized.String(), getModLanguage(modContext)); +} + void TextLocalizationContainer::registerString(const std::string & modContext, const TextIdentifier & UID, const std::string & localized, const std::string & language) { std::lock_guard globalLock(globalTextMutex); @@ -88,13 +95,11 @@ void TextLocalizationContainer::registerString(const std::string & modContext, c 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; @@ -108,63 +113,10 @@ void TextLocalizationContainer::registerString(const std::string & modContext, c 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) +void TextLocalizationContainer::loadTranslationOverrides(const std::string & modContext, const JsonNode & config) { for(const auto & node : config.Struct()) - registerStringOverride(modContext, language, node.first, node.second.String()); + registerStringOverride(modContext, node.first, node.second.String()); } bool TextLocalizationContainer::identifierExists(const TextIdentifier & UID) const diff --git a/lib/texts/TextLocalizationContainer.h b/lib/texts/TextLocalizationContainer.h index 28aabd640..efa907744 100644 --- a/lib/texts/TextLocalizationContainer.h +++ b/lib/texts/TextLocalizationContainer.h @@ -25,15 +25,9 @@ protected: /// Human-readable string that was added on registration std::string baseValue; - /// Language of base string - std::string baseLanguage; - /// Translated human-readable string std::string overrideValue; - /// Language of the override string - std::string overrideLanguage; - /// ID of mod that created this string std::string modContext; @@ -41,7 +35,7 @@ protected: void serialize(Handler & h) { h & baseValue; - h & baseLanguage; + //h & baseLanguage; h & modContext; } }; @@ -52,7 +46,7 @@ protected: std::vector subContainers; /// add selected string to internal storage as high-priority strings - void registerStringOverride(const std::string & modContext, const std::string & language, const TextIdentifier & UID, const std::string & localized); + void registerStringOverride(const std::string & modContext, const TextIdentifier & UID, const std::string & localized); std::string getModLanguage(const std::string & modContext); @@ -60,16 +54,12 @@ protected: bool identifierExists(const TextIdentifier & UID) const; public: - /// validates translation of specified language for specified mod - /// returns true if localization is valid and complete - /// any error messages will be written to log file - bool validateTranslation(const std::string & language, const std::string & modContext, JsonNode const & file) const; - /// Loads translation from provided json /// Any entries loaded by this will have priority over texts registered normally - void loadTranslationOverrides(const std::string & language, const std::string & modContext, JsonNode const & file); + void loadTranslationOverrides(const std::string & modContext, JsonNode const & file); /// add selected string to internal storage + void registerString(const std::string & modContext, const TextIdentifier & UID, const JsonNode & localized); void registerString(const std::string & modContext, const TextIdentifier & UID, const std::string & localized); void registerString(const std::string & modContext, const TextIdentifier & UID, const std::string & localized, const std::string & language);