VB6被很多程序员认为是一个过气的开发工具,但它实在是微软最经典的开发工具,没有之一!编译出的程序短小精悍,一般就几十K,而且从XP以后的操作系统,均携带其运行时库,只要程序只使用VB的标准控件,连安装都不需要,可以直接运行。所以,不太复杂的GUI程序我都使用VB6开发,速度那怎叫一个快字了得!
        最近,我做了一个Mini流图软件,但需要支持多国语言。查了一下网上的资料,方案感觉都很山寨。基本上都是头疼医头,脚疼医脚,没有一个基于系统的全面调理方案。于是,仔细研究了VB6的资源文件体系,发现原来微软早就提供了完美的解决方案,只是中国的程序员大多不习惯这种贵族式的优雅。VC6也使用了这个机制,但GUI做得比VB差几条街,一点儿也不直观,智商低于120的程序员基本无缘此功能,但以后Visual Studio的VC一直继承下来这个机制(虽然表达方式依旧那么烂),不像VB从.net开始抛弃了这一机制,使用了简单粗暴的方法来解决。也许,简单粗暴是这个社会的潮流,但我依然追求优雅。所以以下内容仅适用于对完美有变态追求的同学们。
        VB6的资源文件中一般包括字符串、图标、光标、位图和用户定义的字节流,共5种类型的资源,每种资源的实例都有2个属性,一个是资源ID,另一个就是语言ID。就是说,一个资源需要两个ID共同标识。例如:一个资源ID为101的字符串,其语言ID为1028的字符串内容是台湾中文,其语言ID为1033的字符串内容是美式英文,其语言ID为1049的字符串内容是俄文,其语言ID为2052的字符串内容是中国中文,其语言ID为2057的字符串内容是英式英文等等。如图所示是VB6的字符串资源编辑器,很直观吧!开发VC的项目经理太自大!

        当程序请求资源时,只需要输入一个资源ID参数,运行时库会根据系统语言ID自动返回对应的资源。对于急功近利的同学们,这些基本就够用了。因为项目经理说做8国语言,大部分程序员不会考虑第9国人民的感受。后面将分享VB6资源文件体系的读取策略以便能优雅的解决第9国人民的问题。
        在这之前,得先普及一下Windows内核的多国语言知识。微软从NT开始使用Unicode内核,其好处就是大大降低全球部署的成本,这是微软称霸全球的重要技术支持手段之一。对使用者而言,最直观的好处就是在输出的一个字符串里面可以同时包含多个国家的文字。虽然这种需求很少见,但切换语言这种事在Unicode技术的支持下,那就都不是事!
        虽然Windows在发行时,都指明了语言版本,但实际上,任何一个语言的Windows都支持任意微软支持的语言。所以在语言上,Windows有两种级别的语言,一种是安装级(Installed),即系统(System)语言;另一种是支持级(Supported),即用户(User)语言。
        一般情况下,系统语言和用户语言是一样的。那二般是个什么情况?举个例子,在一个国际学校,老师是美国人,他当然安装英文版Windows,但他的学生分别是法国人、德国人、中国人、韩国人,就是没有美国人!为了考虑学生的爱国情怀,老师给他们每个人分配一个登录账号,登录后,可以修改控制面板中的地区和语言,以便符合每个学生的习惯。这样,在每个学生的登录会话环境中,系统语言都是英语,用户语言是用户在控制面板中设置的语言。
        OK,现在来看看VB6的运行时库对资源请求是如何动作的。当程序请求资源时,只需要输入一个资源ID参数,运行时库首先使用用户语言ID与请求的资源ID所拥有的所有语言ID进行匹配,如果成功,就把请求的资源ID和匹配成功的语言ID对应的资源返回;如果不成功,再使用系统语言ID与请求的资源ID所拥有的所有语言ID进行匹配,如果成功,就把请求的资源ID和匹配成功的语言ID对应的资源返回;如果还不成功,则把请求的资源ID所拥有的所有语言ID中ID值最小的那个对应的资源返回。
        看那个例子,为了方便讲解,我加了一个资源ID是99的字符串,里面的内容是语言ID值。如果登录会话环境的用户语言和系统语言都没有匹配上,则返回中文(台湾)的字符串资源,因为1028是所有提供的语言ID中最小的!
        说到这里,大家可能很快想到,ID值最小的一定是0,那0是怎么定义的呢?那我们得先看看微软是如何定义语言ID的:
        #define MAKELANGID(PrimaryLanguage, SubLanguage) ((((WORD) (SubLanguage)) << 10) | (WORD) (PrimaryLanguage)) 
        意思是语言ID由1个16位的字表示(最多支持65536种语言),其中低10位为主语言ID(最多支持1024种主语言),高6位为子语言ID(每个主语言最多有64种子语言)。
        主语言和子语言策略是表达以下情况:如西班牙语,世界上母语是西班牙语的国家有20多个,比英语还多,这个要问那位15世纪才华横溢、精力充沛的伊莎贝拉女王,是她指使哥伦布同学全球殖民而导致我们现在的问题。这20多个国家的西班牙文叫子语言,但他们都属于西班牙语区,这个区称之为主语言。
        主语言ID为0被微软称之为中性语言(Neutral),它居然也有子语言,分别是SUBLANG_NEUTRAL(0)、SUBLANG_DEFAULT(1)和SUBLANG_SYS_DEFAULT(2),分别对应3种中性语言Neutral、Neutral Default和Neutral System Default。
        所以,前面讲的是个家庭版,现在看看微软的运行时库对资源请求动作的专业版。当程序请求资源时,只需要输入一个资源ID参数,运行时库首先使用用户语言ID与请求的资源ID所拥有的所有语言ID进行匹配,如果成功,就把请求的资源ID和匹配成功的语言ID对应的资源返回;如果不成功,则返回主语言ID为0且子语言ID也为0的资源;如果没找到,再使用系统语言ID与请求的资源ID所拥有的所有语言ID进行匹配,如果成功,就把请求的资源ID和匹配成功的语言ID对应的资源返回;如果还不成功,则把请求的资源ID所拥有的所有语言ID中ID值最小的那个对应的资源返回。
        所以,使用VB6多国语言资源文件的最佳实践是:根据软件主要投放语言区域,把那个语言设置为Neutral Default或Neutral System Default(这两个效果一样,如果设置为Neutral,则系统语言将失去一次匹配的机会)。例如:软件准备投放欧洲市场,项目只准备了英、法、德、意4国语言,你可以把英语设置为Neutral Default。当用户语言和系统语言都不是法、德、意时,均使用英语;如果不这么配置,就会使用语言ID最小的那个语言(德语)。显然,在欧洲,认识英文的人应该比认识德文的人多,这样的用户体验更好。
        当然,最好的方案还是提供所有语言!其实,也不是很难!关键是工欲善其事,必先利其器!
        2001年,有个叫Phil Jollans( http://www.jollans.com)的德国小伙子做了一个叫做World Resource String Editor的VB6插件,可以直接从excel中导入字符串资源!有图有真相:

        我就是用这个工具,只需要填写中国(中文)那一列的内容,把文件分发给各个翻译组,再汇总导入,工作之轻松令人发指!什么?西班牙语有20个国家?来吧,我把西班牙(西班牙)那一列复制20列,再把子语言ID一换,轻松支持所有西班牙地区的国家。羽扇纶巾,樯橹灰飞烟灭的感觉!满足需求都弱爆了,预测需求才能立于不败之地。
        但预测需求也只是个中级水平,只有引领需求才是最高境界!那什么才是最高境界呢?说到这里,上面已经解决了80%的问题,但只花费了20%的功力,下面的内容解决剩下20%的问题,但需要80%的功力。
        其实,微软的整个策略还是对需求了解得不够充分,略显简单粗暴。例如:比利时、瑞士等几个欧洲小国也说法语,它对法国的标准法语进行了一些扩展,就像方言一样,懂比利时法语的人肯定也懂法国的标准法语,这是个非常自然的需求。所以,资源提取的完整最佳策略应该是这样的:
        当程序请求资源时,只需要输入一个资源ID参数,运行时库首先使用用户语言ID与请求的资源ID所拥有的所有语言ID进行匹配,如果成功,就把请求的资源ID和匹配成功的语言ID对应的资源返回;如果不成功,就把用户语言ID的主语言ID与请求的资源ID所拥有的所有语言ID的主语言ID进行匹配,如果成功,就把请求的资源ID和匹配成功的主语言ID里面子语言ID最小的那个语言ID对应的资源返回;如果不成功,则返回主语言ID为0且子语言ID也为0的资源;如果没找到,再使用系统语言ID与请求的资源ID所拥有的所有语言ID进行匹配,如果成功,就把请求的资源ID和匹配成功的语言ID对应的资源返回;如果不成功,就把系统语言ID的主语言ID与请求的资源ID所拥有的所有语言ID的主语言ID进行匹配,如果成功,就把请求的资源ID和匹配成功的主语言ID里面子语言ID最小的那个语言ID对应的资源返回;如果还不成功,则把请求的资源ID所拥有的所有语言ID中ID值最小的那个对应的资源返回。我已经竭尽毕生才华企图让阿甘都能看懂了,如果还看不懂,就洗洗睡吧,不求甚解才是真正的幸福。
        好吧,终极对决如期而至。这么屌暴天的需求怎么优雅地实现呢?翻阅MSDN上所有关于多国语言资源方面的资料,发现一套修改资源的API:BeginUpdateResource, UpdateResource和EndUpdateResource,可以修改资源的语言ID,但还是太复杂,严重损坏VB6的简单美形象。换一个思路,既然改资源那么累,能不能改用户语言呢?又发现了这么一个函数SetLocaleInfo,可以设置用户语言。哈哈,这样的话,大体思路就出来了:程序启动后,首先调用一个调整函数:这个函数首先获取用户语言,与已有的资源语言比对,如果有完全匹配的,就可以退出了;如果没有完全匹配的,再使用用户语言的主语言与已有的资源语言的主语言比对,如果有匹配的,就用SetLocaleInfo把用户语言设置为匹配了主语言的那个语言ID。这样,资源里只需提供一种主语言的标准语言即可支持使用这个主语言的所有国家。系统语言的修改非常麻烦,要调用一系列API,最致命的是需要重启操作系统,这个基本上就放弃了。但也无大碍,因为用户语言才是最重要的依据,匹配到系统语言上多少有点掩耳盗铃的感觉。
        但是,SetLocaleInfo可是真真切切地修改了用户语言,即使你退出前再把原来的用户语言改回去,也会影响到其它在你之后启动的应用,更何况你的程序有可能崩溃,连改回去的机会都没有。
        再经过仔细搜索,又发现这么一个函数SetThreadLocale,参数更简单,最重要的是其修改的语言信息只在本线程内起作用,并不真正地修改用户语言。这下大家满足了吧!
        有意见,请加群3867100讨论,口令:图乃大。或发邮件45672463@qq.com,标题注明图乃大。

使用VB6资源文件开发多国语言应用攻略相关推荐

  1. java开发多国语言互译

    对于一枚对英语盲的人,一旦遇着不会的单词或者句子:以前上学时,老师总是叫我们用词典.现在网络发达,总喜欢上网去度娘了,但是有好几次回老家 想百度就是没网的那种伤心尤然心生,所以我自制了一款适合我自己的 ...

  2. DBGRIDEH 组件在Borland开发工具中应用全攻略

    DBGRIDEH 组件在Borland开发工具中应用全攻略         2003-08-05 16:36:18     陈文彬     DBGRIDEH 是Enlib 3.0组件包中的组件之一.E ...

  3. 2级c语言程序设计无忧考试,计算机二级考试|C语言程序设计攻略

    原标题:计算机二级考试|C语言程序设计攻略 今天我们来介绍一下计算机二级C语言程序设计考试内容 根据<全国计算机等级考试二级c语言程序设计考试大纲(2018年版)>得知,全国计算机二级c语 ...

  4. VM:如何向vmware虚拟机中传输文件(或者共享文件夹)之详细攻略(图文教程)

    VM:如何向vmware虚拟机中传输文件(或者共享文件夹)之详细攻略(图文教程) 目录 如何向vmware虚拟机中传输文件 1.外部点击安装VMware Tools 2.内部客户机进行安装 3.共享文 ...

  5. C++ 软件开发多国语言解决方案汇总

    暂时汇总出了以下几种方法 以Unicode为核心 采用 GNU gettext  基于Qt的多语言开发工具:Qt Linguist  以Unicode为核心 参考:http://www.ibm.com ...

  6. 菜鸟教程之工具使用——国际化资源文件开发凶器MultiProperties

    最近要做一个多语言的东西,大概包含中.繁.日.英.韩几种语言.这样一来就需要编写多个资源文件,不仅工作量繁重,而且容易出错.今天介绍一款非常好用的工具给大家--MultiProperties. Mul ...

  7. android开发多国语言对照表

    android开发,支持多国语言时,都是"语言-地区"简称不好记忆,此处网络收集来作为笔记参考. msm8x12\build\target\product\languages_fu ...

  8. Win10系统下安装编辑器之神(The God of Editor)Vim并且构建Python生态开发环境(2020年最新攻略)

    众神殿内,依次坐着Editplus.Atom.Sublime.Vscode.JetBrains家族.Comodo等等一众编辑器界的大佬们,偌大的殿堂内几无立锥之地,然而在殿内的金漆雕龙宝座上,端坐着一 ...

  9. vim配置python开发环境_Win10系统下安装编辑器之神(The God of Editor)Vim并且构建Python生态开发环境(2020年最新攻略)...

    众神殿内,依次坐着Editplus.Atom.Sublime.Vscode.JetBrains家族.Comodo等等一众编辑器界的大佬们,偌大的殿堂内几无立锥之地,然而在殿内的金漆雕龙宝座上,端坐着一 ...

最新文章

  1. static interface method calls are not supported at language level 1.6
  2. goland/go语言项目--本地包的导入(将项目添加至GOPATH中)(基于macOS)
  3. CSharp设计模式读书笔记(18):中介者模式(学习难度:★★★☆☆,使用频率:★★☆☆☆)...
  4. spring boot集成kaptcha图形验证码
  5. java 图形 登录_Java图形界面——登录框
  6. 关于Yaffs2在u-boot中的支持
  7. 年回报60%!孙正义如何经营“沉迷AI”的愿景基金?
  8. 用c语言实现数据结构算法将两个有序链表并为一个有序链表的算法,,(完整版)数据结构-习题集答案-(C语言版严蔚敏)...
  9. Atitit.软件开发的非功能性需求attilax 总结At
  10. php 写入txt换行_PHP fwrite 函数:将字符串写入文件(追加与换行)
  11. 惠普HP LaserJet 1160 驱动
  12. 微信小程序tabBar边框加|上阴影
  13. 《UnityAPI.Color颜色》(Yanlz+Unity+SteamVR+云技术+5G+AI+VR云游戏+Color+Lerp+RGBToHSV+gamma+linear+立钻哥哥++OK++)
  14. 计算机在运行 显示器出现黑屏,显示器黑屏但电脑一直在运行是什么原因
  15. 互联网企业掀起安全大战 各显神通
  16. 阿里云企业认证时不要让员工做个人认证的原因
  17. NULL与nullptr
  18. 《C语言程序设计(第三版)》苏小红 习题六 答案
  19. 第九章:Android开发之Service
  20. 陈丹琦团队提出低内存高效零阶优化器MeZO,单卡A100可训练300亿参数模型

热门文章

  1. Metasequoia for Mac(水杉3D建模器)
  2. Linux学习-28-用户间切换相关命令
  3. 戏言产品三板斧,拿着三宝来作秀
  4. 2021年宜昌各校高考成绩查询,2021年宜昌高考状元名单公布,宜昌高考状元学校资料及最高分...
  5. python模拟的王者游戏
  6. 高保真Axure原型设计实战 - 自适应后台框架
  7. Fork/Join工作原理解析
  8. 立创eda学习笔记十二:常见pcb板布局约束原则
  9. QT导入百度地图<附代码及动图展示>
  10. 平面设计师都在用的设计素材网站,免费下载~