仅当我没有英文字符串表时,LoadString才有效

时间:2009-07-31 16:18:58

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

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

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

我认为这是一个资源加载器错误,如果资源加载器找到与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();

那么,我该怎么办?这个奇怪的“虫子”有什么解释?

LATER EDIT:

经过一些测试后我发现:

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

3 个答案:

答案 0 :(得分:6)

直接从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的资源
  7. 注意:我没有任何资源来验证该列表,因此如果有人可以更新或更正任何内容,请执行此操作。

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

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

    只有在Vista中使用新功能“SetThreadUILanguage”才能干净利落地确定代码中FindResource的语言。相反使用SetThreadLocale而你看到的每个地方都会有黑客使其工作和/或在UI语言发生变化时出现问题(即:外语窗口安装)。

答案 1 :(得分:5)

您运行的是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/

答案 2 :(得分:4)

  

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

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