Locale

Description

This sample provides a drop-in ready class module, which you can use in either Classic VB or VBA to determine the regional settings currently in use. You have the option to override the user's preferred settings, as well, to determine what the default regional settings for this machine should be. Also, you may (hopefully with the user's permission!) change the current user's preference for regional settings.

The CLocaleInfo class will use Unicode functions by default, when they're available, and ANSI functions when it finds itself operating under older (Win9x) platforms. Using this class is extremely simple. For example:

Dim li As CLocaleInfo
Set li = New CLocaleInfo
li.AllowUserOverride = True

Debug.Print Format$(Now, li.LocaleInfo(LOCALE_SLONGDATE))

Note however that there isn't always a direct 1:1 correspondence between VB's custom formatting strings and those used by Windows. For example, Windows uses "t" or "tt" to represent "A/P" or "AM/PM", so you can't directly pass LOCALE_STIMEFORMAT to the native Format function without some massaging of the results. In order to avoid these messy situations, I added two more functions to the class which show how to call the API functions GetTimeFormat and GetDateFormat.  These are as simple to use as this:

Debug.Print li.LocaleDate(, , DATE_LONGDATE); " at ";
Debug.Print li.LocaleTime()

All the constants used with the Locale functions are conveniently exposed as public enumerations. These are available for your inspection:

Color-coded with vbMarkUp - try it today!
Public Enum LocaleInfoTypes
   LOCALE_ILANGUAGE = &H1             '  language id
   LOCALE_SLANGUAGE = &H2             '  localized name of language
   LOCALE_SENGLANGUAGE = &H1001       '  English name of language
   LOCALE_SABBREVLANGNAME = &H3       '  abbreviated language name
   LOCALE_SNATIVELANGNAME = &H4       '  native name of language
   LOCALE_ICOUNTRY = &H5              '  country code
   LOCALE_SCOUNTRY = &H6              '  localized name of country
   LOCALE_SENGCOUNTRY = &H1002        '  English name of country
   LOCALE_SABBREVCTRYNAME = &H7       '  abbreviated country name
   LOCALE_SNATIVECTRYNAME = &H8       '  native name of country
   LOCALE_IDEFAULTLANGUAGE = &H9      '  default language id
   LOCALE_IDEFAULTCOUNTRY = &HA       '  default country code
   LOCALE_IDEFAULTCODEPAGE = &HB      '  default code page
   LOCALE_SLIST = &HC                 '  list item separator
   LOCALE_IMEASURE = &HD              '  0 = metric, 1 = US
   LOCALE_SDECIMAL = &HE              '  decimal separator
   LOCALE_STHOUSAND = &HF             '  thousand separator
   LOCALE_SGROUPING = &H10            '  digit grouping
   LOCALE_IDIGITS = &H11              '  number of fractional digits
   LOCALE_ILZERO = &H12               '  leading zeros for decimal
   LOCALE_SNATIVEDIGITS = &H13        '  native ascii 0-9
   LOCALE_SCURRENCY = &H14            '  local monetary symbol
   LOCALE_SINTLSYMBOL = &H15          '  intl monetary symbol
   LOCALE_SMONDECIMALSEP = &H16       '  monetary decimal separator
   LOCALE_SMONTHOUSANDSEP = &H17      '  monetary thousand separator
   LOCALE_SMONGROUPING = &H18         '  monetary grouping
   LOCALE_ICURRDIGITS = &H19          '  # local monetary digits
   LOCALE_IINTLCURRDIGITS = &H1A      '  # intl monetary digits
   LOCALE_ICURRENCY = &H1B            '  positive currency mode
   LOCALE_INEGCURR = &H1C             '  negative currency mode
   LOCALE_SDATE = &H1D                '  date separator
   LOCALE_STIME = &H1E                '  time separator
   LOCALE_SSHORTDATE = &H1F           '  short date format string
   LOCALE_SLONGDATE = &H20            '  long date format string
   LOCALE_STIMEFORMAT = &H1003        '  time format string
   LOCALE_IDATE = &H21                '  short date format ordering
   LOCALE_ILDATE = &H22               '  long date format ordering
   LOCALE_ITIME = &H23                '  time format specifier
   LOCALE_ICENTURY = &H24             '  century format specifier
   LOCALE_ITLZERO = &H25              '  leading zeros in time field
   LOCALE_IDAYLZERO = &H26            '  leading zeros in day field
   LOCALE_IMONLZERO = &H27            '  leading zeros in month field
   LOCALE_S1159 = &H28                '  AM designator
   LOCALE_S2359 = &H29                '  PM designator
   LOCALE_SDAYNAME1 = &H2A            '  long name for Monday
   LOCALE_SDAYNAME2 = &H2B            '  long name for Tuesday
   LOCALE_SDAYNAME3 = &H2C            '  long name for Wednesday
   LOCALE_SDAYNAME4 = &H2D            '  long name for Thursday
   LOCALE_SDAYNAME5 = &H2E            '  long name for Friday
   LOCALE_SDAYNAME6 = &H2F            '  long name for Saturday
   LOCALE_SDAYNAME7 = &H30            '  long name for Sunday
   LOCALE_SABBREVDAYNAME1 = &H31      '  abbreviated name for Monday
   LOCALE_SABBREVDAYNAME2 = &H32      '  abbreviated name for Tuesday
   LOCALE_SABBREVDAYNAME3 = &H33      '  abbreviated name for Wednesday
   LOCALE_SABBREVDAYNAME4 = &H34      '  abbreviated name for Thursday
   LOCALE_SABBREVDAYNAME5 = &H35      '  abbreviated name for Friday
   LOCALE_SABBREVDAYNAME6 = &H36      '  abbreviated name for Saturday
   LOCALE_SABBREVDAYNAME7 = &H37      '  abbreviated name for Sunday
   LOCALE_SMONTHNAME1 = &H38          '  long name for January
   LOCALE_SMONTHNAME2 = &H39          '  long name for February
   LOCALE_SMONTHNAME3 = &H3A          '  long name for March
   LOCALE_SMONTHNAME4 = &H3B          '  long name for April
   LOCALE_SMONTHNAME5 = &H3C          '  long name for May
   LOCALE_SMONTHNAME6 = &H3D          '  long name for June
   LOCALE_SMONTHNAME7 = &H3E          '  long name for July
   LOCALE_SMONTHNAME8 = &H3F          '  long name for August
   LOCALE_SMONTHNAME9 = &H40          '  long name for September
   LOCALE_SMONTHNAME10 = &H41         '  long name for October
   LOCALE_SMONTHNAME11 = &H42         '  long name for November
   LOCALE_SMONTHNAME12 = &H43         '  long name for December
   LOCALE_SMONTHNAME13 = &H100E       '  long name for 13th month (if exists)
   LOCALE_SABBREVMONTHNAME1 = &H44    '  abbreviated name for January
   LOCALE_SABBREVMONTHNAME2 = &H45    '  abbreviated name for February
   LOCALE_SABBREVMONTHNAME3 = &H46    '  abbreviated name for March
   LOCALE_SABBREVMONTHNAME4 = &H47    '  abbreviated name for April
   LOCALE_SABBREVMONTHNAME5 = &H48    '  abbreviated name for May
   LOCALE_SABBREVMONTHNAME6 = &H49    '  abbreviated name for June
   LOCALE_SABBREVMONTHNAME7 = &H4A    '  abbreviated name for July
   LOCALE_SABBREVMONTHNAME8 = &H4B    '  abbreviated name for August
   LOCALE_SABBREVMONTHNAME9 = &H4C    '  abbreviated name for September
   LOCALE_SABBREVMONTHNAME10 = &H4D   '  abbreviated name for October
   LOCALE_SABBREVMONTHNAME11 = &H4E   '  abbreviated name for November
   LOCALE_SABBREVMONTHNAME12 = &H4F   '  abbreviated name for December
   LOCALE_SABBREVMONTHNAME13 = &H100F '  abbreviated name for 13th month (if exists)
   LOCALE_SPOSITIVESIGN = &H50        '  positive sign
   LOCALE_SNEGATIVESIGN = &H51        '  negative sign
   LOCALE_IPOSSIGNPOSN = &H52         '  positive sign position
   LOCALE_INEGSIGNPOSN = &H53         '  negative sign position
   LOCALE_IPOSSYMPRECEDES = &H54      '  mon sym precedes pos amt
   LOCALE_IPOSSEPBYSPACE = &H55       '  mon sym sep by space from pos amt
   LOCALE_INEGSYMPRECEDES = &H56      '  mon sym precedes neg amt
   LOCALE_INEGSEPBYSPACE = &H57       '  mon sym sep by space from neg amt

   '#if(WINVER >= 0x0400)
   LOCALE_FONTSIGNATURE = &H58        '  font signature
   LOCALE_SISO639LANGNAME = &H59      '  ISO abbreviated language name
   LOCALE_SISO3166CTRYNAME = &H5A     '  ISO abbreviated country name
   '#endif /* WINVER >= 0x0400 */

   '#if(WINVER >= 0x0500)
   LOCALE_IDEFAULTEBCDICCODEPAGE = &H1012  '  default ebcdic code page
   LOCALE_IPAPERSIZE = &H100A              '  0 = letter, 1 = a4, 2 = legal, 3 = a3
   LOCALE_SENGCURRNAME = &H1007            '  english name of currency
   LOCALE_SNATIVECURRNAME = &H1008         '  native name of currency
   LOCALE_SYEARMONTH = &H1006              '  year month format string
   LOCALE_SSORTNAME = &H1013               '  sort name
   LOCALE_IDIGITSUBSTITUTION = &H1014      '  0 = none, 1 = context, 2 = native digit
   '#endif /* WINVER >= 0x0500 */
End Enum

' Time Flags for GetTimeFormatW.
Public Enum LocaleTimeFlags
   TIME_NOMINUTESORSECONDS = &H1       '  do not use minutes or seconds
   TIME_NOSECONDS = &H2                '  do not use seconds
   TIME_NOTIMEMARKER = &H4             '  do not use time marker
   TIME_FORCE24HOURFORMAT = &H8        '  always use 24 hour format
End Enum

' Date Flags for GetDateFormatW.
Public Enum LocaleDateFlags
   DATE_SHORTDATE = &H1                '  use short date picture
   DATE_LONGDATE = &H2                 '  use long date picture
End Enum

You may notice an odd addition near the end of the module, in the private ForceEnumCase routine. All of these enumerated constants are defined within a conditional compilation block. And, odder still, the test is written such that the block is never compiled! Why? Doing this forces the VB IDE to maintain proper-casing on all these constants. Were they only enumerated, if you typed one manually (rather than choose it from the Intellisense dropdown) and used a different casing, it would change globally throughout your project. I "can't imagine what they were smoking" when they made this design decision in Redmond, can you? Anyway, this trick overrides that idiotic behavior, and doesn't bloat your final EXE at all. VBA users may want to remove the superfluous routine if the added bulk hinders their distribution size.

Published

This sample hasn't been published anywhere except here on this website, but first rights to such publication are jealously guarded - you have been warned. <g>

APIs Usage

This sample uses the following API calls:

Module Library Function
CLocaleInfo.cls kernel32




GetDateFormat
GetLocaleInfo
GetSystemDefaultLangID
GetTimeFormat
GetVersionEx
SetLocaleInfo

Don't see what you're looking for? Here's a complete API cross-reference.

Download

Download Locale.zip   Please, enjoy and learn from this sample. Include its code within your own projects, if you wish. But, in order to insure only the most recent code is available to all, I ask that you don't share the sample by any form of mass distribution.

Download Locale.zip, 8Kb, Last Updated: Thursday, March 22, 2007