Multiple Language Resource Files – Quick & Dirty

Chris recently forwarded me a message from a reader asking for help installing language resource files via MSI and InstallShield. My response ended up being a lot more involved than I had originally planned so I thought I would blog about the topic.

First, a couple of notes:

  1. The information below is probably the easiest method for a few resource files with different names only. That does not mean it is a best practice. In fact, it isn’t a best practice – if you have a lot of resource files or all the resource files have the same name, then you’ll want to review MSDN topic Localizing a Windows Installer Package and the available Localization Example and author the MSI accordingly (to NOT use component conditions to control what files get installed).
  2. If you’re using merge modules, you should review the MSDN topic Authoring Multiple Language Merge Modules AND review the InstallShield topics (because IS doesn’t support authoring multi-language merge modules so if you need to exclude languages at MSI build time then you would need to create a different module for each language).
  3. If your MSI package has UI text streams that are localized, make sure the default code page property is set appropriately, that InstallShield is set up to generate multiple language transforms (1033.mst, 1036.mst, etc.) for each language you will support, and that the database summary information stream properties for the Template Summary and Codepage Summary are set correctly.

If you do need to only install one resource file depending on the OS language, then you need to add each resource file to the merge module as a separate component and then use a component condition to evaluate the SystemLanguageID property. Another advantage of this approach is that you can localize your shortcuts, registry entries, etc. because the records in those tables are tied to a particular component. So, if you had a shortcut with French text you would assign the shortcut table record to the component with resource-fr.xml as the key file and the shortcut would only be installed when the resource-fr.xml is installed.

If having multiple resource-??.xml files on your system is a problem, you need to do the following two things:

  1. Go smack the application developer upside the head. S/he should have coded the application to detect the language and load the approprate resource at run time.
  2. Make sure that the grouping of components is conditioned such that they are all mutually exclusive. IOW, only one of the components can possibly be installed at one time.

For example, to install only the French resource file, add a component with key file resource-fr.xml and set the component condition to:

SystemLanguageID=1036

The component will only be installed on systems where the System Locale Identifier Constant indicates French (0x040c hex – 1036 decimal).

If you need to install the French resource on other French locales (such as Belgium, Canada, Monaco, etc.) you would need to expand the condition to:

SystemLanguageID=1036 OR SystemLanguageID=2060 OR SystemLanguageID=3084 OR SystemLanaguageID=6156

Also, whatever your default language should be (English?) then you want the condition for the component that contains that resource file to evaluate so that it installs on all systems that don’t match any of the conditions for the other resource components. So if you only had French (with the previously mentioned locales) and English and you wanted English to be the default then you would set the condition for the English component to:

SystemLanguageID<>1036 AND SystemLanguageID<>2060 AND SystemLanguageID<>3084 AND SystemLanguageID<>6156

…and NOT to:

SystemLanguageID=1033

…since the latter will only install on systems where the local is set to English-US (IOW, any other system not covered by the other component conditions would never get any resource file installed).

A couple of other issues to consider:

  1. If your MSI can be installed per-user, you will also want to consider conditioning the components using the UserLanguageID property as that can be different from the SystemLanguageID (a user can set their user locale to ‘French’ when the system locale is set English so they see French and other users of the same system see English).
  2. To cover the scenario where your user installs under one language, changes the language settings, and then run’s ‘repair’. Make sure you set the msidbComponentAttributesTransitive attribute flags for your components with conditional statements so the conditions get reevaluated during a maintenance mode installation. This would allow the originally installed language component to be removed and the new language component installed for this scenario.