Creating a multilingual installer for Windows using WiX
- Tutorial
In this article I will share with you the practical experience gained over many years of creating installers in Famatech. Under the cutscene are theoretical calculations and practical instructions, both painlessly and “by feng shui”, in a way compatible with Windows Logo Testing, to create an installer that prompts the user to select the installation language and installs the product in the selected language. In this case, exclusively free solutions are used.
Before moving on to the technical part, I will spread a little thought on the tree and tell you why all these shamanistic dances with a tambourine are needed. So what does a typical Windows installer look like? This is a .msi or .exe file, which at startup is interested in where and what we will put, if possible it puts it, creates shortcuts where it can and launches the installed program so that the user can use it right away. A familiar sight, isn't it? This is how the installer looks until the task in front of the developer in all its glory to make a localized version. Russian, German, Chinese ... For users really want.
And if, as a rule, there are no problems with the program itself, then the installer puts the developer before a rather interesting choice. What are the options?
It’s impossible to honestly make an MSI that speaks to a user in their chosen language. But you can use the “military trick” and use the technique that you all saw in the installers of such big companies as Adobe or DrWeb: the installer is a .exe file that at startup prompts you to select a language, then extracts .msi from itself, conducts with it a number of strange manipulations, and then the installation goes in the selected language. The most popular type of “military trick” is the OrderShare-winning and well-deserved program. She will do MSI, and pack it in .exe, and attach the language selection menu herself. Everything in it is good, except for the price - about five thousand dollars per workplace. Not that it’s very expensive (we have a couple of licenses), but scalability suffers. You won’t put such an installer in open source, honestly you can’t give it to a freelancer for revision. But you can do without InstallShield, exclusively with the help of free programs, a shamanic tambourine and a couple of spells.
To begin with, we will make a simple multilingual program that we will install. The easiest and most visual way is to use the free Qt framework, in which multilingualism is made out of the box very well. Download and install everything to build the program here . Set the QTDIR environment variable to the folder where “bin \ qmake.exe” was installed (for the latest version of Qt, by default it will be “C: \ QtSDK \ Desktop \ Qt \ 4.7.3 \ mingw”) and the MINGWDIR environment variable to the folder where “bin \ mingw32-make.exe” was installed (for the latest version of Qt, when installed by default, it will be “C: \ QtSDK \ mingw”). These environment variables are needed by my build script in order to correctly assemble everything with one click :).
I have already prepared the program itself: we take the sources here, unpack somewhere and run the batch file with the saying name "build.bat". This batch file will collect a demo program from the sources and put the result in "% TEMP% \ multilang_test". If you go into this folder, we will see the executable file of our program, several Qt libraries and a localization file in Russian with the thoughtful extension “qm”. By running the program and using the top menu, we can switch the language between English and Russian on the fly. In order for the installer to tell the program what language it will speak, the first time it launches a special registry key, “HKCU \ Software \ my_company \ multilang_app \ lang_cur”, which can be set to 0 for the English interface language and 1 for Russian :
After the program turned out, you can make an installer for it. To build the installer, we will use the free WiX program from Microsoft (by the way, if my memory serves me right, this is the first Microsoft project that was transferred to open source). You can download and install it from here (requires .net framework). We also need a program to create the aforementioned bootstrapper - for these purposes we will use the free dotnetinstaller program, which you can download and install here . For dotnetinstaller, it is necessary to set the DNIDIR environment variable to the folder where “dotnetinstaller.exe” was installed (for the default installation, it will be “C: \ Program Files \ dotnetinstaller \ bin").
First we need to do MSI. WiX creates MSI from an XML description, which is quite simple and is discussed in detail in a number of articles on the Habr. In order not to go into details, I prepared the installer project: we take the sources here , unpack them somewhere and run the batch file with the saying name “build.bat”, the result of which will be a bunch of intermediate files and the final evolution - file "% TEMP% \ multilang_test \ multilang_install.exe "- the assembled multilanguage installer, running which we will see first the language selection menu, and then the installer interface in the selected language and the installed program also in the selected language:
How is that? Consider a sequence of magical actions leading to a result that is not much inferior to Adobe. First, we create English and Russian installers in MSI format - for this it is enough to indicate the WiX linker the command line key "-cultures: en-US" for English and "-cultures: ru-RU" for Russian (see build file).
We want to unpack and run the resulting MSI installers from our bootstrapper, depending on the language chosen. In principle, nothing prevents us from putting both MSIs in the bootstrapper as they are. But this will not be the best solution, since each MSI will contain ALL the files in our program and they differ only in lines of text and what value it is to write to the registry to set the default language. For small programs and two languages, this is not critical, but if the files of our program weigh at least a hundred megabytes, and it is localized in three dozen languages, then we probably will not want to create an installation package weighing three gigabytes. Therefore, we will only store one MSI in English in the bootstrapper, and for the rest we will store the so-called “transform” - the .MST file, which contains the difference between an English installer and a localized one. Such files are usually small in size and can be "applied" to the English MSI during installation in order to "turn" it into a localized one. To create an MST file, the torch program included with WiX is used. Curious people study the contents of the .bat file again.
Now we have one large MSI file and a small MST to turn it into Russian. Can I put in a bootstrapper? Theoretically, it is possible, in fact, if you put the files as they are, then again we get problems. This time at the stage of uninstalling the program. Uninstalling programs installed via MSI generally takes place in a rather funny way: during installation, Windows saves the MSI in its folder (by the way, one of the reasons for the desperate growth of the Windows folder), and during the uninstall, it uses the saved MSI. The problems with our files is that Windows MST is not able to save, and by installing the Russian version of the application using a combination of MSI and MST file, we will get potential problems when uninstalling through Add / Remove Programs: Windows will try to find the MST that was involved in the installation, will not be able to do this and will be very offended. In order not to upset Windows, MST files can be put inside MSI and applied directly from it. To do this, there is a special script on visual basic from Microsoft, availablehere and prudently put by me in the archive with the installer sources. The use of this script (curious again can look into the batch file) puts MST in MSI, and to run such an MSI in Russian mode, something like:
So, everything is ready - you can build bootstrapper. As already mentioned, for this there is a specially trained open source program with the strange name dotnetinstaller. In general, it is intended to create installers pulling the .NET Framework, but it can also create language selection menus and, depending on the selected language, extract and launch MSI with different command line keys. Like WiX, dotnetinstaller accepts the source in XML format (the already created project source is included). The project as a whole is quite simple: in it I tell dotnetinstaller that you need to make a menu with two languages, for English call MSI as it is, and for Russian with the applied transform.
The UTF-8 encoded sources used in my examples are fully commented in Russian and can serve as an example of a minimal multilingual program and a minimal installer for it. Unfortunately, as can be seen from the spells described above, MSI was not originally designed to create multilingual all-in-one installers, so creating such installers is a rather complicated process. So, if you don’t have an urgent need to certify for “Windows Logo” and have MSI for corporate clients, use InnoSetup or NSIS - there the task of creating a multilingual installer is much easier.
It should be noted that the demo program and demo installer are greatly simplified and contain only the minimum necessary to demonstrate the techniques described in the article.
I don’t say goodbye to sim and wait for comments. All examples are verified, but you understand, anything is possible on user computers. Therefore, if something does not work somewhere - write, fix it.
The results of applying all of the above can be found in our free Advanced IP Scanner program for scanning local networks. Multilingual installer, dynamic choice of interface language and so on. Comments on the scanner are also accepted :).
Why do I need a multilingual installer?
Before moving on to the technical part, I will spread a little thought on the tree and tell you why all these shamanistic dances with a tambourine are needed. So what does a typical Windows installer look like? This is a .msi or .exe file, which at startup is interested in where and what we will put, if possible it puts it, creates shortcuts where it can and launches the installed program so that the user can use it right away. A familiar sight, isn't it? This is how the installer looks until the task in front of the developer in all its glory to make a localized version. Russian, German, Chinese ... For users really want.
And if, as a rule, there are no problems with the program itself, then the installer puts the developer before a rather interesting choice. What are the options?
- The simplest solution is to make a bunch of installers, each of which will have a user interface in the desired language and install the program with the necessary files and settings so that it also displays its interface in the same language. Unfortunately, the method has a slight minus: as the number of localizations increases, managing 30+ installers is not very convenient. Plus, a funny moment pops up: if the user found the program through a search, then he is more likely to download it, if it is written next to it that it supports its language. Alas, not everyone knows English.
- You can make one installer and automatically select the program language at startup. This is the case, for example, with the 64-bit version of the popular 7-zip utility. Alas, this method also has a number of disadvantages. Firstly, users who do not know English can simply not cope with the installer’s interface. Secondly, the program selects the language at startup, often based on the system settings, which do not always correspond to what the user really wants. As a result, the program often does not guess and displays the interface in the wrong language that negatively affects such subtle matter as user experience.
- A good solution would be to offer the user to select the installer language and programs when the installer starts. But here we are faced with purely technological difficulties: the preferred type of installers for Windows, MSI, does not support this possibility in principle, and the use of Innosetup / Nsis leads to another problem - when certifying a program for Windows Logo, Microsoft urgently asks for the installer in the form of MSI . Plus, installers of the MSI form factor are very fond of large companies that use them to automatically update and deploy programs to thousands of computers with one click.
It’s impossible to honestly make an MSI that speaks to a user in their chosen language. But you can use the “military trick” and use the technique that you all saw in the installers of such big companies as Adobe or DrWeb: the installer is a .exe file that at startup prompts you to select a language, then extracts .msi from itself, conducts with it a number of strange manipulations, and then the installation goes in the selected language. The most popular type of “military trick” is the OrderShare-winning and well-deserved program. She will do MSI, and pack it in .exe, and attach the language selection menu herself. Everything in it is good, except for the price - about five thousand dollars per workplace. Not that it’s very expensive (we have a couple of licenses), but scalability suffers. You won’t put such an installer in open source, honestly you can’t give it to a freelancer for revision. But you can do without InstallShield, exclusively with the help of free programs, a shamanic tambourine and a couple of spells.
Exemplary Multilingual Program
To begin with, we will make a simple multilingual program that we will install. The easiest and most visual way is to use the free Qt framework, in which multilingualism is made out of the box very well. Download and install everything to build the program here . Set the QTDIR environment variable to the folder where “bin \ qmake.exe” was installed (for the latest version of Qt, by default it will be “C: \ QtSDK \ Desktop \ Qt \ 4.7.3 \ mingw”) and the MINGWDIR environment variable to the folder where “bin \ mingw32-make.exe” was installed (for the latest version of Qt, when installed by default, it will be “C: \ QtSDK \ mingw”). These environment variables are needed by my build script in order to correctly assemble everything with one click :).
I have already prepared the program itself: we take the sources here, unpack somewhere and run the batch file with the saying name "build.bat". This batch file will collect a demo program from the sources and put the result in "% TEMP% \ multilang_test". If you go into this folder, we will see the executable file of our program, several Qt libraries and a localization file in Russian with the thoughtful extension “qm”. By running the program and using the top menu, we can switch the language between English and Russian on the fly. In order for the installer to tell the program what language it will speak, the first time it launches a special registry key, “HKCU \ Software \ my_company \ multilang_app \ lang_cur”, which can be set to 0 for the English interface language and 1 for Russian :
... and a crippled multilingual installer
After the program turned out, you can make an installer for it. To build the installer, we will use the free WiX program from Microsoft (by the way, if my memory serves me right, this is the first Microsoft project that was transferred to open source). You can download and install it from here (requires .net framework). We also need a program to create the aforementioned bootstrapper - for these purposes we will use the free dotnetinstaller program, which you can download and install here . For dotnetinstaller, it is necessary to set the DNIDIR environment variable to the folder where “dotnetinstaller.exe” was installed (for the default installation, it will be “C: \ Program Files \ dotnetinstaller \ bin").
First we need to do MSI. WiX creates MSI from an XML description, which is quite simple and is discussed in detail in a number of articles on the Habr. In order not to go into details, I prepared the installer project: we take the sources here , unpack them somewhere and run the batch file with the saying name “build.bat”, the result of which will be a bunch of intermediate files and the final evolution - file "% TEMP% \ multilang_test \ multilang_install.exe "- the assembled multilanguage installer, running which we will see first the language selection menu, and then the installer interface in the selected language and the installed program also in the selected language:
How is that? Consider a sequence of magical actions leading to a result that is not much inferior to Adobe. First, we create English and Russian installers in MSI format - for this it is enough to indicate the WiX linker the command line key "-cultures: en-US" for English and "-cultures: ru-RU" for Russian (see build file).
We want to unpack and run the resulting MSI installers from our bootstrapper, depending on the language chosen. In principle, nothing prevents us from putting both MSIs in the bootstrapper as they are. But this will not be the best solution, since each MSI will contain ALL the files in our program and they differ only in lines of text and what value it is to write to the registry to set the default language. For small programs and two languages, this is not critical, but if the files of our program weigh at least a hundred megabytes, and it is localized in three dozen languages, then we probably will not want to create an installation package weighing three gigabytes. Therefore, we will only store one MSI in English in the bootstrapper, and for the rest we will store the so-called “transform” - the .MST file, which contains the difference between an English installer and a localized one. Such files are usually small in size and can be "applied" to the English MSI during installation in order to "turn" it into a localized one. To create an MST file, the torch program included with WiX is used. Curious people study the contents of the .bat file again.
Now we have one large MSI file and a small MST to turn it into Russian. Can I put in a bootstrapper? Theoretically, it is possible, in fact, if you put the files as they are, then again we get problems. This time at the stage of uninstalling the program. Uninstalling programs installed via MSI generally takes place in a rather funny way: during installation, Windows saves the MSI in its folder (by the way, one of the reasons for the desperate growth of the Windows folder), and during the uninstall, it uses the saved MSI. The problems with our files is that Windows MST is not able to save, and by installing the Russian version of the application using a combination of MSI and MST file, we will get potential problems when uninstalling through Add / Remove Programs: Windows will try to find the MST that was involved in the installation, will not be able to do this and will be very offended. In order not to upset Windows, MST files can be put inside MSI and applied directly from it. To do this, there is a special script on visual basic from Microsoft, availablehere and prudently put by me in the archive with the installer sources. The use of this script (curious again can look into the batch file) puts MST in MSI, and to run such an MSI in Russian mode, something like:
msiexec / i multilang_install_en.msi TRANSFORMS =: 1049
So, everything is ready - you can build bootstrapper. As already mentioned, for this there is a specially trained open source program with the strange name dotnetinstaller. In general, it is intended to create installers pulling the .NET Framework, but it can also create language selection menus and, depending on the selected language, extract and launch MSI with different command line keys. Like WiX, dotnetinstaller accepts the source in XML format (the already created project source is included). The project as a whole is quite simple: in it I tell dotnetinstaller that you need to make a menu with two languages, for English call MSI as it is, and for Russian with the applied transform.
Total
The UTF-8 encoded sources used in my examples are fully commented in Russian and can serve as an example of a minimal multilingual program and a minimal installer for it. Unfortunately, as can be seen from the spells described above, MSI was not originally designed to create multilingual all-in-one installers, so creating such installers is a rather complicated process. So, if you don’t have an urgent need to certify for “Windows Logo” and have MSI for corporate clients, use InnoSetup or NSIS - there the task of creating a multilingual installer is much easier.
It should be noted that the demo program and demo installer are greatly simplified and contain only the minimum necessary to demonstrate the techniques described in the article.
I don’t say goodbye to sim and wait for comments. All examples are verified, but you understand, anything is possible on user computers. Therefore, if something does not work somewhere - write, fix it.
And one more result
The results of applying all of the above can be found in our free Advanced IP Scanner program for scanning local networks. Multilingual installer, dynamic choice of interface language and so on. Comments on the scanner are also accepted :).