Archive

Posts Tagged ‘Unicode’

[翻译]使你的C/C++代码支持Unicode

April 22nd, 2009 yaker No comments

译文见 http://www.i18nguy.com/unicode/c-unicode.zh-CN.html
原文见 http://www.i18nguy.com/unicode/c-unicode.html

偶然读到i18nguy上的这篇文章的英文原文,虽然是几年之前的文章,但是觉得作为一个简明手册还是很有价值的。于是给文章的作者Tex Texin先生发了封邮件,得到texin先生的支持后便翻译了一下。

文章并不长,没有使用OmegaT这种辅助翻译的利器,只用了网页编辑器(Kompozer)。刚刚翻译完的时候,自己读了一遍,觉得有些地方很生硬,又润色了一下。之后看了下翻译相关的书籍,对翻译工作的艺术性有了点切身的了解。

Tex Texin先生是XenCraft公司首席架构师及全球化咨询师。Unicode Bulldog Award获得者(2004)。关于他更详细的介绍见这里

Categories: translation, unicode Tags: ,

编写国际化软件的一些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: ,

用wstring存取xml中的unicode字符

November 18th, 2007 yaker 3 comments

unicode实际上是个很复杂的主题,至少不是两个字节那么简单(实际上utf-8是变长的,utf-16也有代用对的概念).有兴趣可以参考一下《国际化软件开发》这本书,我所了解到的关于unicode的知识多数是从这本书上看来的,最早知道unicode是《Joel说软件》里面有一章提到,说:作为一个程序员,unicode是你必须知道的东西.

附带的xml文件是utf-8编码的,utf-8的编码是互联网上常用的格式,用utf-8还有一个好处就是在我的ubuntu系统上我仍然可以查看.要记住,windows操作系统的基本文本表示格式是utf-16.所以用库(我用的TinyXml)函数将xml读出后得到的实际上是utf-8编码的字符,不能在windows程序中直接使用.首先要转换一次,使用MultiByteToWideChar函数(Windows API).转换前要自己创建一个字符缓冲区,这个缓冲区的管理也是个麻烦问题,谁来释放内存呢?因为转换后的字符串要返回的,这样每个调用者都负责自己清理,实际上是很麻烦的事情.我现在的做法是用STL里的string,确切来说是wstring.这样会损失一些效率(如果是引用计数机制的实现的话就没有什么效率损失了),主要的好处还是在于不同部分的代码职责明确.

将utf-8编码的字符串转换为windows内部的unicode编码的代码如下:

using std::wstring;
 
wstring utf_to_ws(const char *utf8)
{
    int len = MultiByteToWideChar(CP_UTF8,0,utf8,strlen(utf8),NULL,0);
    if (len == 0)
        return wstring(TEXT(""));
    TCHAR *unicode = new TCHAR[len+1];
    unicode[len]=L'\0';
    MultiByteToWideChar(CP_UTF8,0,utf8,strlen(utf8),unicode,len+1);
    wstring ws(unicode);
    delete[] unicode;
    return ws;
}

P.S.
如需将Unicode字符转换为ASCII格式,参见编写国际化软件的一些Tips

Reference
1.unicode科普
http://baike.baidu.com/view/40801.htm
2.我所知道的一些
windows操作系统的基本文本表示格式是utf-16.在windows处理任何基于代码页的数据都首先转换为UTF-16,并用unicode处理,在windowsAPI中例如MessageBox有两个版本,MessageBoxA和MessageBoxW,分别代表ANSI和宽字符版本,处理ANSI字符时首先转换为unicode字符.
3.样例xml文件
查看文件

Categories: unicode Tags: , ,