![]() |
Development Lifecycle »
Installation »
General
Beginner
License: The Code Project Open License (CPOL)
An Intelligent .NET Multilanguage InstallerBy ElmueAn article about an intelligent .NET multilanguage installer |
C#.NET 1.1, Dev
|
|
Advanced Search |
|
|
|
||||||||||||||||
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:
You can do two things with the installer:
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.)
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.
Instead of writing long explanations, I recommend to download the project and play around with it. Try this:
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.
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.
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 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.
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.
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.
There are two ways you can deliver the XML file:
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
{
InitializeComponent();
Lng.TranslateForm(this);
}
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.
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.
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:
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\Setup.cab'", you write:
Lng.ErrorBoxFormat(Lng.eXml.Messages_FileNotFound, s_File, 0, 0);
To get a list of words (for example, to fill a combo box or for a table heading), you write in the XML file...
<FileList>
<english>File|Size|Date|MD5</english>
<german>Datei|Größe|Datum|MD5</german>
<spanish>Archivo|Tamaño|Fecha|MD5</spanish>
</FileList>
... and in the code...
string[] s_ColumnHeadings =
Lng.TranslateString(Lng.eXml.Logfile_FileList).Split('|');
... 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 |
| File | Datei |
| Size | Größe |
| Date | Datum |
| MD5 | MD5 |
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.
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 2 Jul 2008 Editor: Deeksha Shenoy |
Copyright 2008 by Elmue Everything else Copyright © CodeProject, 1999-2009 Web10 | Advertise on the Code Project |