Introduction

In Parts 1 & 2, we created a Windows Installer using Wix in the form of an MSI file. In the real-world, installers often require localization, and in this part we'll look at a solution for localizing the installer into a second language; in this example Italian.

Strictly speaking, Windows Installer doesn't support multiple languages and can only store one set of strings at any point in time. However it does provide a mechanism which allows for localization via an implementation of transforms. A transform is a delta MST file which can sit inside or outside of the main MSI package. By supplying the transform to Windows Installer, the MSI content is replaced by matching content in the MST file at runtime before installation begins, which is ideal for localization.

Our localization solution involves the following steps:

Make the Wix source localizable

Generate an Italian version of the MSI file

Create an MST transform file

Embed the transform file into the original MSI

Localizing Wix

Wix contains all of the tools required for localization, and the WixUI library we are using already comes with stock translations for the UI dialogs provided. The localization authoring features allow us to move localizable strings into separate Wix translation files, which can then be swapped out by LIGHT when generating an MSI. This will ultimately make it easier to generate transforms later on in the process.

In the solution provided, all of the custom strings have been moved into external localization files and named with the relevant culture code. These are then referenced in the main source files using the syntax !(loc.VariableName). The WixLocalization element in the localization file must contain correct values for Culture and Codepage attributes for the localized version to function correctly with different character sets. We also add the language LCID as a translation string so that we can reference the language code as a variable in the main project and override the product language attribute.

The final localization file looks something like this:

<WixLocalizationCulture="en-GB"xmlns="http://schemas.microsoft.com/wix/2006/localization"Codepage='1252'><StringId='LANG'Overridable="yes">1033</String><StringId="Windows7Required"Overridable="yes">
This application only runs on Windows 7.</String>
...
</WixLocalization>

The main source code references these localization strings as follows:

Once the strings are re-factored into the localization files, we can go ahead and get these translated into multiple languages. A set of localization files are created for each new language and the culture specific attributes set up accordingly.

Create Localized MSI

LIGHT provides some handy features that allow us to create a localized version of the MSI. Firstly, the utility takes multiple translation files that can contain a mixture of cultures. The output file however will only contain a single set of translation strings. So how does this work?

The trick is the cultures argument that takes a list of cultures in order of precedence. From left to right, LIGHT will look through the supplied translations looking for the first matching culture for each string. This allows us to build fall-backs into our translation set.

Please note that WixVariables cannot reference localized translation variables, and therefore to swap out the path to the T&Cs agreement, we must change our solution so that this is passed through on the command line. We can then pass in references to different agreement files for each localized installer.

So implementing this technique, we can create an Italian version of the Installer as follows:

The example above will look for Italian translations, and for any strings not found, it will fall back to English. Note, the naming of the WXL files is irrelevant to the linker.

Creating a Transform

Now that we have an English and Italian version of the MSI, we can generate a transform file. The transform will contain a set of differences between the two files. In this case, it will contain just the Italian translations and a new agreement file.

The Wix TORCH tool is used to create the transform MST file as follows:

torch.exe setup.msi it-IT\setup.msi -o it-IT.mst

The resultant it-IT.mst file is smaller than the original and contains the transforms which can be applied to the original MSI file in order to localize the installer. It could be deployed alongside the MSI file, but in our case we want to embed the transform and create a single MSI for ease of deployment.

This is where we can leverage an undocumented and unsupported feature of Windows Installer which allows us to auto-detect the language of the installer from the user's region settings. By naming the transform with the corresponding LCID, Windows Installer will automatically apply the transform at runtime.

To test the auto-language detection functionality, change the regional settings by opening control panel and navigating to regional settings. On the first dialog which defines date and time Formats, select Italy from the language selector. Apply the settings and launch the MSI with no parameters. You should then see the Italian version of the installer.

Summary

In this part of the series, we talked through localizing the installer by leveraging some of the Wix tools and by taking advantage of some undocumented features of Windows Installer. Our installer is almost complete. In part 4, I'll show how to create bootstrapper for the installer that will detect and install any prerequisites.

Comments and Discussions

Good article, but I can't make auto-language detection work.
If I run setup as

msiexec /i setup.msi TRANSFORMS=":1046"

It shows Portuguese UI, but without the arguments it shows neutral language (English). I checked that CurrentCulture and CurrentUICulture are both Portuguese (Brazil) LCID=1046.
So it's supposed to work. Any known pitfalls in this area?

Hi Mike, this is a great article. Let me provide an additional information regarding transforms. There is one more way to let the installer apply the embedded transformations automatically (implicitly). In order to do so, we have to extend the list of supported languages in the summary information stream, e.g. calling the WiLangId.vbs script from the SDK (according your example):

cscript.exe WiLangId.vbs setup.msi Package 1033,1040

Thereafter the windows installer will automatically apply the available embedded transform based on the language set in the windows operating system's "Region & Language" option, which could be set using:

In that case simple double clicking the MSI will display the correct UI-Language if available (embedded). Furthermore let me note that unfortunately the explicit TRANSFORMS option will not work anymore.

Thanks for the info, can you clarify how the implicit example works. What is the Package parameter in the example?

Also when you say explicit transforms won't work any more, which version of Windows Installer does this relate to? I'm currently using it and it seems to behave as expected on our test environments (running Windows 7).