# Create a custom formatter

> Write your own formatter to convert a value into text inside a Smart String.

Write your own formatter to convert a value into text inside a Smart String.

To write your own custom formatter, create a class that inherits from the [`FormatterBase`](/engine/6000.7/script-reference/unity/smartstrings/core/extensions/formatterbase.md) class (namespace `Unity.SmartStrings.Core.Extensions`). Override the `DefaultName` property to set the name used to apply it. Override the `TryEvaluateFormat(IFormattingInfo)` method to implement your custom formatting. Register the formatter with `Smart.Default.AddExtensions(...)` so Smart Strings can use it.

## Write the formatter

Inherit from the [`FormatterBase`](/engine/6000.7/script-reference/unity/smartstrings/core/extensions/formatterbase.md) class (namespace `Unity.SmartStrings.Core.Extensions`) in your custom formatter. Override the `TryEvaluateFormat` method and inspect [`IFormattingInfo.CurrentValue`](/engine/6000.7/script-reference/unity/smartstrings/core/extensions/iformattinginfo/currentvalue.md) to check whether the formatter can handle the value. If it can, write the output with [`IFormattingInfo.Write(...)`](/engine/6000.7/script-reference/unity/smartstrings/core/extensions/iformattinginfo/write.md) and return `true`. If it can't, return `false` so the next formatter is tried.

The `CanAutoDetect` property is `false` by default, so your custom formatter only runs when applied by name. You can override this property and set it to `true` to run the formatter implicitly even when no name is given. If this is enabled, return `false` for values you can't handle in the `TryEvaluateFormat` method, so subsequent formatters get a chance to resolve the formatting.

If your custom formatter needs to be set up before it can be used properly (for example, if it needs to read the case-sensitivity setting), you can implement [`IInitializer`](/engine/6000.7/script-reference/unity/smartstrings/core/extensions/iinitializer.md) and its `Initialize(SmartFormatter)`. This method runs when the formatter is registered, and again after the settings asset deserializes.

The following Byte formatter example converts a byte count into a human-readable size. It handles a `long` value and returns `false` for anything else, so it only applies when the value is a `long`.

```cs
public class ByteFormatter : FormatterBase
    {
        public override string DefaultName => "byte";

        public override bool TryEvaluateFormat(IFormattingInfo formattingInfo)
        {
            if (formattingInfo.CurrentValue is long bytes)
            {
                // We are performing a Base 2 conversion here. 1024 bytes = 1 KB
                if (bytes < 512)
                {
                    formattingInfo.Write($"{bytes} B");
                    return true;
                }

                if (bytes < 512 * 1024)
                {
                    var kb = bytes / 1024.0f;
                    formattingInfo.Write($"{kb.ToString("0.00")} KB");
                    return true;
                }

                bytes /= 1024;
                if (bytes < 512 * 1024)
                {
                    var mb = bytes / 1024.0f;
                    formattingInfo.Write($"{mb.ToString("0.00")} MB");
                    return true;
                }

                bytes /= 1024;
                var gb = bytes / 1024.0f;
                formattingInfo.Write($"{gb.ToString("0.00")} GB");
                return true;
            }

            return false;
        }
    }
```

## Register the formatter

To enable your formatter, register it using the `Smart.Default.AddExtensions(...)` method. Then apply it by name:

```cs
Smart.Default.AddExtensions(new ByteFormatter());

            Smart.Format("The file size is {0:byte}", 1234L);  // "The file size is 1.21 KB"
```

| Smart String                | Argument     | Result                   |
| --------------------------- | ------------ | ------------------------ |
| `The file size is {0:byte}` | `100`        | The file size is 100 B   |
| `The file size is {0:byte}` | `1000`       | The file size is 0.98 KB |
| `The file size is {0:byte}` | `1234`       | The file size is 1.21 KB |
| `The file size is {0:byte}` | `10000000`   | The file size is 9.54 MB |
| `The file size is {0:byte}` | `2000000000` | The file size is 1.86 GB |

You can also add a custom formatter to the project's default formatter without code: in the [Smart Strings settings](/engine/6000.7/manual/scripting/smart-strings/settings.md), select **Add** (**+**) on the **Formatters** list and choose your formatter from the menu, which lists every available formatter type by name. Mark the class `[Serializable]` and give it a public parameterless constructor so it can be added and saved with the settings.

## Extract literal text

If your formatter chooses between literal text branches, like the [Choose](/engine/6000.7/manual/scripting/smart-strings/formatters/choose-formatter.md), [Conditional](/engine/6000.7/manual/scripting/smart-strings/formatters/conditional-formatter.md), and [Null](/engine/6000.7/manual/scripting/smart-strings/formatters/null-formatter.md) formatters do, implement [`IFormatterLiteralExtractor`](/engine/6000.7/script-reference/unity/smartstrings/core/extensions/iformatterliteralextractor.md) and its `WriteAllLiterals(IFormattingInfo)` method. In it, write every literal the formatter could output, not only the branch that matches the current value. Tools that walk a Smart String's literal text use this to find text that appears in only some branches.

For example, a tool can call `WriteAllLiterals` across every Smart String in a project to collect all the unique characters those strings could produce, then generate a font atlas that contains exactly those glyphs. Without it, a branch that isn't taken when the text is scanned would be missing from the extracted characters, so its glyphs could be absent from the atlas and fail to render at runtime.

## Additional resources

* [Choose formatter](/engine/6000.7/manual/scripting/smart-strings/formatters/choose-formatter.md)
* [Template formatter](/engine/6000.7/manual/scripting/smart-strings/formatters/template-formatter.md)
* [Smart Strings](/engine/6000.7/manual/scripting/smart-strings.md)
