Locales with the same language

Dmitry Timoshkov dmitry at baikal.ru
Fri Jul 18 03:18:52 CDT 2003


"Vincent Béron" <vberon at mecano.gme.usherb.ca> wrote:

> (after a bit more testing)
> Using only SUBLANG_FRENCH_CANADIAN will display in French on both
> Windows and Wine.
> Using only SUBLANG_FRENCH_SWISS will display in English on both Windows
> and Wine.
> Using only SUBLANG_FRENCH will display in French only in Windows,
> English in Wine (with LANG=fr_CA).
>
> So SUBLANG_FRENCH seems to act (on Windows) the same way as a wildcard,
> matching any of it's sublanguages if an exact match can't be done.

Could you please elaborate a bit, how exactly you did the tests above?

> I also tried defining more than one (ie, SUBLANG_FRENCH and
> SUBLANG_FRENCH_CANADIAN) resources. On Windows it chose the
> SUBLANG_FRENCH, while in Wine it chose the SUBLANG_FRENCH_CANADIAN. That
> gets me a bit puzzled though... unless my installation of Windows is set
> to French, then French Canadian as a fallback (don't know of to check
> this).

All of this highly depend on the exact language set in your system (be it
Windows or Wine).

I've attached my test app. See the results I got eclosed there between
#if 0/#endif.

Note, that if your system doesn't support SetThreadLocale() (i.e. you are
running Win9x), the system will prefer your current locale settings
instead of the provided value and it will influence behaviour of LoadString
and FindResource.

As you might see, Wine doesn't behave exactly like Windows, Wine makes
a preference for the current locale, Windows prefers to choose LANG_ENGLISH
first. As it was discussed previously, Wine's behaviour have to stay as
it is now, otherwise all NLS support for built-in DLLs and apps will broke.

How I did my test:
1. Uncomment all resource strings in locales.rc. If you want, you could
add your own resource strings. Make N = 1.
2. build the test.
3. Run test.exe 0x40C
(0x40C == LANG_FRENCH,SUBLANG_DEFAULT). Note that SUBLANG_FRENCH == SUBLANG_DEFAULT).
4. Write down the result under number N. N = N + 1.
5. Comment out the found resource.
6. Goto 2.

--
Dmitry.
-------------- next part --------------
#include <windows.h>
#include <winnls.h>
#include <stdio.h>

#define TRACE printf

static INT NLS_LoadStringExW(HRSRC hrsrc, LANGID lang_id, UINT res_id, LPWSTR buffer, INT buflen)
{
    HGLOBAL hmem;
    WCHAR *p;
    int string_num;
    int i;

    if(!hrsrc) {
	printf("hrsrc = 0\n");
	return 0;
    }

    hmem = LoadResource(NULL, hrsrc);
    if(!hmem) {
	printf("LoadResource returned 0\n");
	return 0;
    }
    
    p = LockResource(hmem);
    string_num = res_id & 0x000f;
    for(i = 0; i < string_num; i++)
	p += *p + 1;
    
//    TRACE("strlen = %d\n", (int)*p );
    
    if (buffer == NULL) return *p;
    i = min(buflen - 1, *p);
    if (i > 0) {
	memcpy(buffer, p + 1, i * sizeof (WCHAR));
	buffer[i] = (WCHAR) 0;
    } else {
	if (buflen > 1)
	    buffer[0] = (WCHAR) 0;
    }

    FreeResource(hmem);
    TRACE("\"%ws\"\n", buffer);
    return (i + 1);
}

void FindResource_test(LANGID lang_id)
{
    HMODULE hModule = GetModuleHandleW(NULL);
    HRSRC hrsrc;
    WCHAR wcBuffer[128];
    CHAR  acBuffer[128];

    printf("Testing LoadStringA: ");
    if(LoadStringA(hModule, 1, acBuffer, 128))
	printf("\"%s\"\n", acBuffer);
    else
	printf("LoadStringA returned 0\n");

    printf("Testing FindResourceA: ");
    hrsrc = FindResourceA(hModule, (LPCSTR)1, (LPCSTR)RT_STRING);
    if(!hrsrc)
	printf("FindResourceA returned 0\n");
    else
	NLS_LoadStringExW(hrsrc, lang_id, 1, wcBuffer, 128);

    printf("Testing FindResourceExA(%04X; %02X %02X): ",
	lang_id, PRIMARYLANGID(lang_id), SUBLANGID(lang_id));
    hrsrc = FindResourceExA(hModule, (LPCSTR)RT_STRING, (LPCSTR)1, lang_id);
    if(!hrsrc)
	printf("FindResourceExA returned 0\n");
    else
	NLS_LoadStringExW(hrsrc, lang_id, 1, wcBuffer, 128);
}

static BOOL CALLBACK EnumResourceLanguagesProcW(HMODULE hModule, LPCWSTR type,
		LPCWSTR name, WORD LangID, LONG lParam)
{
    printf("%08X\n", (UINT)LangID);
    return TRUE;
}

int main(int argc, char *argv[])
{
    LANGID lang_id;

    if(argc > 1)
	lang_id = (LANGID)strtol(argv[1], NULL, 0);
    else
	lang_id = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);

    SetThreadLocale(MAKELCID(lang_id, SORT_DEFAULT));

    printf("Thread locale = %04X\n", GetThreadLocale());

    EnumResourceLanguagesW(GetModuleHandleA(NULL), (LPCWSTR)RT_STRING,
	    (LPCWSTR)LOCALE_ILANGUAGE, EnumResourceLanguagesProcW, 0);

    FindResource_test(lang_id);

    return 0;
}

#if 0
Win95OS2PE LoadStringA/W and FindResourceA/W do search in the following order:
1. Neutral language with neutral sublanguage
2. Neutral language with default sublanguage
3. LANG_ENGLISH, SUBLANG_DEFAULT
4. Current locale lang id
5. Current locale lang id with neutral sublanguage
6. Return first in the list

Win2000: LoadStringA/W and FindResourceA/W do search in the following order:
1. Neutral language with neutral sublanguage
2. LANG_ENGLISH, SUBLANG_DEFAULT
3. LANG_ENGLISH, SUBLANG_NEUTRAL
4. Current locale lang id
5. Current locale lang id with neutral sublanguage
6. Return first in the list

FindResourceExA/W does search in the following order:
1. Exact specified language
2. Language with neutral sublanguage
3. Neutral language with neutral sublanguage
4. Neutral language with default sublanguage
#endif
-------------- next part --------------
A non-text attachment was scrubbed...
Name: locales.rc
Type: application/octet-stream
Size: 869 bytes
Desc: not available
Url : http://www.winehq.org/pipermail/wine-devel/attachments/20030718/c34986cb/locales.obj
-------------- next part --------------
A non-text attachment was scrubbed...
Name: build.bat
Type: application/octet-stream
Size: 103 bytes
Desc: not available
Url : http://www.winehq.org/pipermail/wine-devel/attachments/20030718/c34986cb/build.obj


More information about the wine-devel mailing list