windows官方多语言方案

编写 Win32 多语言用户界面应用程序

Windows 2000 针对全球市场制定了新的增强支持标准,提供了许多国际化功能,例如完全支持 Unicode、预设支持数百种语言以及用于从右向左语言的镜像技术。在 Microsoft Systems Journal (MSJ) 中已经发表了多篇文章来说明如何针对 Windows 2000 来编写 Unicode、复杂脚本以及镜像的应用程序。

Windows 2000 多语言用户界面(也称为 MUI)是 Windows 2000 中一个最有用的国际化功能,它允许用户将系统的用户界面 (UI) 语言设置并更改为 Windows 2000 已发布的任何本地化语言。

本文将介绍如何在您的应用程序中提供可切换的 UI 功能。在本文中,您将:

  • 了解为什么应该考虑投资编写多语言应用程序。
  • 查看三种不同的多语言用户界面实现方式示例。
  • 寻找建议的最佳方法及指导原则和代码示例。

本页内容

为什么要费力编写多语言应用程序?

为什么采用 Unicode?

实现多语言用户界面

摘要

术语表

为什么要费力编写多语言应用程序?

有多种原因导致需要编写多语言应用程序。最明显的原因当然是通过打入国际市场(毕竟现在已经进入了互联网时代)来增加收入和提高软件销售量,此外还有两个有力的观点:

  • 发布单一的二进制文件。通过向所有平台(和所有不同的语言版本)发布一个核心功能二进制文件来尽可能减少开发的繁琐程度和成本,从而避免对每种语言的源代码都分别提供编译条件和维护。Microsoft Windows 2000、Microsoft Office 2000 和 Microsoft Internet Explorer 5.0 均为单一的二进制文件 – 例如,美国英语、日语和阿拉伯语版本的 Windows 2000 均随附了相同的核心 gdi32.dll。未来 Service Pack 中对此模块的潜在更新可应用到所有语言,而无需任何其他技术方面的工作。
  • 避免成为自身的竞争者。延迟发布不同语言版本的软件可能会严重影响客户的部署,并进而影响您的收入。在发布了应用程序的英语版 1.0 后,让客户等上几个月再发布德语版 1.0 似乎也没什么大不了的。但许多客户在部署之前,会一直等待应用程序首个更新的发布。如向原始版本的发布增量添加更新的发布增量,对客户部署的延误将远远超出您的预计。确保应用程序为多语言应用程序有助于避免出现这种情况。

返回页首

为什么采用 Unicode?

必须要知道,无论使用哪种方法来发布本地化产品,应用程序都必须完全支持 Unicode。通过实现 Unicode 支持,您将不必再操心应用程序运行平台的语言和代码页支持问题。Unicode 是一种 16 位字符的编码,可表示全球各地常用的大多数语言,这明显不同于旧的 8 位字符编码(例如 ANSI,它将语言支持限制为大约 220 个不同字符)。支持 Unicode 的应用程序可处理和显示其中任意一种语言的字符。要了解有关实现 Unicode 和发布将要在 Windows 9x 和 Windows NT 上运行的单一二进制文件的详细信息,请参阅有关使用 Microsoft Layer for Unicode 开发应用程序的文章。.

Windows 2000 通过系统区域设置(从“区域选项”控制面板配置,如图 1 所示)选项来支持传统的 ANSI 应用程序。这意味着基于 ANSI 的应用程序的行为完全取决于系统设置(图 2)。更好的一种方法是全面采用 Unicode 字符编码。


图 1:系统区域设置是通过区域选项控制面板中的设置默认值…按钮来配置的。



图 2:在系统区域设置与应用程序语言不匹配的 Windows 2000 系统上运行的 ANSI 本地化消息框。


返回页首

实现多语言用户界面

通常有三种方法可用来实现多语言用户界面二进制:

  • 依赖于语言的二进制文件和内置资源
  • 一个核心二进制文件和一个国际化资源 DLL
  • 一个核心二进制文件和一个与每种目标语言对应的资源 DLL

图 3 展示了使用上述每种方法针对英语、德语和日语的国际化应用程序进行的文件分发。

依赖于语言的二进制文件

一个核心二进制文件和一个国际化资源 DLL

基于语言的附属 DLL

图 3:文件分发比较



以下部分将介绍每种实现的优点、缺点以及技术限制。下面是一个重要的假设:无论用户界面的语言是什么,都会发布一个核心二进制文件并且应用程序的核心功能均相同。这应该是多语言用户界面所有实现中的终极目标。

方法 1:依赖于语言的二进制文件

此传统方法包括编译一个二进制文件,既有源代码又有资源。每种目标语言都需要一个单独的二进制文件。

方法 1(依赖于语言的二进制文件)的优缺点总结
优点 缺点
  • 易于实现
  • 分离每种语言所需的源树
  • 资源更改需要完全的二进制编译
  • 切换 UI 需要不同的应用程序实例
  • 浪费磁盘空间:多个核心二进制文件副本

依赖于语言的二进制文件的缺点使得此方法现已被淘汰。以下介绍的两种方法更适合于需要切换 UI 的应用程序。

方法 2:适用于所有语言的一个资源 DLL

此方法的主要思想是将资源从源代码中分离出来,创建一个包含所有目标语言的全部本地化资源的仅资源 DLL。相同资源 ID 的多个副本在不同语言标记下的 RC 文件中定义。在以下示例中,针对法语和英语定义了字符串 ID IDS_ENUMSTRTEST。

// French (France) resources
#ifdef _WIN32LANGUAGE LANG_FRENCH, SUBLANG_FRENCH
#pragma code_page(1252)
#endif //_WIN32

// String Table
STRINGTABLE DISCARDABLE 
BEGINIDS_ENUMSTRTEST "Cette phrase est en français...(France)"
END
#endif // French (France) resources

// English (U.S.) resources
#ifdef _WIN32
LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif _win32

// String TableSTRINGTABLE DISCARDABLE 
BEGINIDS_ENUMSTRTEST "This is an English string...(USA)"
END
#endif // English (U.S.) resources

为了在运行时访问资源,因此通过 LoadLibrary API 加载了资源 DLL。然后,可使用 EnumResourceLanguages 来查找给定控件/资源的可用语言列表,使用 FindResourceEx 来确定具有指定类型、名称和语言的资源的位置。要显示给定的语言,接下来只需选择 DLL 中正确的资源即可。可通过重新加载新选择的资源并刷新客户端区域来实现语言的切换。

必须注意,Windows 资源加载程序始终使用默认的当前用户区域设置(线程区域设置会继承当前登录用户的用户区域设置 – 请参阅图 1)。GetThreadLocale 允许查询线程区域设置。在此方法中,加载 API 的预定义资源(LoadIconLoadStringLoadCursor…)始终返回与此区域设置相关的资源。例如,在以上资源示例中,如果系统区域设置被设为英语 (0x0409),将无法使用 LoadString 来加载法语资源。但实际并非完全如此:线程区域设置在创建线程时被继承后,将独立于用户区域设置,这意味着在这种情况下,可使用 SetThreadLocale 将线程区域设置改为法语 (0x040C),然后可调用 LoadString 来获取法语字符串。

// if our thread locale is English to start with…
g_hInst = LoadLibrary(_TEXT(“intl_res.dll”));
LoadString(g_hInst, IDS_ENUMSTRTEST,g_szTemp, MAX_STR);

// g_szTemp would then point to the English resources
// changing our thread locale to French.

// Always make sure that French is in fact one of the
// valid languages returned by EnumResourceLanguages()

// Save a copy of the current thread-locale to set back later

Lcid = GetThreadLocale();SetThreadLocale(MAKELCID(0x040c, SORT_DEFAULT));
LoadString(g_hInst, IDS_ENUMSTRTEST, g_szTemp, MAX_STR);

// g_szTemp would then point to the French resources

在此要注意的是,如果线程区域设置与当前选择的用户区域设置相同,系统的资源加载程序将默认使用语言 ID 0(中立)。如果所需的资源被定义为中立语言,则会返回此值。否则将会枚举所有语言资源(以语言 ID 顺序),并返回首个匹配的资源 ID(不论其语言是什么)。

可举例来说明此问题,比如在美国英语和法国法语资源中,用户区域设置被设为日语,则:原始线程区域设置将是日语 (0x0411)。如果找不到字符串 ID 且枚举时英语 (0x0409) 在法语 (0x40C) 之前,则首次调用 LoadString 时会在 0x0411 版本后返回英语资源。接下来,如果用户区域设置首先是法语:原始线程区域设置将是法语 (0x040C)。由于用户区域设置和线程区域设置匹配,因此系统资源加载程序将使用语言 ID 0 并开始枚举资源,然后再次返回英语版本!

对此的最佳解决方法是首先放弃更改线程区域设置。可通过调用 FindResourceEx 从多语言资源文件中手动加载资源。另一种解决方法是在所有者定义的语言标记中定义资源。在以上的 RC 示例中,英语部分定义为:

LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US

这将防止线程区域设置被切换回美国英语。但是,将资源定义为:

LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL

将保证 SetThreadLocale 调用的成功,因为此语言 ID 没有匹配的用户区域设置,仍可继续使用预定义的资源加载程序 API。

方法 2(适用于所有语言的一个资源 DLL)的优缺点总结
优点 缺点
  • 相对易于实现
  • 允许动态切换 UI
  • 可实现“无编译”资源更新
  • 更新为新语言很困难
  • 安装 UI 语言的字集很困难
  • 不支持的语言会浪费内存和磁盘空间
  • 没有简单的方法来实现直接资源
    加载接口(LoadMenuLoadString 等)
  • 无法在 Windows 9x 中更改线程区域设置

方法 3:每种目标语言一个资源 DLL

这是先前技术的扩展。现在不是在单个 DLL 中包含所有语言,而是针对每种语言创建一个单独的 DLL。Microsoft Office 2000、Microsoft Internet Explorer 5.x 和 Microsoft Windows 2000 使用的都是这种方法。每种产品的实现不同,此方法的名称也各异,但附属 DLL 是这种方法的常用名称。

此方法会再一次用到要通过 LoadLibrary API 加载的资源 DLL。但这一次,必须选择适当的语言 DLL。通常应假设 Windows UI 语言是用户的首选语言,应用程序可通过加载此语言资源来启动。接下来,当用户选择另一种语言时,可释放当前语言并加载新语言。当然,此方法会使用新加载的资源重新创建窗口并初始化对话框。

系统 UI 语言的检测在不同版本的 Windows 中其处理方式也互不相同:

  • 在 Windows 2000 中,可利用 GetUserDefaultUILanguage API 来查找当前用户的 UI 语言(请注意,在 Windows 2000 多语言版本中,可以有选择了不同 UI 语言的不同用户)。
  • 在 Windows 95、Windows 98 和 Windows 98 SE 中,UI 语言存储在注册表的以下位置:HKCU\Control Panel\Desktop\ResourceLocale。此注册表项将以十六进制形式返回 UI 的语言 ID (LangID),例如,英语是 00000409。
  • 在 Windows NT 3.5x 和 Windows NT 4.0 中,由于缺少相关的 API 和一致的注册表项,因此检查操作系统语言的最安全方式是检查 NTDLL.DLL 的版本戳记。此文件的语言与用户界面的语言相同。同样,唯一例外情况是阿拉伯语、希伯来语和泰语,这时版本戳记可帮助您检测启用的操作系统。具体步骤如下:
    • 加载 ntdll.dll 文件
    • 枚举版本戳记资源中的语言
    • 如果有多种语言可用,它将是非美国英语语言
    • 如果仅找到美国英语,则可能仍需要处理启用的语言,并且应该对活动代码页进行检查。

由于语言检测 API 和注册表项会返回 UI 语言的 LangID,因此对附属 DLL 进行相应命名会非常有用:不要将英语文件命名为 res_eng.dll 或 res_en.dll,而应使用 res409.dll。

以下代码示例显示了如何在 Windows 2000 中检测 UI 语言并加载正确的资源 DLL:

wLangId = GetUserDefaultUILanguage();
_stprintf(g_tcsTemp, _TEXT("res%x.dll"), wLangId);

if((hRes = LoadLibrary(g_tcsTemp)) == NULL)
   {
   // we didn‘t find the desired language satellite DLL, lets go with English (default).
   hRes = LoadLibrary(_TEXT("res409.dll"));
   } 

如果未能加载相应的语言 DLL(例如,在应用程序中仅支持操作系统语言的一个子集),唯一的解决方案是假设系统中存在默认/首选语言 DLL。

另一种可能的方法是将英语(或默认语言)资源包括到可执行主文件中并发布其他语言的附属 DLL(方法 1 和 3 的混合)。由于此方法并无实际优点况且英语毕竟只是另一本地化语言,因此不再详细讨论此技术。

方法 3(每种目标语言一个资源 DLL)的优缺点总结
优点 缺点
  • 允许切换用户界面
  • 可实现“无编译”资源更新
  • 完全控制安装的语言
  • 轻松更新为新语言
  • 特定于语言的更新不会影响所有语言
  • 不必担心用户、系统和线程区域设置
  • 可在 Windows 9x、Windows NT 和 Windows 2000 中实施
  • 需要保持所有语言附属 DLL 同步

返回页首

摘要

编写单一二进制代码是实现真正的全球通用产品的第一步,并且有助于降低开发和支持成本。实现多语言用户界面以允许用户在所有支持的语言之间切换,是达成令全球客户满意的下一个逻辑步骤。通过编写识别 Unicode 的代码和创建语言资源的附属 DLL,即可达成这些目标,轻松程度可能会超出您的想像。

返回页首

术语表

线程区域设置 - 给定线程所处的区域设置。是在创建时从当前用户区域设置继承来的,可以在运行时改为有效的任何区域设置(按线程)。通过调用 NLS API,可使用此区域设置来格式化数字、日期、时间...

系统区域设置 - 并非真正的区域设置。可决定将要支持哪个脚本非 Unicode 应用程序。因此,在应用程序角度来看,它是系统模拟出来的区域设置。系统区域设置的作用范围是整个系统,因此适用于所有用户。更改系统区域设置需要重新启动。

UI 语言 - 操作系统显示其菜单、帮助文件和对话框时所使用的语言。

用户区域设置 - 格式化日期、货币、数字等项目时用户的首选项。用户区域设置是针对每个用户设置的,无需重新启动或注销/登录。

时间: 2024-10-27 07:28:15

windows官方多语言方案的相关文章

170103、Redis官方集群方案 Redis Cluster

前面我们谈了Redis Sharding多服务器集群技术,Redis Sharding是客户端Sharding技术,对于服务端来说,各个Redis服务器彼此是相互独立的,这对于服务端根据需要灵活部署Redis非常轻便,Redis Sharding具有很好的灵活性.可伸缩性,是一种轻量级集群技术. 本篇,介绍另外一种多Redis服务器集群技术,即Redis Cluster.Redis Cluster是一种服务器Sharding技术,3.0版本开始正式提供. Redis Cluster中,Shard

windows下备份mysql方案

总体思想 定时任务调用备份脚本 1.定时任务, 自行研究 2.脚本 c:\mysql_bak\bin\mysqldump.exe -ugbds -pxxxx gbds --hex-blob>c:\mysql_bak\sql\gbds_%date:~0,4%%date:~5,2%%date:~8,2%_%time:~0,2%%time:~3,2%%time:~6,2%.sql 备注: 对于mysqldump.exe可以使用快捷方式复制到使用目录 windows下备份mysql方案,布布扣,bubu

Eclipse 官方简体中文语言包下载地址及安装方法

Eclipse 官方简体中文语言包下载地址及安装方法 打开Eclipse Babel Project 主页: http://www.eclipse.org/babel/downloads.php 根据Eclipse的版本找到相应的插件地址,复制下来. 进入Eclipse,选择Help->Install New Software... 点击Add按钮,把刚才复制的地址粘贴到Location:,再随便取一个名字. 等待Pending一会儿,再在Babel Language Packs in Chin

windows平台多语言显示

为了实现windows平台的多语言显示,即在不同系统语言(中英繁)环境下,正确显示不同配置语言(中英繁)的内容,做了一个测试工程.得出的结论是配置文件使用ucs2小端编码,工程使用unicode编码,涉及的类型使用TCHAR*相关类型,即可实现此需求. 配置文件的编码可以通过notepad++查看. 代码工程链接 windows平台多语言显示,布布扣,bubuko.com

关于WIndows内核自映射方案的通俗解释

在一次操作系统课程上听老师说了这么一个有意思的东西,windows的自映射方案居然达到了把4K的页目录的线性地址“藏”在4M页表里的效果,感觉甚是奇特,于是乎就想着说怎么去算.光会算之后仍旧不满足,我又感觉对我而言有两个问题是很模糊的: 为什么说0xC0300000是可行的页目录线性地址起始处? 在以0xC0000000为页表的线性地址的条件下,页目录的线性地址的起始处必须是0xC0300000吗? 为了解决这两个问题,我查看了很多个博客,但是大多数博客或文章对原理进行了充分的解释,但是并没有例

Windows下C语言的Socket编程例子(TCP和UDP)

一.  <TCP> server端: 1 #include "stdafx.h" 2 #include <stdio.h> 3 #include <winsock2.h> 4 5 #pragma comment(lib,"ws2_32.lib") 6 7 int main(int argc, char* argv[]) 8 { 9 //初始化WSA 10 WORD sockVersion = MAKEWORD(2,2); 11 W

项目笔记---WPF多语言方案

近期由于朋友邀请帮忙给一个开源的游戏“外挂”做一个I18N的解决方案,恰好也是WPF做的,之前有过相关经验,就忙了一个星期终于搞定了,已经提交给作者了,现在这里做一个分享. 这里分享下我个人Fork的GitHub地址: https://github.com/Cuiyansong/Hearthstone-Deck-Tracker 什么是I18N 简单来说就是多语言,为什么多语言叫I18N,请参见结语中的引用. 如何实现 其实WPF上实现多语言于winform有些相似,就是更换软件运行时资源(Res

windows server 2012语言包安装命令

dism /online /add-package /packagepath:<cab文件路径> 比较慢,大约需要20分钟 windows server 2012语言包安装命令

微软:要不将 Python弄成Excel官方脚本语言?

微软正考虑将 Python 作为 Excel 官方脚本语言之一,在 Excel 用户反馈平台中,「Python 作为 Excel 的脚本语言」成为了最热议的话题,是排名第二的提议的两倍多 目前为止,超过 3883 人赞同将 Python 集成到 Excel 中,成为 VBA 替代品,甚至像单元格函数 functions (=SUM(A1:A2)) 也可以用 Python 函数 sum(a1, a2) 来代替 目前微软官方已经作出积极回应,通过发起投票来收集更多用户的反馈信息,在线调查用户想要如何