Some LCID links and notes
Posted by jpluimers on 2021/02/10
Document locations changed, so here are some links to newer and older documentation on LCID related things:
- Delphi: a few short notes on LoadString and loading shell resource strings for specific LCIDs, for which I need to check which ones have suffered from link rot.
- [WayBack] MAKELCID macro | Microsoft Docs:
Creates a locale identifier from a language identifier and a sort order identifier.
- Table: [WayBack] Locale Identifiers – Windows applications | Microsoft Docs with special values:
- 0x007F [WayBack]
LOCALE_INVARIANT
– Windows applications | Microsoft Docs The locale used for operating system-level functions that require consistent and locale-independent results. - 0x0400 [WayBack]
LOCALE_USER_DEFAULT
– Windows applications | Microsoft Docs: The default locale for the user or process.- Delphi 2009 added support for it and names it
VAR_LOCALE_USER_DEFAULT
: [WayBack] VarUtils.VAR_LOCALE_USER_DEFAULT Constant
- Delphi 2009 added support for it and names it
- 0x0800 [WayBack]
LOCALE_SYSTEM_DEFAULT
– Windows applications | Microsoft Docs: The default locale for the operating system. - [WayBack]
LOCALE_CUSTOM
* Constants – Windows applications | Microsoft Docs- 0x0C00
LOCALE_CUSTOM_DEFAULT
The default custom locale.- When an NLS function must return a locale identifier for a supplemental locale for the current user, the function returns this value instead of
LOCALE_USER_DEFAULT
.
- When an NLS function must return a locale identifier for a supplemental locale for the current user, the function returns this value instead of
- 0x1000
LOCALE_CUSTOM_UNSPECIFIED
An unspecified custom locale, used to identify all supplemental locales except the locale for the current user.- Supplemental locales cannot be distinguished from one another by their locale identifiers, but can be distinguished by their locale names. Certain NLS functions can return this constant to indicate that they cannot provide a useful identifier for a particular locale.
- 0x1400
LOCALE_CUSTOM_UI_DEFAULT
The default custom locale for MUI.- The user preferred UI languages and the system preferred UI languages can include at most a single language that is implemented by a Language Interface Pack (LIP) and for which the language identifier corresponds to a supplemental locale. If there is such a language in a list, the constant is used to refer to that language in certain contexts.
- 0x0C00
- 0x007F [WayBack]
- List: [WayBack] Language Identifiers – Windows applications | Microsoft Docs
The following are predefined language identifiers:
LANG_SYSTEM_DEFAULT
. The operating system default language.LANG_USER_DEFAULT
. The language of the current user.
- Table: [WayBack] Language Identifier Constants and Strings – Windows applications | Microsoft Docs
- Table: [WayBack] [MS-LCID]: Windows Language Code Identifier (LCID) Reference | Microsoft Docs
- Table: [WayBack] Microsoft Locale ID Values | Microsoft Docs via [WayBack] Locale ID (LCID) Chart | Microsoft Docs
- Table: [WayBack] Sort Order Identifiers – Windows applications | Microsoft Docs
- Conversion macros and their documentation in [WayBack] moflow/ntdef.h at master · Cisco-Talos/moflow · GitHub:
// A locale ID is a 32 bit value which is the combination of a // language ID, a sort ID, and a reserved area. The bits are // allocated as follows: // // +-------------+---------+-------------------------+ // | Reserved | Sort ID | Language ID | // +-------------+---------+-------------------------+ // 31 20 19 16 15 0 bit // // WARNING: This pattern isn't always followed (es-ES_tradnl vs es-ES for example) // // It is recommended that applications test for locale names or actual LCIDs. // // Locale ID creation/extraction macros: // // MAKELCID - construct the locale id from a language id and a sort id. // MAKESORTLCID - construct the locale id from a language id, sort id, and sort version. // LANGIDFROMLCID - extract the language id from a locale id. // SORTIDFROMLCID - extract the sort id from a locale id. // SORTVERSIONFROMLCID - extract the sort version from a locale id. // // Note that the LANG, SUBLANG construction is not always consistent. // The named locale APIs (eg GetLocaleInfoEx) are recommended. // // LCIDs do not exist for all locales.
- Equivalent C# translations of these marcos are in [WayBack] MediaPortal-2/DSHelper.cs at master · MediaPortal/MediaPortal-2 · GitHub.
- Table: [WayBack] Locale Identifiers – Windows applications | Microsoft Docs with special values:
- Setting and restoring the default user language:
- [WayBack] Nasty gotcha: SetThreadUILanguage cannot be used to restore the thread UI language – The Old New Thing
- [WayBack] What is the correct way of temporarily changing a thread’s preferred UI language? – The Old New Thing
- [WayBack] When changing behavior is like killing puppies
- [Archive.is] site:archives.miloush.net/michkap SetThreadPreferredUILanguages – Google Search
- API calls:
- [WayBack] GetSystemDefaultLCID function | Microsoft Docs
- [WayBack] GetSystemDefaultLocaleName function | Microsoft Docs
- [WayBack] GetThreadLocale function | Microsoft Docs
- [WayBack] GetThreadPreferredUILanguages function | Microsoft Docs
- [WayBack] GetThreadUILanguage function | Microsoft Docs
- [WayBack] GetUserDefaultLCID function | Microsoft Docs (has no Set* equivalent)
- [WayBack] GetUserDefaultLocaleName function | Microsoft Docs
- [WayBack] SetThreadLocale function | Microsoft Docs
- [WayBack] SetThreadPreferredUILanguages function | Microsoft Docs
- [WayBack] SetThreadUILanguage function | Microsoft Docs
- Saving/restoring data between locales:
- [WayBack] Using Persistent Locale Data – Windows applications | Microsoft Docs
Using Persistent Locale Data
A globalized application often persists or transmits data, for example, time and date. When deciding how your application should handle data persistence, remember that data is not guaranteed to be the same from computer to computer or between runs of the application. This is true for both locales that ship with Windows and custom locales.
Design of the application must take into account a variety of locale-related data changes that can occur. For example:
- Currency symbols can change as countries adopt the Euro.
- Regional preferences can change. For example, the format d/m/y might change to the format m/d/y for a particular locale.
- The spelling of day names can change due to spelling reforms. Additionally, casing can change for month or day names.
Use Locale-Independent Formats for Storage and Data Interchange
An application that persists data should use locale-independent formats for storage and data interchange. Examples are hard-coded or standard formats; the invariant locale LOCALE_NAME_INVARIANT; and binary storage formats.
If persistent sorting data is required, the application must use the CompareStringOrdinal function. Remember that an invariant format does not remain invariant for sorting, only for locale and calendar data.
Use the User Default Locale for Data Presentation
To present persistent data, it is best for the application to reformat the data using the user default locale. Use of this locale allows user overrides. For more information, see LOCALE_USER_DEFAULT.
- [WayBack] Using Persistent Locale Data – Windows applications | Microsoft Docs
More Delphi related links:
- [WayBack] windows – Which date format does VarToDateTime(VarDateFromStr) use? – Stack Overflow
- [WayBack] windows – What can make VarDateFromStr fail to use the current user’s Locale when VAR_LOCALE_USER_DEFAULT is supplied as an argument – Stack Overflow
- Variant string to double conversion issues:
- [WayBack] variant to double – delphi
Assume this code and default decimal separator is , :
var v: Variant; d: Double; begin v:= '0.12'; d:= v; ShowMessage(FloatToStr(d)); end;
It will show 12 (not correct).
Now add this in the first line:
DecimalSeparator:= '.';
It still gives the same result. If you enable debug dcu’s you will see that
the problem occurs in functionVarToDoubleAsString
, which callsVarR8FromStr
withVAR_LOCALE_USER_DEFAULT
as locale, so there is no chance to change it as I tried. What is the rationale behind this setup?Only workaround seems to either force users to have the correct default
locale or use d:= StrToFloat(v) instead of d:= v; This makes the code less readable.- [WayBack] VarR8FromStr function | Microsoft Docs: Converts an
OLECHAR
string to a double value.
- [WayBack] VarR8FromStr function | Microsoft Docs: Converts an
- [WayBack] delphi – Cast from Variant String to Double ignores decimal point – Stack Overflow
- [WayBack] Wrinting decimal value to the XML / on embarcadero.public.delphi.xml / NNTP Conversation
- [WayBack] variant to double – delphi
–jeroen
Leave a Reply