Still problem here. Missing String Tables show and localization dashboard cannot gather texts ![]()
I was having a similar issue (and confusion) on earlier versions, is this code still of use?
Confusion with String Table localization, c++ - #3 by Roy_Wierer.Seda145
I am on 4.2, gathered the texts, confirmed that they are there, and yet these specific texts do not show up and i also did the GameInstance BP change to the locale I gathered (“en”)
Hmm, i restarted the project, collected the texts again, Editor got stuck while I tried to edit the translations just to look at what it gathhered, so then I restarted the editor again, and now it works.
So many bugs in this crucial system ![]()
This needs to be solved ASAP. So many marketplace plugins can’t update to 5.4 because of it.
It was finally fixed in 5.4.2!
I solved this for me by adding the folder where my tables were to my packaging. Please let me know if this is a bad idea, but nothing else seems to fix it.
That’s actually required for them to be loaded if not referenced elsewhere (by a pointer in a UAsset). Otherwise you will get missing strings when attempting to localize from code, say by calling "FText::FromStringTable(InStringTableId, InKey)"
A “reference” from c++ does not count. For this reason I prefer to just add my string tables (and datatables too) directly from c++ to the scan settings, done from C++ like this:
/**Copyright: Roy Wierer (Ferrefy). All Rights Reserved.**/
#include "AssetUtils.h"
#include "Modules/ModuleManager.h"
#include "PropertyEditorModule.h"
#include "PropertyEditorDelegates.h"
#include "Settings/ProjectPackagingSettings.h"
#include "Engine/AssetManagerSettings.h"
void UAssetUtils::AddDirectoryToScanAndCook(const FString& InDirectory, const FName& InAssetType, const TSoftClassPtr<UObject> InAssetBaseClass) {
UProjectPackagingSettings* PackagingSettings = GetMutableDefault<UProjectPackagingSettings>();
check(IsValid(PackagingSettings));
// For whatever reason the datatype required is a poorly implemented directory one, containing just a string path.
const FDirectoryPath* PathX = PackagingSettings->DirectoriesToAlwaysCook.FindByPredicate([&InDirectory](const FDirectoryPath& PathX) { return PathX.Path == InDirectory; });
if (PathX == nullptr) {
FDirectoryPath NewPath = FDirectoryPath();
NewPath.Path = InDirectory;
PackagingSettings->DirectoriesToAlwaysCook.Add(NewPath);
}
UAssetManagerSettings* AssetManagerSettings = GetMutableDefault<UAssetManagerSettings>();
check(IsValid(AssetManagerSettings));
check(!InAssetBaseClass.IsNull());
/*
* The following error appears when managing assets in the asset manager which don't implement GetPrimaryAssetID, which is oddly.... the datatable and string table.
* [UE5.1.1] LogAssetManager: Error: Registered PrimaryAssetId DataTable:DT_XXXX for asset /SomePlugin/DT_XXXX.XXXX does not match object’s real id of ! This will not load properly at runtime!
* Setting the bShouldManagerDetermineTypeAndName to true works around this.
*/
AssetManagerSettings->bShouldManagerDetermineTypeAndName = true;
/**
* Note that there can only be one entry in the array per type, so merge the rules into an existing one:
* LogAssetManager: Error: Found multiple "StringTable" Primary Asset Type entries in "Primary Asset Types To Scan" config. Only a single entry per type is supported.
*/
FPrimaryAssetTypeInfo* ExistingInfo = AssetManagerSettings->PrimaryAssetTypesToScan.FindByPredicate([&InAssetType](const FPrimaryAssetTypeInfo& InfoX) { return InfoX.PrimaryAssetType == InAssetType; });
if (ExistingInfo == nullptr) {
FPrimaryAssetTypeInfo NewInfo = FPrimaryAssetTypeInfo();
NewInfo.PrimaryAssetType = InAssetType;
NewInfo.SetAssetBaseClass(InAssetBaseClass);
FDirectoryPath NewDir = FDirectoryPath();
NewDir.Path = InDirectory;
NewInfo.GetDirectories().Add(NewDir);
NewInfo.Rules.CookRule = EPrimaryAssetCookRule::AlwaysCook;
AssetManagerSettings->PrimaryAssetTypesToScan.Add(NewInfo);
}
else {
// See if the directory exists already and return if so.
if (ExistingInfo->GetDirectories().ContainsByPredicate([&InDirectory](const FDirectoryPath& PathX) { return PathX.Path == InDirectory; })) {
return;
}
// Let's not assume there is an existing entry with valid data, just because we can. Set the properties we need.
//ExistingInfo->PrimaryAssetType = InAssetType; // We already know this is set.
ExistingInfo->SetAssetBaseClass(InAssetBaseClass);
FDirectoryPath NewDir = FDirectoryPath();
NewDir.Path = InDirectory;
ExistingInfo->GetDirectories().Add(NewDir);
ExistingInfo->Rules.CookRule = EPrimaryAssetCookRule::AlwaysCook;
}
}
And called like this:
/**Copyright: Roy Wierer (Ferrefy). All Rights Reserved.**/
#include "CustomSettingsPluginEditorInstaller.h"
#include "AssetUtils.h"
#include "Engine/DataTable.h"
#include "Internationalization/StringTable.h"
// Setup
void FCustomSettingsPluginEditorInstaller::RunAutomatedInstaller() {
UAssetUtils::AddDirectoryToScanAndCook(TEXT("/CustomSettingsPlugin/Localization/Text"), TEXT("StringTable"), UStringTable::StaticClass());
UAssetUtils::AddDirectoryToScanAndCook(TEXT("/CustomSettingsPlugin/Data/DataTables"), TEXT("DataTable"), UDataTable::StaticClass());
}
Users just localizing UI through a text node in a UAsset (selecting a datatable and key) should not have to go through all that, since their node references the string table for them.
