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 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.
Inherit from the FormatterBase class (namespace Unity.SmartStrings.Core.Extensions) in your custom formatter. Override the TryEvaluateFormat method and inspect IFormattingInfo.CurrentValue to check whether the formatter can handle the value. If it can, write the output with IFormattingInfo.Write(...) 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 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.
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;
}
}
To enable your formatter, register it using the Smart.Default.AddExtensions(...) method. Then apply it by name:
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, 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.
If your formatter chooses between literal text branches, like the Choose, Conditional, and Null formatters do, implement IFormatterLiteralExtractor 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.