• windows官方多语言方案


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

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

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

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

    • 了解为什么应该考虑投资编写多语言应用程序。

    • 查看三种不同的多语言用户界面实现方式示例。

    • 寻找建议的最佳方法及指导原则和代码示例。

    3 个方块

    本页内容

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

    为什么采用 Unicode?为什么采用 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 字符编码。

    syslocale

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


    ansiapp

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


    返回页首返回页首

    实现多语言用户界面

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

    • 依赖于语言的二进制文件和内置资源

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

    • 一个核心二进制文件和一个与每种目标语言对应的资源 DLL

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

    filedist1

    依赖于语言的二进制文件

    filedist2

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

    filedist3

    基于语言的附属 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 语言存储在注册表的以下位置:HKCUControl PanelDesktopResourceLocale。此注册表项将以十六进制形式返回 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 语言 - 操作系统显示其菜单、帮助文件和对话框时所使用的语言。

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

  • 相关阅读:
    OpenGL ES应用开发实践指南:iOS卷
    WCF(1)----服务创建
    算法设计--电路布线问题(分支限界法求解)
    Oracle 删除用户和表空间
    从最简单的源代码开始,切勿眼高手低---(第一波)
    pinyin4j的使用
    ios学习:AVAudioPlayer播放音乐文件及读取ipod库中的音乐文件
    ArcGIS多面体(multipatch)解析——引
    [珠玑之椟]位向量/位图的定义和应用
    搭建自己的XenServer+CloudStack云平台,提供IaaS服务(一)环境搭建
  • 原文地址:https://www.cnblogs.com/liangxiaofeng/p/4929360.html
Copyright © 2020-2023  润新知