Archive

Posts Tagged ‘国际化’

编写国际化软件的一些Tips

December 20th, 2007 yaker No comments

前一段时间项目里遇到这方面的问题,一直没来得及总结一下。核心内容还是unicode,如果不太清楚unicode可以参考我前一段时间里写的一篇blog(用wstring存取xml中的unicode字符)里的reference。

说国际化实际上有点大了,这里采用的是《国际化软件开发》里的说法,通俗一点就是支持多种语言。现在的项目里的语言只有英语和汉语两种(并且不声称支持多语言),但是我觉得在支持多语言方面做一些努力是值得的,譬如我现在用英文的系统,使用我们的软件也没有问题。unicode不能解决一切问题,但是它是目前我所见到的最好的解决方案。

编写这样的软件在编程方面有一些小的tips,总结一下:
1.用Visual Studio 的话把在工程设置里做如下设置:”Configuration Properties”->”General”->”Character set”设置为”Use Unicode Character Set”,使用unicode字符集。编程环境就会预定义UNICODE这个宏,CRT里定义_UNICODE,这样当你调用一个通用函数时就会调用其unicode版本(如果有)。
2.代码中尽量不要出现硬编码的字符串。
比如cout << “hello”这样的代码。“hello”这样的字符串将使国际化工作变得异常困难。
3.如果不得不出现硬编码的字符串,使用宽字符的字符串,上例中的字符串可以写作TEXT(”hello”)或者L”hello”。我的建议是所有的字符串都用宽字符表示,不管是不是纯英文的字符串。在需要纯英文字符串的情况下(譬如某些库要求这样:TiXmlDocument(const char *))的情况下,可以利用特定的函数实现宽字符字符串向ASCII字符串的转换。
4.定义字符数组时使用TCHAR或者wchar_t,而不是char。C++里使用wstring和wstringstream类。
5.调用通用版本(不指定是ANSI还是unicode类型)的函数而不是其特殊化版本,例如不要显式的调用MessageBoxA函数,应该调用MessageBox,定义了UNICODE宏后MessageBox会被替换为MessageBoxW,即宽字符版本。调用crt里的字符串函数,调用_tcscpy而不是strcpy。
6.常用的多语言资源解决方案:资源dll。即将资源编译到dll中,每种语言一个dll,程序运行时动态加载。事实上当然没有我说的这么简单,但是思路如此。

P.S.
1.一个非常糟糕的消息是Windows 98和Windows Me这样的系统是只支持unicode的一个子集的,如果你的用户使用这么老的系统…那你的麻烦就大了。现在这个项目里,与甲方交流的过程中,他们希望可以支持多种版本的Windows操作系统,我很遗憾的表示不保证支持Windows 2000以下版本的Windows操作系统。
2.宽字符字符数组向ASCII字符转换的函数

std::string CharsetConverter::uni_to_str( const TCHAR* unicode )
{
    int nLen = ::WideCharToMultiByte(CP_ACP, 0, unicode, -1, NULL, 0, NULL, NULL);
 
    if (nLen<= 0)
        return string("");
 
    char* pszDst = new char[nLen];
    if (NULL == pszDst)
        return string("");
 
    ::WideCharToMultiByte(CP_ACP, 0, unicode, -1, pszDst, nLen, NULL, NULL);
    pszDst[nLen -1] = 0;
 
    string strTemp(pszDst);
    delete[] pszDst;
 
    return strTemp;
}
Categories: unicode Tags: ,