程序国际化的编码问题

场景: 有一个程序需要国际化, 需要支持多国语言(中文, 英文, 日文, 阿拉伯文等等)


实现的大致思路: 

  1. 把语言信息保存在对应的xml文件中, 用户选择语言时, 加载对应的xml文件显示.
  2. 我知道有一个叫 GetText的, 支持国际化的工具(搜索poEdit或者po文件可以了解). 我也使用过, 很好用, 很方便.
  3. 自己还是有一点折腾吧, 想自己实现.(可能会给自己带来风险, 如果万一实现不了.)

背景: Win7简体中文系统, 使用VC构建的工程.

遇到的问题:


一. VC的Character Set问题.

  VC工程有一个Character Set选项, 可以选择Not Set / Use Unicode Character Set / Use Multi-Byte Character Set.
  相信很多人为选择哪一项而纠结, 我也是一样, 所以把心一横, 自己一律使用Multi-Byte Character Set.


1.1 Multi-Byte Character Set下: 

  

  1). 在CEdit上输入/拷贝/粘贴中文, 英文, 日文都没有问题.

  2). 在CEdit上输入/拷贝/粘贴阿拉伯文不行, 全部变成"?????".
  3). 但是执行下面语句可以正确显示阿拉伯文
  std::wstring str = L" كيف حالك؟ "; // 阿拉伯文
  ::SetWindowTextW(GetDlgItem(IDC_STATIC_SHOW)->m_hWnd, str.c_str());

1.2 Use Unicode Character Set下: 


  1). 在CEdit上输入/拷贝/粘贴中文, 英文, 日文都没有问题.

  2). 在CEdit上输入/拷贝/粘贴阿拉伯文也没有问题.
  3). 执行下面语句也可以正确显示阿拉伯文
  std::wstring str = L" كيف حالك؟ ";// 阿拉伯文
  ::SetWindowTextW(GetDlgItem(IDC_STATIC_SHOW)->m_hWnd, str.c_str());

  4). 但是执行下面语句就不行了.
  std::wstring str = " كيف حالك؟ ";// 阿拉伯文(其实在这一句已经是不行的了)
  ::SetWindowTextA(GetDlgItem(IDC_STATIC_SHOW)->m_hWnd, str.c_str());


1.3 说明


  1). 查了这一句阿拉伯文的值, 发现有一个值是0x002E. 所以很明显, 是Unicode编码, 需要使用std::wstring存储.(暂时这么理解)

  2). 在中文/日文中, 并没有类似0x00XX的编码, 所以中文也可以使用std::string存储.(暂时这么理解)
  3). 或者说阿拉伯文只有Unicode编码, 没有多字节编码.
  4). Multi-Byte Character Set下, 都输入不了阿拉伯文, 个人理解就是编码的原因吧. 所以建议以后还是使用Use Unicode Character Set.

二. 保存为xml文件问题.

  我一直使用自己写的xml文件操作类, 使用std::iofstream进行xml文件的读写. 很明显, 这些都是以多字节的形式处理的.xml文件中保存/加载中英日文都没有问题
现在增加阿拉伯文, 问题就是阿拉伯文用Unicode编码形式, 有类似0x00XX的编码, 在多字节形式的字符中, 一遇上0x00就被截断了.


2.1 std::wofstream 与 std::ofstream

  

  1). 我第一时间想到std::wofstream,但是std::wofstream只是文件名支持Unicode, 输入内容最终还是多字节编码的.

  2). std::wofstream在处理 unicode字符时, 必须进行内部编码转换(Unicode -> 多字节); 但是怎么转换的呢? 明显是与你本地系统编码或者与std::locale::global(std::locale(""))设置的有关系.
  3). 例如std::wofstream输出std::wstring(内容是中英日文)到文件, 最终在文件上是多字节形式的, 内容是正确的.(内部自动的正确转换了).
  4). 例如std::wofstream输出std::wstring(内容是阿拉伯文)到文件, 最终在文件上是多字节形式的, 但内容是错误的.(内部自动转换了, 但转换错误的).
  5). 或者可以使用std::locale::global(std::locale(""))设置转换的编码吧, 但我没有尝试.

2.2 解决方法

  

  现在的矛盾在于: xml文件是多字节形式存储, 但是又要存储Unicode编码数据. 思路无非就是Unicode编码转多字节后再保存到xml文件中. 或者xml文件使用Unicode的形式.


  1). 方法1. 使用std::locale::global(std::locale("")): 这种方法不够通用. 例如我同时要转换中文, 阿拉伯文, 就需要频繁的切换. 容易犯错.
  2). 方法2. xml文件保存为Unicode形式: 这是一个终极解决方法.(对于我来说, 需要花时间实现(我想用C/C++的标准函数实现), 而且我之前的xml数据怎么兼容?).
  3). 方法3. 手动对所有Unicode编码转换成统一的多字节编码(例如可视十六进制), 再存储到多字节形式的xml文件中.(保存前需要转换, 加载后需要逆转换, 增加了运行时间.)(这方法对我来说是最兼容的.)


三. 小结


  1). VC工程需要选择Use Unicode Character Set, 保证Unicode编码的语言可以输入/输出.

  2). Unicode编码的文本不能保存到多字节的文本中, 要保存到Unicode编码的文件中, 不能简单的使用std::iofstream/std::wiofstream来处理. 
  3). std::iofstream/std::wiofstream最终处理的还是多字节, 而且转换与本地环境相关, 没有一个通用性.
  4). 可以考虑可视十六进制来存储(还是多字节文件), 我喜欢.

你可能感兴趣的:(C/C++,VC)