【问题标题】:LoadString works only if I don't have an English string tableLoadString 仅在我没有英文字符串表时才有效
【发布时间】:2010-11-15 20:35:09
【问题描述】:

我希望能够以编程方式修改应用程序的语言,或者至少使用控制面板 -> 区域和语言选项 -> 格式中指定的语言。

如果我添加一个英文字符串表,制作一份法文和德文副本,然后删除英文的,我可以通过编程方式在加载法文和德文字符串之间切换。 如果我保留英文副本,无论如何,当我尝试加载德文或法文时,英文字符串都会被加载。

我认为这是一个资源加载器错误,如果资源加载器找到与 windows ui 语言相同的语言(例如 windows 资源管理器菜单的语言)的字符串表,则资源加载器会忽略 SetThreadLocale。

我尝试将控制面板 -> 区域和语言选项 -> 格式更改为法语,但没有效果。资源编辑器显示没有附加语言的法语字符串表,但我的程序仍然总是加载英语字符串。将此更改复制到系统帐户也无效。

这是我尝试过的代码:

#include "stdafx.h"
#include <iostream>
#include "windows.h" // this should go to stdafx.h
#include "resource.h" // this should not go to stdafx.h
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    // 1036 = french, 1031 = german
    SetThreadLocale(MAKELCID(1036, SORT_DEFAULT));
    const int maxSize = 100;
    wchar_t c[maxSize];
    LoadString(GetModuleHandle(NULL), IDS_STRING101, c, maxSize);
    std::cout << c;
    return 0;
}

Here 有一半是错误的,不完整的解释(在方法 2 的后半部分)。那里提出的第二种解决方法,只使用国家中性字符串表是没有用的,因为我有单独的葡萄牙语-葡萄牙和葡萄牙语-巴西字符串表。

那里提出的第一个解决方法不起作用。使用下面的代码,我得到错误 1814。

HRSRC r = FindResource(
    GetModuleHandle(NULL),
    MAKEINTRESOURCE(IDS_STRING101),
    RT_STRING);
DWORD e = GetLastError();

那么,我该怎么办?这个奇怪的“bug”的解释是什么?

稍后编辑:

经过更多测试,我发现:

  1. GetThreadLocale() 返回什么是 在控制面板中设置 -> 区域和 语言选项 -> 格式。
  2. 资源加载器错误本质上是如果我的程序也有美国英语资源,那么无论在格式中设置什么,这些资源都会被加载。如果没有美国英语资源,将使用格式设置的语言。
  3. 如果我有一个法语(中性)和一个德语(中性)字符串表,并且我将格式设置为法语(法国),则加载德语字符串。如果我添加一个英文(中性)字符串表,则会加载英文字符串。因此,中性文化回退不适用于 Formats 中设置的内容。
  4. 如果我添加一个中性字符串表,即使我有另一个英语(中性)或英语(美国)字符串表,也会使用该表。

【问题讨论】:

    标签: c++ windows localization visual-c++


    【解决方案1】:

    详细说明如何直接从 MSDN 中选择本地化资源(包括 FindResource 的搜索顺序):Multiple-Language Resources

    编辑:但是,根据我的经验(至少在 Windows XP 上),该页面上 FindResource 的详细搜索顺序并未描述实际行为。实际行为似乎是:

    1. LANG_NEUTRAL 资源
    2. Lang 和 SubLang 与 UI 语言 Lang 和 SubLang 匹配的资源
    3. Lang 与 UI 语言 Lang 匹配且资源 Sublang 是中性的资源
    4. Lang 和 SubLang 与区域设置语言 Lang 和 SubLang 匹配的资源
    5. Lang 匹配区域设置语言 Lang 且资源 Sublang 是中性的资源
    6. LANGID 数值最低的资源

    注意:我没有任何来源可以验证该列表,所以如果有人可以更新或更正任何内容,请这样做。

    编辑:要理解这种行为,重要的是要认识到“语言环境”和“UIlanguage”之间的区别,如下所述:NLS Terminology。 FindResource 函数语言选择主要基于 UI 语言,它不是“区域和语言选项”中的“区域选项”设置(即“区域设置”设置,与调用 SetThreadLocale() 相同)。

    据我所知,语言环境设置或“SetThreadLocale()”影响 FindResource() 的原因是@Kirill V. Lyadvinsky 在此处的答案之一中描述的异常情况,详细解释了Michael Kaplan's blog

    只有在 Vista 及更高版本中使用新功能“SetThreadUILanguage”才能在代码中清晰而确定地设置 FindResource 的语言。您看到的每个使用 SetThreadLocale 的地方都会有一些技巧来使其工作和/或在 UI 语言更改时出现问题(即:外语窗口安装)。

    【讨论】:

    • Multiple-Language Resources 链接来自于 1995 年左右写的一本书(提到 Windows 95 和 Visual C++ 2.0)。从那时起,某些功能/行为似乎发生了变化,因此需要对链接中的信息持保留态度。
    • 是的,MLR 链接是旧的 - 请参阅我在答案末尾关于从 Vista 开始的版本以及您应该始终使用 SetThreadUILanguage 的版本的注释
    【解决方案2】:

    您运行的是 Vista 还是 Windows 7?如果是这样,那么SetThreadLocale 不起作用(即使它返回 TRUE,叹息),您必须使用 SetThreadUILanguage

    我刚刚完成了一个已翻译成 7 种不同语言的 WTL 应用程序,用户可以切换语言而不会出现您所描述的问题。我在 XP 上使用SetThreadLocale,在 Vista/7 上使用SetThreadUILanguage

    更多信息:

    http://social.msdn.microsoft.com/forums/en-US/windowscompatibility/thread/d3a44b1c-900c-4c64-bdf8-fe94e46722e2/

    http://www.curlybrace.com/words/2008/06/10/setthreadlocale-and-setthreaduilanguage-for-localization-on-windows-xp-and-vista/

    【讨论】:

      【解决方案3】:

      这里要注意的是,如果线程区域设置与当前选择的用户区域设置相同,系统的资源加载器将默认使用语言 ID 0(中性)。如果所需资源被定义为中性语言,则将返回此值。否则,将枚举所有语言资源(按语言 ID 顺序),并返回第一个匹配的资源 ID(无论其语言如何)。

      控制资源的唯一方法是为每种语言使用单独的资源 DLL。

      【讨论】:

      • 当前选择的用户语言环境是什么?它是 Windows 资源管理器中菜单的语言,并且不可更改。在我有机会修改它之前检查线程语言环境?如何使用资源编辑器设置默认语言环境?
      • 在控制面板的区域设置中选择的是区域设置。
      • 这与“格式”选项卡无关。它是高级选项卡。
      • 如果您在未经用户许可的情况下更改设置,我认为用户不会高兴。单独的资源 DLL 将以最佳方式工作,而不会打扰用户。
      猜你喜欢
      • 1970-01-01
      • 2022-10-26
      • 2016-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-09
      • 1970-01-01
      • 2015-11-18
      相关资源
      最近更新 更多