// Copyright Epic Games, Inc. All Rights Reserved. #include "LocalizationTargetSetDetailCustomization.h" #include "Containers/UnrealString.h" #include "CoreTypes.h" #include "DesktopPlatformModule.h" #include "DetailCategoryBuilder.h" #include "DetailLayoutBuilder.h" #include "DetailWidgetRow.h" #include "FileHelpers.h" #include "Framework/Application/SlateApplication.h" #include "Framework/Commands/Commands.h" #include "Framework/Commands/InputChord.h" #include "Framework/Commands/UIAction.h" #include "Framework/Commands/UICommandInfo.h" #include "Framework/Commands/UICommandList.h" #include "Framework/MultiBox/MultiBoxBuilder.h" #include "Framework/MultiBox/MultiBoxDefs.h" #include "Framework/MultiBox/MultiBoxExtender.h" #include "Framework/Views/ITypedTableView.h" #include "GenericPlatform/GenericWindow.h" #include "HAL/PlatformMisc.h" #include "IDesktopPlatform.h" #include "IDetailsView.h" #include "ILocalizationServiceModule.h" #include "ILocalizationServiceProvider.h" #include "Internationalization/Culture.h" #include "Internationalization/Internationalization.h" #include "Internationalization/Text.h" #include "LocalizationCommandletTasks.h" #include "LocalizationSettings.h" #include "LocalizationTargetTypes.h" #include "Misc/AssertionMacros.h" #include "Misc/Attribute.h" #include "Misc/MessageDialog.h" #include "Misc/Paths.h" #include "ObjectEditorUtils.h" #include "PropertyHandle.h" #include "SLocalizationDashboardTargetRow.h" #include "SlotBase.h" #include "Styling/AppStyle.h" #include "Templates/Casts.h" #include "Textures/SlateIcon.h" #include "Types/SlateEnums.h" #include "UObject/NameTypes.h" #include "UObject/ObjectPtr.h" #include "UObject/UObjectGlobals.h" #include "UObject/UnrealNames.h" #include "UObject/UnrealType.h" #include "UObject/WeakObjectPtr.h" #include "Widgets/DeclarativeSyntaxSupport.h" #include "Widgets/Input/SButton.h" #include "Widgets/SBoxPanel.h" #include "Widgets/SWindow.h" #include "Widgets/Views/SHeaderRow.h" #include "Widgets/Views/SListView.h" #include "Widgets/Views/STableRow.h" class ITableRow; class STableViewBase; class UObject; #define LOCTEXT_NAMESPACE "LocalizationDashboard" FLocalizationTargetSetDetailCustomization::FLocalizationTargetSetDetailCustomization() : DetailLayoutBuilder(nullptr) , NewEntryIndexToBeInitialized(INDEX_NONE) { } namespace { class FLocalizationDashboardCommands : public TCommands { public: FLocalizationDashboardCommands() : TCommands("LocalizationDashboard", NSLOCTEXT("Contexts", "LocalizationDashboard", "Localization Dashboard"), NAME_None, FAppStyle::GetAppStyleSetName()) { } TSharedPtr GatherTextAllTargets; TSharedPtr ImportTextAllTargets; TSharedPtr ExportTextAllTargets; TSharedPtr ImportDialogueScriptAllTargets; TSharedPtr ExportDialogueScriptAllTargets; TSharedPtr ImportDialogueAllTargets; TSharedPtr CountWordsForAllTargets; TSharedPtr CompileTextAllTargets; /** Initialize commands */ virtual void RegisterCommands() override; }; void FLocalizationDashboardCommands::RegisterCommands() { UI_COMMAND(GatherTextAllTargets, "Gather Text", "Gather text for all targets in the project.", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(ImportTextAllTargets, "Import Text", "Import translations for all cultures of all targets in the project.", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(ExportTextAllTargets, "Export Text", "Export translations for all cultures of all targets in the project.", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(ImportDialogueScriptAllTargets, "Import Script", "Import dialogue scripts for all cultures of all targets in the project.", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(ExportDialogueScriptAllTargets, "Export Script", "Export dialogue scripts for all cultures of all targets in the project.", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(ImportDialogueAllTargets, "Import Dialogue", "Import dialogue WAV files for all cultures of all targets in the project.", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(CountWordsForAllTargets, "Count Words", "Count translations for all targets in the project.", EUserInterfaceActionType::Button, FInputChord()); UI_COMMAND(CompileTextAllTargets, "Compile Text", "Compile translations for all targets in the project.", EUserInterfaceActionType::Button, FInputChord()); } } void FLocalizationTargetSetDetailCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) { DetailLayoutBuilder = &DetailBuilder; { TArray< TWeakObjectPtr > ObjectsBeingCustomized; DetailLayoutBuilder->GetObjectsBeingCustomized(ObjectsBeingCustomized); TargetSet = CastChecked(ObjectsBeingCustomized.Top().Get()); } { const ILocalizationServiceProvider& LSP = ILocalizationServiceModule::Get().GetProvider(); TargetObjectsPropertyHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(ULocalizationTargetSet,TargetObjects)); if (TargetObjectsPropertyHandle->IsValidHandle()) { FText CategoryDisplayName; bool bCollapseCategory = false; if (TargetSet == ULocalizationSettings::GetEngineTargetSet()) { CategoryDisplayName = LOCTEXT("EngineTargetsCategoryDisplayName", "Engine Targets"); bCollapseCategory = true; } else if (TargetSet == ULocalizationSettings::GetGameTargetSet()) { CategoryDisplayName = LOCTEXT("GameTargetsCategoryDisplayName", "Game Targets"); } const FName CategoryName = FObjectEditorUtils::GetCategoryFName(TargetObjectsPropertyHandle->GetProperty()); IDetailCategoryBuilder& DetailCategoryBuilder = DetailBuilder.EditCategory(CategoryName, CategoryDisplayName); DetailCategoryBuilder.InitiallyCollapsed(bCollapseCategory); DetailCategoryBuilder.RestoreExpansionState(false); // disable this for now as both the game and engine targets share the same state variable TargetObjectsPropertyHandle->MarkHiddenByCustomization(); TargetsArrayPropertyHandle_OnNumElementsChanged = FSimpleDelegate::CreateSP(this, &FLocalizationTargetSetDetailCustomization::RebuildTargetsList); TargetObjectsPropertyHandle->AsArray()->SetOnNumElementsChanged(TargetsArrayPropertyHandle_OnNumElementsChanged); FLocalizationDashboardCommands::Register(); const TSharedRef< FUICommandList > CommandList = MakeShareable(new FUICommandList); // Let the localization service extend this toolbar TSharedRef LocalizationServiceExtender = MakeShareable(new FExtender); #if LOCALIZATION_SERVICES_WITH_SLATE if (TargetSet.IsValid() && ILocalizationServiceModule::Get().IsEnabled()) { LSP.CustomizeTargetSetToolbar(LocalizationServiceExtender, TargetSet); } #endif FToolBarBuilder ToolBarBuilder( CommandList, FMultiBoxCustomization::AllowCustomization("LocalizationDashboard"), LocalizationServiceExtender, /*bForceSmallIcons*/true ); TAttribute GatherAllTargetsToolTipTextAttribute = TAttribute::Create(TAttribute::FGetter::CreateLambda([this]() -> FText { return CanGatherTextAllTargets() ? FLocalizationDashboardCommands::Get().GatherTextAllTargets->GetDescription() : LOCTEXT("GatherAllTargetsDisabledToolTip", "At least one target must have a native culture specified in order to gather."); })); CommandList->MapAction(FLocalizationDashboardCommands::Get().GatherTextAllTargets, FExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::GatherTextAllTargets), FCanExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::CanGatherTextAllTargets)); ToolBarBuilder.AddToolBarButton(FLocalizationDashboardCommands::Get().GatherTextAllTargets, NAME_None, TAttribute(), GatherAllTargetsToolTipTextAttribute, FSlateIcon(FAppStyle::GetAppStyleSetName(), "LocalizationDashboard.GatherTextAllTargets")); CommandList->MapAction(FLocalizationDashboardCommands::Get().ImportTextAllTargets, FExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::ImportTextAllTargets), FCanExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::CanImportTextAllTargets)); ToolBarBuilder.AddToolBarButton(FLocalizationDashboardCommands::Get().ImportTextAllTargets, NAME_None, TAttribute(), TAttribute(), FSlateIcon(FAppStyle::GetAppStyleSetName(), "LocalizationDashboard.ImportTextAllTargetsAllCultures")); CommandList->MapAction(FLocalizationDashboardCommands::Get().ExportTextAllTargets, FExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::ExportTextAllTargets), FCanExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::CanExportTextAllTargets)); ToolBarBuilder.AddToolBarButton(FLocalizationDashboardCommands::Get().ExportTextAllTargets, NAME_None, TAttribute(), TAttribute(), FSlateIcon(FAppStyle::GetAppStyleSetName(), "LocalizationDashboard.ExportTextAllTargetsAllCultures")); CommandList->MapAction(FLocalizationDashboardCommands::Get().ImportDialogueScriptAllTargets, FExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::ImportDialogueScriptAllTargets), FCanExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::CanImportDialogueScriptAllTargets)); ToolBarBuilder.AddToolBarButton(FLocalizationDashboardCommands::Get().ImportDialogueScriptAllTargets, NAME_None, TAttribute(), TAttribute(), FSlateIcon(FAppStyle::GetAppStyleSetName(), "LocalizationDashboard.ImportDialogueScriptAllTargetsAllCultures")); CommandList->MapAction(FLocalizationDashboardCommands::Get().ExportDialogueScriptAllTargets, FExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::ExportDialogueScriptAllTargets), FCanExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::CanExportDialogueScriptAllTargets)); ToolBarBuilder.AddToolBarButton(FLocalizationDashboardCommands::Get().ExportDialogueScriptAllTargets, NAME_None, TAttribute(), TAttribute(), FSlateIcon(FAppStyle::GetAppStyleSetName(), "LocalizationDashboard.ExportDialogueScriptAllTargetsAllCultures")); CommandList->MapAction(FLocalizationDashboardCommands::Get().ImportDialogueAllTargets, FExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::ImportDialogueAllTargets), FCanExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::CanImportDialogueAllTargets)); ToolBarBuilder.AddToolBarButton(FLocalizationDashboardCommands::Get().ImportDialogueAllTargets, NAME_None, TAttribute(), TAttribute(), FSlateIcon(FAppStyle::GetAppStyleSetName(), "LocalizationDashboard.ImportDialogueAllTargetsAllCultures")); CommandList->MapAction(FLocalizationDashboardCommands::Get().CountWordsForAllTargets, FExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::CountWordsForAllTargets), FCanExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::CanCountWordsForAllTargets)); ToolBarBuilder.AddToolBarButton(FLocalizationDashboardCommands::Get().CountWordsForAllTargets, NAME_None, TAttribute(), TAttribute(), FSlateIcon(FAppStyle::GetAppStyleSetName(), "LocalizationDashboard.CountWordsForAllTargets")); CommandList->MapAction(FLocalizationDashboardCommands::Get().CompileTextAllTargets, FExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::CompileTextAllTargets), FCanExecuteAction::CreateSP(this, &FLocalizationTargetSetDetailCustomization::CanCompileTextAllTargets)); ToolBarBuilder.AddToolBarButton(FLocalizationDashboardCommands::Get().CompileTextAllTargets, NAME_None, TAttribute(), TAttribute(), FSlateIcon(FAppStyle::GetAppStyleSetName(), "LocalizationDashboard.CompileTextAllTargetsAllCultures")); if (ILocalizationServiceModule::Get().IsEnabled()) { ToolBarBuilder.BeginSection("LocalizationService"); ToolBarBuilder.EndSection(); } BuildTargetsList(); DetailCategoryBuilder.AddCustomRow(TargetObjectsPropertyHandle->GetPropertyDisplayName()) .WholeRowContent() [ SNew(SVerticalBox) +SVerticalBox::Slot() .AutoHeight() [ ToolBarBuilder.MakeWidget() ] +SVerticalBox::Slot() .AutoHeight() [ SAssignNew(TargetsListView, SListView< TSharedPtr >) .OnGenerateRow(this, &FLocalizationTargetSetDetailCustomization::OnGenerateRow) .ListItemsSource(&TargetsList) .SelectionMode(ESelectionMode::None) .HeaderRow ( SNew(SHeaderRow) +SHeaderRow::Column("Target") .DefaultLabel( LOCTEXT("TargetColumnLabel", "Target")) .HAlignHeader(HAlign_Left) .HAlignCell(HAlign_Left) .VAlignCell(VAlign_Center) +SHeaderRow::Column("Status") .DefaultLabel( LOCTEXT("StatusColumnLabel", "Conflict Status")) .HAlignHeader(HAlign_Center) .HAlignCell(HAlign_Center) .VAlignCell(VAlign_Center) +SHeaderRow::Column("WordCount") .DefaultLabel( LOCTEXT("WordCountColumnLabel", "Word Count")) .HAlignHeader(HAlign_Center) .HAlignCell(HAlign_Center) .VAlignCell(VAlign_Center) +SHeaderRow::Column("Actions") .DefaultLabel(FText::GetEmpty()) .HAlignHeader(HAlign_Right) .HAlignCell(HAlign_Right) .VAlignCell(VAlign_Center) ) ] +SVerticalBox::Slot() .AutoHeight() .VAlign(VAlign_Center) [ SNew(SButton) .Text(LOCTEXT("AddNewTargetButtonLabel", "Add New Target")) .OnClicked(this, &FLocalizationTargetSetDetailCustomization::OnNewTargetButtonClicked) ] ]; } } } void FLocalizationTargetSetDetailCustomization::BuildTargetsList() { const TSharedPtr TargetObjectsArrayPropertyHandle = TargetObjectsPropertyHandle->AsArray(); if (TargetObjectsArrayPropertyHandle.IsValid()) { uint32 ElementCount = 0; TargetObjectsArrayPropertyHandle->GetNumElements(ElementCount); for (uint32 i = 0; i < ElementCount; ++i) { const TSharedPtr TargetObjectPropertyHandle = TargetObjectsArrayPropertyHandle->GetElement(i); TargetsList.Add(TargetObjectPropertyHandle); } } } void FLocalizationTargetSetDetailCustomization::RebuildTargetsList() { const TSharedPtr TargetObjectsArrayPropertyHandle = TargetObjectsPropertyHandle->AsArray(); if (TargetObjectsArrayPropertyHandle.IsValid() && NewEntryIndexToBeInitialized != INDEX_NONE) { const TSharedPtr TargetObjectPropertyHandle = TargetObjectsArrayPropertyHandle->GetElement(NewEntryIndexToBeInitialized); if (TargetObjectPropertyHandle.IsValid() && TargetObjectPropertyHandle->IsValidHandle()) { ULocalizationTarget* const NewTarget = NewObject(TargetSet.Get()); TArray RawData; TargetObjectsPropertyHandle->AccessRawData(RawData); void* RawDatum = RawData.Top(); TArray& TargetObjectsArray = *(reinterpret_cast< TArray* >(RawDatum)); FString NewTargetName = "NewTarget"; auto TargetNameIsIdentical = [&](ULocalizationTarget* Target) -> bool { return (Target != NewTarget) && Target && (Target->Settings.Name == NewTargetName); }; for (uint32 i = 0; TargetObjectsArray.ContainsByPredicate(TargetNameIsIdentical); ++i) { NewTargetName = FString::Printf(TEXT("NewTarget%u"), i); } NewTarget->Settings.Name = NewTargetName; const int32 NativeCultureIndex = NewTarget->Settings.SupportedCulturesStatistics.Add( FCultureStatistics(FInternationalization::Get().GetCurrentCulture()->GetName()) ); NewTarget->Settings.NativeCultureIndex = NativeCultureIndex; TargetObjectPropertyHandle->SetValue(NewTarget); NewEntryIndexToBeInitialized = INDEX_NONE; } } TargetsList.Empty(); BuildTargetsList(); if (TargetsListView.IsValid()) { TargetsListView->RequestListRefresh(); } } bool FLocalizationTargetSetDetailCustomization::CanGatherTextAllTargets() const { for (ULocalizationTarget* const LocalizationTarget : TargetSet->TargetObjects) { // If any target can be gathered, then gathering all can be executed. if (LocalizationTarget && LocalizationTarget->Settings.SupportedCulturesStatistics.Num() > 0 && LocalizationTarget->Settings.SupportedCulturesStatistics.IsValidIndex(LocalizationTarget->Settings.NativeCultureIndex)) { return true; } } return false; } void FLocalizationTargetSetDetailCustomization::GatherTextAllTargets() { // Save unsaved packages. const bool bPromptUserToSave = true; const bool bSaveMapPackages = true; const bool bSaveContentPackages = true; const bool bFastSave = false; const bool bNotifyNoPackagesSaved = false; const bool bCanBeDeclined = true; bool DidPackagesNeedSaving; const bool WerePackagesSaved = FEditorFileUtils::SaveDirtyPackages(bPromptUserToSave, bSaveMapPackages, bSaveContentPackages, bFastSave, bNotifyNoPackagesSaved, bCanBeDeclined, &DidPackagesNeedSaving); if (DidPackagesNeedSaving && !WerePackagesSaved) { // Give warning dialog. const FText MessageText = NSLOCTEXT("LocalizationCultureActions", "UnsavedPackagesWarningDialogMessage", "There are unsaved changes. These changes may not be gathered from correctly."); const FText TitleText = NSLOCTEXT("LocalizationCultureActions", "UnsavedPackagesWarningDialogTitle", "Unsaved Changes Before Gather"); switch(FMessageDialog::Open(EAppMsgType::OkCancel, MessageText, TitleText)) { case EAppReturnType::Cancel: { return; } } } TArray TargetObjectsToProcess; for (ULocalizationTarget* const LocalizationTarget : TargetSet->TargetObjects) { if (LocalizationTarget && LocalizationTarget->Settings.SupportedCulturesStatistics.Num() > 0) { TargetObjectsToProcess.Add(LocalizationTarget); } } // Execute gather. const TSharedPtr ParentWindow = FSlateApplication::Get().FindWidgetWindow(DetailLayoutBuilder->GetDetailsViewSharedPtr().ToSharedRef()); LocalizationCommandletTasks::GatherTextForTargets(ParentWindow.ToSharedRef(), TargetObjectsToProcess); for (ULocalizationTarget* const LocalizationTarget : TargetObjectsToProcess) { UpdateTargetFromReports(LocalizationTarget); } } bool FLocalizationTargetSetDetailCustomization::CanImportTextAllTargets() const { for (ULocalizationTarget* const LocalizationTarget : TargetSet->TargetObjects) { // If any target can be imported, then importing all can be executed. if (LocalizationTarget && LocalizationTarget->Settings.SupportedCulturesStatistics.Num() > 0 && LocalizationTarget->Settings.SupportedCulturesStatistics.IsValidIndex(LocalizationTarget->Settings.NativeCultureIndex)) { return true; } } return false; } void FLocalizationTargetSetDetailCustomization::ImportTextAllTargets() { IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); if (DesktopPlatform) { void* ParentWindowWindowHandle = NULL; const TSharedPtr ParentWindow = FSlateApplication::Get().FindWidgetWindow(DetailLayoutBuilder->GetDetailsViewSharedPtr().ToSharedRef()); if (ParentWindow.IsValid() && ParentWindow->GetNativeWindow().IsValid()) { ParentWindowWindowHandle = ParentWindow->GetNativeWindow()->GetOSWindowHandle(); } const FString DefaultPath = FPaths::ConvertRelativePathToFull(FPaths::ProjectContentDir() / TEXT("Localization")); // Prompt the user for the directory FString OutputDirectory; if (DesktopPlatform->OpenDirectoryDialog(ParentWindowWindowHandle, LOCTEXT("ImportAllTranslationsDialogTitle", "Import All Translations from Directory").ToString(), DefaultPath, OutputDirectory)) { TArray TargetObjectsToProcess; for (ULocalizationTarget* const LocalizationTarget : TargetSet->TargetObjects) { if (LocalizationTarget && LocalizationTarget->Settings.SupportedCulturesStatistics.Num() > 0) { TargetObjectsToProcess.Add(LocalizationTarget); } } LocalizationCommandletTasks::ImportTextForTargets(ParentWindow.ToSharedRef(), TargetObjectsToProcess, TOptional(OutputDirectory)); for (ULocalizationTarget* const LocalizationTarget : TargetObjectsToProcess) { UpdateTargetFromReports(LocalizationTarget); } } } } bool FLocalizationTargetSetDetailCustomization::CanExportTextAllTargets() const { for (ULocalizationTarget* const LocalizationTarget : TargetSet->TargetObjects) { // If any target can be exported, then exporting all can be executed. if (LocalizationTarget && LocalizationTarget->Settings.SupportedCulturesStatistics.Num() > 0 && LocalizationTarget->Settings.SupportedCulturesStatistics.IsValidIndex(LocalizationTarget->Settings.NativeCultureIndex)) { return true; } } return false; } void FLocalizationTargetSetDetailCustomization::ExportTextAllTargets() { IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); if (DesktopPlatform) { void* ParentWindowWindowHandle = NULL; const TSharedPtr ParentWindow = FSlateApplication::Get().FindWidgetWindow(DetailLayoutBuilder->GetDetailsViewSharedPtr().ToSharedRef()); if (ParentWindow.IsValid() && ParentWindow->GetNativeWindow().IsValid()) { ParentWindowWindowHandle = ParentWindow->GetNativeWindow()->GetOSWindowHandle(); } const FString DefaultPath = FPaths::ConvertRelativePathToFull(FPaths::ProjectContentDir() / TEXT("Localization")); // Prompt the user for the directory FString OutputDirectory; if (DesktopPlatform->OpenDirectoryDialog(ParentWindowWindowHandle, LOCTEXT("ExportAllTranslationsDialogTitle", "Export All Translations to Directory").ToString(), DefaultPath, OutputDirectory)) { TArray TargetObjectsToProcess; for (ULocalizationTarget* const LocalizationTarget : TargetSet->TargetObjects) { if (LocalizationTarget && LocalizationTarget->Settings.SupportedCulturesStatistics.Num() > 0) { TargetObjectsToProcess.Add(LocalizationTarget); } } LocalizationCommandletTasks::ExportTextForTargets(ParentWindow.ToSharedRef(), TargetObjectsToProcess, TOptional(OutputDirectory)); } } } bool FLocalizationTargetSetDetailCustomization::CanImportDialogueScriptAllTargets() const { for (ULocalizationTarget* const LocalizationTarget : TargetSet->TargetObjects) { // If any target can be imported, then importing dialogue can be executed. if (LocalizationTarget && LocalizationTarget->Settings.SupportedCulturesStatistics.Num() > 0 && LocalizationTarget->Settings.SupportedCulturesStatistics.IsValidIndex(LocalizationTarget->Settings.NativeCultureIndex)) { return true; } } return false; } void FLocalizationTargetSetDetailCustomization::ImportDialogueScriptAllTargets() { IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); if (DesktopPlatform) { void* ParentWindowWindowHandle = NULL; const TSharedPtr ParentWindow = FSlateApplication::Get().FindWidgetWindow(DetailLayoutBuilder->GetDetailsViewSharedPtr().ToSharedRef()); if (ParentWindow.IsValid() && ParentWindow->GetNativeWindow().IsValid()) { ParentWindowWindowHandle = ParentWindow->GetNativeWindow()->GetOSWindowHandle(); } const FString DefaultPath = FPaths::ConvertRelativePathToFull(FPaths::ProjectContentDir() / TEXT("Localization")); // Prompt the user for the directory FString OutputDirectory; if (DesktopPlatform->OpenDirectoryDialog(ParentWindowWindowHandle, LOCTEXT("ImportAllDialogueScriptsDialogTitle", "Import All Dialogue Scripts from Directory").ToString(), DefaultPath, OutputDirectory)) { TArray TargetObjectsToProcess; for (ULocalizationTarget* const LocalizationTarget : TargetSet->TargetObjects) { if (LocalizationTarget && LocalizationTarget->Settings.SupportedCulturesStatistics.Num() > 0) { TargetObjectsToProcess.Add(LocalizationTarget); } } LocalizationCommandletTasks::ImportDialogueScriptForTargets(ParentWindow.ToSharedRef(), TargetObjectsToProcess, TOptional(OutputDirectory)); for (ULocalizationTarget* const LocalizationTarget : TargetObjectsToProcess) { UpdateTargetFromReports(LocalizationTarget); } } } } bool FLocalizationTargetSetDetailCustomization::CanExportDialogueScriptAllTargets() const { for (ULocalizationTarget* const LocalizationTarget : TargetSet->TargetObjects) { // If any target can be exported, then exporting dialogue can be executed. if (LocalizationTarget && LocalizationTarget->Settings.SupportedCulturesStatistics.Num() > 0 && LocalizationTarget->Settings.SupportedCulturesStatistics.IsValidIndex(LocalizationTarget->Settings.NativeCultureIndex)) { return true; } } return false; } void FLocalizationTargetSetDetailCustomization::ExportDialogueScriptAllTargets() { IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); if (DesktopPlatform) { void* ParentWindowWindowHandle = NULL; const TSharedPtr ParentWindow = FSlateApplication::Get().FindWidgetWindow(DetailLayoutBuilder->GetDetailsViewSharedPtr().ToSharedRef()); if (ParentWindow.IsValid() && ParentWindow->GetNativeWindow().IsValid()) { ParentWindowWindowHandle = ParentWindow->GetNativeWindow()->GetOSWindowHandle(); } const FString DefaultPath = FPaths::ConvertRelativePathToFull(FPaths::ProjectContentDir() / TEXT("Localization")); // Prompt the user for the directory FString OutputDirectory; if (DesktopPlatform->OpenDirectoryDialog(ParentWindowWindowHandle, LOCTEXT("ExportAllDialogueScriptsDialogTitle", "Export All Dialogue Scripts to Directory").ToString(), DefaultPath, OutputDirectory)) { TArray TargetObjectsToProcess; for (ULocalizationTarget* const LocalizationTarget : TargetSet->TargetObjects) { if (LocalizationTarget && LocalizationTarget->Settings.SupportedCulturesStatistics.Num() > 0) { TargetObjectsToProcess.Add(LocalizationTarget); } } LocalizationCommandletTasks::ExportDialogueScriptForTargets(ParentWindow.ToSharedRef(), TargetObjectsToProcess, TOptional(OutputDirectory)); } } } bool FLocalizationTargetSetDetailCustomization::CanImportDialogueAllTargets() const { for (ULocalizationTarget* const LocalizationTarget : TargetSet->TargetObjects) { // If any target can be imported, then importing dialogue can be executed. if (LocalizationTarget && LocalizationTarget->Settings.SupportedCulturesStatistics.Num() > 0 && LocalizationTarget->Settings.SupportedCulturesStatistics.IsValidIndex(LocalizationTarget->Settings.NativeCultureIndex)) { return true; } } return false; } void FLocalizationTargetSetDetailCustomization::ImportDialogueAllTargets() { TArray TargetObjectsToProcess; for (ULocalizationTarget* const LocalizationTarget : TargetSet->TargetObjects) { if (LocalizationTarget && LocalizationTarget->Settings.SupportedCulturesStatistics.Num() > 0) { TargetObjectsToProcess.Add(LocalizationTarget); } } // Warn about potentially loaded audio assets if (!LocalizationCommandletTasks::ReportLoadedAudioAssets(TargetObjectsToProcess)) { return; } // Execute import dialogue. const TSharedPtr ParentWindow = FSlateApplication::Get().FindWidgetWindow(DetailLayoutBuilder->GetDetailsViewSharedPtr().ToSharedRef()); LocalizationCommandletTasks::ImportDialogueForTargets(ParentWindow.ToSharedRef(), TargetObjectsToProcess); } bool FLocalizationTargetSetDetailCustomization::CanCountWordsForAllTargets() const { for (ULocalizationTarget* const LocalizationTarget : TargetSet->TargetObjects) { // If any target can be imported, then counting words for all can be executed. if (LocalizationTarget && LocalizationTarget->Settings.SupportedCulturesStatistics.Num() > 0 && LocalizationTarget->Settings.SupportedCulturesStatistics.IsValidIndex(LocalizationTarget->Settings.NativeCultureIndex)) { return true; } } return false; } void FLocalizationTargetSetDetailCustomization::CountWordsForAllTargets() { TArray TargetObjectsToProcess; for (ULocalizationTarget* const LocalizationTarget : TargetSet->TargetObjects) { if (LocalizationTarget && LocalizationTarget->Settings.SupportedCulturesStatistics.Num() > 0) { TargetObjectsToProcess.Add(LocalizationTarget); } } // Execute compile. const TSharedPtr ParentWindow = FSlateApplication::Get().FindWidgetWindow(DetailLayoutBuilder->GetDetailsViewSharedPtr().ToSharedRef()); LocalizationCommandletTasks::GenerateWordCountReportsForTargets(ParentWindow.ToSharedRef(), TargetObjectsToProcess); } bool FLocalizationTargetSetDetailCustomization::CanCompileTextAllTargets() const { for (ULocalizationTarget* const LocalizationTarget : TargetSet->TargetObjects) { // If any target can be imported, then compiling all can be executed. if (LocalizationTarget && LocalizationTarget->Settings.SupportedCulturesStatistics.Num() > 0 && LocalizationTarget->Settings.SupportedCulturesStatistics.IsValidIndex(LocalizationTarget->Settings.NativeCultureIndex)) { return true; } } return false; } void FLocalizationTargetSetDetailCustomization::CompileTextAllTargets() { TArray TargetObjectsToProcess; for (ULocalizationTarget* const LocalizationTarget : TargetSet->TargetObjects) { if (LocalizationTarget && LocalizationTarget->Settings.SupportedCulturesStatistics.Num() > 0) { TargetObjectsToProcess.Add(LocalizationTarget); } } // Execute compile. const TSharedPtr ParentWindow = FSlateApplication::Get().FindWidgetWindow(DetailLayoutBuilder->GetDetailsViewSharedPtr().ToSharedRef()); LocalizationCommandletTasks::CompileTextForTargets(ParentWindow.ToSharedRef(), TargetObjectsToProcess); } void FLocalizationTargetSetDetailCustomization::UpdateTargetFromReports(ULocalizationTarget* const LocalizationTarget) { //TArray< TSharedPtr > WordCountPropertyHandles; //const TSharedPtr TargetSettingsPropertyHandle = TargetEditor->GetTargetSettingsPropertyHandle(); //if (TargetSettingsPropertyHandle.IsValid() && TargetSettingsPropertyHandle->IsValidHandle()) //{ // const TSharedPtr NativeCultureStatisticsPropertyHandle = TargetSettingsPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLocalizationTargetSettings, NativeCultureStatistics)); // if (NativeCultureStatisticsPropertyHandle.IsValid() && NativeCultureStatisticsPropertyHandle->IsValidHandle()) // { // const TSharedPtr WordCountPropertyHandle = NativeCultureStatisticsPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FCultureStatistics, WordCount)); // if (WordCountPropertyHandle.IsValid() && WordCountPropertyHandle->IsValidHandle()) // { // WordCountPropertyHandles.Add(WordCountPropertyHandle); // } // } // const TSharedPtr SupportedCulturesStatisticsPropertyHandle = TargetSettingsPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FLocalizationTargetSettings, SupportedCulturesStatistics)); // if (SupportedCulturesStatisticsPropertyHandle.IsValid() && SupportedCulturesStatisticsPropertyHandle->IsValidHandle()) // { // uint32 SupportedCultureCount = 0; // SupportedCulturesStatisticsPropertyHandle->GetNumChildren(SupportedCultureCount); // for (uint32 i = 0; i < SupportedCultureCount; ++i) // { // const TSharedPtr ElementPropertyHandle = SupportedCulturesStatisticsPropertyHandle->GetChildHandle(i); // if (ElementPropertyHandle.IsValid() && ElementPropertyHandle->IsValidHandle()) // { // const TSharedPtr WordCountPropertyHandle = SupportedCulturesStatisticsPropertyHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FCultureStatistics, WordCount)); // if (WordCountPropertyHandle.IsValid() && WordCountPropertyHandle->IsValidHandle()) // { // WordCountPropertyHandles.Add(WordCountPropertyHandle); // } // } // } // } //} //for (const TSharedPtr& WordCountPropertyHandle : WordCountPropertyHandles) //{ // WordCountPropertyHandle->NotifyPreChange(); //} LocalizationTarget->UpdateWordCountsFromCSV(); LocalizationTarget->UpdateStatusFromConflictReport(); //for (const TSharedPtr& WordCountPropertyHandle : WordCountPropertyHandles) //{ // WordCountPropertyHandle->NotifyPostChange(); //} } TSharedRef FLocalizationTargetSetDetailCustomization::OnGenerateRow(TSharedPtr TargetObjectPropertyHandle, const TSharedRef& Table) { return SNew(SLocalizationDashboardTargetRow, Table, DetailLayoutBuilder->GetPropertyUtilities(), TargetObjectPropertyHandle.ToSharedRef()); } FReply FLocalizationTargetSetDetailCustomization::OnNewTargetButtonClicked() { if(TargetObjectsPropertyHandle.IsValid() && TargetObjectsPropertyHandle->IsValidHandle()) { uint32 NewElementIndex; TargetObjectsPropertyHandle->AsArray()->GetNumElements(NewElementIndex); NewEntryIndexToBeInitialized = NewElementIndex; TargetObjectsPropertyHandle->AsArray()->AddItem(); } return FReply::Handled(); } #undef LOCTEXT_NAMESPACE