wixtoolset / issues

WiX Toolset Issues Tracker
http://wixtoolset.org/
129 stars 36 forks source link

WIP: add support for multilingual MSI packages #7544

Open jmairboeck opened 1 year ago

jmairboeck commented 1 year ago

This is the WIP that was requested in RISCSoftware/CreateEmbedLangTransform#1:

Windows Installer unofficially allows using MSI packages that contain the UI in multiple languages and automatically show the UI in the user's language (from the Windows region setting).

This is accomplished by creating transforms that make up the differences between the languages and embedding these transforms as substorage objects into the MSI. The name of that must be the language id (LCID) in decimal (e.g. "1033" for en-US or "1031" for de-DE). Additionally, the list of supported languages must be declared in the Summary Information "Template" property. Officially (according to the documentation), for MSI packages, only a single language is supported and only merge modules support multiple.

However in practice, Windows Installer seems to support multiple languages also for MSI packages. When the installer is launched and the installer has declared support for the user's language and an appropriate transform is embedded in the installer, Windows Installer automatically applies that transform and displays the localized UI.

This WIP aims to support creating multilingual MSI packages, as described above, directly in WiX.

The WiX MSBuild build system currently supports creating multiple MSI packages when building a single .wixproj by using multiple .wxl files. This is achieved by calling wix build multiple times. Each of the created MSI packages contains a single language only. There exist some tools to create transforms from the MSIs and embed them into the main MSI, as well as adding the supported language IDs to the Summary information as described above, which can be used as a post-build step. Either some combination of the scripts provided by the Windows SDK can be used, or (more conveniently) a little command line tool that I wrote which does the necessary steps in one.

WiX 3 supported declaring support for multiple languages in the Summary information directly, using the Package/@Languages attribute. However, this resulted in broken MSI packages which would display an error when running them because the embedded transforms were missing. Creating and embedding the transforms would make the MSIs runnable. The second part of the post-processing was thus not necessary with WiX 3.

WiX should support creating multilingual MSI packages natively without the need for building multiple packages (caveat: if it is possible to build transforms without building full packages) and the post-processing steps described above. Even though support for this in Windows Installer is not officially documented, it is apparently used successfully by multiple projects and it would be nice if WiX supported this.

How to use this

The -culture switch of wix build should be extended to take a list of cultures instead of a single one. Alternatively, the switch should be able to be passed multiple times. The first culture specified is the "main" culture. The additional cultures are embedded into the package as language transforms. (Alternative proposal: is the -culture switch even needed in this case, or can the languages be inferred from the localization files?)

It is probably not needed to extend the source code for this (e.g. by restoring the Package/@Languages attribute). The language IDs can probably be inferred by the values that are used for the Package/@Language attribute. That attribute should be a localization key (e.g. Language="$(loc.LCID)", as it already is often) with the concrete values coming from the .wxl files.

The MSBuild build system needs some adjustments to not call WixBuild multiple times when building multiple cultures, but rather pass all cultures at once to wix build. A property should be added to opt in the new behavior, e.g. EnableMultilingualPackage.

The WiX compiler should create transforms for all additional cultures (languages) describing the differences between the language and the main one. These transforms must be stored in substorages (the _Storages table) of the package, using the language ID as the name. All language IDs should be added to the "Template" property of Summary information.

jmairboeck commented 1 year ago

I don't have any experience with WiX internals, so I probably can't implement this myself. The command line tool that I wrote uses the MSI query API and is more or less based on the scripts provided by the Windows SDK.

chrpai commented 1 year ago

reference: http://www.installsite.org/pages/en/msi/articles/embeddedlang/

I'm a little week in localization because I've always worked in EN_US enviornments. If I recall correctly, the MSI hack mentioned only supports ANSI localizations and not Unicode localizations? Does that sound correct or crazy?

FWIW, there's waning interest in Native MSI UI. Rich robost localized UI is fairly easy to accomplish using a bootstrapper. I've done this for a Swedish customer and he was very happy.

Without WiX support, this is still pretty easy to do using some custom build automation. Build your MSI, make a copy and update all the places you want changed and then generate a transform. Do that several times, load the transforms into the MSI and udpdate the SummaryInfo stream. Finally resign your MSI if you do that already.

jmairboeck commented 1 year ago

If I recall correctly, the MSI hack mentioned only supports ANSI localizations and not Unicode localizations? Does that sound correct or crazy?

We use UTF-8 (I think this is code page 65001) for our Chinese localization. It is not supported for Summary information though, so we use SummaryInformationCodepage="936" there additionally.

jmairboeck commented 8 months ago

I'm currently watching the recording of the latest WiX Online Meeting:

Thanks for unassigning me and putting it "up for grabs". I probably won't be able to do this myself. Last summer, I had a quick look how this could be done, but as I have no experience with the Wix codebase, I didn't actually implement anything. It turned out that this is probably more complicated than I thought.

Our current solution with our external tool works "good enough" for us. I will also maintain that as long as needed when we upgrade to a newer Wix version and there are changes needed (as I already did when migrating from Wix 3 to 4).

Having this built into Wix would surely be nice though, but it is not a big priority for us.