# Generate dynamic text with Smart Strings

> Understand how Smart Strings format dynamic text using named placeholders, sources, and formatters.

Understand how Smart Strings format dynamic text using named placeholders, sources, and formatters.

Smart Strings are a Unity port of the [SmartFormat](https://github.com/axuno/SmartFormat) library, provided by the `Unity.SmartStrings` module. They are an alternative to [String.Format](https://learn.microsoft.com/en-us/dotnet/api/system.string.format) for generating dynamic text.

You can create data-driven templates that support pluralization, gender conjugation, lists, and conditional logic. Named placeholders give translators more context, and make variables more readable and less error-prone than numeric indices.

Format a Smart String with [`Smart.Format`](/engine/6000.7/script-reference/unity/smartstrings/smart/format.md):

```cs
// "The name is Lara."
            Smart.Format("The name is {Name}.", new Character { Name = "Lara" });
```

## Placeholders

A Smart String is literal text interspersed with placeholders. A placeholder is wrapped in braces (`{` and `}`) and contains up to four parts, in order: a selector, a formatter name, formatter options, and a format.

{ /*  Mermaid source kept for the future doc platform; shown as the static image below until mermaid rendering is supported.  */ }

```mermaid
flowchart TD
    full["{slider.value:choose(1|2|3):one|two|three}"]

    full --> p1["slider.value"]
    full --> p2["choose"]
    full --> p3["(1|2|3)"]
    full --> p4["one|two|three"]

    p1 --> d1["Selectors"]
    p2 --> d2["Formatter name"]
    p3 --> d3["Formatter options"]
    p4 --> d4["Format"]

    classDef code   fill:#F5F5F5,stroke:#BDBDBD,color:#111;
    classDef orange fill:none,stroke:none,color:#F37021;
    classDef green  fill:none,stroke:none,color:#67BC6B;
    classDef pink   fill:none,stroke:none,color:#EB417A;
    classDef purple fill:none,stroke:none,color:#765BA7;

    class full code;
    class p1,d1 orange;
    class p2,d2 green;
    class p3,d3 pink;
    class p4,d4 purple;

    linkStyle default stroke:#2196F3,stroke-width:1.5px;
```


**The parts of a Smart String placeholder: selectors, formatter name, formatter options, and format.:**
![](/api/media?file=/engine/6000.7/media/images/smart-strings-placeholder-parts.svg)

For example, in the Smart String `{player.score:choose(1|2|3):one|two|three}`, the parts can be split into the following:

| Part              | Example           | Description                                                                               |
| ----------------- | ----------------- | ----------------------------------------------------------------------------------------- |
| Selectors         | `player.score`    | Extracts the value to format. A [source](#selectors-and-sources) evaluates the selectors. |
| Formatter name    | `choose`          | The [formatter](#formatters) to apply. Optional: omit it to apply an implicit formatter.  |
| Formatter options | `(1\|2\|3)`       | Options passed to the formatter, inside parentheses.                                      |
| Format            | `one\|two\|three` | The output template the formatter uses.                                                   |

To escape a literal brace, use a backslash: `\{` and `\}`.

> **Note:**
>
> By default, Smart Strings use `{` and `}` as the placeholder characters and a backslash to escape them (`\{` and `\}`). The parser also interprets character escapes such as `\n` and `\t` in the format string. Refer to [Smart Strings settings reference](/engine/6000.7/manual/scripting/smart-strings/settings.md) for information on the different settings and how to enable them.

## How a Smart String is formatted

To format a placeholder, Smart Strings evaluate the sources to extract a value and then apply a formatter to convert that value to text.

{ /*  Mermaid source kept for the future doc platform; shown as the static image below until mermaid rendering is supported.  */ }

```mermaid
flowchart TD
    parse["Parse the format string"]

    subgraph item["For each format item"]
        literal{"Literal text?"}
        resolve["Resolve the value<br/>using the Sources"]
        resolved{"Value resolved?"}
        format["Format the value<br/>using the Formatters"]
        formatted{"Value formatted?"}
        writeText["Write text to output"]
        writeVal["Write result to output"]
        errSel["Error: could not<br/>evaluate the selector"]
        errFmt["Error: no suitable<br/>Formatter found"]

        literal -->|Yes| writeText
        literal -->|No| resolve
        resolve --> resolved
        resolved -->|No| errSel
        resolved -->|Yes| format
        format --> formatted
        formatted -->|No| errFmt
        formatted -->|Yes| writeVal
    end

    parse --> literal
    item --> returnStr["Return the output string"]

    classDef proc fill:#F5F5F5,stroke:#2196F3,color:#111;
    classDef err  fill:#FCE5EC,stroke:#EB417A,color:#111;
    classDef ok   fill:#E9F4E9,stroke:#67BC6B,color:#111;

    class parse,literal,resolve,resolved,format,formatted,returnStr proc;
    class errSel,errFmt err;
    class writeText,writeVal ok;

    style item fill:#DAEDFD,stroke:#2196F3;
    linkStyle default stroke:#2196F3,stroke-width:1.5px;
```


**How a Smart String is formatted: the format string is parsed, then each item is resolved by the sources and formatted by the formatters, producing output text or a formatting error.:**
![](/api/media?file=/engine/6000.7/media/images/smart-strings-format-process.svg)

> **Note:**
>
> By default, a selector that no source can evaluate, or a value that no formatter can handle, raises a formatting error. Change the parser and formatter error actions in the Smart Strings settings to instead ignore the error, output it in the result, or leave the placeholder unchanged. Refer to [Smart Strings settings reference](/engine/6000.7/manual/scripting/smart-strings/settings.md) for information on the different settings and how to enable them.

## Selectors and sources

Selectors extract the object to format, usually from an argument. Sources evaluate the selectors. Each source is tried in order until one can handle the selector. For example, the [Properties source](/engine/6000.7/manual/scripting/smart-strings/sources/properties-source.md) reads a member by name from the current object.

Selector syntax is similar to C# [interpolated strings](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated):

* Use dot notation to drill into values, for example `{1.gameObject.name}`. When no index is given, the argument at index `0` is used.
* Use the null-conditional operator `?.` for safe access (`{gameObject?.transform?.parent}`). If a selector before the null-conditional operator `?.` is null, the placeholder evaluates to null instead of raising an error.
* Access list elements by index with brackets, for example `{items[0]}`.

Because sources are tried in order, the order can change the result. Refer to [Smart Strings settings](/engine/6000.7/manual/scripting/smart-strings/settings.md) for information on how to configure the order in which sources are tried.

Avoid named placeholders that conflict across sources. Refer to the source pages for the available sources, such as [Default](/engine/6000.7/manual/scripting/smart-strings/sources/default-source.md), [Properties](/engine/6000.7/manual/scripting/smart-strings/sources/properties-source.md), [Dictionary](/engine/6000.7/manual/scripting/smart-strings/sources/dictionary-source.md), and [String](/engine/6000.7/manual/scripting/smart-strings/sources/string-source.md).

### Multiple arguments

Pass multiple arguments and select them by index:

```cs
var person = new Character { Name = "John" };
            var location = new Place { City = "Washington" };

            // "First: John, second: Washington"
            Smart.Format("First: {0.Name}, second: {1.City}", person, location);
```

### Nesting and scope

Nest placeholders to avoid repeating a selector. The following are equivalent:

```text
{User.Name} ({User.Age}) {User.Address.City}
{User:{Name} ({Age})} {User.Address:{City}}
```

You can still reach outer scopes from within a nested scope. An empty placeholder `{}` refers to the current value in scope.

## Formatters

Formatters convert the value returned by the selectors into text. You can format date and time, lists, plurals, or conditional logic.

Each formatter has a single name. Apply a formatter explicitly by name, or omit the name to let any formatter that supports automatic detection apply implicitly:

| Use      | Example                                |
| -------- | -------------------------------------- |
| Explicit | `I have {0:plural:1 apple\|{} apples}` |
| Implicit | `I have {0:1 apple\|{} apples}`        |

> **Note:**
>
> Each formatter has one name (for example, `plural`) and a `CanAutoDetect` flag that controls implicit use.

Implicit formatters are tried in order, so prefer an explicit name to avoid conflicts. Some formatters take options in parentheses, for example the `1`, `2`, and `3` in `{0:choose(1|2|3):one|two|three}`.

Refer to [Smart Strings settings](/engine/6000.7/manual/scripting/smart-strings/settings.md) for information on how to configure the order in which formatters are tried.

Refer to the formatter pages for the available formatters, such as [Choose](/engine/6000.7/manual/scripting/smart-strings/formatters/choose-formatter.md), [Conditional](/engine/6000.7/manual/scripting/smart-strings/formatters/conditional-formatter.md), [Plural](/engine/6000.7/manual/scripting/smart-strings/formatters/plural-formatter.md), [List](/engine/6000.7/manual/scripting/smart-strings/formatters/list-formatter.md), and [Sub String](/engine/6000.7/manual/scripting/smart-strings/formatters/substring-formatter.md). To add your own, inherit from [`FormatterBase`](/engine/6000.7/script-reference/unity/smartstrings/core/extensions/formatterbase.md). Refer to [Create a custom formatter](/engine/6000.7/manual/scripting/smart-strings/formatters/create-a-custom-formatter.md) for more information.

## Alignment

Add an alignment after the selectors, separated by a comma, to pad the result to a fixed width, like [String.Format](https://learn.microsoft.com/en-us/dotnet/api/system.string.format) alignment. A positive value right-aligns the value and a negative value left-aligns it:

```cs
Smart.Format("[{Name,10}]", new Character { Name = "Joe" });   // "[       Joe]"
            Smart.Format("[{Name,-10}]", new Character { Name = "Joe" });  // "[Joe       ]"
```

Alignment works with every formatter, not only the default formatter.

## Additional resources

* [Choose formatter](/engine/6000.7/manual/scripting/smart-strings/formatters/choose-formatter.md)
* [Plural formatter](/engine/6000.7/manual/scripting/smart-strings/formatters/plural-formatter.md)
* [Create a custom formatter](/engine/6000.7/manual/scripting/smart-strings/formatters/create-a-custom-formatter.md)
* [Default source](/engine/6000.7/manual/scripting/smart-strings/sources/default-source.md)
* [SmartFormat library](https://github.com/axuno/SmartFormat)
