TranslationSerializer.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <Translation/TranslationSerializer.h>
  9. #include <Translation/TranslationAsset.h>
  10. namespace GraphCanvas
  11. {
  12. AZ_CLASS_ALLOCATOR_IMPL(TranslationFormatSerializer, AZ::SystemAllocator);
  13. void AddEntryToDatabase(const AZStd::string& baseKey, const AZStd::string& name, const rapidjson::Value& it, TranslationFormat* translationFormat)
  14. {
  15. if (it.IsString())
  16. {
  17. auto translationDbItr = translationFormat->m_database.find(baseKey);
  18. if (translationDbItr == translationFormat->m_database.end())
  19. {
  20. translationFormat->m_database[baseKey] = it.GetString();
  21. }
  22. else
  23. {
  24. [[maybe_unused]] const AZStd::string& existingValue = translationDbItr->second;
  25. // There is a name collision
  26. AZ_Error("TranslationSerializer", existingValue == it.GetString(),
  27. R"(Unable to store key: "%s" with value: "%s" because that key already exists with value: "%s" (proposed: "%s"))",
  28. baseKey.c_str(), it.GetString(), existingValue.c_str(), it.GetString());
  29. }
  30. }
  31. else if (it.IsObject())
  32. {
  33. AZStd::string finalKey = baseKey;
  34. if (!name.empty())
  35. {
  36. finalKey.append(".");
  37. finalKey.append(name);
  38. }
  39. AZStd::string itemKey;
  40. for (auto objIt = it.MemberBegin(); objIt != it.MemberEnd(); ++objIt)
  41. {
  42. itemKey = finalKey;
  43. itemKey.append(".");
  44. itemKey.append(objIt->name.GetString());
  45. AddEntryToDatabase(itemKey, name, objIt->value, translationFormat);
  46. }
  47. }
  48. else if (it.IsArray())
  49. {
  50. AZStd::string key = baseKey;
  51. if (!name.empty())
  52. {
  53. key.append(".");
  54. key.append(name);
  55. }
  56. AZStd::string itemKey;
  57. const rapidjson::Value& array = it;
  58. for (rapidjson::SizeType i = 0; i < array.Size(); ++i)
  59. {
  60. itemKey = key;
  61. // if there is a "base" member within the object, then use it, otherwise use the index
  62. const auto& element = array[i];
  63. if (element.IsObject())
  64. {
  65. rapidjson::Value::ConstMemberIterator innerKeyItr = element.FindMember(Schema::Field::key);
  66. if (innerKeyItr != element.MemberEnd())
  67. {
  68. itemKey.append(AZStd::string::format(".%s", innerKeyItr->value.GetString()));
  69. }
  70. else
  71. {
  72. itemKey.append(AZStd::string::format(".%d", i));
  73. }
  74. rapidjson::Value::ConstMemberIterator innerContextItr = element.FindMember(Schema::Field::context);
  75. if (innerContextItr != element.MemberEnd())
  76. {
  77. itemKey.append(AZStd::string::format(".%s", innerContextItr->value.GetString()));
  78. }
  79. rapidjson::Value::ConstMemberIterator innerVariantItr = element.FindMember(Schema::Field::variant);
  80. if (innerVariantItr != element.MemberEnd())
  81. {
  82. itemKey.append(AZStd::string::format(".%s", innerVariantItr->value.GetString()));
  83. }
  84. }
  85. AddEntryToDatabase(itemKey, "", element, translationFormat);
  86. }
  87. }
  88. }
  89. AZ::JsonSerializationResult::Result TranslationFormatSerializer::Load(void* outputValue, const AZ::Uuid& outputValueTypeId,
  90. const rapidjson::Value& inputValue, AZ::JsonDeserializerContext& context)
  91. {
  92. AZ_Assert(azrtti_typeid<TranslationFormat>() == outputValueTypeId,
  93. "Unable to deserialize TranslationFormat to json because the provided type is %s",
  94. outputValueTypeId.ToString<AZStd::string>().c_str());
  95. AZ_UNUSED(outputValueTypeId);
  96. TranslationFormat* translationFormat = reinterpret_cast<TranslationFormat*>(outputValue);
  97. AZ_Assert(translationFormat, "Output value for TranslationFormatSerializer can't be null.");
  98. namespace JSR = AZ::JsonSerializationResult;
  99. JSR::ResultCode result(JSR::Tasks::ReadField);
  100. if (!inputValue.IsObject())
  101. {
  102. return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported, "Translation data must be a JSON object.");
  103. }
  104. if (!inputValue.HasMember(Schema::Field::entries) || !inputValue[Schema::Field::entries].IsArray())
  105. {
  106. return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported, "Translation data must be have a top level array of: entries");
  107. }
  108. // Go over the entries
  109. {
  110. const rapidjson::Value::ConstMemberIterator entries = inputValue.FindMember(Schema::Field::entries);
  111. AZStd::string keyStr;
  112. AZStd::string contextStr;
  113. AZStd::string variantStr;
  114. AZStd::string baseKey;
  115. rapidjson::SizeType entryCount = entries->value.Size();
  116. for (rapidjson::SizeType i = 0; i < entryCount; ++i)
  117. {
  118. const rapidjson::Value& entry = entries->value[i];
  119. rapidjson::Value::ConstMemberIterator keyItr = entry.FindMember(Schema::Field::key);
  120. keyStr = keyItr != entry.MemberEnd() ? keyItr->value.GetString() : "";
  121. rapidjson::Value::ConstMemberIterator contextItr = entry.FindMember(Schema::Field::context);
  122. contextStr = contextItr != entry.MemberEnd() ? contextItr->value.GetString() : "";
  123. rapidjson::Value::ConstMemberIterator variantItr = entry.FindMember(Schema::Field::variant);
  124. variantStr = variantItr != entry.MemberEnd() ? variantItr->value.GetString() : "";
  125. if (keyStr.empty())
  126. {
  127. AZ_Warning("TranslationDatabase", false, "Every entry in the Translation data must have a key: %s", baseKey.c_str());
  128. return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported, "Every entry in the Translation data must have a key");
  129. }
  130. baseKey = contextStr;
  131. if (!baseKey.empty())
  132. {
  133. baseKey.append(".");
  134. }
  135. baseKey.append(keyStr);
  136. if (!variantStr.empty())
  137. {
  138. baseKey.append(".");
  139. baseKey.append(variantStr);
  140. }
  141. // Iterate over all members of entry
  142. for (auto it = entry.MemberBegin(); it != entry.MemberEnd(); ++it)
  143. {
  144. // Skip the fixed elements
  145. if (it == keyItr || it == contextItr || it == variantItr)
  146. {
  147. continue;
  148. }
  149. AddEntryToDatabase(baseKey, it->name.GetString(), it->value, translationFormat);
  150. }
  151. }
  152. }
  153. return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Success, "Translation load success");
  154. }
  155. AZ::JsonSerializationResult::Result TranslationFormatSerializer::Store(rapidjson::Value& /*outputValue*/, const void* /*inputValue*/,
  156. const void* /*defaultValue*/, const AZ::Uuid& /*valueTypeId*/, AZ::JsonSerializerContext& context)
  157. {
  158. namespace JSR = AZ::JsonSerializationResult;
  159. return context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::Unsupported, "Storing a Translation asset is not currently supported");
  160. }
  161. }