by Michael S. Kaplan, published on 2005/08/31 03:03 -04:00, original URI: http://blogs.msdn.com/b/michkap/archive/2005/08/31/458266.aspx
I can hardly believe it has been a year since I asked and answered the questions What is a neutral culture? What is a neutral locale?
I spent a bunch of time talking about how lame neutral locales were on Wn32 given how they are not supported by any of the NLS functions.
They are very useful for resources though, something Stuart reminded me of the other day when he asked the following question in the newsgroups:
In XP my user is set to German (Switzerland) and in my COM dll (built in Visual Studio 6) I have resources for German (Germany) and English (U.S.)
However the German (Germany) string table is ignored and the LoadString win32 call loads the English (U.S.) resource.
Why is the German (Switzerland) user loading the English (U.S.) resource?
Well, once upon a time this is what may have happened -- if you look at the section of Chapter 4 of the first edition of Developing International Software for Windows 95 and Windows NT entitled Multiple Language Resources:
On Windows NT, FindResource searches for resources tagged with the language ID of the calling thread. On Windows 95, it searches for resources tagged with the default system language ID. On Windows NT, you can search for a resource in a specific language by calling FindResourceEx, which takes a language ID as a parameter. Both FindResource and FindResourceEx first attempt to find a resource tagged with a language ID, as described above. If they don't find anything, they then search for a resource tagged with the same primary language as that of the specified language ID. (If several resources with the same primary language but different sublanguages exist, the functions will return whatever they encounter first.) If, for example, the program requests resources in Standard German that aren't available, the program can retrieve Austrian German or Swiss German resources and still provide a user interface that the user can understand.
If the FindResource and FindResourceEx functions do not find any resources that match the language ID's primary language, they search for resources tagged as "language-neutral." This language ID is useful for resource elements such as icons or cursors that are identical for all languages. If a bitmap or an icon will differ for some languages, you can define one language-neutral bitmap as the default and specify language IDs for as many other customized bitmaps as required. For example, bidirectional applications might require bitmaps with right-to-left directionality. Because the FindResource and FindResourceEx functions always search for specific language IDs first, they will always find a bitmap tagged with that language ID before they find one tagged as language-neutral. The search algorithm they follow is summarized in the following list:
- Primary language/sublanguage
- Primary language
- Language-neutral
- English (skipped if primary language is English)
- Any
But a lot has changed since this book was published (hell, just after the section I quoted is the one that talks about how you can use SetThreadLocale to choose the language and if you are a regular reader here then you know how I feel about SetThreadLocale.
But there have been other changes in resource loading since NT 3.1 and Windows 95 that invalidate some of the priorities in resource loading. To understand why, it might be a good idea to think back to my post in May when I talked about The weird, weird world of the SUBLANGID. The truth is that each of these locales is different, and there are times that the behavior Stuart wanted (if not the full language I wanted, give me something close) may actually cause more problems then it could solve. Possibly not for German, but you never know. And there are times that you want to define an entirely different fallback logic, such as Basque or Catalan falling back to Spanish. and times that you do not want Bosnian to fall back to Croatian (or Simplified Chinese to fall back to Traditional Chinese).
So things had to change, they really did. And they have been changing over the last few versions.
The specific change prior to Windows Vista is to meet the same numbered steps as above, skipping the text above the list, i.e. (If several resources with the same primary language but different sublanguages exist, the functions will return whatever they encounter first.).
(At this point, people pretty much universally recommend that "best practice" in this case involves separate language resource DLLs, one per language. I will get into why this is the case at a later time.)
But specifically it is important if you do not want to follow the multiple DLL advice that you use neutral language resources to use a language that you want to have all of the various specific locales fall back upon. As I mentioned back in June, Using full locales rather than the neutral ones is often not a terribly good idea.
Because sometimes, it pays to be neutral!
(Editorial request of readers who wish to comment -- I would prefer if comments if any for this post not try to get into the religious issue of separate language resource DLLs and limit themselves to the religious issue of neutral vs. specific resources. I promise I will be covering the other issue soon!)
This post brought to you by "₦" (U+20a6, NAIRA SIGN)
# Vorn on 31 Aug 2005 4:41 AM:
# Michael S. Kaplan on 31 Aug 2005 9:26 AM:
# Michael S. Kaplan on 31 Aug 2005 9:31 AM:
# Michael S. Kaplan on 31 Aug 2005 10:55 PM:
# Martin Bohring on 1 Sep 2005 3:34 AM:
# Stuart Barlow on 1 Sep 2005 6:19 AM:
# Michael S. Kaplan on 1 Sep 2005 9:27 AM:
# Michael S. Kaplan on 1 Sep 2005 9:33 AM:
# Tialaramex on 3 Sep 2005 8:26 AM: