Click here to Skip to main content
15,744,149 members
Articles / Programming Languages / C#
Posted 31 May 2008

Tagged as


96 bookmarked

An Intelligent .NET Multilanguage Installer

Rate me:
Please Sign up or sign in to vote.
4.92/5 (58 votes)
2 Jul 2008CPOL9 min read
An article about an intelligent .NET multilanguage installer

Installer / Updater

This project is based on my Cabinet Library CabLib which is also published with source code on The Code Project.

The original purpose was to create an Installer or Setup which installs an ASPX server consisting of 3000 files. But obviously you can use this Installer to install any software package.

The installation files consist of only a tiny EXE file (the installer) and a CAB file which contains all files of the software package.

The CAB file can be:

  1. on the local disk (CAB file in the same folder as the EXE file)
  2. in the local network (LNK file which points to a fileserver)
  3. on the Internet (URL file which points to an HTTP(S) or FTP server).

You can do two things with the installer:

  1. Complete Setup (the whole software package is installed)
  2. Update of an existing installation (only the files that need an update are replaced).
    If an update is done via Internet, a partial download of the CAB file is possible:
    Only the parts of the CAB file will be downloaded which contain the files that require an update.

Obviously you can extend the existing code to your needs: for example add some Registry entries or run a script when the installation is done.


If you don't need an installer, you can still use the versatile multi-language class from this project and use it in your own .NET projects. (See below.)

Image 1


  • The installation process is 100% transparent: The log file shows exactly which files have been replaced. (depending on their MD5)
  • Before installing new files, the user can make a backup of the current software installation into a CAB file.
  • If there should be any problems with the new version of your software, it is very easy to restore the backup.
  • The data in the CAB files can be encrypted.
  • The GUI and the Log file entries are multi-language.
    You can easily add a new language by simply adding entries to a XML translation file without modifying one line of code.


  • The total size of files which are to be packed into the CAB file must not exceed 2 GB.
  • The resulting CAB file must not exceed 2 GB.

Source Code

You will find a very clean C# (Visual Studio 2003) source code with tidy error handling and plenty of comments written by a very experienced programmer.
The code is reusable, as for example the translation class, the MultiHashtable or the Logfile output.

The Installation Process

Instead of writing long explanations, I recommend to download the project and play around with it. Try this:

  1. Set the checkbox "Create a backup" and specify any folder on your harddisk. For example: C:\Program Files\Microsoft Office.
  2. Do NOT set the checkbox "The file to be installed".
  3. Click "Start".
  4. Now the installer will pack all files (which have the file extensions which are specified in the code) into a CAB file like
  5. If you open this CAB file, you also find a file _FileList.txt which stores a list of all packed files and their MD5.
  6. Now you can uncheck "Create a Backup" and check "The file to be installed" and specify the CAB file you created recently.
  7. If you click "Start" again, the installer will not install anything because all files are up to date.
  8. Now delete some files from your folder C:\Program Files\Microsoft Office.
  9. If you run the same setup again, the installer will show you a list of all the files you have deleted and ask you if want to install them (if "... confirm the installation" is checked).
  10. At the end, open the log file and you see exactly what has happened.

Installation from a File Server

If you want to put the CAB file on a file server in your company for internal setups, put a link (*.LNK) in the same folder as the Installer.exe.
The link will also be listed in the combo box of the files to be installed.

Installation via Internet

You can also put the CAB file on a HTTP(S) or FTP server and specify the address in a *.URL file in the same folder as the Installer.exe.

If your FTP server supports resuming broken downloads or your HTTP(S) server runs a tiny script (see CabLib article) you can make updates with partial downloads.
This means that only the parts of the CAB file are downloaded which are required to extract the outdated files.

Example: Your software package consists of 500 files, of which only 15 files have changed in the latest version. The CAB archive on the server contains the latest version of your entire software package and no matter which version is currently installed on your client's computer: the installer will only download the files which are out of date.

Image 2

The data transferred will be compressed data and optionally encrypted data. (Read about CAB encryption.)

The Installer automatically takes the decision if it is more intelligent to download the entire CAB file or to download it partially.
If more than 50% of the files need an update, an entire download will be faster than multiple partial downloads.


If your server does NOT support partial downloads, you must modify the blocksize in the file Defaults.cs:
In this case, always the entire CAB file will be downloaded.

public static int GetDownloadBlocksize(bool b_Calculate)
    return 0;

For a detailed description of this important parameter, read the CabLib article!

The Log File

The logfile contains all information which is required to analyze any problem that might arise after installing a new version of a software package.
The Log files can be stored on a server as a history of all installations.
The CAB file stores all files in UTC time. This has the advantage that the file times are independent of the local timezone.


File Extensions

You must adapt the file Defaults.cs to your needs.
There you can specify which file extensions to include into a backup (whitelist) and which file extensions to ignore (blacklist).
If while scanning a folder, a file extension isn't found neither in the whitelist nor in the blacklist, a warning is written to the debugfile to inform you that you have to update your file extension lists.


All the compression and extraction functionality is contained in CabLib.dll.
This file is compiled as an embedded resource into the EXE file.
So the only files you have to deliver are the EXE and the CAB file.

The Multi-Language Translation Class

How Not To Do It

If you ever tried to build a multilanguage application with Visual Studio .NET, you already know that this is a real nightmare.
The only chance you have is creating one RESX file for each language and each GUI form.
If your GUI has 50 Windows and you want to support 10 languages you need 500 resource files!!
To add a new language, you have to beg the translator to translate 50 cryptic RESX files!
For every tiny change in a GUI form (e.g. adding a button) you have to modify 10 resource files.
Ugly, ugly, ugly, ugly, ugly!!

Conclusion: Visual Studio .NET does not offer any multilanguage support which is worth thinking about it.
You will only waste your time with Microsoft's approach!


Instead of using the translation class of this installer in your own projects, you will be able to build multilanguage applications without effort.

  1. You can add an additional language by simply editing ONE XML file. You can pass this XML file to the translators which can edit it with WordPad.
  2. There is no need to recompile your project - neither for correcting translation errors nor for adding languages.

There are two ways you can deliver the XML file:

  1. You compile the XML file into the EXE as an embedded resource. In this way it is "fixed".
  2. You can put the XML file into the same folder as the EXE and load it when the program starts.
    In this case, the user can edit it and if he likes, he can correct translation errors himself or add new languages.
    You can ask your users to email you the XML file when they have added a new language, so with time, your program will support more and more languages and you don't even have to do anything for that!

GUI Design

Image 4

The XML file contains a section for each form.
In the form designer, you put a keyword into braces {...} and in the code, you simply add one line:

public panelSettings() // Constructor

It cannot be easier anymore!


It is your responsibility when designing GUI forms to let enough space for texts which may be longer in other languages.
It is the responsibility of the translator to check that his translation fits into the GUI and, if it should not, to abbreviate his prose.

The XML File

Additionally to the forms, the XML file contains a section for error messages and for logfile entries.
Obviously you can add your own sections as you need.
The section "Common" will automatically be searched if an entry is not found in the specified section.
So you can put texts like "Next", which are used in multiple locations, into the section "Common" instead of repeating them multiple times.

Enum eXml

The translation class contains an enum eXml for all translations which are not part of a GUI (e.g. error messages).
If you add an error message to the XML file, you must also add an entry into this enum.
This enum is essential to automatically check for missing translations (see below).

Each nesting level in the XML file is represented by an underscore in the enum eXml:

Image 5


To translate a string like "Scanning files", you simple write:

string s_Scanning = Lng.TranslateString(Lng.eXml.Logfile_ScanFiles);

To translate a formatted string like "Backed up {0} files successfully.", you write:

string s_Success = Lng.TranslateFormat
    (Lng.eXml.Logfile_BackupSuccess, s32_FileCount, 0, 0);

To display a messagebox with an error icon and the text "File not found: 'D:\Data\'", you write:

Lng.ErrorBoxFormat(Lng.eXml.Messages_FileNotFound, s_File, 0, 0);

Word Lists

To get a list of words (for example, to fill a combo box or for a table heading), you write in the XML file...


... and in the code...

string[] s_ColumnHeadings =

... which returns only the values for the current language or...

Hashtable i_Hash = Lng.GetMultiString(Lng.eXml.Logfile_FileList);

... which returns a Hashtable with an English key and a value translated to the current language (e.g. German, Spanish, English):

Key Value

Auto Error Checking

The translation class contains code which automatically checks for missing translations.
Into a menu of your program, you can put an item "Check Translations" and the user gets an error for missing strings.

The following code checks all translations:

Lng.XmlErrorCheck(new Type[]
    { typeof(frmMain), typeof(panelSettings), .... } );

You must pass the types of all your GUI forms and panels.
Therefore all your forms and panels must support a default (parameterless) constructor!
Then the checking routine will create an instance of each form and panel and check the XML file for missing translations.
Additionally it will check if there are translations missing for one of the entries in the enum eXml.
If translations are missing, it shows a messagebox with a detailed error message.

P.S.: If you want to merge changes on an XML file made by another person into your version, I recommend using merge tools like Araxis Merge.


  • 31st May, 2008: Initial post


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Written By
Software Developer (Senior) ElmüSoft
Chile Chile
Software Engineer since 40 years.

Comments and Discussions

GeneralMy vote of 5 Pin
Manoj Kumar Choubey23-Feb-12 19:36
professionalManoj Kumar Choubey23-Feb-12 19:36 
GeneralMy vote of 5 Pin
JamesHurst18-Jul-11 0:11
JamesHurst18-Jul-11 0:11 
GeneralI'll try it out Pin
eumone10-Aug-10 3:08
eumone10-Aug-10 3:08 
QuestionTranslation of menu items. Pin
Moon_Walker21-May-10 3:45
Moon_Walker21-May-10 3:45 
AnswerHow to translate menu's Pin
Elmue21-May-10 4:42
Elmue21-May-10 4:42 
GeneralMy vote of 1 Pin
mikejobu235-Mar-10 15:08
mikejobu235-Mar-10 15:08 
GeneralInstallation Guide Pin
Syed Shahid Hussain3-Mar-10 3:30
Syed Shahid Hussain3-Mar-10 3:30 
GeneralWorks well for websites, but needs a different strategy for product deployment Pin
dB.2-Dec-09 3:41
dB.2-Dec-09 3:41 
GeneralRe: Works well for websites, but needs a different strategy for product deployment Pin
Elmue4-Dec-09 0:16
Elmue4-Dec-09 0:16 
GeneralMy vote of 1 Pin
mikejobu2320-Aug-09 12:17
mikejobu2320-Aug-09 12:17 
GeneralRe: My vote of 1 Pin
Paw Jershauge25-Mar-10 22:09
Paw Jershauge25-Mar-10 22:09 
GeneralError while attempting to download files from a URL Pin
rcole30-Sep-08 9:28
professionalrcole30-Sep-08 9:28 
GeneralRe: Error while attempting to download files from a URL Pin
Elmue15-Oct-08 14:31
Elmue15-Oct-08 14:31 
GeneralRe: Error while attempting to download files from a URL Pin
rcole20-Oct-08 7:22
professionalrcole20-Oct-08 7:22 
GeneralRe: Error while attempting to download files from a URL Pin
Elmue27-Oct-08 7:44
Elmue27-Oct-08 7:44 
GeneralRe: Error while attempting to download files from a URL Pin
rcole27-Oct-08 15:32
professionalrcole27-Oct-08 15:32 
NewsVersion 4.0 released Pin
Elmue1-Sep-08 12:30
Elmue1-Sep-08 12:30 
QuestionRe: Version 4.0 released Pin
Florin Pănescu31-Aug-14 7:25
Florin Pănescu31-Aug-14 7:25 
AnswerRe: Version 4.0 released Pin
Elmue6-Sep-14 7:02
Elmue6-Sep-14 7:02 
QuestionCompact Framework Pin
Merica25-Jun-08 7:38
Merica25-Jun-08 7:38 
QuestionRe-inventing the wheel? Pin
TopazJester4-Jun-08 23:28
TopazJester4-Jun-08 23:28 
AnswerRe: Re-inventing the wheel? Pin
Elmue6-Jun-08 14:03
Elmue6-Jun-08 14:03 
GeneralRe: Re-inventing the wheel? Pin
TopazJester11-Jun-08 2:38
TopazJester11-Jun-08 2:38 
GeneralInstallation advice Pin
Leblanc Meneses2-Jun-08 11:16
Leblanc Meneses2-Jun-08 11:16 
GeneralRe: Uninstaller Pin
Elmue2-Jun-08 17:56
Elmue2-Jun-08 17:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.