I've spent the last couple of days rewriting an installer to make use of Burn. 
My goal was to have one executable that would present a localized user 
interface based off the user's UI language settings. I have documented my 
experiences below in case someone else would find the information useful. I am 
particularly interested to hear from anyone who has solutions (or better 
workarounds) for the problems I ran into.

I began by taking a copy of RtfTheme.wxl, and translating it into German and 
Dutch, saving the resulting files as RRtfTheme.de.wxl and RRtfTheme.nl.wxl 
respectively. I also created RRtfTheme.en_GB.wxl for testing purposes. I 
included these files into the bundle as follows:

<Bundle Name="English Title">
  <WixVariable Id="WixStdbaThemeWxl" Value="RRtfTheme.wxl"/>
    <BootstrapperApplicationRef 
Id="WixStandardBootstrapperApplication.RtfLicense">
    <!-- LCID reference: <http://msdn.microsoft.com/en-us/goglobal/bb895996> -->

    <Payload Id="thm-en_GB" Compressed="yes" Name="2057\thm.wxl" 
SourceFile="RRtfTheme.en_GB.wxl"/>

    <Payload Id="thm-de_DE" Compressed="yes" Name="1031\thm.wxl" 
SourceFile="RRtfTheme.de.wxl"/>
    <Payload Id="thm-de_CH" Compressed="yes" Name="2055\thm.wxl" 
SourceFile="RRtfTheme.de.wxl"/>
    <Payload Id="thm-de_AT" Compressed="yes" Name="3079\thm.wxl" 
SourceFile="RRtfTheme.de.wxl"/>
    <Payload Id="thm-de_LU" Compressed="yes" Name="4103\thm.wxl" 
SourceFile="RRtfTheme.de.wxl"/>
    <Payload Id="thm-de_LI" Compressed="yes" Name="5127\thm.wxl" 
SourceFile="RRtfTheme.de.wxl"/>

    <Payload Id="thm-nl_NL" Compressed="yes" Name="1043\thm.wxl" 
SourceFile="RRtfTheme.nl.wxl"/>
    <Payload Id="thm-nl_BE" Compressed="yes" Name="2067\thm.wxl" 
SourceFile="RRtfTheme.nl.wxl"/>
  </BootstrapperApplicationRef>
</Bundle>

At runtime, the generated setup.exe calls GetUserDefaultUILanguage and looks 
for its resources (theme, localization strings, logo, RTF license, etc.) within 
a directory corresponding to the result. If they don't exist, it will try the 
same for the result of GetSystemDefaultUILangauge. If this also fails, it will 
fall back to the files in the parent directory.

In order to have the translation for each language be activated in all the 
locales where the language is used, it was necessary to embed the language file 
multiple times, once for each locale. This is not ideal; I would prefer for 
Burn to use locale names rather than numeric IDs[0]; the above would then look 
more like the following.

    <Payload Id="thm-en_GB" Compressed="yes" Name="en-GB\thm.wxl" 
SourceFile="RRtfTheme.en_GB.wxl"/>
    <Payload Id="thm-de" Compressed="yes" Name="de\thm.wxl" 
SourceFile="RRtfTheme.de.wxl"/>
    <Payload Id="thm-nl" Compressed="yes" Name="nl\thm.wxl" 
SourceFile="RRtfTheme.nl.wxl"/>

Different locales can be tested by running the installer with the "-lang" 
argument; for instance, "-lang 1031" gave me the German UI. At this point, I 
noticed a few problems:

 1. The strings in RtfTheme.wxl reference the WixBundleName variable 
(initialized from the Bundle/@Name attribute), which the documentation says can 
be changed at run-time, however I couldn't work out how to do this based on the 
user's UI language. While it's easy to hardcode the translated product name in 
the .wxl file for each language, the value of WixBundleName is still used in 
Add/Remove Programs, which therefore remains unlocalized. I am assuming that it 
is currently necessary to provide custom bootstrapper application code to 
perform this change.

 2. The location and sizes of all the controls in the theme files are hardcoded 
based on the English strings. I had to make a copy of RtfTheme.xml for each 
language, modifying the control layout in order to get things looking good. 
Fortunately the default Burn UI is very clean and simple, so this didn't take 
too long. However... does anyone know what happens when you run the installer 
on Windows XP, which doesn't have the Segoe UI font? I haven't got a working XP 
machine to test with at the moment, but I think I may have to change the font 
to MS Sans Serif, or another font that is present on all XP machines...

 3. The prompt that asks if you really want to cancel installation is not 
translated. This is only a minor problem that I guess will be fixed when Burn 
receives more i18n work. :)

I wanted my installer to contain several MSI packages, and choose which one to 
install based on the user's language. This is just so that the user gets Start 
Menu entries in their own language; the actual files installed are the same, no 
matter which MSI is installed. This is done by creating product_en.msi, 
product_de.msi and product_nl.msi with their Product/Media/@Name attribute set 
to the same cabinet file name, and with their @EmbedCab attribute set to 'no'. 
Light will happily create the cab files when the first MSI package is built, 
and re-use them thanks to the -reusecab option when the second and third 
packages are built. All three packages are then added to the Bundle's Chain, 
making use of the MsiPackage/@InstallCondition attribute to ensure that only 
one is actually installed:

<Chain>
  <!-- Keep these in sync with the payloads in the BootstrapperApplicationRef 
above -->
  <?define ic_de = "UserUILanguage = 1031 OR UserUILanguage = 2055 OR 
UserUILanguage = 3079 OR UserUILanguage = 4103 OR UserUILanguage = 5127"?>
  <?define ic_nl = "UserUILanguage = 1043 OR UserUILanguage = 2067"?>

  <!-- As the default package, the InstallCondition for product_en.msi must 
complement the InstallConditions for the other product_*.msi packages. -->
  <MsiPackage Compressed="yes" SourceFile="product_en.msi" Vital="yes" 
InstallCondition="NOT ($(var.ic_de) OR $(var.ic_nl))">
    <MsiProperty Name='INSTALLDIR' Value='[InstallFolder]'/>
    <MsiProperty Name='ARPSYSTEMCOMPONENT' Value='1'/>
  </MsiPackage>

  <MsiPackage Compressed="yes" SourceFile="product_de.msi" Vital="yes" 
InstallCondition="$(var.ic_de)">
    <MsiProperty Name='INSTALLDIR' Value='[InstallFolder]'/>
    <MsiProperty Name='ARPSYSTEMCOMPONENT' Value='1'/>
  </MsiPackage>

  <MsiPackage Compressed="yes" SourceFile="product_nl.msi" Vital="yes" 
InstallCondition="$(var.ic_nl)">
    <MsiProperty Name='INSTALLDIR' Value='[InstallFolder]'/>
    <MsiProperty Name='ARPSYSTEMCOMPONENT' Value='1'/>
  </MsiPackage>
</Chain>

At first I thought this would be a bit of a nightmare to maintain, but the use 
of preprocessor defines means it is pretty sane in practice. If only the 
Conditional Statement Syntax had the concepts of lists, and a way to test if 
the current language is within such a list... :)

I was initially puzzled that, while the -lang argument to the installer caused 
the correct translation to be activated, it did not cause the corresponding MSI 
package to be installed. This could be fixed if Burn were to expose the  locale 
ID that chose to use for resource loading (taking into account a manual 
override with -lang) in a new built-in variable, which I would use instead of 
UserUILanguage. This would also take care of the inconsistency that occurs if 
Burn choses to use the result of GetSystemDefaultUILanguage to load the UI 
resources. If this variable were to be persisted, then the user would be 
presented with the same UI language when preforming repair/modify/uninstall 
options from Add/Remove Programs.

Overall I'm very happy with the resulting installer. Burn is going to be an 
excellent tool once WiX 3.6 is finally released!

[0] This is possible without dropping support for Windows XP; you can use 
GetLocaleInfo to query the language and country codes used by a locale, and 
then construct your own "ll-CC" string for use in your application). To emulate 
Vista's GetUILanguageInfo function you can perform your own fallback search 
process (i.e., try "ll" after "ll-CC").


------------------------------------------------------------------------------
Keep Your Developer Skills Current with LearnDevNow!
The most comprehensive online learning library for Microsoft developers
is just $99.99! Visual Studio, SharePoint, SQL - plus HTML5, CSS3, MVC3,
Metro Style Apps, more. Free future releases when you subscribe now!
http://p.sf.net/sfu/learndevnow-d2d
_______________________________________________
WiX-users mailing list
WiX-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/wix-users

Reply via email to