在开发多语言支持的 MFC 应用程序时,如何实现动态语言切换是一个常见的问题。在本文中,我们将介绍两种实现语言切换的方式,并讨论其优缺点。同时,我们还会介绍如何通过保存配置文件来记住用户的语言选择,以及如何在程序启动时加载该语言设置。
第一种方式:通过资源切换实现语言切换
基本思路
在这种方式中,通过将应用程序的主要资源文件扩展为多语言版本(如中文和英文),并在程序运行时根据需要加载对应的资源来实现语言切换。
实现步骤
-
资源文件的多语言版本创建:
- 为每种语言创建独立的资源文件版本(如简体中文和英文)。
- 在资源视图中添加各自的语言对话框和字符串表。
-
加载对应语言的资源:
- 使用
SetThreadUILanguage
和SetThreadLocale
动态设置线程的语言和区域设置。 - 在应用程序启动时,根据语言配置文件选择合适的资源。
- 使用
-
保存语言配置文件:
-
使用
.ini
文件保存用户选择的语言。 -
例如:
ini[Settings] Language=zh-CN
-
优点
- 易于实现,直接利用 MFC 的多语言资源支持。
- 无需动态加载外部 DLL。
缺点
- 程序体积较大,因为所有语言的资源都嵌入在一个 EXE 文件中。
- 无法动态扩展语言,需要重新编译程序。
第二种方式:通过资源动态库实现语言切换
基本思路
在这种方式中,将每种语言的资源文件提取到独立的 DLL 文件中,程序运行时根据用户选择动态加载对应的资源 DLL。这样可以实现程序的轻量化,并支持动态扩展语言包。
实现步骤
-
创建语言资源动态库:
- 创建多个独立的资源 DLL 项目,例如
MFCApplication_en.dll
和MFCApplication_zh.dll
。 - 每个 DLL 包含对应语言的资源。
- 创建多个独立的资源 DLL 项目,例如
-
动态加载资源库:
- 在程序运行时,使用
AfxLoadLibrary
动态加载指定的资源 DLL。 - 使用
AfxSetResourceHandle
设置当前使用的资源句柄。
- 在程序运行时,使用
-
保存语言配置文件:
- 与第一种方式类似,使用
.ini
文件保存用户选择的语言。
- 与第一种方式类似,使用
优点
- 程序体积较小,每种语言的资源独立存储。
- 支持动态扩展语言,只需添加新的 DLL 即可。
缺点
- 实现复杂度较高,需要处理 DLL 的加载与释放。
- 程序运行时依赖外部资源文件(DLL)。
保存语言设置并实现自动加载
无论使用哪种方式,都需要保存用户的语言选择,并在程序启动时自动加载对应的语言设置。
初始化和退出实例
程序启动时自动加载;程序退出时释放资源库:
cpp
// CMFCApplicationApp 初始化
BOOL CMFCApplicationApp::InitInstance()
{
// 省略......
// 加载语言配置
CString language = LoadLanguageFromIni();
SetLanguage(language);
// 省略......
return FALSE;
}
int CMFCApplicationApp::ExitInstance()
{
if (g_hCurrentResource != NULL) {
FreeLibrary(g_hCurrentResource); // 释放当前资源库
g_hCurrentResource = NULL; // 清空资源句柄
}
return CWinApp::ExitInstance();
}
保存语言到 .ini
文件
以下代码用于保存用户选择的语言到 .ini
文件:
cpp
void CMFCApplicationApp::SaveLanguageToIni(const CString& language)
{
// 获取当前执行文件的目录
TCHAR szPath[MAX_PATH];
GetModuleFileName(NULL, szPath, MAX_PATH);
CString strPath = szPath;
strPath = strPath.Left(strPath.ReverseFind('\\')) + _T("\\Settings.ini");
// 保存语言配置到 .ini 文件
WritePrivateProfileString(_T("Settings"), _T("Language"), language, strPath);
}
加载语言设置
在应用程序启动时,读取 .ini 文件,加载对应的语言设置:
cpp
CString CMFCApplicationApp::LoadLanguageFromIni()
{
TCHAR szPath[MAX_PATH];
GetModuleFileName(NULL, szPath, MAX_PATH);
CString strPath = szPath;
strPath = strPath.Left(strPath.ReverseFind('\\')) + _T("\\Settings.ini");
TCHAR szLanguage[16] = { 0 };
GetPrivateProfileString(_T("Settings"), _T("Language"), _T("en-US"), szLanguage, 16, strPath);
return CString(szLanguage);
}
设置语言
在应用程序启动时,设置语言的两种方式:
cpp
void CMFCApplicationApp::SetLanguage(const CString& language)
{
#if 1
LANGID idLang = 0;
if (language == _T("zh-CN")) {
idLang = MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT);
}
else if (language == _T("en-US")) {
idLang = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
}
if (idLang != 0) {
SetThreadUILanguage(idLang);
SetThreadLocale(idLang);
}
#else
CString strLanguage;
if (language == _T("zh-CN")) {
strLanguage.Format(_T("MFCApplication_zh.dll"));
}
else if (language == _T("en-US")) {
strLanguage.Format(_T("MFCApplication_en.dll"));
}
// 加载新的资源库
g_hCurrentResource = AfxLoadLibrary(strLanguage);
// 设置新的资源句柄
if (g_hCurrentResource != NULL) {
AfxSetResourceHandle(g_hCurrentResource);
}
#endif // 0
}
实现语言切换后自动重启
为了应用新的语言设置,可以在用户切换语言后重启应用程序:
重启实现代码
在主对话框中,当用户点击按钮切换语言后,保存设置并触发程序重启:
cpp
void CMFCApplicationDlg::OnBnClickedButtonTestCN()
{
theApp.SaveLanguageToIni(_T("zh-CN"));
m_bRestartFlag = TRUE;
PostMessage(WM_CLOSE, 0, 0);
}
void CMFCApplicationDlg::OnBnClickedButtonTestUS()
{
theApp.SaveLanguageToIni(_T("en-US"));
m_bRestartFlag = TRUE;
PostMessage(WM_CLOSE, 0, 0);
}
void CMFCApplicationDlg::OnClose()
{
if (m_bRestartFlag) {
CString strFileName = _T("");
GetModuleFileName(NULL, strFileName.GetBuffer(MAX_PATH), MAX_PATH);
ShellExecute(NULL, _T(""), strFileName, NULL, NULL, SW_SHOWNORMAL);
strFileName.ReleaseBuffer();
}
CDialogEx::OnClose();
}
总结
通过上述两种方式,可以实现 MFC 应用程序的多语言支持:
方式一
适用于语言资源固定、无需动态扩展的情况。方式二
适用于需要动态扩展语言资源的情况。文件化存储方式
:- 将所有控件的 ID 和文本保存到文件中(例如 .ini 或 .json 文件)。
- 程序运行时动态加载文件内容,更新控件的文本。
- 无需重启即可切换语言。
通过保存用户选择的语言设置,并在程序启动时加载对应的语言,用户可以获得无缝的多语言体验。同时,结合程序的重启机制,可以确保语言切换后的即时生效。