Set up a project-wide default formatter and customize Smart Strings formatting in code.
A Smart String is formatted by a SmartFormatter, which holds an ordered list of sources and formatters. You configure the formatter once for the whole project in a settings asset, or build a custom formatter in code and call it directly.
Create a Smart Strings settings asset to define the default formatter for the project and include it in player builds:
The asset is a SmartStringsSettings ScriptableObject. Its SmartFormatter property is initialized with Smart.CreateDefaultSmartFormat(). The active asset is stored as an EditorBuildSettings config object and added to the player’s preloaded assets at build time, so it ships in the player and registers itself at startup.
For details on the asset’s properties, refer to Smart Strings settings.
Smart.Default is the default SmartFormatter used by the static Smart.Format methods. It is created on first use from Smart.CreateDefaultSmartFormat(), which registers all core sources and formatters.
Smart.Default is marked [ThreadStatic], so each thread gets its own instance. Configure it on every thread that uses it.
To start from a fresh formatter with the core extensions registered, call Smart.CreateDefaultSmartFormat():
var formatter = Smart.CreateDefaultSmartFormat();
Sources and formatters are tried in list order, so the order changes which one handles a placeholder. Configure the lists on a SmartFormatter with these methods:
| Method | Description |
|---|---|
AddExtensions(params ISource[]) |
Adds source extensions. Well-known sources are inserted at their recommended position; others go at the end. A type that’s already present is skipped. |
AddExtensions(params IFormatter[]) |
Adds formatter extensions, with the same insertion and deduplication rules. |
InsertExtension(int, ISource) / InsertExtension(int, IFormatter)
|
Inserts a single extension at an explicit position in the list. |
RemoveSourceExtension<T>() / RemoveFormatterExtension<T>()
|
Removes the extension of type T. Returns true if it was found and removed. |
GetSourceExtension<T>() / GetFormatterExtension<T>()
|
Returns the extension of type T, or null if it isn’t registered. |
Refer to Smart.Format for API reference.
An extension that implements both ISource and IFormatter is registered in both lists automatically. The AddExtensions and InsertExtension methods return the same SmartFormatter, so you can chain calls.
// Remove a source and a formatter.
formatter.RemoveSourceExtension<DictionarySource>();
formatter.RemoveFormatterExtension<PluralLocalizationFormatter>();
// Add a custom source at the front so it's tried first.
formatter.InsertExtension(0, new MySource());
// Look up an existing extension.
var properties = formatter.GetSourceExtension<PropertiesSource>();
Call the static Smart.Format to format with Smart.Default. Pass an IFormatProvider (such as a CultureInfo) to control culture-dependent formatting:
// "Total: 1,234.5"
Smart.Format("Total: {0}", 1234.5);
// Format with a specific culture.
Smart.Format(CultureInfo.GetCultureInfo("de-DE"), "Total: {0}", 1234.5);
The SmartExtensions class adds convenience methods that use the same semantics as Smart.Format:
| Method | Description |
|---|---|
string.FormatSmart(params object[]) |
Formats the string as a template and returns the result. |
StringBuilder.AppendSmart(string, params object[]) |
Appends the formatted result to the StringBuilder. |
StringBuilder.AppendLineSmart(string, params object[]) |
Appends the formatted result followed by a line terminator. |
TextWriter.WriteSmart(string, params object[]) |
Writes the formatted result to the TextWriter. |
TextWriter.WriteLineSmart(string, params object[]) |
Writes the formatted result followed by a line terminator. |
var result = "Hello {Name}.".FormatSmart(new Character { Name = "Lara" });
var sb = new StringBuilder();
sb.AppendSmart("Score: {0}", 42);
To write directly into a StringBuilder or TextWriter without allocating an intermediate string, call SmartFormatter.FormatInto(IOutput, ...). The convenience methods above wrap an IOutput around the target for you.