Files
UnrealEngine/Engine/Source/Developer/Localization/Private/Serialization/JsonInternationalizationMetadataSerializer.cpp
2025-05-18 13:04:45 +08:00

195 lines
5.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Serialization/JsonInternationalizationMetadataSerializer.h"
#include "Serialization/JsonSerializer.h"
struct FCompareLocMetadataValue
{
FORCEINLINE bool operator()( TSharedPtr< FLocMetadataValue > A, TSharedPtr< FLocMetadataValue > B ) const
{
if( A.IsValid() && B.IsValid() )
{
return (*A < *B);
}
else if( A.IsValid() != B.IsValid() )
{
return B.IsValid();
}
return false;
}
};
TSharedPtr<FLocMetadataValue> JSonValueToLocMetaDataValue( const TSharedRef< FJsonValue > JsonValue )
{
switch( JsonValue->Type )
{
case EJson::Boolean:
{
return MakeShareable( new FLocMetadataValueBoolean( JsonValue->AsBool() ) );
}
case EJson::String:
{
return MakeShareable( new FLocMetadataValueString( JsonValue->AsString() ) );
}
case EJson::Array:
{
TArray< TSharedPtr< FLocMetadataValue > > MetadataArray;
TArray< TSharedPtr< FJsonValue > > JsonArray = JsonValue->AsArray();
for( auto ArrayIter = JsonArray.CreateConstIterator(); ArrayIter; ++ArrayIter )
{
const TSharedPtr< FJsonValue >& Item = *ArrayIter;
if( Item.IsValid() )
{
TSharedPtr< FLocMetadataValue > Entry = JSonValueToLocMetaDataValue( Item.ToSharedRef() );
if( Entry.IsValid() )
{
MetadataArray.Add( Entry );
}
}
}
if( MetadataArray.Num() > 0 )
{
return MakeShareable( new FLocMetadataValueArray( MetadataArray ) );
}
}
break;
case EJson::Object:
{
TSharedPtr< FLocMetadataObject > MetadataSubObject = MakeShareable( new FLocMetadataObject );
TSharedPtr< FJsonObject > JsonObject = JsonValue->AsObject();
for( auto ValueIter = JsonObject->Values.CreateConstIterator(); ValueIter; ++ValueIter )
{
const FString Name = (*ValueIter).Key;
TSharedPtr< FJsonValue > Value = (*ValueIter).Value;
if( Value.IsValid() )
{
TSharedPtr< FLocMetadataValue > MetadataValue = JSonValueToLocMetaDataValue( Value.ToSharedRef() );
if( MetadataValue.IsValid() )
{
MetadataSubObject->SetField( Name, MetadataValue );
}
}
}
return MakeShareable( new FLocMetadataValueObject(MetadataSubObject) );
}
default:
{
// At the moment we do not support all the json types as metadata. In the future these types will be handled in a way that they can be stored in an unprocessed way.
}
break;
}
return NULL;
}
TSharedPtr<FJsonValue> LocMetaDataValueToJsonValue( const TSharedRef< FLocMetadataValue > MetadataValue )
{
switch( MetadataValue->GetType() )
{
case ELocMetadataType::Boolean:
{
return MakeShareable( new FJsonValueBoolean( MetadataValue->AsBool() ) );
}
case ELocMetadataType::String:
{
return MakeShareable( new FJsonValueString( MetadataValue->AsString() ) );
}
case ELocMetadataType::Array:
{
TArray< TSharedPtr<FJsonValue> > JsonArrayVals;
TArray< TSharedPtr< FLocMetadataValue > > MetaDataArray = MetadataValue->AsArray();
MetaDataArray.Sort( FCompareLocMetadataValue() );
for( auto ArrayIter = MetaDataArray.CreateConstIterator(); ArrayIter; ++ArrayIter )
{
const TSharedPtr<FLocMetadataValue>& Item = *ArrayIter;
if( Item.IsValid() )
{
TSharedPtr<FJsonValue> Entry = LocMetaDataValueToJsonValue( Item.ToSharedRef() );
if( Entry.IsValid() )
{
JsonArrayVals.Add( Entry );
}
}
}
if( JsonArrayVals.Num() > 0 )
{
return MakeShareable( new FJsonValueArray( JsonArrayVals ) );
}
}
break;
case ELocMetadataType::Object:
{
TSharedPtr< FJsonObject > JsonSubObject = MakeShareable( new FJsonObject );
TSharedPtr< FLocMetadataObject > MetaDataObject = MetadataValue->AsObject();
for( auto ValueIter = MetaDataObject->Values.CreateConstIterator(); ValueIter; ++ValueIter )
{
const FString Name = (*ValueIter).Key;
TSharedPtr< FLocMetadataValue > Value = (*ValueIter).Value;
if( Value.IsValid() )
{
TSharedPtr< FJsonValue > JsonValue = LocMetaDataValueToJsonValue( Value.ToSharedRef() );
if( JsonValue.IsValid() )
{
JsonSubObject->SetField( Name, JsonValue );
}
}
}
// Sorting by key is probably sufficient for now but ideally we would sort the resulting json object using
// the same logic that is in the FLocMetadata < operator
JsonSubObject->Values.KeySort( TLess<FString>() );
return MakeShareable( new FJsonValueObject(JsonSubObject) );
}
default:
break;
}
return NULL;
}
void FJsonInternationalizationMetaDataSerializer::DeserializeMetadata( const TSharedRef< FJsonObject > JsonObj, TSharedPtr< FLocMetadataObject >& OutMetaDataObj )
{
OutMetaDataObj = JSonValueToLocMetaDataValue( MakeShareable( new FJsonValueObject( JsonObj ) ) )->AsObject();
}
void FJsonInternationalizationMetaDataSerializer::SerializeMetadata( const TSharedRef< FLocMetadataObject > MetaData, TSharedPtr< FJsonObject >& OutJsonObj )
{
OutJsonObj = LocMetaDataValueToJsonValue( MakeShareable( new FLocMetadataValueObject( MetaData ) ) )->AsObject();
}
FString FJsonInternationalizationMetaDataSerializer::MetadataToString( const TSharedPtr<FLocMetadataObject> Metadata )
{
FString StringMetadata = TEXT("");
if( Metadata.IsValid() )
{
TSharedPtr< FJsonObject > JsonKeyMetadata;
FJsonInternationalizationMetaDataSerializer::SerializeMetadata( Metadata.ToSharedRef(), JsonKeyMetadata );
if( JsonKeyMetadata.IsValid() )
{
JsonKeyMetadata->Values.KeySort( TLess<FString>() );
TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create( &StringMetadata );
FJsonSerializer::Serialize( JsonKeyMetadata.ToSharedRef(), Writer );
Writer->Close();
StringMetadata.ReplaceInline( TEXT("\t"), TEXT(" ") );
StringMetadata.ReplaceInline( TEXT("\r\n"), TEXT(" ") );
StringMetadata.ReplaceInline( TEXT("\n"), TEXT(" ") );
}
}
return StringMetadata;
}