LCIDs vs Locale Names and the deprecation of LCIDs.

As Windows XP nears the end of its extended support (see lifecycle fact sheet), I thought I’d mention Locale Names again.  I’ve been asking for years for people to use locale names, but now we’re reaching a step closer to deprecating LCIDs.

In the modern and managed worlds we’ve been using Locale Names/Culture Names/Language Names for some time, but in native windows code, those pesky LCIDs have been hanging on.  Probably a huge part of that is because the locale name and newer concepts (like the Windows.Globalization APIs) were introduced in Windows Vista and later.  Applications that wanted to run on XP might still see LCIDs, but everyone else could have been using names.

However now there’s an opportunity to reconsider what has probably been the default choice for many developers, and to use the modern Windows.Globalization APIs, or at least start using the Locale Name with older APIs like GetLocaleInfoEx.

Locale names are far more robust than the older LCIDs, allowing many more combinations.  In Windows 8.1, users can even select their own combination in the language profile, even if it isn’t a built-in locale.  They could pick “fj-FJ” or other language names.  (I personally play with tlh-Qaak sometimes).  There are over 6000 valid language codes, and hundreds of region ids (both ISO and UN M.49), allowing an millions of possibilities for the entire world.

Compare that to LCIDs/Locale Identifiers/Language Identifiers.  The original LCID idea worked when it was developed, but it’s pretty much limited to fewer than 512 “primary” languages, and 32 variations.  With languages spoken in many regions, there aren’t enough sublangs, like English, yet adding an additional primary language might break applications’ assumptions about which languages were English.  The macros to parse an LCID start breaking down.  To conserve the limited space, some related but different languages have been stuck in the same langid.  In other cases, thinking about the LCIDs structure has changed since their original inception.  “Neutrals” also collide with the sublangs in some cases, making it unclear if an LCID is specific or neutral.

  • LANGIDs might actually represent more than one language, it’s better to ask GetLocaleInfo for the ISO Language name.
  • SUBLANGs depend on Langid.  The “US” variation of en and es for example have different sublangs.  It’s far easier to ask GetLocaleInfo for the ISO region code and test that.
  • Multiple LANGIDs will likely actually represent the same language in the future.
  • Newer locales in Windows 8.1 don’t have assigned LCIDs (they can all return the same LCID, or transient variations if they’re an explicit user preference). 

So, if you aren’t already using language/locale names, please think about moving to them.  Your code will be more understandable, future proof and robust.

And whether you’re using names or LCIDs, the user default is often a good choice (eg, pass LOCALE_NAME_USER_DEFAULT to your GetLocaleInfoEx call)


PS: If you’re still stuck for a while on LCIDs, please at least don’t expect the LANGID parsing macros to be perfect or useful while you transition towards names.  Also realize that some user settings are going to end up with the LOCALE_CUSTOM_DEFAULT or other variations.  The LCID might be OK to query GetLocaleInfo for information, but on a later date or a different machine, it might have a different meaning.

Comments (6)

  1. Sandy says:


    Is there any way we can get a LCID in a Windows Store App. We need the LCID to take the user to a culture and region specific URL for the Privacy Statement. And one of the parameters in building this URL at runtime is a LCID. We can't use any of the native code API's to do the conversion from Locale to the LCID because of cert issues. At this point the only solution I see is to build a table and map the locale. Any other suggestions ?.



  2. For a Windows Store app, please use the user's language list.  That will resolve the user's declared language preferences with the ones you're application supports and provide a prioritized matching list.  You can then get the language tag(s) from that list to forward to your server.

    See Windows.Globalization.ApplicationLanguages.languages at…/windows.globalization.applicationlanguages.languages.aspx

    Note that these may be contain a regional variant, like "en-US" vs "en-CA", or only a general language tag, like "da", so the server probably needs to handle language tag fallback per the BCP 47 rules.

  3. Erik Fortune says:

    Shawn is correct – for most purposes you'll want to use the user's application language list from Windows.Globalization.ApplicationLanguages.Languages.

    To qualify things a bit further, though  _Don't_ assume anything from the "region" part of a language tag – "en-US" means "English as spoken in the United States" _not_ an English speaker located in the United States.   Specifically, the _language_ tag for a speaker of American English is "en-US", even if he happens to be sitting in London or Bombay.

    To determine a user's location you should use:


    With the caveat that HomeGeographicRegion is a preference that the user is free to change, so there's no guarantee that it will be accurate.   Put differently, HomeGeographicRegion is intended for headlines and sports scores, not for anything legally binding.

    One final note is that the API surface for Windows Store applications uses proper BCP-47 language tags to represent language.   Win32 locale names are very close to BCP-47, but for some languages and language variants they differ, mostly for historical reasons.

  4. Sandy says:

    Shawn/Erik – Sounds like we will need to make changes in the way the server is setup. For the short term will have to work with what we have. Thanks for your insightful responses and help.


  5. Doug Ewell says:

    Thanks for using 'Qaak' from my list of proposed ISO 15924 PUA assignments.

  6. I'd forgotten where I'd found Qaak.  Bing translator uses Qaak too now 🙂

Skip to main content