diff --git a/Content/ELTEditorWidget_BP.uasset b/Content/ELTEditorWidget_BP.uasset index 938762f..7beb0a8 100644 Binary files a/Content/ELTEditorWidget_BP.uasset and b/Content/ELTEditorWidget_BP.uasset differ diff --git a/Source/EasyLocalizationToolEditor/Private/ELTEditor.cpp b/Source/EasyLocalizationToolEditor/Private/ELTEditor.cpp index e4dfc65..785774c 100644 --- a/Source/EasyLocalizationToolEditor/Private/ELTEditor.cpp +++ b/Source/EasyLocalizationToolEditor/Private/ELTEditor.cpp @@ -1,14 +1,18 @@ // Copyright (c) 2026 Damian Nowakowski. All rights reserved. #include "ELTEditor.h" +#include "AssetToolsModule.h" #include "Internationalization/TextLocalizationResource.h" #include "Internationalization/TextLocalizationManager.h" +#include "Internationalization/StringTableCore.h" +#include "Internationalization/StringTable.h" #include "Misc/FileHelper.h" #include "Misc/Paths.h" #include "Misc/MessageDialog.h" #include "ELTEditorSettings.h" #include "ELTEditorWidget.h" #include "ELTSettings.h" +#include "UObject/SavePackage.h" #if ((ENGINE_MAJOR_VERSION == 5) && (ENGINE_MINOR_VERSION >= 1)) #include "AssetRegistry/AssetRegistryModule.h" @@ -162,6 +166,7 @@ void UELTEditor::InitializeTheWidget() EditorWidget->OnGlobalNamespaceChangedDelegate.BindUObject(this, &UELTEditor::OnGlobalNamespaceChanged); EditorWidget->OnSeparatorChangedDelegate.BindUObject(this, &UELTEditor::OnSeparatorChanged); EditorWidget->OnFallbackWhenEmptyChangedDelegate.BindUObject(this, &UELTEditor::OnFallbackWhenEmptyChanged); + EditorWidget->OnGenerateKeyReferenceStringTableChangedDelegate.BindUObject(this, &UELTEditor::OnGenerateKeyReferenceStringTableChanged); EditorWidget->OnLogDebugChangedDelegate.BindUObject(this, &UELTEditor::OnLogDebugChanged); EditorWidget->OnPreviewInUIChangedDelegate.BindUObject(this, &UELTEditor::OnPreviewInUIChanged); @@ -198,6 +203,9 @@ void UELTEditor::InitializeTheWidget() EditorWidget->CallSetLocalizationOnFirstRun(UELTSettings::GetOverrideLanguageAtFirstLaunch()); EditorWidget->CallSetLocalizationOnFirstRunLang(UELTSettings::GetLanguageToOverrideAtFirstLaunch()); + // Set the Generate Key Reference String Table current value to the Widget. + EditorWidget->CallSetGenerateKeyReferenceStringTable(UELTEditorSettings::GetGenerateKeyReferenceStringTable()); + // Set LogDebug value to the Widget. EditorWidget->CallSetLogDebug(UELTEditorSettings::GetLogDebug()); @@ -357,6 +365,11 @@ void UELTEditor::OnFallbackWhenEmptyChanged(const FString& NewFallback) UELTEditorSettings::SetFallbackWhenEmpty(NewFallback); } +void UELTEditor::OnGenerateKeyReferenceStringTableChanged(bool bNewGenerateKeyReferenceStringTable) +{ + UELTEditorSettings::SetGenerateKeyReferenceStringTable(bNewGenerateKeyReferenceStringTable); +} + void UELTEditor::OnLogDebugChanged(bool bNewLogDebug) { // "Log Debug" flag has been changed in the Widget. Save this setting. @@ -502,8 +515,12 @@ bool UELTEditor::GenerateLocFilesImpl(const TArray& CSVPaths, const FSt const FString MetaFileName = LocPath / LocName + TEXT(".locmeta"); const bool bLogDebug = UELTEditorSettings::GetLogDebug(); + const bool bGenerateStringTable = UELTEditorSettings::GetGenerateKeyReferenceStringTable(); + bool bFirstCSV = true; TMap LocReses; + TMap> NamespaceToKeysMap; + for (const FString& CSVPath : CSVPaths) { const FString CSVFilePath = FPaths::ConvertRelativePathToFull(CSVPath); @@ -636,6 +653,11 @@ bool UELTEditor::GenerateLocFilesImpl(const TArray& CSVPaths, const FSt Keys.Values[Key], LocalizedString, 0); + + if (bGenerateStringTable && !Keys.Values[Key].IsEmpty()) + { + NamespaceToKeysMap.FindOrAdd(Namespace).Add(Keys.Values[Key]); + } } } } @@ -674,6 +696,78 @@ bool UELTEditor::GenerateLocFilesImpl(const TArray& CSVPaths, const FSt LocRes.Value.SaveToFile(LocFileName); } + // Generate Key Reference String Table + if (bGenerateStringTable && NamespaceToKeysMap.Num() > 0) + { + FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked("AssetTools"); + + for (const auto& KVP : NamespaceToKeysMap) + { + const FString& Namespace = KVP.Key; + const TSet& Keys = KVP.Value; + + FString AssetName = FString::Printf(TEXT("ELT_KeyReferences_%s_%s"), *LocName, *Namespace); + FString VirtualPath = LocPath.StartsWith(TEXT("/Game")) ? LocPath : FPackageName::FilenameToLongPackageName(LocPath); + FString PackagePath = FPaths::Combine(VirtualPath, AssetName); + FPaths::NormalizeFilename(PackagePath); + + if (!PackagePath.StartsWith(TEXT("/"))) + { + PackagePath = TEXT("/") + PackagePath; + } + + UPackage* Package = CreatePackage(*PackagePath); + if (!Package) + { + OutMessage = FString::Printf(TEXT("ERROR: Failed to create package path for StringTable: %s"), *PackagePath); + return false; + } + + UStringTable* StringTableAsset = Cast(StaticFindObject(UStringTable::StaticClass(), Package, *AssetName)); + if (!StringTableAsset) + { + StringTableAsset = Cast(AssetToolsModule.Get().CreateAsset( + AssetName, + VirtualPath, + UStringTable::StaticClass(), + nullptr + )); + } + + if (!StringTableAsset) + { + OutMessage = FString::Printf(TEXT("ERROR: Failed to create StringTable asset: %s"), *AssetName); + return false; + } + + FStringTableRef StringTableRef = StringTableAsset->GetMutableStringTable(); + StringTableRef->SetNamespace(Namespace); + + for (const FString& Key : Keys) + { + StringTableRef->SetSourceString(FTextKey(Key), Key); + } + + Package->MarkPackageDirty(); + + FString PackageFileName = FPackageName::LongPackageNameToFilename(PackagePath, FPackageName::GetAssetPackageExtension()); + FSavePackageArgs SaveArgs; + SaveArgs.TopLevelFlags = RF_Public | RF_Standalone; + SaveArgs.Error = GError; + + if (!UPackage::SavePackage(Package, StringTableAsset, *PackageFileName, SaveArgs)) + { + OutMessage = FString::Printf(TEXT("ERROR: Failed to save StringTable package file to disk path: %s"), *PackageFileName); + return false; + } + + if (bLogDebug) + { + UE_LOG(ELTEditorLog, Log, TEXT("Saved String Table Asset: %s"), *PackageFileName); + } + } + } + OutMessage = TEXT("SUCCESS: Localization import complete!"); return true; } diff --git a/Source/EasyLocalizationToolEditor/Private/ELTEditorSettings.cpp b/Source/EasyLocalizationToolEditor/Private/ELTEditorSettings.cpp index 6a74ded..c7b1704 100644 --- a/Source/EasyLocalizationToolEditor/Private/ELTEditorSettings.cpp +++ b/Source/EasyLocalizationToolEditor/Private/ELTEditorSettings.cpp @@ -72,6 +72,16 @@ void UELTEditorSettings::SetReimportAtEditorStartup(bool bNewReimportAtEditorSta ELTE_SET_SETTING(bReimportAtEditorStartup, bNewReimportAtEditorStartup); } +bool UELTEditorSettings::GetGenerateKeyReferenceStringTable() +{ + ELTE_GET_SETTING(bGenerateKeyReferenceStringTable); +} + +void UELTEditorSettings::SetGenerateKeyReferenceStringTable(bool bNewGenerateKeyReferenceStringTable) +{ + ELTE_SET_SETTING(bGenerateKeyReferenceStringTable, bNewGenerateKeyReferenceStringTable); +} + bool UELTEditorSettings::GetPreviewInUIEnabled() { ELTE_GET_SETTING(bPreviewInUI); diff --git a/Source/EasyLocalizationToolEditor/Private/ELTEditorWidget.cpp b/Source/EasyLocalizationToolEditor/Private/ELTEditorWidget.cpp index c3d0b07..dbe5394 100644 --- a/Source/EasyLocalizationToolEditor/Private/ELTEditorWidget.cpp +++ b/Source/EasyLocalizationToolEditor/Private/ELTEditorWidget.cpp @@ -153,6 +153,18 @@ void UELTEditorWidget::CallSetLocalizationOnFirstRun(bool LocalizationOnFirstRun #endif } +void UELTEditorWidget::CallSetGenerateKeyReferenceStringTable(bool bGenerateKeyReferenceStringTable) +{ +#if ELTEDITOR_USE_SLATE_EDITOR_UI + if (MyWidget.IsValid()) + { + MyWidget->SetGenerateKeyReferenceStringTable(bGenerateKeyReferenceStringTable); + } +#else + SetReimportAtEditorStartup(bReimportAtEditorStartup); +#endif +} + void UELTEditorWidget::CallSetLocalizationOnFirstRunLang(const FString& OnFirstRunLang) { #if ELTEDITOR_USE_SLATE_EDITOR_UI @@ -281,6 +293,11 @@ void UELTEditorWidget::OnLocalizationOnFirstRunLangChanged(const FString& OnFirs OnLocalizationOnFirstRunLangChangedDelegate.ExecuteIfBound(OnFirstRunLang); } +void UELTEditorWidget::OnGenerateKeyReferenceStringTableChanged(bool bGenerateKeyReferenceStringTable) +{ + OnGenerateKeyReferenceStringTableChangedDelegate.ExecuteIfBound(bGenerateKeyReferenceStringTable); +} + void UELTEditorWidget::OnGlobalNamespaceChanged(const FString& NewGlobalNamespace) { OnGlobalNamespaceChangedDelegate.ExecuteIfBound(NewGlobalNamespace); diff --git a/Source/EasyLocalizationToolEditor/Private/SELTEditorWidget.cpp b/Source/EasyLocalizationToolEditor/Private/SELTEditorWidget.cpp index 5f59a13..47cd258 100644 --- a/Source/EasyLocalizationToolEditor/Private/SELTEditorWidget.cpp +++ b/Source/EasyLocalizationToolEditor/Private/SELTEditorWidget.cpp @@ -476,6 +476,43 @@ KEY - use the key of this entry")) ] ] ] + // > Generate Key Reference String Table on Import Box ================ + +SVerticalBox::Slot() + .AutoHeight() + .Padding(FMargin(0.f, 4.f, 0.f, 0.f)) + [ + SNew(SHorizontalBox) + .ToolTipText(INVTEXT("\ +On CSV Import, a String Table filled with Key References will be generated PER namespace.\n\ +These String Table can be used to easily assign keys to FText properties.\n\n\ +The String Table will be generated in the Localization Folder path and IS OVERRIDDEN if it already exists.")) + // >>>> Generate Key Reference String Table CSV Import Label + +SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(STextBlock) + .Font(FCoreStyle::GetDefaultFontStyle("Light", 12)) + .Text(INVTEXT("Generate Key Reference String Table on Import:")) + ] + // >>>> Generate Key Reference String Table on Import checkbox + +SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SCheckBox) + .IsChecked_Lambda([this]() -> ECheckBoxState + { + return bGenerateKeyReferenceStringTable_Chkbox ? ECheckBoxState::Checked : ECheckBoxState::Unchecked; + }) + .OnCheckStateChanged_Lambda([this](ECheckBoxState InCheckBoxState) -> void + { + bGenerateKeyReferenceStringTable_Chkbox = (InCheckBoxState == ECheckBoxState::Checked); + if (WidgetController.IsValid()) + { + WidgetController->OnGenerateKeyReferenceStringTableChanged(bGenerateKeyReferenceStringTable_Chkbox); + } + }) + ] + ] // > Spacer ================ +SVerticalBox::Slot() .AutoHeight() @@ -819,6 +856,11 @@ void SELTEditorWidget::SetFallbackWhenEmpty(const FString& FallbackWhenEmpty) } } +void SELTEditorWidget::SetGenerateKeyReferenceStringTable(bool bGenerateKeyReferenceStringTable) +{ + bGenerateKeyReferenceStringTable_Chkbox = bGenerateKeyReferenceStringTable; +} + void SELTEditorWidget::SetLogDebug(bool bLogDebug) { bLogDebug_Chkbox = bLogDebug; diff --git a/Source/EasyLocalizationToolEditor/Public/ELTEditor.h b/Source/EasyLocalizationToolEditor/Public/ELTEditor.h index 9e2668b..25fac18 100644 --- a/Source/EasyLocalizationToolEditor/Public/ELTEditor.h +++ b/Source/EasyLocalizationToolEditor/Public/ELTEditor.h @@ -144,6 +144,11 @@ class EASYLOCALIZATIONTOOLEDITOR_API UELTEditor : public UObject */ void OnFallbackWhenEmptyChanged(const FString& NewFallback); + /** + * Called when "GenerateKeyReferenceStringTable" option has been changed in the Widget. + */ + void OnGenerateKeyReferenceStringTableChanged(bool bNewGenerateKeyReferenceStringTable); + /** * Called when "LogDebug" option has been changed in the Widget. */ diff --git a/Source/EasyLocalizationToolEditor/Public/ELTEditorSettings.h b/Source/EasyLocalizationToolEditor/Public/ELTEditorSettings.h index dcd8da2..e748c96 100644 --- a/Source/EasyLocalizationToolEditor/Public/ELTEditorSettings.h +++ b/Source/EasyLocalizationToolEditor/Public/ELTEditorSettings.h @@ -59,6 +59,9 @@ class EASYLOCALIZATIONTOOLEDITOR_API UELTEditorSettings : public UObject static bool GetReimportAtEditorStartup(); static void SetReimportAtEditorStartup(bool bNewReimportAtEditorStartup); + static bool GetGenerateKeyReferenceStringTable(); + static void SetGenerateKeyReferenceStringTable(bool bNewGenerateKeyReferenceStringTable); + /** * Get/Set if the preview should be displayed on UI. */ @@ -99,7 +102,10 @@ class EASYLOCALIZATIONTOOLEDITOR_API UELTEditorSettings : public UObject UPROPERTY(config) bool bReimportAtEditorStartup = false; - + + UPROPERTY(config) + bool bGenerateKeyReferenceStringTable = false; + UPROPERTY(config) bool bPreviewInUI = true; diff --git a/Source/EasyLocalizationToolEditor/Public/ELTEditorWidget.h b/Source/EasyLocalizationToolEditor/Public/ELTEditorWidget.h index 3853c5a..b4060c5 100644 --- a/Source/EasyLocalizationToolEditor/Public/ELTEditorWidget.h +++ b/Source/EasyLocalizationToolEditor/Public/ELTEditorWidget.h @@ -23,6 +23,7 @@ DECLARE_DELEGATE_OneParam(FOnLocalizationPreviewLangChanged, const FString&); DECLARE_DELEGATE_OneParam(FManuallySetLastLanguageChanged, bool); DECLARE_DELEGATE_OneParam(FOnLocalizationOnFirstRunChanged, bool); DECLARE_DELEGATE_OneParam(FOnLocalizationOnFirstRunLangChanged, const FString&); +DECLARE_DELEGATE_OneParam(FOnGenerateKeyReferenceStringTableChanged, bool); DECLARE_DELEGATE_OneParam(FOnGlobalNamespaceChanged, const FString&); DECLARE_DELEGATE_OneParam(FOnSeparatorChanged, const FString&); DECLARE_DELEGATE_OneParam(FOnFallbackWhenEmptyChanged, const FString&); @@ -196,6 +197,20 @@ class EASYLOCALIZATIONTOOLEDITOR_API UELTEditorWidget : public UEditorUtilityWid + /** + * Set "Generate Key Reference String Table On CSV Import" to the Widget. + */ + UFUNCTION(BlueprintImplementableEvent, Category = "Easy Localization Tool Editor") + void SetGenerateKeyReferenceStringTable(bool bGenerateKeyReferenceStringTable); + void CallSetGenerateKeyReferenceStringTable(bool bGenerateKeyReferenceStringTable); + + /** + * "Generate Key Reference String Table On CSV Import" option has been changed on the Widget. + */ + UFUNCTION(BlueprintCallable, Category = "Easy Localization Tool Editor") + void OnGenerateKeyReferenceStringTableChanged(bool bGenerateKeyReferenceStringTable); + + /** * Set "Global Namespace" option to the Widget. */ @@ -287,6 +302,7 @@ class EASYLOCALIZATIONTOOLEDITOR_API UELTEditorWidget : public UEditorUtilityWid FManuallySetLastLanguageChanged OnManuallySetLastLanguageChangedDelegate; FOnLocalizationOnFirstRunChanged OnLocalizationOnFirstRunChangedDelegate; FOnLocalizationOnFirstRunLangChanged OnLocalizationOnFirstRunLangChangedDelegate; + FOnGenerateKeyReferenceStringTableChanged OnGenerateKeyReferenceStringTableChangedDelegate; FOnGlobalNamespaceChanged OnGlobalNamespaceChangedDelegate; FOnSeparatorChanged OnSeparatorChangedDelegate; FOnFallbackWhenEmptyChanged OnFallbackWhenEmptyChangedDelegate; diff --git a/Source/EasyLocalizationToolEditor/Public/SELTEditorWidget.h b/Source/EasyLocalizationToolEditor/Public/SELTEditorWidget.h index 58f6487..cdcf909 100644 --- a/Source/EasyLocalizationToolEditor/Public/SELTEditorWidget.h +++ b/Source/EasyLocalizationToolEditor/Public/SELTEditorWidget.h @@ -33,6 +33,7 @@ class EASYLOCALIZATIONTOOLEDITOR_API SELTEditorWidget : public SUserWidget void SetGlobalNamespace(const FString& GlobalNamespace); void SetSeparator(const FString& Separator); void SetFallbackWhenEmpty(const FString& FallbackWhenEmpty); + void SetGenerateKeyReferenceStringTable(bool bGenerateKeyReferenceStringTable); void SetLogDebug(bool bLogDebug); void SetPreviewInUI(bool bPreviewInUI); @@ -54,6 +55,7 @@ class EASYLOCALIZATIONTOOLEDITOR_API SELTEditorWidget : public SUserWidget bool bIsLocalisationPreviewEnabled_Chkbox = false; bool bManuallySetLastLanguage_Chkbox = false; bool bOverrideLanguageOnStartup_Chkbox = false; + bool bGenerateKeyReferenceStringTable_Chkbox = false; bool bLogDebug_Chkbox = false; bool bPreviewInUI_Chkbox = false;