Yet another digit substitution[.Net] problem

by Michael S. Kaplan, published on 2010/01/18 07:01 -05:00, original URI: http://blogs.msdn.com/b/michkap/archive/2010/01/18/9949627.aspx


I have a blog I have been writing off and on for a couple of years now all about digit substitution.

That blog is coming soon and will be my definitive and final thoughts on the feature and its implementation(s).

This is not that blog.

This is a blog about digit substitution, though.

Digit substitution and GDI+, this one is about, actually.

The question:

Issue:

Need to get the lang id and “standard digits” values that the user has chosen for digits.

Scenario:

the user locale is set to "English (United Status)"
In "Additional settings..." in Region and Language,
        "Standard digits" has been set to ٠١٢٣٤٥٦٧٨٩.
             "Use native digits" has been set to National.

Problem:

In the above scenario, all the windows UIs like shell, notepad, etc are showing ٠١٢٣٤٥٦٧٨٩.
However, when I render text using GDIplus drawstring, it is rendered as 0123456789

I was able to get the desired output when I used format.SetDigitSubstitution(0x0C01, Gdiplus::StringDigitSubstituteNational); (Our code is in C++.)

Question:

Does anyone know the win 32 api or how to get the lang id and “standard digits” values that the user has chosen for digits.

This ought to be easy enough to answer, one might expect.

Unless of course one has spent any time dealing with digit substitution, of course!

Unfortunately, the answer is that there is no way to query for this information, this scenario where one changes  the fundamental digit choice to be different than the user's standards and formats language, al so known as the default user locale for the given user.

Now if one looks at the internal tables behind Uniscribe and GDI+ one will see lots of hard-coded, locale based info (as discussed in Digits -- there is no substitute) but the fact that they are kind of locale based is hidden from the caller of both technologies, though hidden in very different ways (in the case of GDI+ this way is a lot harder to work around as this problem illustrates, as there is no intrinsic way to say "use the default user locale setting as modified by the user when appropriate". This is the setting that would easily solve this StringFormat::SetDigitSubstitution Method-based question.

Now in theory one could hope that not calling the above method with its limitations would lead to correct behavior, but this is apparently not the case. Before one gets too haughty it is reasonable to consider that one of the most common reported performance complaints about Uniscribe is its overabundant interest in user locale settings due to the anal retentive checking of the digit substitution settings.

So GDI+ is giving us some gain for the lack of this functionality - one less performance issue!

Unfortunately, if it is not giving a parameter on a StringFormat::SetDigitSubstitution Method overload that lets one say this (like the Uniscribe ScriptRecordDigitSubstitution Function not only allows but explicitly documents) then GDI+ is leaving this hole in support, a hole that really has no good excuse (if the lookup is only triggered by a StringFormat::SetDigitSubstitution Method call with LOCALE_USER_DEFAULT then it is hardly a negative performance issue since no one is monitoring anything at all, really -- it can be a one-time lookup.

Note also that the Uniscribe ScriptRecordDigitSubstitution Function and in particular the SCRIPT_DIGITSUBSTITUTE structure that both it and the ScriptApplyDigitSubstitution Function depend on, introduces the notion of separate NationalDigitLanguage and TraditionalDigitLanguage values that do not have to be the same as the user locale since they can be updated via other processes.

There is a part of me that would like to mistrust the report from the questioner that LOCALE_USER_DEFAULT to the GDI+ StringFormat::SetDigitSubstitution Method really fails here, but I'm going to trust that it did fail to fix the problem as they told me when I made the suggestion.

Worst case has me reporting that I was mistaken here and I will only be the second most embarrassed person and I can live with that! :-)

Plus if it does actually work I'll still get the last word about how weird it would be that LOCALE_USER_DEFAULT and the LCID that is the current default user locale would have different behavior, despite all the work that NLS does to make them the same thing. Even though it is a screwy semantic at times, it has been there for a long time and it really ought to be respected by people who wish to opt in to the "LCID" datatype....


# Mihai on 19 Jan 2010 11:39 AM:

"Unfortunately, the answer is that there is no way to query for this information"

Unless I don't understand the problem, then GetLocaleInfoEx with LOCALE_SNATIVEDIGITS to get the digits, and LOCALE_IDIGITSUBSTITUTION to find out if the setting is in effect is exactly what's needed here.

# Michael S. Kaplan on 19 Jan 2010 12:40 PM:

That will not tell you the locale to pass to the GDI+ method.

# Michael S. Kaplan on 19 Jan 2010 12:43 PM:

Note that GDI+ wants the locale so *it* can look up the digits. It doesn't want the digits themselves....


referenced by

2010/11/12 Suddenly, in a bit more time than a blink of an eye, "standards support" becomes "less i18n support"

go to newer or older post, or back to index or month or day