2015-07-09 19:38:01 -04:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "TranslationEditorPrivatePCH.h"
# include "TranslationEditor.h"
# include "WorkspaceMenuStructureModule.h"
2014-04-23 18:47:10 -04:00
# include "TranslationUnit.h"
2014-03-14 14:13:41 -04:00
# include "ISourceControlModule.h"
# include "MessageLog.h"
2014-04-23 17:49:26 -04:00
# include "TextLocalizationManager.h"
2014-09-25 18:03:04 -04:00
# include "JsonInternationalizationArchiveSerializer.h"
# include "JsonInternationalizationManifestSerializer.h"
2014-10-14 22:50:06 -04:00
# include "SNotificationList.h"
# include "NotificationManager.h"
2015-07-01 17:12:23 -04:00
# include "PortableObjectFormatDOM.h"
# include "ILocalizationServiceModule.h"
2015-07-14 09:59:44 -04:00
# include "LocalizationModule.h"
2015-07-06 14:49:51 -04:00
# include "LocalizationTargetTypes.h"
2015-07-02 09:26:26 -04:00
# include "LocalizationConfigurationScript.h"
2014-09-25 18:03:04 -04:00
2014-03-14 14:13:41 -04:00
DEFINE_LOG_CATEGORY_STATIC ( LogTranslationEditor , Log , All ) ;
# define LOCTEXT_NAMESPACE "TranslationDataManager"
2014-09-25 18:03:04 -04:00
2015-07-09 19:38:01 -04:00
FTranslationDataManager : : FTranslationDataManager ( const FString & InManifestFilePath , const FString & InNativeArchiveFilePath , const FString & InArchiveFilePath )
2015-07-10 15:30:12 -04:00
: OpenedManifestFilePath ( InManifestFilePath )
2015-07-09 19:38:01 -04:00
, NativeArchiveFilePath ( InNativeArchiveFilePath )
, OpenedArchiveFilePath ( InArchiveFilePath )
, bLoadedSuccessfully ( true )
{
Initialize ( ) ;
}
FTranslationDataManager : : FTranslationDataManager ( ULocalizationTarget * const LocalizationTarget , const FString & CultureToEdit )
2015-08-06 22:33:48 -04:00
: bLoadedSuccessfully ( true )
2015-07-09 19:38:01 -04:00
{
check ( LocalizationTarget ) ;
const FString ManifestFile = LocalizationConfigurationScript : : GetManifestPath ( LocalizationTarget ) ;
FString NativeCultureName ;
if ( LocalizationTarget - > Settings . SupportedCulturesStatistics . IsValidIndex ( LocalizationTarget - > Settings . NativeCultureIndex ) )
{
NativeCultureName = LocalizationTarget - > Settings . SupportedCulturesStatistics [ LocalizationTarget - > Settings . NativeCultureIndex ] . CultureName ;
}
const FString NativeArchiveFile = NativeCultureName . IsEmpty ( ) ? FString ( ) : LocalizationConfigurationScript : : GetArchivePath ( LocalizationTarget , NativeCultureName ) ;
const FString ArchiveFileToEdit = LocalizationConfigurationScript : : GetArchivePath ( LocalizationTarget , CultureToEdit ) ;
OpenedManifestFilePath = ManifestFile ;
NativeArchiveFilePath = NativeArchiveFile ;
OpenedArchiveFilePath = ArchiveFileToEdit ;
Initialize ( ) ;
}
void FTranslationDataManager : : Initialize ( )
2014-03-14 14:13:41 -04:00
{
GWarn - > BeginSlowTask ( LOCTEXT ( " LoadingTranslationData " , " Loading Translation Data... " ) , true ) ;
2014-04-23 18:48:34 -04:00
TArray < UTranslationUnit * > TranslationUnits ;
2014-03-14 14:13:41 -04:00
2015-07-09 19:38:01 -04:00
ManifestAtHeadRevisionPtr = ReadManifest ( OpenedManifestFilePath ) ;
2014-03-14 14:13:41 -04:00
if ( ManifestAtHeadRevisionPtr . IsValid ( ) )
{
TSharedRef < FInternationalizationManifest > ManifestAtHeadRevision = ManifestAtHeadRevisionPtr . ToSharedRef ( ) ;
int32 ManifestEntriesCount = ManifestAtHeadRevision - > GetNumEntriesBySourceText ( ) ;
if ( ManifestEntriesCount < 1 )
{
2015-06-17 11:39:02 -04:00
bLoadedSuccessfully = false ;
2014-03-14 14:13:41 -04:00
FFormatNamedArguments Arguments ;
2015-07-09 19:38:01 -04:00
Arguments . Add ( TEXT ( " ManifestFilePath " ) , FText : : FromString ( OpenedManifestFilePath ) ) ;
2014-03-14 14:13:41 -04:00
Arguments . Add ( TEXT ( " ManifestEntriesCount " ) , FText : : AsNumber ( ManifestEntriesCount ) ) ;
FMessageLog TranslationEditorMessageLog ( " TranslationEditor " ) ;
TranslationEditorMessageLog . Error ( FText : : Format ( LOCTEXT ( " CurrentManifestEmpty " , " Most current translation manifest ({ManifestFilePath}) has {ManifestEntriesCount} entries. " ) , Arguments ) ) ;
TranslationEditorMessageLog . Notify ( LOCTEXT ( " TranslationLoadError " , " Error Loading Translations! " ) ) ;
TranslationEditorMessageLog . Open ( EMessageSeverity : : Error ) ;
}
2015-07-09 19:38:01 -04:00
ArchivePtr = ReadArchive ( OpenedArchiveFilePath ) ;
NativeArchivePtr = NativeArchiveFilePath ! = OpenedArchiveFilePath ? ReadArchive ( NativeArchiveFilePath ) : ArchivePtr ;
2014-03-14 14:13:41 -04:00
if ( ArchivePtr . IsValid ( ) )
{
int32 NumManifestEntriesParsed = 0 ;
GWarn - > BeginSlowTask ( LOCTEXT ( " LoadingCurrentManifest " , " Loading Entries from Current Translation Manifest... " ) , true ) ;
2015-08-03 18:49:41 -04:00
// Get all manifest entries by source text (same source text in multiple contexts will only show up once, unless they have unique key metadata)
2014-03-14 14:13:41 -04:00
for ( auto ManifestItr = ManifestAtHeadRevision - > GetEntriesBySourceTextIterator ( ) ; ManifestItr ; + + ManifestItr , + + NumManifestEntriesParsed )
{
GWarn - > StatusUpdate ( NumManifestEntriesParsed , ManifestEntriesCount , FText : : Format ( LOCTEXT ( " LoadingCurrentManifestEntries " , " Loading Entry {0} of {1} from Current Translation Manifest... " ) , FText : : AsNumber ( NumManifestEntriesParsed ) , FText : : AsNumber ( ManifestEntriesCount ) ) ) ;
const TSharedRef < FManifestEntry > ManifestEntry = ManifestItr . Value ( ) ;
2015-08-03 18:49:41 -04:00
TMap < TSharedPtr < FLocMetadataObject > , UTranslationUnit * > KeyMetaDataToTranslationUnitMap ;
2014-03-14 14:13:41 -04:00
for ( auto ContextIter ( ManifestEntry - > Contexts . CreateConstIterator ( ) ) ; ContextIter ; + + ContextIter )
{
FTranslationContextInfo ContextInfo ;
const FContext & AContext = * ContextIter ;
ContextInfo . Context = AContext . SourceLocation ;
ContextInfo . Key = AContext . Key ;
2015-08-03 18:49:41 -04:00
// Make sure we have a unique translation unit for each unique key metadata object.
UTranslationUnit * & TranslationUnit = KeyMetaDataToTranslationUnitMap . FindOrAdd ( AContext . KeyMetadataObj ) ;
if ( ! TranslationUnit )
{
TranslationUnit = NewObject < UTranslationUnit > ( ) ;
check ( TranslationUnit ! = nullptr ) ;
// We want Undo/Redo support
TranslationUnit - > SetFlags ( RF_Transactional ) ;
TranslationUnit - > HasBeenReviewed = false ;
TranslationUnit - > Source = ManifestEntry - > Source . Text ;
TranslationUnit - > Namespace = ManifestEntry - > Namespace ;
TranslationUnit - > KeyMetaDataObject = AContext . KeyMetadataObj ;
}
2015-07-09 19:38:01 -04:00
if ( NativeArchivePtr . IsValid ( ) & & NativeArchivePtr ! = ArchivePtr )
{
const TSharedPtr < FArchiveEntry > NativeArchiveEntry = NativeArchivePtr - > FindEntryBySource ( ManifestEntry - > Namespace , ManifestEntry - > Source , AContext . KeyMetadataObj ) ;
// If the native archive contains a translation for the source string that isn't identical to the source string, use the translation as the source string.
if ( NativeArchiveEntry . IsValid ( ) & & ! NativeArchiveEntry - > Translation . IsExactMatch ( NativeArchiveEntry - > Source ) )
{
TranslationUnit - > Source = NativeArchiveEntry - > Translation . Text ;
}
}
2014-04-23 18:47:10 -04:00
TranslationUnit - > Contexts . Add ( ContextInfo ) ;
2014-03-14 14:13:41 -04:00
}
2015-08-03 18:49:41 -04:00
TArray < UTranslationUnit * > TranslationUnitsToAdd ;
KeyMetaDataToTranslationUnitMap . GenerateValueArray ( TranslationUnitsToAdd ) ;
TranslationUnits . Append ( TranslationUnitsToAdd ) ;
2014-03-14 14:13:41 -04:00
}
GWarn - > EndSlowTask ( ) ;
2014-04-23 19:14:07 -04:00
LoadFromArchive ( TranslationUnits ) ;
2014-03-14 14:13:41 -04:00
}
else // ArchivePtr.IsValid() is false
{
2015-06-17 11:39:02 -04:00
bLoadedSuccessfully = false ;
2014-03-14 14:13:41 -04:00
FFormatNamedArguments Arguments ;
2015-07-09 19:38:01 -04:00
Arguments . Add ( TEXT ( " ArchiveFilePath " ) , FText : : FromString ( OpenedArchiveFilePath ) ) ;
2014-03-14 14:13:41 -04:00
FMessageLog TranslationEditorMessageLog ( " TranslationEditor " ) ;
TranslationEditorMessageLog . Error ( FText : : Format ( LOCTEXT ( " FailedToLoadCurrentArchive " , " Failed to load most current translation archive ({ArchiveFilePath}), unable to load translations. " ) , Arguments ) ) ;
TranslationEditorMessageLog . Notify ( LOCTEXT ( " TranslationLoadError " , " Error Loading Translations! " ) ) ;
TranslationEditorMessageLog . Open ( EMessageSeverity : : Error ) ;
}
}
else // ManifestAtHeadRevisionPtr.IsValid() is false
{
2015-06-17 11:39:02 -04:00
bLoadedSuccessfully = false ;
2014-03-14 14:13:41 -04:00
FFormatNamedArguments Arguments ;
2015-07-09 19:38:01 -04:00
Arguments . Add ( TEXT ( " ManifestFilePath " ) , FText : : FromString ( OpenedManifestFilePath ) ) ;
2014-03-14 14:13:41 -04:00
FMessageLog TranslationEditorMessageLog ( " TranslationEditor " ) ;
TranslationEditorMessageLog . Error ( FText : : Format ( LOCTEXT ( " FailedToLoadCurrentManifest " , " Failed to load most current translation manifest ({ManifestFilePath}), unable to load translations. " ) , Arguments ) ) ;
TranslationEditorMessageLog . Notify ( LOCTEXT ( " TranslationLoadError " , " Error Loading Translations! " ) ) ;
TranslationEditorMessageLog . Open ( EMessageSeverity : : Error ) ;
}
GWarn - > EndSlowTask ( ) ;
}
2014-05-01 23:21:37 -04:00
FTranslationDataManager : : ~ FTranslationDataManager ( )
{
RemoveTranslationUnitArrayfromRoot ( AllTranslations ) ; // Re-enable garbage collection for all current UTranslationDataObjects
}
2014-04-23 17:49:26 -04:00
TSharedPtr < FInternationalizationManifest > FTranslationDataManager : : ReadManifest ( const FString & ManifestFilePathToRead )
2014-03-14 14:13:41 -04:00
{
2014-04-23 17:49:26 -04:00
TSharedPtr < FJsonObject > ManifestJsonObject = ReadJSONTextFile ( ManifestFilePathToRead ) ;
2014-03-14 14:13:41 -04:00
if ( ! ManifestJsonObject . IsValid ( ) )
{
2014-04-23 17:49:26 -04:00
UE_LOG ( LogTranslationEditor , Error , TEXT ( " Could not read manifest file %s. " ) , * ManifestFilePathToRead ) ;
2014-03-14 14:13:41 -04:00
return TSharedPtr < FInternationalizationManifest > ( ) ;
}
TSharedRef < FInternationalizationManifest > InternationalizationManifest = MakeShareable ( new FInternationalizationManifest ) ;
ManifestSerializer . DeserializeManifest ( ManifestJsonObject . ToSharedRef ( ) , InternationalizationManifest ) ;
return InternationalizationManifest ;
}
2015-07-09 19:38:01 -04:00
TSharedPtr < FInternationalizationArchive > FTranslationDataManager : : ReadArchive ( const FString & ArchiveFilePath )
2014-03-14 14:13:41 -04:00
{
// Read in any existing archive for this culture.
TSharedPtr < FJsonObject > ArchiveJsonObject = ReadJSONTextFile ( ArchiveFilePath ) ;
if ( ! ArchiveJsonObject . IsValid ( ) )
{
UE_LOG ( LogTranslationEditor , Error , TEXT ( " Could not read archive file %s. " ) , * ArchiveFilePath ) ;
2014-09-25 18:03:04 -04:00
return nullptr ;
2014-03-14 14:13:41 -04:00
}
TSharedRef < FInternationalizationArchive > InternationalizationArchive = MakeShareable ( new FInternationalizationArchive ) ;
ArchiveSerializer . DeserializeArchive ( ArchiveJsonObject . ToSharedRef ( ) , InternationalizationArchive ) ;
return InternationalizationArchive ;
}
TSharedPtr < FJsonObject > FTranslationDataManager : : ReadJSONTextFile ( const FString & InFilePath )
{
//read in file as string
FString FileContents ;
if ( ! FFileHelper : : LoadFileToString ( FileContents , * InFilePath ) )
{
UE_LOG ( LogTranslationEditor , Error , TEXT ( " Failed to load file %s. " ) , * InFilePath ) ;
2014-09-25 18:03:04 -04:00
return nullptr ;
2014-03-14 14:13:41 -04:00
}
//parse as JSON
TSharedPtr < FJsonObject > JSONObject ;
TSharedRef < TJsonReader < > > Reader = TJsonReaderFactory < > : : Create ( FileContents ) ;
if ( ! FJsonSerializer : : Deserialize ( Reader , JSONObject ) | | ! JSONObject . IsValid ( ) )
{
UE_LOG ( LogTranslationEditor , Error , TEXT ( " Invalid JSON in file %s. " ) , * InFilePath ) ;
2014-09-25 18:03:04 -04:00
return nullptr ;
2014-03-14 14:13:41 -04:00
}
return JSONObject ;
}
2014-04-23 19:14:07 -04:00
bool FTranslationDataManager : : WriteTranslationData ( bool bForceWrite /*= false*/ )
2014-03-14 14:13:41 -04:00
{
2015-06-17 11:39:02 -04:00
bool bSuccess = false ;
2014-03-14 14:13:41 -04:00
2015-06-17 11:39:02 -04:00
// If the archive hasn't been loaded correctly, don't try and write anything
if ( ArchivePtr . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
2015-06-17 11:39:02 -04:00
TSharedRef < FInternationalizationArchive > Archive = ArchivePtr . ToSharedRef ( ) ;
bool bNeedsWrite = false ;
for ( UTranslationUnit * TranslationUnit : Untranslated )
2014-03-14 14:13:41 -04:00
{
2015-06-17 11:39:02 -04:00
if ( TranslationUnit ! = nullptr )
2014-05-01 00:16:11 -04:00
{
2015-06-17 11:39:02 -04:00
const FLocItem SearchSource ( TranslationUnit - > Source ) ;
FString OldTranslation = Archive - > FindEntryBySource ( TranslationUnit - > Namespace , SearchSource , nullptr ) - > Translation . Text ;
FString TranslationToWrite = TranslationUnit - > Translation ;
if ( ! TranslationToWrite . Equals ( OldTranslation ) )
{
Archive - > SetTranslation ( TranslationUnit - > Namespace , TranslationUnit - > Source , TranslationToWrite , nullptr ) ;
bNeedsWrite = true ;
}
2014-05-01 00:16:11 -04:00
}
2014-03-14 14:13:41 -04:00
}
2015-06-17 11:39:02 -04:00
for ( UTranslationUnit * TranslationUnit : Review )
2014-03-14 14:13:41 -04:00
{
2015-06-17 11:39:02 -04:00
if ( TranslationUnit ! = nullptr )
2014-05-01 00:16:11 -04:00
{
2015-06-17 11:39:02 -04:00
const FLocItem SearchSource ( TranslationUnit - > Source ) ;
FString OldTranslation = Archive - > FindEntryBySource ( TranslationUnit - > Namespace , SearchSource , nullptr ) - > Translation . Text ;
FString TranslationToWrite = TranslationUnit - > Translation ;
if ( TranslationUnit - > HasBeenReviewed & & ! TranslationToWrite . Equals ( OldTranslation ) )
{
Archive - > SetTranslation ( TranslationUnit - > Namespace , TranslationUnit - > Source , TranslationToWrite , nullptr ) ;
bNeedsWrite = true ;
}
2014-05-01 00:16:11 -04:00
}
2014-03-14 14:13:41 -04:00
}
2015-06-17 11:39:02 -04:00
for ( UTranslationUnit * TranslationUnit : Complete )
2014-03-14 14:13:41 -04:00
{
2015-06-17 11:39:02 -04:00
if ( TranslationUnit ! = nullptr )
2014-05-01 00:16:11 -04:00
{
2015-06-17 11:39:02 -04:00
const FLocItem SearchSource ( TranslationUnit - > Source ) ;
FString OldTranslation = Archive - > FindEntryBySource ( TranslationUnit - > Namespace , SearchSource , nullptr ) - > Translation . Text ;
FString TranslationToWrite = TranslationUnit - > Translation ;
if ( ! TranslationToWrite . Equals ( OldTranslation ) )
{
Archive - > SetTranslation ( TranslationUnit - > Namespace , TranslationUnit - > Source , TranslationToWrite , nullptr ) ;
bNeedsWrite = true ;
}
2014-05-01 00:16:11 -04:00
}
2014-03-14 14:13:41 -04:00
}
2015-06-17 11:39:02 -04:00
bSuccess = true ;
2014-04-23 19:14:07 -04:00
2015-06-17 11:39:02 -04:00
if ( bForceWrite | | bNeedsWrite )
{
TSharedRef < FJsonObject > FinalArchiveJsonObj = MakeShareable ( new FJsonObject ) ;
ArchiveSerializer . SerializeArchive ( Archive , FinalArchiveJsonObj ) ;
2014-03-14 14:13:41 -04:00
2015-07-09 19:38:01 -04:00
bSuccess = WriteJSONToTextFile ( FinalArchiveJsonObj , OpenedArchiveFilePath ) ;
2015-06-17 11:39:02 -04:00
}
2014-03-14 14:13:41 -04:00
}
2014-04-23 19:14:07 -04:00
return bSuccess ;
2014-03-14 14:13:41 -04:00
}
bool FTranslationDataManager : : WriteJSONToTextFile ( TSharedRef < FJsonObject > & Output , const FString & Filename )
{
bool CheckoutAndSaveWasSuccessful = true ;
bool bPreviouslyCheckedOut = false ;
// If the user specified a reference file - write the entries read from code to a ref file
if ( ! Filename . IsEmpty ( ) )
{
2015-03-18 06:03:00 -04:00
// If source control is enabled, try to check out the file. Otherwise just try to write it
if ( ISourceControlModule : : Get ( ) . IsEnabled ( ) )
2014-03-14 14:13:41 -04:00
{
2015-03-18 06:03:00 -04:00
// Already checked out?
if ( CheckedOutFiles . Contains ( Filename ) )
{
bPreviouslyCheckedOut = true ;
}
else if ( ! SourceControlHelpers : : CheckOutFile ( Filename ) )
{
FFormatNamedArguments Arguments ;
Arguments . Add ( TEXT ( " Filename " ) , FText : : FromString ( Filename ) ) ;
// Use Source Control Message Log here because there might be other useful information in that log for the user.
FMessageLog SourceControlMessageLog ( " SourceControl " ) ;
SourceControlMessageLog . Error ( FText : : Format ( LOCTEXT ( " CheckoutFailed " , " Check out of file '{Filename}' failed. " ) , Arguments ) ) ;
SourceControlMessageLog . Notify ( LOCTEXT ( " TranslationArchiveCheckoutFailed " , " Failed to Check Out Translation Archive! " ) ) ;
SourceControlMessageLog . Open ( EMessageSeverity : : Error ) ;
CheckoutAndSaveWasSuccessful = false ;
}
else
{
CheckedOutFiles . Add ( Filename ) ;
}
2014-03-14 14:13:41 -04:00
}
if ( CheckoutAndSaveWasSuccessful )
{
//Print the JSON data out to the ref file.
FString OutputString ;
TSharedRef < TJsonWriter < > > Writer = TJsonWriterFactory < > : : Create ( & OutputString ) ;
FJsonSerializer : : Serialize ( Output , Writer ) ;
if ( ! FFileHelper : : SaveStringToFile ( OutputString , * Filename , FFileHelper : : EEncodingOptions : : ForceUnicode ) )
{
// If we already checked out the file, but cannot write it, perhaps the user checked it in via perforce, so try to check it out again
if ( bPreviouslyCheckedOut )
{
bPreviouslyCheckedOut = false ;
if ( ! SourceControlHelpers : : CheckOutFile ( Filename ) )
{
FFormatNamedArguments Arguments ;
Arguments . Add ( TEXT ( " Filename " ) , FText : : FromString ( Filename ) ) ;
// Use Source Control Message Log here because there might be other useful information in that log for the user.
FMessageLog SourceControlMessageLog ( " SourceControl " ) ;
SourceControlMessageLog . Error ( FText : : Format ( LOCTEXT ( " CheckoutFailed " , " Check out of file '{Filename}' failed. " ) , Arguments ) ) ;
SourceControlMessageLog . Notify ( LOCTEXT ( " TranslationArchiveCheckoutFailed " , " Failed to Check Out Translation Archive! " ) ) ;
SourceControlMessageLog . Open ( EMessageSeverity : : Error ) ;
CheckoutAndSaveWasSuccessful = false ;
CheckedOutFiles . Remove ( Filename ) ;
}
}
FFormatNamedArguments Arguments ;
Arguments . Add ( TEXT ( " Filename " ) , FText : : FromString ( Filename ) ) ;
FMessageLog TranslationEditorMessageLog ( " TranslationEditor " ) ;
TranslationEditorMessageLog . Error ( FText : : Format ( LOCTEXT ( " WriteFileFailed " , " Failed to write localization entries to file '{Filename}'. " ) , Arguments ) ) ;
TranslationEditorMessageLog . Notify ( LOCTEXT ( " FileWriteFailed " , " Failed to Write Translations to File! " ) ) ;
TranslationEditorMessageLog . Open ( EMessageSeverity : : Error ) ;
CheckoutAndSaveWasSuccessful = false ;
}
}
}
else
{
CheckoutAndSaveWasSuccessful = false ;
}
// If this is the first time, let the user know the file was checked out
if ( ! bPreviouslyCheckedOut & & CheckoutAndSaveWasSuccessful )
{
struct Local
{
/**
* Called by our notification ' s hyperlink to open the Source Control message log
*/
static void OpenSourceControlMessageLog ( )
{
FMessageLog ( " SourceControl " ) . Open ( ) ;
}
} ;
FFormatNamedArguments Arguments ;
Arguments . Add ( TEXT ( " Filename " ) , FText : : FromString ( Filename ) ) ;
// Make a note in the Source Control log, including a note to check in the file later via source control application
FMessageLog TranslationEditorMessageLog ( " SourceControl " ) ;
TranslationEditorMessageLog . Info ( FText : : Format ( LOCTEXT ( " TranslationArchiveCheckedOut " , " Successfully checked out and saved translation archive '{Filename}'. Please check-in this file later via your source control application. " ) , Arguments ) ) ;
// Display notification that save was successful, along with a link to the Source Control log so the user can see the above message.
FNotificationInfo Info ( LOCTEXT ( " ArchiveCheckedOut " , " Translation Archive Successfully Checked Out and Saved. " ) ) ;
Info . ExpireDuration = 5 ;
Info . Hyperlink = FSimpleDelegate : : CreateStatic ( & Local : : OpenSourceControlMessageLog ) ;
2014-06-17 12:05:50 -04:00
Info . HyperlinkText = LOCTEXT ( " ShowMessageLogHyperlink " , " Show Message Log " ) ;
2014-03-14 14:13:41 -04:00
Info . bFireAndForget = true ;
Info . bUseSuccessFailIcons = true ;
Info . Image = FEditorStyle : : GetBrush ( TEXT ( " NotificationList.SuccessImage " ) ) ;
FSlateNotificationManager : : Get ( ) . AddNotification ( Info ) ;
}
return CheckoutAndSaveWasSuccessful ;
}
2014-11-18 03:20:09 -05:00
void FTranslationDataManager : : GetHistoryForTranslationUnits ( )
2014-03-14 14:13:41 -04:00
{
GWarn - > BeginSlowTask ( LOCTEXT ( " LoadingSourceControlHistory " , " Loading Translation History from Source Control... " ) , true ) ;
2014-11-18 03:20:09 -05:00
TArray < UTranslationUnit * > & TranslationUnits = AllTranslations ;
2015-07-09 19:38:01 -04:00
const FString & InManifestFilePath = OpenedManifestFilePath ;
2014-11-18 03:20:09 -05:00
// Unload any previous history information, going to retrieve it all again.
UnloadHistoryInformation ( ) ;
2014-04-23 17:47:40 -04:00
// Force history update
2014-03-14 14:13:41 -04:00
ISourceControlProvider & SourceControlProvider = ISourceControlModule : : Get ( ) . GetProvider ( ) ;
TSharedRef < FUpdateStatus , ESPMode : : ThreadSafe > UpdateStatusOperation = ISourceControlOperation : : Create < FUpdateStatus > ( ) ;
UpdateStatusOperation - > SetUpdateHistory ( true ) ;
2014-05-29 17:14:20 -04:00
ECommandResult : : Type Result = SourceControlProvider . Execute ( UpdateStatusOperation , InManifestFilePath ) ;
2014-04-23 17:47:40 -04:00
bool bGetHistoryFromSourceControlSucceeded = Result = = ECommandResult : : Succeeded ;
// Now we can get information about the file's history from the source control state, retrieve that
TArray < FString > Files ;
TArray < TSharedRef < ISourceControlState , ESPMode : : ThreadSafe > > States ;
2014-05-29 17:14:20 -04:00
Files . Add ( InManifestFilePath ) ;
2014-04-23 17:47:40 -04:00
Result = SourceControlProvider . GetState ( Files , States , EStateCacheUsage : : ForceUpdate ) ;
bGetHistoryFromSourceControlSucceeded = bGetHistoryFromSourceControlSucceeded & & ( Result = = ECommandResult : : Succeeded ) ;
2014-04-23 17:49:15 -04:00
FSourceControlStatePtr SourceControlState ;
if ( States . Num ( ) = = 1 )
{
SourceControlState = States [ 0 ] ;
}
2014-04-23 17:47:40 -04:00
// If all the source control operations went ok, continue
if ( bGetHistoryFromSourceControlSucceeded & & SourceControlState . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
int32 HistorySize = SourceControlState - > GetHistorySize ( ) ;
2014-04-02 18:09:23 -04:00
for ( int HistoryItemIndex = HistorySize - 1 ; HistoryItemIndex > = 0 ; - - HistoryItemIndex )
2014-03-14 14:13:41 -04:00
{
2014-04-02 18:09:23 -04:00
GWarn - > StatusUpdate ( HistorySize - HistoryItemIndex , HistorySize , FText : : Format ( LOCTEXT ( " LoadingOldManifestRevisionNumber " , " Loading Translation History from Manifest Revision {0} of {1} from Source Control... " ) , FText : : AsNumber ( HistorySize - HistoryItemIndex ) , FText : : AsNumber ( HistorySize ) ) ) ;
2014-03-14 14:13:41 -04:00
TSharedPtr < ISourceControlRevision , ESPMode : : ThreadSafe > Revision = SourceControlState - > GetHistoryItem ( HistoryItemIndex ) ;
if ( Revision . IsValid ( ) )
{
2014-05-29 17:14:20 -04:00
FString ManifestFullPath = FPaths : : ConvertRelativePathToFull ( InManifestFilePath ) ;
2014-04-02 18:09:23 -04:00
FString EngineFullPath = FPaths : : ConvertRelativePathToFull ( FPaths : : EngineContentDir ( ) ) ;
bool IsEngineManifest = false ;
if ( ManifestFullPath . StartsWith ( EngineFullPath ) )
2014-03-14 14:13:41 -04:00
{
2014-04-02 18:09:23 -04:00
IsEngineManifest = true ;
}
FString ProjectName ;
FString SavedDir ; // Store these cached translation history files in the saved directory
if ( IsEngineManifest )
{
ProjectName = " Engine " ;
SavedDir = FPaths : : EngineSavedDir ( ) ;
}
else
{
2014-10-14 10:31:43 -04:00
ProjectName = FApp : : GetGameName ( ) ;
2014-04-02 18:09:23 -04:00
SavedDir = FPaths : : GameSavedDir ( ) ;
}
2014-05-29 17:14:20 -04:00
FString TempFileName = SavedDir / " CachedTranslationHistory " / " UE4-Manifest- " + ProjectName + " - " + FPaths : : GetBaseFilename ( InManifestFilePath ) + " -Rev- " + FString : : FromInt ( Revision - > GetRevisionNumber ( ) ) ;
2014-04-02 18:09:23 -04:00
if ( ! FPaths : : FileExists ( TempFileName ) ) // Don't bother syncing again if we already have this manifest version cached locally
{
Revision - > Get ( TempFileName ) ;
}
TSharedPtr < FInternationalizationManifest > OldManifestPtr = ReadManifest ( TempFileName ) ;
if ( OldManifestPtr . IsValid ( ) ) // There may be corrupt manifests in the history, so ignore them.
{
TSharedRef < FInternationalizationManifest > OldManifest = OldManifestPtr . ToSharedRef ( ) ;
2014-04-23 18:47:10 -04:00
for ( UTranslationUnit * TranslationUnit : TranslationUnits )
2014-03-14 14:13:41 -04:00
{
2014-09-25 18:03:04 -04:00
if ( TranslationUnit ! = nullptr & & TranslationUnit - > Contexts . Num ( ) > 0 )
2014-03-14 14:13:41 -04:00
{
2014-04-23 18:47:10 -04:00
for ( FTranslationContextInfo & ContextInfo : TranslationUnit - > Contexts )
2014-03-14 14:13:41 -04:00
{
2014-04-02 18:09:23 -04:00
FString PreviousSourceText = " " ;
// If we already have history, then compare against the newest history so far
if ( ContextInfo . Changes . Num ( ) > 0 )
2014-03-14 14:13:41 -04:00
{
2014-04-02 18:09:23 -04:00
PreviousSourceText = ContextInfo . Changes [ 0 ] . Source ;
}
2014-03-14 14:13:41 -04:00
2014-04-02 18:09:23 -04:00
FContext SearchContext ;
SearchContext . Key = ContextInfo . Key ;
2014-04-23 18:47:10 -04:00
TSharedPtr < FManifestEntry > OldManifestEntryPtr = OldManifest - > FindEntryByContext ( TranslationUnit - > Namespace , SearchContext ) ;
2014-04-02 18:09:23 -04:00
if ( ! OldManifestEntryPtr . IsValid ( ) )
{
// If this version of the manifest didn't know anything about this string, move onto the next
continue ;
}
2014-03-14 14:13:41 -04:00
2014-04-02 18:09:23 -04:00
// Always add first instance of this string, and then add any versions that changed since
2014-09-17 16:37:28 -04:00
if ( ContextInfo . Changes . Num ( ) = = 0 | | ! OldManifestEntryPtr - > Source . Text . Equals ( PreviousSourceText ) )
2014-04-02 18:09:23 -04:00
{
2014-09-25 18:03:04 -04:00
TSharedPtr < FArchiveEntry > OldArchiveEntry = ArchivePtr - > FindEntryBySource ( OldManifestEntryPtr - > Namespace , OldManifestEntryPtr - > Source , nullptr ) ;
2014-04-02 18:09:23 -04:00
if ( OldArchiveEntry . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
2014-04-02 18:09:23 -04:00
FTranslationChange Change ;
2014-09-17 16:37:28 -04:00
Change . Source = OldManifestEntryPtr - > Source . Text ;
Change . Translation = OldArchiveEntry - > Translation . Text ;
2014-04-02 18:09:23 -04:00
Change . DateAndTime = Revision - > GetDate ( ) ;
Change . Version = FString : : FromInt ( Revision - > GetRevisionNumber ( ) ) ;
ContextInfo . Changes . Insert ( Change , 0 ) ;
2014-03-14 14:13:41 -04:00
}
}
}
}
}
2014-04-02 18:09:23 -04:00
}
else // OldManifestPtr.IsValid() is false
{
FFormatNamedArguments Arguments ;
2014-05-29 17:14:20 -04:00
Arguments . Add ( TEXT ( " ManifestFilePath " ) , FText : : FromString ( InManifestFilePath ) ) ;
2014-04-02 18:09:23 -04:00
Arguments . Add ( TEXT ( " ManifestRevisionNumber " ) , FText : : AsNumber ( Revision - > GetRevisionNumber ( ) ) ) ;
FMessageLog TranslationEditorMessageLog ( " TranslationEditor " ) ;
TranslationEditorMessageLog . Warning ( FText : : Format ( LOCTEXT ( " PreviousManifestCorrupt " , " Previous revision {ManifestRevisionNumber} of {ManifestFilePath} failed to load correctly. Ignoring. " ) , Arguments ) ) ;
2014-03-14 14:13:41 -04:00
}
}
}
}
2014-04-23 17:47:40 -04:00
// If source control operations failed, display error message
else // (bGetHistoryFromSourceControlSucceeded && SourceControlState.IsValid()) is false
2014-03-14 14:13:41 -04:00
{
FFormatNamedArguments Arguments ;
2014-05-29 17:14:20 -04:00
Arguments . Add ( TEXT ( " ManifestFilePath " ) , FText : : FromString ( InManifestFilePath ) ) ;
2014-03-14 14:13:41 -04:00
FMessageLog TranslationEditorMessageLog ( " SourceControl " ) ;
TranslationEditorMessageLog . Warning ( FText : : Format ( LOCTEXT ( " SourceControlStateQueryFailed " , " Failed to query source control state of file {ManifestFilePath}. " ) , Arguments ) ) ;
TranslationEditorMessageLog . Notify ( LOCTEXT ( " RetrieveTranslationHistoryFailed " , " Unable to Retrieve Translation History from Source Control! " ) ) ;
}
2014-11-18 03:20:09 -05:00
// Go though all translation units
for ( int32 CurrentTranslationUnitIndex = 0 ; CurrentTranslationUnitIndex < TranslationUnits . Num ( ) ; + + CurrentTranslationUnitIndex )
{
UTranslationUnit * TranslationUnit = TranslationUnits [ CurrentTranslationUnitIndex ] ;
if ( TranslationUnit ! = nullptr )
{
if ( TranslationUnit - > Translation . IsEmpty ( ) )
{
bool bHasTranslationHistory = false ;
int32 MostRecentNonNullTranslationIndex = - 1 ;
int32 ContextForRecentTranslation = - 1 ;
// Check all contexts for history
for ( int32 ContextIndex = 0 ; ContextIndex < TranslationUnit - > Contexts . Num ( ) ; + + ContextIndex )
{
for ( int32 ChangeIndex = 0 ; ChangeIndex < TranslationUnit - > Contexts [ ContextIndex ] . Changes . Num ( ) ; + + ChangeIndex )
{
if ( ! ( TranslationUnit - > Contexts [ ContextIndex ] . Changes [ ChangeIndex ] . Translation . IsEmpty ( ) ) )
{
bHasTranslationHistory = true ;
MostRecentNonNullTranslationIndex = ChangeIndex ;
ContextForRecentTranslation = ContextIndex ;
break ;
}
}
if ( bHasTranslationHistory )
{
break ;
}
}
// If we have history, but current translation is empty, this goes in the Needs Review tab
if ( bHasTranslationHistory )
{
// Offer the most recent translation (for the first context in the list) as a suggestion or starting point (not saved unless user checks "Has Been Reviewed")
TranslationUnit - > Translation = TranslationUnit - > Contexts [ ContextForRecentTranslation ] . Changes [ MostRecentNonNullTranslationIndex ] . Translation ;
TranslationUnit - > HasBeenReviewed = false ;
// Move from Untranslated to review
if ( Untranslated . Contains ( TranslationUnit ) )
{
Untranslated . Remove ( TranslationUnit ) ;
}
if ( ! Review . Contains ( TranslationUnit ) )
{
Review . Add ( TranslationUnit ) ;
}
}
}
}
}
2014-03-14 14:13:41 -04:00
GWarn - > EndSlowTask ( ) ;
}
2014-04-02 18:09:23 -04:00
void FTranslationDataManager : : HandlePropertyChanged ( FName PropertyName )
{
// When a property changes, write the data so we don't lose changes if user forgets to save or editor crashes
WriteTranslationData ( ) ;
}
2015-08-06 22:33:48 -04:00
void FTranslationDataManager : : PreviewAllTranslationsInEditor ( ULocalizationTarget * LocalizationTarget )
2014-04-23 17:49:26 -04:00
{
2015-07-09 19:38:01 -04:00
FString ManifestFullPath = FPaths : : ConvertRelativePathToFull ( OpenedManifestFilePath ) ;
2014-04-23 17:49:26 -04:00
FString EngineFullPath = FPaths : : ConvertRelativePathToFull ( FPaths : : EngineContentDir ( ) ) ;
bool IsEngineManifest = false ;
if ( ManifestFullPath . StartsWith ( EngineFullPath ) )
{
IsEngineManifest = true ;
}
2015-08-06 22:33:48 -04:00
if ( LocalizationTarget ! = nullptr )
2014-04-23 17:49:26 -04:00
{
2015-08-06 22:33:48 -04:00
const FString ConfigFilePath = LocalizationConfigurationScript : : GetRegenerateResourcesScriptPath ( LocalizationTarget ) ;
LocalizationConfigurationScript : : GenerateRegenerateResourcesScript ( LocalizationTarget ) . Write ( ConfigFilePath ) ;
2015-07-02 09:26:26 -04:00
FJsonInternationalizationArchiveSerializer LocalizationArchiveSerializer ;
FJsonInternationalizationManifestSerializer LocalizationManifestSerializer ;
FTextLocalizationManager : : Get ( ) . LoadFromManifestAndArchives ( ConfigFilePath , LocalizationArchiveSerializer , LocalizationManifestSerializer ) ;
2014-04-23 17:49:26 -04:00
}
else
{
2015-07-02 09:26:26 -04:00
FText ErrorNotify = LOCTEXT ( " PreviewAllTranslationsInEditorFail " , " Failed to preview translations in Editor! " ) ;
FMessageLog TranslationEditorMessageLog ( " TranslationEditor " ) ;
TranslationEditorMessageLog . Error ( ErrorNotify ) ;
TranslationEditorMessageLog . Notify ( ErrorNotify ) ;
2014-04-23 17:49:26 -04:00
}
}
2014-04-23 18:48:34 -04:00
void FTranslationDataManager : : PopulateSearchResultsUsingFilter ( const FString & SearchFilter )
{
SearchResults . Empty ( ) ;
for ( UTranslationUnit * TranslationUnit : AllTranslations )
{
2014-09-25 18:03:04 -04:00
if ( TranslationUnit ! = nullptr )
2014-04-23 18:48:34 -04:00
{
2014-09-15 17:32:46 -04:00
bool bAdded = false ;
2014-05-01 00:16:11 -04:00
if ( TranslationUnit - > Source . Contains ( SearchFilter ) | |
2014-09-15 17:32:46 -04:00
TranslationUnit - > Translation . Contains ( SearchFilter ) | |
TranslationUnit - > Namespace . Contains ( SearchFilter ) )
2014-05-01 00:16:11 -04:00
{
SearchResults . Add ( TranslationUnit ) ;
2014-09-15 17:32:46 -04:00
bAdded = true ;
}
for ( FTranslationContextInfo CurrentContext : TranslationUnit - > Contexts )
{
if ( ! bAdded & &
( CurrentContext . Context . Contains ( SearchFilter ) | |
CurrentContext . Key . Contains ( SearchFilter ) ) )
{
SearchResults . Add ( TranslationUnit ) ;
break ;
}
2014-05-01 00:16:11 -04:00
}
2014-04-23 18:48:34 -04:00
}
}
}
2014-04-23 19:14:07 -04:00
void FTranslationDataManager : : LoadFromArchive ( TArray < UTranslationUnit * > & InTranslationUnits , bool bTrackChanges /*= false*/ , bool bReloadFromFile /*=false*/ )
{
GWarn - > BeginSlowTask ( LOCTEXT ( " LoadingArchiveEntries " , " Loading Entries from Translation Archive... " ) , true ) ;
if ( bReloadFromFile )
{
2015-07-09 19:38:01 -04:00
ArchivePtr = ReadArchive ( OpenedArchiveFilePath ) ;
NativeArchivePtr = NativeArchiveFilePath ! = OpenedArchiveFilePath ? ReadArchive ( NativeArchiveFilePath ) : ArchivePtr ;
2014-04-23 19:14:07 -04:00
}
if ( ArchivePtr . IsValid ( ) )
{
2015-08-03 18:49:41 -04:00
const TSharedRef < FInternationalizationArchive > Archive = ArchivePtr . ToSharedRef ( ) ;
2014-04-23 19:14:07 -04:00
// Make a local copy of this array before we empty the arrays below (we might have been passed AllTranslations array)
TArray < UTranslationUnit * > TranslationUnits ;
TranslationUnits . Append ( InTranslationUnits ) ;
AllTranslations . Empty ( ) ;
Untranslated . Empty ( ) ;
Review . Empty ( ) ;
Complete . Empty ( ) ;
ChangedOnImport . Empty ( ) ;
for ( int32 CurrentTranslationUnitIndex = 0 ; CurrentTranslationUnitIndex < TranslationUnits . Num ( ) ; + + CurrentTranslationUnitIndex )
{
UTranslationUnit * TranslationUnit = TranslationUnits [ CurrentTranslationUnitIndex ] ;
2014-09-25 18:03:04 -04:00
if ( TranslationUnit ! = nullptr )
2014-04-23 19:14:07 -04:00
{
2014-05-01 23:21:37 -04:00
if ( ! TranslationUnit - > IsRooted ( ) )
{
TranslationUnit - > AddToRoot ( ) ; // Disable garbage collection for UTranslationUnit objects
}
2014-05-01 00:16:11 -04:00
AllTranslations . Add ( TranslationUnit ) ;
2014-04-23 19:14:07 -04:00
2014-05-01 00:16:11 -04:00
GWarn - > StatusUpdate ( CurrentTranslationUnitIndex , TranslationUnits . Num ( ) , FText : : Format ( LOCTEXT ( " LoadingCurrentArchiveEntries " , " Loading Entry {0} of {1} from Translation Archive... " ) , FText : : AsNumber ( CurrentTranslationUnitIndex ) , FText : : AsNumber ( TranslationUnits . Num ( ) ) ) ) ;
const FLocItem SourceSearch ( TranslationUnit - > Source ) ;
2015-08-03 18:49:41 -04:00
TSharedPtr < FArchiveEntry > ArchiveEntry = Archive - > FindEntryBySource ( TranslationUnit - > Namespace , SourceSearch , TranslationUnit - > KeyMetaDataObject ) ;
2014-05-01 00:16:11 -04:00
if ( ArchiveEntry . IsValid ( ) )
2014-04-23 19:14:07 -04:00
{
2014-05-01 00:16:11 -04:00
const FString PreviousTranslation = TranslationUnit - > Translation ;
TranslationUnit - > Translation = " " ; // Reset to null string
2014-09-17 16:37:28 -04:00
const FString TranslatedString = ArchiveEntry - > Translation . Text ;
2014-04-23 19:14:07 -04:00
2014-09-17 16:37:28 -04:00
if ( TranslatedString . IsEmpty ( ) )
2014-04-23 19:14:07 -04:00
{
2014-05-01 00:16:11 -04:00
bool bHasTranslationHistory = false ;
int32 MostRecentNonNullTranslationIndex = - 1 ;
int32 ContextForRecentTranslation = - 1 ;
for ( int32 ContextIndex = 0 ; ContextIndex < TranslationUnit - > Contexts . Num ( ) ; + + ContextIndex )
2014-04-23 19:14:07 -04:00
{
2014-05-01 00:16:11 -04:00
for ( int32 ChangeIndex = 0 ; ChangeIndex < TranslationUnit - > Contexts [ ContextIndex ] . Changes . Num ( ) ; + + ChangeIndex )
{
if ( ! ( TranslationUnit - > Contexts [ ContextIndex ] . Changes [ ChangeIndex ] . Translation . IsEmpty ( ) ) )
{
bHasTranslationHistory = true ;
MostRecentNonNullTranslationIndex = ChangeIndex ;
ContextForRecentTranslation = ContextIndex ;
break ;
}
}
if ( bHasTranslationHistory )
2014-04-23 19:14:07 -04:00
{
break ;
}
}
2014-05-01 00:16:11 -04:00
// If we have history, but current translation is empty, this goes in the Needs Review tab
2014-04-23 19:14:07 -04:00
if ( bHasTranslationHistory )
{
2014-05-01 00:16:11 -04:00
// Offer the most recent translation (for the first context in the list) as a suggestion or starting point (not saved unless user checks "Has Been Reviewed")
TranslationUnit - > Translation = TranslationUnit - > Contexts [ ContextForRecentTranslation ] . Changes [ MostRecentNonNullTranslationIndex ] . Translation ;
Review . Add ( TranslationUnit ) ;
}
else
{
Untranslated . Add ( TranslationUnit ) ;
2014-04-23 19:14:07 -04:00
}
}
else
{
2014-09-17 16:37:28 -04:00
TranslationUnit - > Translation = TranslatedString ;
2014-05-01 00:16:11 -04:00
TranslationUnit - > HasBeenReviewed = true ;
Complete . Add ( TranslationUnit ) ;
2014-04-23 19:14:07 -04:00
}
2014-05-12 23:27:09 -04:00
// Add to changed array if we're tracking changes (i.e. when we import from .po files)
if ( bTrackChanges )
2014-05-01 00:16:11 -04:00
{
2014-05-12 23:27:09 -04:00
if ( PreviousTranslation ! = TranslationUnit - > Translation )
{
FString PreviousTranslationTrimmed = PreviousTranslation ;
PreviousTranslationTrimmed . Trim ( ) . TrimTrailing ( ) ;
FString CurrentTranslationTrimmed = TranslationUnit - > Translation ;
CurrentTranslationTrimmed . Trim ( ) . TrimTrailing ( ) ;
// Ignore changes to only whitespace at beginning and/or end of string on import
if ( PreviousTranslationTrimmed = = CurrentTranslationTrimmed )
{
TranslationUnit - > Translation = PreviousTranslation ;
}
else
{
ChangedOnImport . Add ( TranslationUnit ) ;
TranslationUnit - > TranslationBeforeImport = PreviousTranslation ;
}
}
2014-05-01 00:16:11 -04:00
}
2014-04-23 19:14:07 -04:00
}
}
}
2015-07-09 19:38:01 -04:00
2014-04-23 19:14:07 -04:00
}
else // ArchivePtr.IsValid() is false
{
FFormatNamedArguments Arguments ;
2015-07-09 19:38:01 -04:00
Arguments . Add ( TEXT ( " ArchiveFilePath " ) , FText : : FromString ( OpenedArchiveFilePath ) ) ;
2014-04-23 19:14:07 -04:00
FMessageLog TranslationEditorMessageLog ( " TranslationEditor " ) ;
TranslationEditorMessageLog . Error ( FText : : Format ( LOCTEXT ( " FailedToLoadCurrentArchive " , " Failed to load most current translation archive ({ArchiveFilePath}), unable to load translations. " ) , Arguments ) ) ;
TranslationEditorMessageLog . Notify ( LOCTEXT ( " TranslationLoadError " , " Error Loading Translations! " ) ) ;
TranslationEditorMessageLog . Open ( EMessageSeverity : : Error ) ;
}
GWarn - > EndSlowTask ( ) ;
}
2014-05-01 23:21:37 -04:00
void FTranslationDataManager : : RemoveTranslationUnitArrayfromRoot ( TArray < UTranslationUnit * > & TranslationUnits )
{
for ( UTranslationUnit * TranslationUnit : TranslationUnits )
{
TranslationUnit - > RemoveFromRoot ( ) ;
}
}
2014-11-18 03:20:09 -05:00
void FTranslationDataManager : : UnloadHistoryInformation ( )
{
TArray < UTranslationUnit * > & TranslationUnits = AllTranslations ;
for ( int32 CurrentTranslationUnitIndex = 0 ; CurrentTranslationUnitIndex < TranslationUnits . Num ( ) ; + + CurrentTranslationUnitIndex )
{
UTranslationUnit * TranslationUnit = TranslationUnits [ CurrentTranslationUnitIndex ] ;
if ( TranslationUnit ! = nullptr )
{
// If HasBeenReviewed is false, this is a suggestion translation from a previous translation for the same Namespace/Key pair
if ( ! TranslationUnit - > HasBeenReviewed )
{
if ( ! Untranslated . Contains ( TranslationUnit ) )
{
Untranslated . Add ( TranslationUnit ) ;
}
if ( Review . Contains ( TranslationUnit ) )
{
Review . Remove ( TranslationUnit ) ;
}
// Erase previously suggested translation from history (it has not been reviewed)
TranslationUnit - > Translation . Empty ( ) ;
// Remove all history entries
for ( FTranslationContextInfo Context : TranslationUnit - > Contexts )
{
Context . Changes . Empty ( ) ;
}
}
}
}
}
2015-07-01 17:12:23 -04:00
bool FTranslationDataManager : : SaveSelectedTranslations ( TArray < UTranslationUnit * > TranslationUnitsToSave , bool bSaveChangesToTranslationService )
2014-11-18 03:20:09 -05:00
{
bool bSucceeded = true ;
TMap < FString , TSharedPtr < TArray < UTranslationUnit * > > > TextsToSavePerProject ;
// Regroup the translations to save by project
for ( UTranslationUnit * TextToSave : TranslationUnitsToSave )
{
FString LocresFilePath = TextToSave - > LocresPath ;
if ( ! LocresFilePath . IsEmpty ( ) )
{
if ( ! TextsToSavePerProject . Contains ( LocresFilePath ) )
{
TextsToSavePerProject . Add ( LocresFilePath , MakeShareable ( new TArray < UTranslationUnit * > ( ) ) ) ;
}
TSharedPtr < TArray < UTranslationUnit * > > ProjectArray = TextsToSavePerProject . FindRef ( LocresFilePath ) ;
ProjectArray - > Add ( TextToSave ) ;
}
}
for ( auto TextIt = TextsToSavePerProject . CreateIterator ( ) ; TextIt ; + + TextIt )
{
auto Item = * TextIt ;
FString CurrentLocResPath = Item . Key ;
FString ManifestAndArchiveName = FPaths : : GetBaseFilename ( CurrentLocResPath ) ;
2015-09-16 00:12:42 -04:00
2014-11-18 03:20:09 -05:00
FString ArchiveFilePath = FPaths : : GetPath ( CurrentLocResPath ) ;
FString CultureName = FPaths : : GetBaseFilename ( ArchiveFilePath ) ;
FString ManifestPath = FPaths : : GetPath ( ArchiveFilePath ) ;
FString ArchiveFullPath = ArchiveFilePath / ManifestAndArchiveName + " .archive " ;
FString ManifestFullPath = ManifestPath / ManifestAndArchiveName + " .manifest " ;
2015-07-01 17:12:23 -04:00
FString EngineFullPath = FPaths : : ConvertRelativePathToFull ( FPaths : : EngineContentDir ( ) ) ;
bool IsEngineManifest = false ;
if ( ManifestFullPath . StartsWith ( EngineFullPath ) )
{
IsEngineManifest = true ;
}
2014-11-18 03:20:09 -05:00
2015-09-16 00:12:42 -04:00
ULocalizationTarget * LocalizationTarget = FLocalizationModule : : Get ( ) . GetLocalizationTargetByName ( ManifestAndArchiveName , IsEngineManifest ) ;
FString NativeCultureName ;
if ( LocalizationTarget - > Settings . SupportedCulturesStatistics . IsValidIndex ( LocalizationTarget - > Settings . NativeCultureIndex ) )
{
NativeCultureName = LocalizationTarget - > Settings . SupportedCulturesStatistics [ LocalizationTarget - > Settings . NativeCultureIndex ] . CultureName ;
}
FString NativeArchiveFullPath = ManifestPath / NativeCultureName / ManifestAndArchiveName + " .archive " ;
2015-08-06 22:33:48 -04:00
2014-11-18 03:20:09 -05:00
if ( FPaths : : FileExists ( ManifestFullPath ) & & FPaths : : FileExists ( ArchiveFullPath ) )
{
2015-07-09 19:38:01 -04:00
TSharedRef < FTranslationDataManager > DataManager = MakeShareable ( new FTranslationDataManager ( ManifestFullPath , NativeArchiveFullPath , ArchiveFullPath ) ) ;
2014-11-18 03:20:09 -05:00
2015-07-01 17:12:23 -04:00
if ( DataManager - > GetLoadedSuccessfully ( ) )
2014-11-18 03:20:09 -05:00
{
2015-07-01 17:12:23 -04:00
FPortableObjectFormatDOM PortableObjectDom ;
PortableObjectDom . SetProjectName ( ManifestAndArchiveName ) ;
PortableObjectDom . SetLanguage ( CultureName ) ;
PortableObjectDom . CreateNewHeader ( ) ;
2014-11-18 03:20:09 -05:00
2015-07-01 17:12:23 -04:00
TArray < UTranslationUnit * > & TranslationsArray = DataManager - > GetAllTranslationsArray ( ) ;
TSharedPtr < TArray < UTranslationUnit * > > EditedItems = Item . Value ;
// For each edited item belonging to this manifest/archive pair
for ( auto EditedItemIt = EditedItems - > CreateIterator ( ) ; EditedItemIt ; + + EditedItemIt )
2014-11-18 03:20:09 -05:00
{
2015-07-01 17:12:23 -04:00
UTranslationUnit * EditedItem = * EditedItemIt ;
// Search all translations for the one that matches this FText
for ( UTranslationUnit * Translation : TranslationsArray )
2014-11-18 03:20:09 -05:00
{
2015-07-01 17:12:23 -04:00
// If namespace matches...
if ( Translation - > Namespace = = EditedItem - > Namespace )
2014-11-18 03:20:09 -05:00
{
2015-07-01 17:12:23 -04:00
// And source matches
if ( Translation - > Source = = EditedItem - > Source )
{
// Update the translation in TranslationDataManager, and finish searching these translations
Translation - > Translation = EditedItem - > Translation ;
TSharedRef < FPortableObjectEntry > NewEntry = MakeShareable ( new FPortableObjectEntry ) ;
for ( FTranslationContextInfo ContextInfo : Translation - > Contexts )
{
NewEntry - > ExtractedComments . Add ( ContextInfo . Key ) ;
NewEntry - > ReferenceComments . Add ( ContextInfo . Context ) ;
}
NewEntry - > MsgCtxt = Translation - > Namespace ;
NewEntry - > MsgId = Translation - > Source ;
NewEntry - > MsgStr . Add ( Translation - > Translation ) ;
PortableObjectDom . AddEntry ( NewEntry ) ;
break ;
}
2014-11-18 03:20:09 -05:00
}
}
}
2015-07-01 17:12:23 -04:00
if ( bSaveChangesToTranslationService )
{
FString UploadFilePath = FPaths : : GameSavedDir ( ) / " Temp " / CultureName / ManifestAndArchiveName + " .po " ;
FFileHelper : : SaveStringToFile ( PortableObjectDom . ToString ( ) , * UploadFilePath ) ;
FGuid LocalizationTargetGuid ;
2015-08-06 22:33:48 -04:00
if ( LocalizationTarget )
2015-07-01 17:12:23 -04:00
{
2015-08-06 22:33:48 -04:00
LocalizationTargetGuid = LocalizationTarget - > Settings . Guid ;
2015-07-01 17:12:23 -04:00
}
ILocalizationServiceProvider & Provider = ILocalizationServiceModule : : Get ( ) . GetProvider ( ) ;
TSharedRef < FUploadLocalizationTargetFile , ESPMode : : ThreadSafe > UploadTargetFileOp = ILocalizationServiceOperation : : Create < FUploadLocalizationTargetFile > ( ) ;
UploadTargetFileOp - > SetInTargetGuid ( LocalizationTargetGuid ) ;
UploadTargetFileOp - > SetInLocale ( CultureName ) ;
FPaths : : MakePathRelativeTo ( UploadFilePath , * FPaths : : GameDir ( ) ) ;
UploadTargetFileOp - > SetInRelativeInputFilePathAndName ( UploadFilePath ) ;
UploadTargetFileOp - > SetPreserveAllText ( true ) ;
Provider . Execute ( UploadTargetFileOp , TArray < FLocalizationServiceTranslationIdentifier > ( ) , ELocalizationServiceOperationConcurrency : : Asynchronous , FLocalizationServiceOperationComplete : : CreateStatic ( & FTranslationDataManager : : SaveSelectedTranslationsToTranslationServiceCallback ) ) ;
}
}
else
{
bSucceeded = false ;
2014-11-18 03:20:09 -05:00
}
// Save the data to file, and preview in editor
bSucceeded = bSucceeded & & DataManager - > WriteTranslationData ( ) ;
2015-08-06 22:33:48 -04:00
DataManager - > PreviewAllTranslationsInEditor ( LocalizationTarget ) ;
2014-11-18 03:20:09 -05:00
}
else
{
bSucceeded = false ;
}
}
return bSucceeded ;
}
2015-07-01 17:12:23 -04:00
void FTranslationDataManager : : SaveSelectedTranslationsToTranslationServiceCallback ( const FLocalizationServiceOperationRef & Operation , ELocalizationServiceOperationCommandResult : : Type Result )
{
2015-07-15 09:20:54 -04:00
TSharedPtr < FUploadLocalizationTargetFile , ESPMode : : ThreadSafe > UploadLocalizationTargetOp = StaticCastSharedRef < FUploadLocalizationTargetFile > ( Operation ) ;
2015-07-01 17:12:23 -04:00
bool bError = ! ( Result = = ELocalizationServiceOperationCommandResult : : Succeeded ) ;
FText ErrorText = FText : : GetEmpty ( ) ;
FGuid InTargetGuid ;
FString InLocale ;
FString InRelativeOutputFilePathAndName ;
FString TargetName = " " ;
FString TargetPath = " " ;
FString CultureName = " " ;
2015-07-15 09:20:54 -04:00
if ( UploadLocalizationTargetOp . IsValid ( ) )
2015-07-01 17:12:23 -04:00
{
2015-07-15 09:20:54 -04:00
ErrorText = UploadLocalizationTargetOp - > GetOutErrorText ( ) ;
InTargetGuid = UploadLocalizationTargetOp - > GetInTargetGuid ( ) ;
InLocale = UploadLocalizationTargetOp - > GetInLocale ( ) ;
InRelativeOutputFilePathAndName = UploadLocalizationTargetOp - > GetInRelativeInputFilePathAndName ( ) ;
2015-07-01 17:12:23 -04:00
TargetName = FPaths : : GetBaseFilename ( InRelativeOutputFilePathAndName ) ;
TargetPath = FPaths : : GetPath ( InRelativeOutputFilePathAndName ) ;
CultureName = FPaths : : GetBaseFilename ( TargetPath ) ;
}
// Try to get display name
FInternationalization & I18N = FInternationalization : : Get ( ) ;
FCulturePtr CulturePtr = I18N . GetCulture ( CultureName ) ;
FString CultureDisplayName = CultureName ;
if ( CulturePtr . IsValid ( ) )
{
CultureName = CulturePtr - > GetDisplayName ( ) ;
}
if ( ! bError & & ErrorText . IsEmpty ( ) )
{
FText SuccessText = FText : : Format ( LOCTEXT ( " SaveSelectedTranslationsToTranslationServiceSuccess " , " {0} translations for {1} target uploaded for processing to Translation Service. " ) , FText : : FromString ( CultureDisplayName ) , FText : : FromString ( TargetName ) ) ;
FMessageLog TranslationEditorMessageLog ( " TranslationEditor " ) ;
TranslationEditorMessageLog . Info ( SuccessText ) ;
TranslationEditorMessageLog . Notify ( SuccessText , EMessageSeverity : : Info , true ) ;
}
else
{
if ( ErrorText . IsEmpty ( ) )
{
2015-07-15 09:20:54 -04:00
ErrorText = LOCTEXT ( " SaveToLocalizationServiceUnspecifiedError " , " An unspecified error occured when trying to save to the Localization Service. " ) ;
2015-07-01 17:12:23 -04:00
}
FText ErrorNotify = FText : : Format ( LOCTEXT ( " SaveSelectedTranslationsToTranslationServiceFail " , " {0} translations for {1} target failed to save to Translation Service! " ) , FText : : FromString ( CultureDisplayName ) , FText : : FromString ( TargetName ) ) ;
FMessageLog TranslationEditorMessageLog ( " TranslationEditor " ) ;
TranslationEditorMessageLog . Error ( ErrorNotify ) ;
TranslationEditorMessageLog . Error ( ErrorText ) ;
TranslationEditorMessageLog . Notify ( ErrorNotify ) ;
}
}
2014-04-02 18:09:23 -04:00
# undef LOCTEXT_NAMESPACE