Explorar el Código

Replaced 'convert txt' command with more convenient 'translate' and
'translate maps' commands.

Ivan Savenko hace 1 año
padre
commit
8582bd7d66

+ 84 - 17
client/ClientCommandManager.cpp

@@ -183,44 +183,108 @@ void ClientCommandManager::handleNotDialogCommand()
 	LOCPLINT->showingDialog->setn(false);
 }
 
-void ClientCommandManager::handleConvertTextCommand()
+void ClientCommandManager::handleTranslateGameCommand()
 {
-	logGlobal->info("Searching for available maps");
-	std::unordered_set<ResourcePath> mapList = CResourceHandler::get()->getFilteredFiles([&](const ResourcePath & ident)
+	std::map<std::string, std::map<std::string, std::string>> textsByMod;
+	VLC->generaltexth->exportAllTexts(textsByMod);
+
+	const boost::filesystem::path outPath = VCMIDirs::get().userExtractedPath() / "translation";
+	boost::filesystem::create_directories(outPath);
+
+	for(const auto & modEntry : textsByMod)
 	{
-		return ident.getType() == EResType::MAP;
-	});
+		JsonNode output;
 
-	std::unordered_set<ResourcePath> campaignList = CResourceHandler::get()->getFilteredFiles([&](const ResourcePath & ident)
+		for(const auto & stringEntry : modEntry.second)
+		{
+			if(boost::algorithm::starts_with(stringEntry.first, "map."))
+				continue;
+			if(boost::algorithm::starts_with(stringEntry.first, "campaign."))
+				continue;
+
+			output[stringEntry.first].String() = stringEntry.second;
+		}
+
+		if (!output.isNull())
+		{
+			const boost::filesystem::path filePath = outPath / (modEntry.first + ".json");
+			std::ofstream file(filePath.c_str());
+			file << output.toString();
+		}
+	}
+
+	printCommandMessage("Translation export complete");
+}
+
+void ClientCommandManager::handleTranslateMapsCommand()
+{
+	CMapService mapService;
+
+	printCommandMessage("Searching for available maps");
+	std::unordered_set<ResourcePath> mapList = CResourceHandler::get()->getFilteredFiles([&](const ResourcePath & ident)
 	{
-		return ident.getType() == EResType::CAMPAIGN;
+		return ident.getType() == EResType::MAP;
 	});
 
-	CMapService mapService;
+	std::vector<std::unique_ptr<CMap>> loadedMaps;
+	std::vector<std::shared_ptr<CampaignState>> loadedCampaigns;
 
-	logGlobal->info("Loading maps for export");
+	printCommandMessage("Loading maps for export");
 	for (auto const & mapName : mapList)
 	{
 		try
 		{
 			// load and drop loaded map - we only need loader to run over all maps
-			mapService.loadMap(mapName, nullptr);
+			loadedMaps.push_back(mapService.loadMap(mapName, nullptr));
 		}
 		catch(std::exception & e)
 		{
-			logGlobal->error("Map %s is invalid. Message: %s", mapName.getName(), e.what());
+			logGlobal->warn("Map %s is invalid. Message: %s", mapName.getName(), e.what());
 		}
 	}
 
+	printCommandMessage("Searching for available campaigns");
+	std::unordered_set<ResourcePath> campaignList = CResourceHandler::get()->getFilteredFiles([&](const ResourcePath & ident)
+	{
+		return ident.getType() == EResType::CAMPAIGN;
+	});
+
 	logGlobal->info("Loading campaigns for export");
 	for (auto const & campaignName : campaignList)
 	{
-		auto state = CampaignHandler::getCampaign(campaignName.getName());
-		for (auto const & part : state->allScenarios())
-			state->getMap(part, nullptr);
+		loadedCampaigns.push_back(CampaignHandler::getCampaign(campaignName.getName()));
+		for (auto const & part : loadedCampaigns.back()->allScenarios())
+			loadedCampaigns.back()->getMap(part, nullptr);
 	}
 
-	VLC->generaltexth->dumpAllTexts();
+	std::map<std::string, std::map<std::string, std::string>> textsByMod;
+	VLC->generaltexth->exportAllTexts(textsByMod);
+
+	const boost::filesystem::path outPath = VCMIDirs::get().userExtractedPath() / "translation";
+	boost::filesystem::create_directories(outPath);
+
+	for(const auto & modEntry : textsByMod)
+	{
+		JsonNode output;
+
+		for(const auto & stringEntry : modEntry.second)
+		{
+			if(boost::algorithm::starts_with(stringEntry.first, "map."))
+				output[stringEntry.first].String() = stringEntry.second;
+
+			if(boost::algorithm::starts_with(stringEntry.first, "campaign."))
+				output[stringEntry.first].String() = stringEntry.second;
+		}
+
+		if (!output.isNull())
+		{
+			const boost::filesystem::path filePath = outPath / (modEntry.first + ".json");
+			std::ofstream file(filePath.c_str());
+			file << output.toString();
+		}
+	}
+
+	printCommandMessage("Translation export complete");
 }
 
 void ClientCommandManager::handleGetConfigCommand()
@@ -522,8 +586,11 @@ void ClientCommandManager::processCommand(const std::string & message, bool call
 	else if(commandName == "not dialog")
 		handleNotDialogCommand();
 
-	else if(message=="convert txt")
-		handleConvertTextCommand();
+	else if(message=="translate" || message=="translate game")
+		handleTranslateGameCommand();
+
+	else if(message=="translate maps")
+		handleTranslateMapsCommand();
 
 	else if(message=="get config")
 		handleGetConfigCommand();

+ 5 - 2
client/ClientCommandManager.h

@@ -48,8 +48,11 @@ class ClientCommandManager //take mantis #2292 issue about account if thinking a
 	// Set the state indicating if dialog box is active to "no"
 	void handleNotDialogCommand();
 
-	// Dumps all game text, maps text and campaign maps text into Client log between BEGIN TEXT EXPORT and END TEXT EXPORT
-	void handleConvertTextCommand();
+	// Extracts all translateable game texts into Translation directory, separating files on per-mod basis
+	void handleTranslateGameCommand();
+
+	// Extracts all translateable texts from maps and campaigns into Translation directory, separating files on per-mod basis
+	void handleTranslateMapsCommand();
 
 	// Saves current game configuration into extracted/configuration folder
 	void handleGetConfigCommand();

+ 21 - 12
lib/CGeneralTextHandler.cpp

@@ -10,15 +10,16 @@
 #include "StdInc.h"
 #include "CGeneralTextHandler.h"
 
-#include "filesystem/Filesystem.h"
-#include "serializer/JsonSerializeFormat.h"
 #include "CConfigHandler.h"
 #include "GameSettings.h"
-#include "mapObjects/CQuest.h"
-#include "modding/CModHandler.h"
-#include "VCMI_Lib.h"
 #include "Languages.h"
 #include "TextOperations.h"
+#include "VCMIDirs.h"
+#include "VCMI_Lib.h"
+#include "filesystem/Filesystem.h"
+#include "mapObjects/CQuest.h"
+#include "modding/CModHandler.h"
+#include "serializer/JsonSerializeFormat.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -386,18 +387,26 @@ bool TextLocalizationContainer::identifierExists(const TextIdentifier & UID) con
 	return stringsLocalizations.count(UID.get());
 }
 
-void TextLocalizationContainer::dumpAllTexts()
+void TextLocalizationContainer::exportAllTexts(std::map<std::string, std::map<std::string, std::string>> & storage) const
 {
-	logGlobal->info("BEGIN TEXT EXPORT");
-	for(const auto & entry : stringsLocalizations)
+	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())
-			logGlobal->info(R"("%s" : "%s",)", entry.first, TextOperations::escapeString(entry.second.overrideValue));
+			textToWrite = entry.second.overrideValue;
 		else
-			logGlobal->info(R"("%s" : "%s",)", entry.first, TextOperations::escapeString(entry.second.baseValue));
-	}
+			textToWrite = entry.second.baseValue;
 
-	logGlobal->info("END TEXT EXPORT");
+		storage[modName][entry.first] = textToWrite;
+	}
 }
 
 std::string TextLocalizationContainer::getModLanguage(const std::string & modContext)

+ 3 - 2
lib/CGeneralTextHandler.h

@@ -181,8 +181,9 @@ public:
 	/// converts identifier into user-readable string
 	const std::string & deserialize(const TextIdentifier & identifier) const;
 	
-	/// Debug method, dumps all currently known texts into console using Json-like format
-	void dumpAllTexts();
+	/// Debug method, returns all currently stored texts
+	/// Format: [mod ID][string ID] -> human-readable text
+	void exportAllTexts(std::map<std::string, std::map<std::string, std::string>> & storage) const;
 	
 	/// Add or override subcontainer which can store identifiers
 	void addSubContainer(const TextLocalizationContainer & container);