Localization - joric/supraland GitHub Wiki
String table
Before implementing a text search, we need a string table for the items. It is in localization folder, can be extracted with FModel. String have unique ids and sorted alphabetically. Example data: (Supraland/Content/Localization/Game/en/Game.json
):
{
"": {
"B24F0E5044975DE4E498E4949A8B85D7": "Hmph! You're a resourceful one. Now scram!",
"A0C635784B282CA2F8CEB4A69D546723": "Hold and Release to attach beam to surface",
"41D92EB44FF35FE3BF9D119BCFC15B7B": "Hold to project",
"C970E3F84876734231CB2380B6C98467": "Hold to project",
"DA865FFA41B789D5BBB775BE6122B2DA": "Hold to scan for suitable surfaces",
"4E2D753A45BD0DE6B91338A868C4EE82": "Holy Gun",
"A4EEA0994A47894991E031B148C7DDFD": "Holy Gun",
"728A3CFA4C013A24881DC3849D321415": "Holy Sword",
"DFFC8061460EEDD467DD87AFA17989B6": "Holy Sword",
"66633FC5473999C260CD3595BEF98BAB": "Honey, do you have something to shoot that thing above me?",
}
}
Not all items have names, e.g. EnemySpawn1_C
(wooden grave) has no name, there's no "Wooden grave" string, only "Destroy Wooden Graves" and "You can now destroy wooden graves and prevent enemy respawning from these." for the "Holy Sword". Repeated entries are for different kinds of weapons, e.g. there are two holy swords, BuySwordHoly1_C
and BuySwordHoly2_C
.
From the UE documentation:
An FText object is then created for each UI text element. This isn’t just a string of text: it has a special structure that allows you to change cultures on the fly. When an FText object is created and the Localizable parameter is set to Yes (as it is by default), the text element is assigned a key that looks like this: «9567B129548DD2468752BA0F5». This key allows the text element to be identified during localization.
Probably can be extracted with scripting, objects have text entries, e.g.
{
"Type": "DeadHero_C",
"Name": "DeadHero2Austin",
"Properties" : {
"Name of Souvenir": {
"Namespace": "",
"Key": "ADAD6E46431FCFF06C3B429C195BAA88",
"SourceString": "Spy glasses"
}
}
Has its own string table entry:
"ADAD6E46431FCFF06C3B429C195BAA88": "Spy glasses",
Most of the items don't have strings in level data, it's in the blueprints.
E.g. Supraland/Content/Blueprints/Levelobjects/BuySwordHoly2.uasset
:
{
"Type": "TextRenderComponent",
"Name": "Name2_GEN_VARIABLE",
"Outer": "BuySwordHoly2_C",
"Class": "UScriptClass'TextRenderComponent'",
"Properties": {
"Text": {
"Namespace": "",
"Key": "728A3CFA4C013A24881DC3849D321415",
"SourceString": "Holy Sword",
"LocalizedString": "Holy Sword"
}
}
}
Has its own entry:
"728A3CFA4C013A24881DC3849D321415": "Holy Sword",
Hash
According to UE source (TextKey.cpp) it's Google's CityHash64:
uint32 HashString(const FTCHARToUTF16& InStr)
{
const uint64 StrHash = CityHash64((const char*)InStr.Get(), InStr.Length() * sizeof(UTF16CHAR));
return GetTypeHash(StrHash);
}
I coundn't find a match with Python's cityhash
module right away, and the actual hash is longer:
pip install cityhash
python
from cityhash import *
hex(CityHash64('Holy Sword'))
'0x27a21381d716238e'
But it's not really supposed to match, because those string hashes are never the same for the same strings, so there's some kind of deduplication added on top of the existing hash, but I didn't bother to investigate that.
Issues
Item names are in blueprints (mostly) as "SourceString" but I can't find any of the item descriptions, and some of the quest messages (a few of them are in the level data). I still can't find messages like "You can now destroy wooden graves", I just can't find this particular message anywhere aside from the localization data, either by hash or by string, I exported everything in FModel, and there are no matches. I guess those hashes are still in binary data somewere where it cannot be exported in json. Not sure what type of assets did I miss.