: Why UI Text Isn't a string — Verse Wiki">
Verse Wiki — the Verse handbook for Blueprint authors
EXTRA

message & <localizes>: Why UI Text Isn't a string

Fresh off learning string, you march up to a billboard to set its text — and the compiler coldly informs you: this takes a message, not a string. Nearly every creator has hit this wall. This page explains what message is, why it exists, and the one true path from string to the other side.

1. The Crash Site: SetText Refuses Your string

Building UI in UEFN — billboards, text_block widgets, any device with a SetText — you'll notice these device nodes' input pins want a message, not a string. More blindsiding still: there is no direct conversion between the two. No ToMessage() node, and no wire can connect a string straight into a message pin — force it and the pin types clash, going red the moment you hit Compile.

On the Epic developer forums, "how do I turn an @editable (a variable with Instance Editable ticked, in Blueprint terms) string exposed on the panel into a message for SetText" and "how do I dynamically create a localizes message" are two perennially hot threads. Both answers point at the same pattern — read on.

2. Why message Exists: A Text Asset, Not a Character Sequence

Why would Epic build two text types just to torment everyone? Because they answer two different questions.

A string is a character sequence: a definite []char — countable, iterable, concatenable — displayed exactly as the program wrote it. A message is a localizable text asset: it stands for a line meant for the player's eyes, and whether it shows up in Chinese, English or Japanese is decided by the player's language settings. When your project ships worldwide, message-typed text can enter the localization pipeline and get translated; a string stays forever the hard-coded characters it was born as.

So those UI device nodes insisting on message isn't hazing — it's a reminder: text shown to players should be translatable. Which fits Verse's standing philosophy — drag the hidden hazard (here, text welded in place that can never be translated into other languages) into the open early, so you have to face it while you're still wiring things up.

3. The Standard Fix: a <localizes> Function + Interpolation

The standard road from string to message is to build a Blueprint-style function, hang the <localizes> marker on it, and put a single interpolated line of text inside:

message_helper.verse
# Universal wrapper: pack any dynamic string into a message
MakeMessage<localizes>(Text:string):message = "{Text}"

# Parameterized version: fixed template, dynamic value — closer to what localization intends
ScoreMessage<localizes>(Score:int):message = "Score: {Score}"

Usage sketch:

billboard_text_device.verse
using { /Fortnite.com/Devices }

billboard_text_device := class(creative_device):

    @editable
    WelcomeText:string = "Welcome to the Arena"

    OnBegin<override>()<suspends>:void =
        Welcome := MakeMessage(WelcomeText)
        # Welcome is now a message — pass it to any UI API that expects one
        # Consult the Verse API Reference for the specifics

Blueprint translation: this billboard device makes WelcomeText a variable with Instance Editable ticked (@editable) — drop the device into a level and you can edit the text right in the Details panel; at start (Event BeginPlay) it feeds the text to the MakeMessage we just wrote, gets back a message, and can now plug into UI nodes that only accept message.

Unpacking the magic: <localizes> is like slapping a label on the function that says my output is a translatable text asset, so the line of text inside is treated as a message instead of a plain string; interpolation — {Text}, {Score} — handles embedding whatever dynamic values arrive at runtime. The interpolation syntax from Lesson 10 is reused verbatim here — only the product changes from string to message.

One practical tip: prefer the parameterized version over the universal wrapper whenever you can. With the ScoreMessage(120) shape — fixed template, dynamic value — translators receive the full sentence pattern to work with; MakeMessage(any string) merely launders a string into a message, and the localization pipeline can do nothing with it. The former is what message was designed for; the latter is a stopgap for @editable dynamic copy — only when you can use both is the wall truly behind you.

4. Pop Quiz ★

You want an @editable string (one with Instance Editable ticked) displayed on UI that requires a message. The correct approach is?

What is the essential difference between message and string?

Sources & Further Reading

This page draws on two heavily trafficked Epic developer forum threads:

Forum thread: How to convert strings from exposed properties into messages (SetText) ↗
Forum thread: How do you dynamically create <localizes> message ↗