随着贸易国际化,在软件开发过程中,常会碰到需在现有中文版软件加入多语言支持的情况。由于不同语言版本间的差别通常仅是软件操作界面的不同,为实现多语言支持,使用纯资源DLL是一个不错的解决之道。所谓纯资源DLL是指只包含资源的DLL,譬如:快捷键、对话框、字符串、菜单、工具条、位图、图标、版本信息等等。
具体做法是:利用VC可视化编辑环境为每种语言制作一套资源ID一一对应的资源集并编译生成DLL文件。应用程序初始化时按预设的语言设置选择合适的资源DLL调入,使用资源时依据资源ID进行访问,这样即可实现软件的多语言支持。当然了,应用程序退出前,注意将动态调入的DLL文件占用的资源释放。
现有一个心电图查看程序,工程名为DispECG,语言为中文,现需加入英文支持。下面根据这个具体实例来说明在VC中加入多语言支持的具体实施方法。
(一)建立纯资源DLL
a)打开DispECG工程,在当前工作区中添加一个工程。方法:使用菜单FileNew…
b)从弹出的对话框中选择“Projects”页面,选择“Win32 Dynamic-Link Library”,工程名设置为“DispECG_ENG”,DispECG工程的工作目录为D:MyProjectDispECG,DispECG_ENG工程的工作目录为D:MyProjectDispECGDispECG_ENG。选择添加到当前工作区(注意Dependency of前的框不选),然后按OK。
c)建立一个简单的DLL工程
选择“A simple DLL project”,然后按“Finish”。此时新建的DispECG_ENG工程中会建立如下几个文件:DispECG_ENG.cpp,StdAfx.cpp,StdAfx.h以及ReadMe.txt。注意没有后缀为*.RC的资源文件。
其中DispECG_ENG.cpp中文件内容如下:
// DispECG_ENG.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
BOOL APIENTRY DllMain( HANDLE hModule,DWORD ul_reason_for_call,
LPVOID lpReserved)
{
return TRUE;
}
(二)为DispECG_ENG加入资源并编辑
a)使用Windows资源管理器将DispECG工程下的resource.h和DispECG.rc拷贝到DispECG_ENG工程下,将DispECG工程下的res子目录拷贝到DispECG工程下;
b)使用Windows资源管理器将DispECG_ENG工程下的DispECG.rc改名为DispECG_ENG.rc,将DispECG_ENG es下的DispECG.rc2改名为DispECG_ENG.rc2;
c)回到VC编辑环境。选择工作区中的文件视(FileView),选择“DispECG_ENG files”,单击右键,选择“Add Files to Project…”将DispECG_ENG工程下的resource.h和DispECG_ENG.rc加入到DispECG_ENG工程。
资源文件DispECG_ENG.rc及资源ID定义文件resource.h加入工程后:
d)修改编辑resource.h和DispECG_ENG.rc
d.1)将文件头的注释“Used by DispECG_ENG.rc”修改为“Used by DispECG_ENG.rc”
d.2)修改资源文件DispECG_ENG.rc,将
"#include ""res\DispECG.rc2"" // non-Microsoft Visual C++ edited resources "
"#include ""l.chs\afxres.rc"" // Standard components "
"#include "" l.chs\afxprint.rc"" // printing/print preview resources "
修改为
"#include ""res\DispECG_ENG.rc2"" // non-Microsoft Visual C++ edited resources "
"#include ""afxres.rc"" // Standard components "
"#include ""afxprint.rc"" // printing/print preview resources "
需要说明的是:MFC中含有一些预定义好的资源,不同的语言版本保存在不同的目录下,英文版保存在MFCInclude下,其它语言的版本则保存在Include的子目录中,譬如中文版对应的目录为l.chs,日文版对应l.jpn,韩文版对应l.kor,等等。
e)使用可视化编辑环境编辑对话框、菜单、字符串、版本等语言依赖性资源,将中文版翻译为英文版。当然,如果对资源文件的结构非常了解,可使用文本编辑器对资源文件直接编辑。方法是:使用“FileOpen…”打开文件对化框,找到“DispECG_ENG.rc”,注意打开方式选择“Text”。
完成文本的翻译是一项费时耗力的体力活儿,请耐心地仔细地一一做完。
f)修改工程设置,调整编译后DLL文件的存放位置。
由于按照默认的工程设置,DispECG_ENG.DLL的Release版自动生成在D:My ProjectDispECGDispECG_ENGRelease下,Debug版自动生成在D:My ProjectDispECGDispECG_ENGDebug下。为了程序的处理方便,资源DLL最好和应用程序的可执行文件存放在同一目录。为做到这一点,请修改工程配置。
方法:操作菜单“ProjectProject Settings…”
在“Project Settings”中选择“DispECG_ENG”工程,再选择“Link”页面,将输出文件名由“Release/DispECG_ENG.dll”修改为“../Release/DispECG_ENG.dll”,这样编译后生成的DLL文件将保存在D:My ProjectDispECGRelease下。
调试版也作类似的修改,使得编译后生成的DLL文件将保存在D:My ProjectDispECGDebug下。
g)编译DispECG_ENG工程,生成发行版和调试版的DispECG_ENG.DLL。
(三)在程序中添加多语言支持程序
a) 定义资源名称
在DispECG工程中的StdAfx.h中添加:
#define CHINESE 0
#define ENGLISH 1
b)定义两个全局变量,一个表示当前的语言选择,另一个为资源句柄。
UINT nLanguage = ENGLISH;
HINSTANCE hResourceHandle = NULL;
c)添加资源DLL载入程序
在完成应用程序初始化的BOOL CDispECGApp::InitInstance()中添加依据语言选择资源DLL的程序代码。
nLanguage = GetProfileInt("SETTINGS","LANGUAGE",ENGLISH);
if (nLanguage != CHINESE)
{
CString strFile;
strFile = "NewDispECG_ENG.dll";
hResourceHandle = AfxLoadLibrary(strFile);
ASSERT(hResourceHandle);
if (hResourceHandle)
{
AfxSetResourceHandle(hResourceHandle);
}
else
{
CString strText;
strText.Format("%s not found!",strFile);
::MessageBox(NULL,strText,"Error",MB_OK|MB_ICONERROR);
return FALSE;
}
}
d)添加资源DLL卸载程序
CDispECGApp::~CDispECGApp()
{
if (hResourceHandle)
AfxFreeLibrary(hResourceHandle);
}
e) 添加语言选择菜单和命令实现代码。
同步更新各种版本的资源,编辑菜单加入语言选择菜单项。注意同一菜单项不同语言版本的命令ID保持一致。
使用类向导添加命令响应:
void CDispECGApp::OnSwitchVersion()
{
WriteProfileInt("SETTINGS","LANGUAGE",1-nLanguage);
AfxMessageBox(ID_SWITCH_VERSION);
TRACE("%s %s %d
%s ",m_pszAppName,m_lpCmdLine,m_nCmdShow,m_pszExeName);
}
(四)修改程序代码,根据资源ID调用资源
如果原先的程序未考虑到多语言支持,在显示提示信息时可能使用如下的语句:
AfxMessageBox("文件无法打开!");
此时应该将诸如"文件无法打开!"此类的字符串添加到字符串资源中,其它语言版本同步更新。同样,注意字符串ID的彼此一致。一个好的习惯是,各版本的资源同步更新后,使用VC开发环境自带的WinDiff.exe对各个版本下的resource.h进行文件内容比较,以确保各语言的资源ID彼此完全一致。
修改完毕后,改用根据资源ID进行资源访问的函数。在实际编程中,最常用到的是对字符串资源的访问以及提示信息的显示,所以下面这些函数在需多语言支持的应用程序中会常被使用:
int AFXAPI AfxMessageBox( UINT nIDPrompt, UINT nType = MB_OK, UINT nIDHelp = (UINT) -1 );
BOOL LoadString( UINT nID );
void Format( UINT nFormatID, ... );
void FormatMessage( UINT nFormatID, ... );
...
至于其它资源,比如对话框、菜单等,通常由系统自动完成加载,无需程序员在软件中进行特别处理。
(五)编译调试
...