@Increated’s method would work but I would not recommend using touched events on the clients and by client, I mean that you cannot use LocalPlayer in a serverScript, instead, use remote events, they are used to call the server and the client to do stuff like print something because before with filtering enabled off, hackers can just write in a normal script:
-- Hacker will type
part.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
-- Give money
end
end)
and everyone will see the money and the hacker can buy everything, but with filtering enabled on, if the hacker does the same thing, people cannot see the changes and the money will be the same (by that I mean not change) on the server, hence, he cannot buy anything, first you have to insert a remote event in a place where both a local script and a script can reach, like ReplicatedStorage, name it whatever, and then put a script into a part and type the traditional touch event:
part.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
end
end)
but instead of going into the PlayerGui (I don’t even think you can access it in a normal script), we need to “Fire the client”, I will explain this later but type
part.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
game.ReplicatedStorage.YourRemoteEventHere:FireClient()
end
end)
but if you run this, it would give an error, it is because the remote event does not know which player (client) to fire to, so the first parameter will be the player, assuming you already know the GetPlayerFromCharacter event, (if not then check it out here)
so because the hit.Parent will be a plr because it has a humanoid, but it can also be npc’s, so maybe you can check if the player for it exists with an if statement, and we can also “pass” the text, so type this:
part.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
local plr = game.Players:GetPlayerFromCharacter(hit.Parent)
game.ReplicatedStorage.YourRemoteEventHere:FireClient(plr,"Yourtexthere") -- this can have infinite arguments that you can "pass" to the client like the text
end
end)
then you can have a localscript in StarterGui or the gui where you want the text to type in, for now, I will put it in the gui textlabel where you want to put your text in
local typeLabel = script.Parent
local player = game.Players.LocalPlayer
game.ReplicatedStorage.YourRemoteEvent.OnClientEvent:Connect(function(passedText) -- The first parameter is the text you passed from the script, but you might be thinking that we sent two parameters, so it's because the first parameter of the player will not be passed because it's used to know who to fire the client, (and we can get it through localPlayer)
if passedText then
typeLabel.Text = passedText
wait(2)
typeLabel.Text = ""
end
end)
we are done, but keep it in mind that if you are firing the client or all clients, you need remoteEvent.OnClientEvent, but if you are firing the server, from the client, you need to do onServerEvent, and the OnServerEvent has the first parameter of player, not the fire, but the event itself, 
Edit: you can also put the string.sub in the client Event, just like in the server