zoukankan      html  css  js  c++  java
  • 多语言实现

    多语言示例

    本地化与国际化

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

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

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

    多语言要求

    对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

  • 相关阅读:
    android 启动报错
    android 百度地图
    android LayoutInflater使用
    spring mvc No mapping found for HTTP request with URI [/web/test.do] in DispatcherServlet with name 'spring'
    sql mysql和sqlserver存在就更新,不存在就插入的写法(转)
    jsp include
    json 解析
    css
    Scrapy组件之item
    Scrapy库安装和项目创建
  • 原文地址:https://www.cnblogs.com/xzh1993/p/12424727.html
Copyright © 2011-2022 走看看