一个智能的.NET多语言安装程序
一篇关于智能.NET多语言安装程序的文章
安装程序 / 更新程序
此项目基于我的 Cabinet 库 CabLib,该库也附带源代码发布在 The Code Project 上。
最初的目的是创建一个安装程序或安装包,用于安装一个包含 3000 个文件的 ASPX 服务器。但显然,您可以使用此安装程序来安装任何软件包。
安装文件仅包含一个微小的 EXE 文件(安装程序)和一个包含软件包所有文件的 CAB 文件。
CAB 文件可以是
- 在本地磁盘上(CAB 文件与 EXE 文件在同一文件夹中)
- 在本地网络中(指向文件服务器的 LNK 文件)
- 在互联网上(指向 HTTP(S) 或 FTP 服务器的 URL 文件)。
您可以使用安装程序做两件事
- 完成设置(安装整个软件包)
- 更新现有安装(只替换需要更新的文件)。
如果通过互联网进行更新,则可以部分下载CAB 文件
只会下载 CAB 文件中包含需要更新文件的部分。
显然,您可以根据需要扩展现有代码:例如,添加一些注册表项或在安装完成后运行脚本。
多语言
如果您不需要安装程序,您仍然可以使用此项目中的多功能多语言类,并在您自己的 .NET 项目中使用它。(请参阅下文。)

特点
- 安装过程是 100% 透明的:日志文件会准确显示哪些文件已被替换。(取决于它们的 MD5)
- 在安装新文件之前,用户可以将当前软件安装备份到一个 CAB 文件中。
- 如果您的新版本软件出现任何问题,可以非常轻松地恢复备份。
- CAB 文件中的数据可以加密。
- GUI 和日志文件条目是多语言的。
您可以通过简单地向 XML 翻译文件添加条目来轻松添加新语言,而无需修改一行代码。
限制
- 要打包到 CAB 文件中的文件总大小不得超过 2 GB。
- 生成的 CAB 文件不得超过 2 GB。
源代码
您将找到一份非常干净的 C# (Visual Studio 2003) 源代码,其中包含整洁的错误处理和由经验丰富的程序员编写的大量注释。
代码是可重用的,例如翻译类、MultiHashtable
或 Logfile
输出。
安装过程
与其长篇大论,我建议您下载项目并试用。请尝试以下操作:
- 勾选“创建备份”复选框,并在您的硬盘上指定任何文件夹。例如:C:\Program Files\Microsoft Office。
- 不要勾选“要安装的文件”复选框。
- 点击“开始”。
- 现在,安装程序将把所有文件(具有代码中指定的文件扩展名)打包成一个 CAB 文件,例如 Backup_2008.05.27_13.04.cab。
- 如果您打开此 CAB 文件,您还会找到一个 _FileList.txt 文件,其中存储了所有打包文件及其 MD5 列表。
- 现在您可以取消勾选“创建备份”并勾选“要安装的文件”,然后指定您最近创建的 CAB 文件。
- 如果您再次点击“开始”,安装程序将不会安装任何东西,因为所有文件都是最新的。
- 现在从您的文件夹 C:\Program Files\Microsoft Office 中删除一些文件。
- 如果您再次运行相同的安装程序,安装程序将向您显示您已删除的所有文件的列表,并询问您是否要安装它们(如果勾选了“...确认安装”)。
- 最后,打开日志文件,您会准确看到发生了什么。
从文件服务器安装
如果您想将 CAB 文件放在公司内部的文件服务器上进行内部安装,请在与 Installer.exe 相同的文件夹中放置一个链接 (*.LNK)。
该链接也将列在要安装文件的组合框中。
通过互联网安装
您还可以将 CAB 文件放在 HTTP(S) 或 FTP 服务器上,并在与 Installer.exe 相同的文件夹中的 *.URL 文件中指定地址。
如果您的 FTP 服务器支持断点续传,或者您的 HTTP(S) 服务器运行了一个微型脚本(参见 CabLib 文章),您可以使用部分下载进行更新。
这意味着只会下载 CAB 文件中提取过时文件所需的部分。
示例:您的软件包包含 500 个文件,其中只有 15 个文件在最新版本中发生了更改。服务器上的 CAB 存档包含您整个软件包的最新版本,无论您的客户端计算机上当前安装的是哪个版本:安装程序将只下载过时的文件。

传输的数据将是压缩数据,可选地是加密数据。(阅读关于 CAB 加密的内容。)
安装程序会自动决定是下载整个 CAB 文件还是部分下载更智能。
如果超过 50% 的文件需要更新,则整个下载将比多次部分下载更快。
重要提示
如果您的服务器不支持部分下载,您必须修改 Defaults.cs 文件中的块大小
在这种情况下,总是会下载整个 CAB 文件。
public static int GetDownloadBlocksize(bool b_Calculate)
{
return 0;
}
有关此重要参数的详细说明,请阅读 CabLib 文章!
日志文件
日志文件包含分析安装新版本软件包后可能出现的任何问题所需的所有信息。
日志文件可以作为所有安装的历史记录存储在服务器上。
CAB 文件以 UTC 时间存储所有文件。这样做的好处是文件时间独立于本地时区。

文件扩展名
您必须根据您的需求调整文件 Defaults.cs。
在那里您可以指定要包含在备份中的文件扩展名(白名单)和要忽略的文件扩展名(黑名单)。
如果在扫描文件夹时,文件扩展名既不在白名单中也不在黑名单中,则会在调试文件中写入警告,通知您必须更新文件扩展名列表。
CabLib.dll
所有压缩和解压功能都包含在 CabLib.dll 中。
此文件作为嵌入资源编译到 EXE 文件中。
因此,您唯一需要提供的文件是 EXE 和 CAB 文件。
多语言翻译类
如何避免
如果您曾尝试使用 Visual Studio .NET 构建多语言应用程序,您已经知道这简直是一场噩梦。
您唯一的选择是为每种语言和每个 GUI 窗体创建一个 RESX 文件。
如果您的 GUI 有 50 个窗口,并且您想支持 10 种语言,您将需要 500 个资源文件!!
要添加新语言,您必须恳求翻译人员翻译 50 个神秘的 RESX 文件!
对于 GUI 窗体中的每一个微小更改(例如添加一个按钮),您都必须修改 10 个资源文件。
丑陋,丑陋,丑陋,丑陋,丑陋!!
结论:Visual Studio .NET 提供的多语言支持不值得考虑。
您只会浪费时间在 Microsoft 的方法上!
简单
通过在您自己的项目中使用此安装程序的翻译类,您将能够轻松构建多语言应用程序。
- 您只需编辑一个XML 文件即可添加其他语言。您可以将此 XML 文件交给翻译人员,他们可以使用 WordPad 进行编辑。
- 无需重新编译您的项目——无论是纠正翻译错误还是添加语言。
有两种方法可以交付 XML 文件
- 您将 XML 文件作为嵌入资源编译到 EXE 中。这样它就是“固定”的。
- 您可以将 XML 文件放在与 EXE 相同的文件夹中,并在程序启动时加载它。
在这种情况下,用户可以编辑它,如果他喜欢,他可以自己纠正翻译错误或添加新语言。
您可以要求您的用户在添加新语言后通过电子邮件将 XML 文件发送给您,这样随着时间的推移,您的程序将支持越来越多的语言,而您甚至无需为此做任何事情!
GUI 设计

XML 文件包含每个表单的部分。
在表单设计器中,您将关键字放入大括号 {...} 中,在代码中,您只需添加一行
public panelSettings() // Constructor
{
InitializeComponent();
Lng.TranslateForm(this);
}
再简单不过了!
注意
在设计 GUI 窗体时,您有责任为其他语言中可能较长的文本留出足够的空间。
翻译人员有责任检查其翻译是否符合 GUI,如果不行,则应缩短其散文。
XML文件
除了窗体,XML 文件还包含错误消息和日志文件条目的部分。
显然,您可以根据需要添加自己的部分。
如果在指定部分中找不到条目,则会自动搜索“Common”部分。
因此,您可以将“Next”之类的文本(在多个位置使用)放入“Common”部分,而不是重复多次。
枚举 eXml
翻译类包含一个枚举 eXml
,用于所有不属于 GUI 的翻译(例如错误消息)。
如果您向 XML 文件添加错误消息,您还必须在此枚举中添加一个条目。
此枚举对于自动检查缺失的翻译至关重要(请参阅下文)。
XML 文件中的每个嵌套级别都由枚举 eXml
中的下划线表示

消息
要翻译像“Scanning files”这样的string
,您只需编写
string s_Scanning = Lng.TranslateString(Lng.eXml.Logfile_ScanFiles);
要翻译格式化的string
,例如“Backed up {0} files successfully.”,您需要编写
string s_Success = Lng.TranslateFormat
(Lng.eXml.Logfile_BackupSuccess, s32_FileCount, 0, 0);
要显示带有错误图标和文本“File not found: 'D:\Data\Setup.cab'”的消息框,您可以编写
Lng.ErrorBoxFormat(Lng.eXml.Messages_FileNotFound, s_File, 0, 0);
词语列表
要获取词语列表(例如,填充组合框或用于表格标题),您可以在 XML 文件中编写...
<FileList>
<english>File|Size|Date|MD5</english>
<german>Datei|Größe|Datum|MD5</german>
<spanish>Archivo|Tamaño|Fecha|MD5</spanish>
</FileList>
...在代码中...
string[] s_ColumnHeadings =
Lng.TranslateString(Lng.eXml.Logfile_FileList).Split('|');
...它只返回当前语言的值,或者...
Hashtable i_Hash = Lng.GetMultiString(Lng.eXml.Logfile_FileList);
...它返回一个 Hashtable
,其中包含英文键和翻译成当前语言的值(例如德语、西班牙语、英语)
键 | 值 |
文件 | 文件 |
大小 | 大小 |
日期 | 日期 |
MD5 | MD5 |
自动错误检查
翻译类包含自动检查缺失翻译的代码。
在您的程序菜单中,您可以放置一个“检查翻译”项,用户将收到缺少 string
的错误。
以下代码检查所有翻译
Lng.XmlErrorCheck(new Type[]
{ typeof(frmMain), typeof(panelSettings), .... } );
您必须传递所有 GUI 窗体和面板的类型。
因此,您的所有窗体和面板都必须支持默认(无参数)构造函数!
然后,检查例程将创建每个窗体和面板的实例,并检查 XML 文件中是否存在缺失的翻译。
此外,它还会检查枚举 eXml
中的条目是否缺少翻译。
如果缺少翻译,它会显示一个带有详细错误消息的消息框。
附注:如果您想将他人对 XML 文件所做的更改合并到您的版本中,我建议使用像 Araxis Merge 这样的合并工具。
历史
- 2008年5月31日:初次发布