• 多语言实现


    多语言示例

    本地化与国际化

    先解释两个名词,本地化国际化

    • 本地化 在软件工程中一般将外文界面的软件翻译为本土语言称为本地化,在中国也叫汉化。
    • 国际化 与本地化相反,一般将本土语言翻译成外文称为国际化

    其实二者没什么本质区别,在软件工程上都是实现软件的多语言支持。

    多语言要求

    对c++程序,实现多语言的基础是资源化,所有需要实现多语言的字段,都应该存在于资源中而不应该以明文的方式写在代码中。

    例如:

    acutPrintf(_T("测试资源"));	// 错误
    
    // 正确的示范:
    CString str;
    str.LoadString(IDS_STRING1);
    acutPrintf(str);

    一. 资源副本

    实现多语言的方案有很多,我们先说一种最简单的实现方案,这种方案的实现方式是分别编译不同语言版本的程序。这种方案实现简单,我们就以一个简单的mfc程序为例,代码在 ML_Demo_MultiVersion里。

    1. 创建一个简单的MFC 对话框程序

      image-20200304191526832
    2. 创建不同的语言配置

      image-20200304191617110

      image-20200304191726815

    3. 为资源创建不同语言的副本

      image-20200304191845976

      image-20200304191930775

      image-20200304192012713

    4. 在资源ID上右键属性,为不同副本设置条件

      image-20200304193032211image-20200304193102937

      注意,它们ID相同,但语言不同,条件也不相同(语言相同其实也没有关系)

      原有语言也要设置条件,Condition

    5. 修改不同语言对应的资源内容

      image-20200304192136001

    6. 在项目上右键属性,修改资源配置

      image-20200304193353651

      image-20200304193315500

      注意默认配置也要修改

    7. 现在分别运行两个配置可以看到效果

      Debug_enu:

      image-20200304193513865

      Debug:

      image-20200304193554124

    8. 总结:

      这种方式实现的多语言实现简单,只需要新增加配置,创建已有资源的副本就可以。但维护困难,适合已经完成的项目

      这种方式多语言的资源存在于同一个rc文件中,如果要对资源进行修改,必须同时修改多处,很容易遗漏,也没有太好的办法使用各种本地化工具进行维护。

    二、翻译多个资源文件

    资源副本存在于同一个rc文件中,不方便管理,我们的第二个方案,是使用不同的rc文件来管理资源。本示例代码在 MLDemo_MultiRc 文件夹中。我们还是以mfc对话框应用程序为例。

    1. 重复方案一中的步骤 1和2,创建 debug_enu配置。

      image-20200304191526832

      image-20200304191617110image-20200304191726815

    2. 复制资源文件

      在工程文件夹下,找到MLDemoMultiRc.rc,复制到同名文件夹下的 MLDemoMultiRc_en.rc

      image-20200305110450963

      注意,在同文件夹中复制,它可以和原rc文件共用同一个resource.h

    3. 将新的资源文件加入工程

      image-20200305103757280

      在资源文件夹上右键添加现有项,添加新的资源文件。

    4. 修改资源

      在资源界面下选择英文资源文件,修改其中的资源使用的字体

      image-20200305110540970

    5. 为不同配置选择资源

      此时,编译项目会提示资源重复:

      image-20200305104122315

    我们需要为不同的配置配置字体,在解决方案资源管理器视图分别选择两个rc文件,点击属性,为不同的配置排除不正确的字体:

    image-20200305104346809

    img

    注意这里是排除而不是选择,所以要为中文配置排除其它语言的资源,为英文配置排除中文资源。

    1. 编译运行

      image-20200305104536611image-20200305104555426

    到目前为止,所有操作都是手动完成,与方案一并无区别。也存在当资源更改好维护不便的问题。但是由于不同语言的资源存在于不同的文件,我们可以借助工具。

    三、 使用工具翻译多个资源文件

    多语言工具有很多,我们在这里使用经典的 Lingobit Localizer 。在方案2的基础上优化:

    1. 打开 Localizer软件,新建项目

    image-20200305105020713

    1. 选择本地化的原始语言,我们是中文,目标语言是英文:

    image-20200305105119360

    1. 选择要本地化的文件 MLDemoMultiRc.rc

    image-20200305105220305

    1. 完成后可以看到资源文件中的所有条目:

    image-20200305105413746

    1. 我们忽略代码条目,将中文条目翻译成英文:

    image-20200305105949210

    1. 配置翻译文件目标路径:

    image-20200305110135475

    1. 生成目标文件:

    点击创建或运行,选择要输出的语言。

    image-20200305110259920

    此时可以看到已经生成了MLDemoMultiRc_en.rc文件

    image-20200305110357304

    1. 重新编译运行

    image-20200305111827172

    1. 当资源发生改变时,比如添加一个字符串

    image-20200305111931157

    在Localizer中点击扫描:

    image-20200305112159220

    可以看到新添加的资源已经被导入进来了。

    1. 总结

      使用工具可以方便的管理翻译资源,避免重复劳动,也避免了难维护的缺点。这种方式可以为不同的语言管理不同的资源。一般已经可以满足我们的需求。

    四、资源dll

    以上三个方案,都是直接将代码编译为不同的语言版本,需要分别向客户提供分发包,或者将程序分为多个语言目录,无法实现同一个程序加载、切换多个不同的语言版本。

    要实现在同一个编译版本中实现多语言,就需要使用资源dll。核心思想是将资源编译为单独的dll。

    仍然以mfc对话框工程类型为例,资源dll的示例代码存放在 MLDemo_ResDll中。

    1. 创建mfc对话框应用程序

      image-20200305141203067

    2. 使用Localizer 创建多语言资源

      image-20200305141421351

      这次与之前不同,我们添加两种目标语言: 繁体中文和英文

      image-20200305141715900

      生成位置设置在语言对应的子目录中。

    3. 切换当前翻译语言进行翻译

    image-20200305142447291

    image-20200305142607442

    1. 创建资源dll项目

      在解决方案中添加新建项目:

      image-20200305142656792

      选择动态链接库项目,项目名称与语言一致,这里是 zh-TWen

      image-20200305142819273

      并删除所有代码文件

      image-20200305143224690

    2. 使用Localizer翻译资源

      翻译后,资源文件刚好生成在两个对应的工程目录中

      将其添加到对应工程中

      image-20200305143421573

      此时编译工程会报错

      image-20200305143456429

      这是因为resource.h在主工程目录中,我们在包含目录中添加该目录

      image-20200305143551575

      注意,是资源选项

      还要设置dll入口点为无,否则会报错

      2>LINK : error LNK2001: 无法解析的外部符号 __DllMainCRTStartup@12
      2>W:WorkgitslocalizationdemoMLDemo_ResDllDebugen.dll : fatal error LNK1120: 1 个无法解析的外部命令

      image-20200305143743791

    3. 配置项目生成路径,最终生成目录如下所示:

      -- MLDemo_ResDll.exe
      -- zh-TW
      ----- ML_Demo_ResDll.dll
      -- en
      ----- ML_Demo_ResDll.dll
      

      image-20200305144309656

    到现在为止,资源dll已经创建,下面应该修改代码来为不同的语言配置不同的资源

    1. 加载资源dll
    HINSTANCE _hResInstance = nullptr;
    
    BOOL LoadResDll(LPCTSTR szLan)
    {
    	if (nullptr != _hResInstance)
    	{
    		::FreeLibrary(_hResInstance);
    		_hResInstance = nullptr;
    	}
    	
    	
    	CString strExePath;
    	AfxGetModuleFileName(AfxGetInstanceHandle(), strExePath);
    
    	TCHAR szDrive[_MAX_DRIVE];
    	TCHAR szDir[_MAX_DIR];
    	TCHAR szFName[_MAX_FNAME];
    	TCHAR szExt[_MAX_EXT];
    	_tsplitpath_s(strExePath, szDrive, szDir, szFName, szExt);
    
    	CString strDir;
    	strDir = szDrive;
    	strDir += szDir;
    
    	strDir += szLan;
    
    	CString strResDll = strDir + _T("\") + szFName + _T(".dll");
    
    	_hResInstance = ::LoadLibraryEx(strResDll, nullptr, LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_AS_DATAFILE);
    	
    }

    为了测试,我们简单的依次弹出不同语言的对话框:

    	LoadResDll(_T("chs"));	// 其实没有这种语言,会加载失败
    	if (nullptr != _hResInstance)
    	{
    		AfxSetResourceHandle(_hResInstance);
    	}
    
    	CMLDemoResDllDlg dlg;
    	INT_PTR nResponse = dlg.DoModal();
    
    	LoadResDll(_T("en"));	// 其实没有这种语言,会加载失败
    	if (nullptr != _hResInstance)
    	{
    		AfxSetResourceHandle(_hResInstance);
    	}
    	
    	nResponse = dlg.DoModal();
    
    	LoadResDll(_T("zh-TW"));
    	if (nullptr != _hResInstance)
    	{
    		AfxSetResourceHandle(_hResInstance);
    	}
    
    	nResponse = dlg.DoModal();
    

    运行可以看到,三个语言版本的界面会依次弹出。

    我们可以通过配置、注册表等方式在程序运行时,用于控制当前语言版本。

    image-20200305154028664

    image-20200305154043649

    image-20200305154053656

  • 相关阅读:
    UVALive 6909 Kevin's Problem 数学排列组合
    UVALive 6908 Electric Bike dp
    UVALive 6907 Body Building tarjan
    UVALive 6906 Cluster Analysis 并查集
    八月微博
    hdu 5784 How Many Triangles 计算几何,平面有多少个锐角三角形
    hdu 5792 World is Exploding 树状数组
    hdu 5791 Two dp
    hdu 5787 K-wolf Number 数位dp
    hdu 5783 Divide the Sequence 贪心
  • 原文地址:https://www.cnblogs.com/xzh1993/p/12424727.html
Copyright © 2020-2023  润新知