Localized strings in setup, especially setup UI, tend to be full of flowery and marketing-driven language. They’re distasteful to type once, much less many times. You might have tried to use preprocessor variables in your WiX localization strings, like this:
<String Id="ProductLongName">$(var.ProductShortName)(R) $(var.ProductMarketingVersion)</String>
Then you discover that your product is now named “$(var.ProductShortName)(R) $(var.ProductMarketingVersion).” The reason for that is simple, if not obvious: $(var) references are handled by the WiX preprocessor, which happens before compilation, as part of Candle.exe. Localization strings are handled at bind time by Light.exe. The compiler and preprocessor are nowhere to be found.
One solution is to simply repeat yourself. It makes for straightforward localization strings but it means that some changes have to be reflected in multiple localization strings. For example, version numbers frequently show up in multiple strings.
Luckily, it doesn’t have to come to that. Though not explicitly documented (quelle surprise!), localization strings can contain references to other localization strings. For example, the following strings are legal:
<String Id="ProductShortName">BobStudio</String> <String Id="ProductMarketingVersion">2013 Update 2</String> <String Id="ProductLongName">!(loc.ProductShortName)(R) !(loc.ProductMarketingVersion)</String>
When used in authoring:
<Product Name="!(loc.ProductLongName)" ...
the resulting ProductName property is, exactly as you’d expect:
BobStudio(R) 2013 Update 2
The code in WiX responsible for this behavior is WixVariableResolver. As the name implies, it’s not limited to just localization variables, but also works for other bind-time variables. For example, you can also use the special !(bind) variables:
<String Id="ProductLongName">!(loc.ProductShortName)(R) !(loc.ProductMarketingVersion) [!(bind.fileVersion.App.exe)]</String>
BobStudio(R) 2013 Update 2 [3.7.1224.0]