views:

935

answers:

2

I want to be able to modify the application's language programatically, or at least use the language specified in Control Panel -> Regional and Language Options -> Formats.

If I add an english string table, make a french and a german copy of it, and delete the english one, I can programatically switch between loading the french and the german strings. If I keep the english copy, the english strings get loaded, no matter what, when I try to load the german or the french ones.

I think that this is a resource loader bug, and that the resource loader ignores SetThreadLocale, if it finds a string table in the same language as the windows ui language (the language of the windows explorer menus for example).

I tried to change Control Panel -> Regional and Language Options -> Formats to French, but that has no effect. The resource editor shows the french string table without the language appended, but my program still always loads the english strings. Copying this change to the system account has no effect either.

Here is the code I tried this with:

#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 is a half wrong, incomplete explanation (in the second half of Method 2). The second workaround proposed there, using only coutry-neutral string tables is useless, because I have separate portuguese-Portugal and portuguese-Brazil string tables.

The first workaround proposed there does not work. With the code below, I get error 1814.

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

So, what should I do ? What's the explanation of this strange "bug" ?

LATER EDIT:

After some more tests I found out that:

  1. GetThreadLocale() returns what is set in Control Panel -> Regional and Language Options -> Formats.
  2. The resource loader bug is essentially that if my program has US English resources too, those resources will be loaded, no matter what is set at Formats. If it does not have US English resources, the language set at Formats will be used.
  3. If I have a French (Neutral) and a German (Neutral) string table, and I set Formats to French (France), the german strings are loaded. If I add an English (Neutral) string table, the english strings are loaded. So, the neutral culture fallback does not work for what is set at Formats.
  4. If I add a Neutral string table, that one will be used, even if I have another English (Neutral) or an English (United States) string table.
+1  A: 

The catch here is that if the thread locale is the same as the currently selected user locale, system’s resource loader will by default use the language ID 0 (neutral). If the desired resource is defined as a neutral language, then this value will be returned. Otherwise, all of the language resources will be enumerated (in language ID order) and the first matching resource ID – regardless of its language – will be returned.

The only way to control resources is to use separate resource DLLs for each language.

Kirill V. Lyadvinsky
What is the currently selected user locale ? Is it the language of the menus in Windows Explorer, and unchangeable.The thread locale is checked before I have the chance to modify it ?How can I set the default locale with the resource editor ?
csuporj
It is locale that selected in Regional settings in Control Panel.
Kirill V. Lyadvinsky
That's not related to Format tab. It is Advanced tab.
Kirill V. Lyadvinsky
And I don't think that user will be happy if you'll change that settings without users permission. Separate resource DLLs would work in the best way without bothering user.
Kirill V. Lyadvinsky
+1  A: 

Are you running Vista or Windows 7? If so then SetThreadLocale doesn't work (even though it returns TRUE, sigh) and you have to use SetThreadUILanguage.

I have just completed a WTL app that has been translated into 7 different languages and the user can switch languages without the problems you are describing. I am using SetThreadLocale on XP and SetThreadUILanguage on Vista/7.

More info:

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/

Rob