Code Samples for Businesses, Schools & Developers

First Published 22 Sept 2026



My previous article Get Office/Windows Language Info Using Code provided all the VBA code needed to get the language information for the current user in conjunction with data stored in a reference table.

This article shows how the same results can be obtained using an API based approach, with no need for a reference table. In addition, unlike the table-based approach, this method will remain up-to-date even if Microsoft make additional Office languages available in the future.

All the code provided below is available in module modLocaleEx in the attached example database



Locale Info Using APIs

The locale identifier (LCID) consists of both the language and the country/region. In older Windows versions, the LCID was a long integer value e.g. 1033 for English (United States), 2057 for English (United Kingdom), 1036 for French (France).

In modern Windows versions, locale names are preferred e.g. en-US, en-GB, fr-FR with the language in lower case and the country/region in upper case.

The APIs designed to be used with locales have been updated accordingly for use with Windows 7 or later:

' Memory & Module APIs
' https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandlea
' Retrieves a module handle for the specified module.
Private Declare PtrSafe Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" _
(ByVal lpModuleName As String) As LongPtr

' https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulefilenamea
' Retrieves the fully qualified path for the file that contains the specified module.
Private Declare PtrSafe Function GetModuleFileName Lib "kernel32" Alias "GetModuleFileNameA" _
(ByVal hModule As LongPtr, ByVal lpFilename As String, ByVal nSize As Long) As Long

' Windows Locale APIs (Windows Vista/7 and later)
' https://learn.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getlocaleinfoex
' Retrieves information about a locale specified by name
Private Declare PtrSafe Function GetLocaleInfoEx Lib "kernel32" ( _
ByVal lpLocaleName As LongPtr, _
ByVal lcType As Long, _
ByVal lpLCData As LongPtr, _
ByVal cchData As Long) As Long

' https://learn.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-lcidtolocalename
' Converts a locale identifier to a locale name.
Private Declare PtrSafe Function LCIDToLocaleName Lib "kernel32" ( _
ByVal Locale As Long, _
ByVal lpName As LongPtr, _
ByVal cchName As Long, _
ByVal dwFlags As Long) As Long

' Windows Locale Constants
' https://learn.microsoft.com/en-us/windows/win32/intl/locale-slocalized-constants
Private Const LOCALE_SLOCALIZEDCOUNTRYNAME As Long = &H6 'e.g. España
Private Const LOCALE_SLOCALIZEDLANGUAGENAME As Long = &H6F 'e.g. Español
Private Const LOCALE_SLOCALIZEDDISPLAYNAME As Long = &H72 'e.g. Español (España)
Private Const LOCALE_NAME_MAX_LENGTH As Long = 85


Two helper functions are used: first to convert the numerical LCID value to a locale name string, then to use that value with locale constants to obtain specific information.

' Helper: Converts a numeric LCID to a Locale Name String (e.g. 3082 -> "es-ES")
Public Function ConvertLCIDToLocaleName(ByVal lcid As Long) As String
Dim buffer As String
Dim ret As Long

buffer = String$(LOCALE_NAME_MAX_LENGTH, vbNullChar)
ret = LCIDToLocaleName(lcid, StrPtr(buffer), LOCALE_NAME_MAX_LENGTH, 0)

If ret > 0 Then
ConvertLCIDToLocaleName = Left$(buffer, ret - 1)
Else
ConvertLCIDToLocaleName = vbNullString
End If
End Function

' Core helper using GetLocaleInfoEx
Private Function GetLocaleStringEx(ByVal localeName As String, ByVal lcType As Long) As String
Dim n As Long
Dim s As String

If LenB(localeName) = 0 Then Exit Function

' Pass StrPtr(localeName) directly to GetLocaleInfoEx
n = GetLocaleInfoEx(StrPtr(localeName), lcType, 0, 0)

If n > 0 Then
s = String$(n, vbNullChar)
GetLocaleInfoEx StrPtr(localeName), lcType, StrPtr(s), n
GetLocaleStringEx = Left$(s, n - 1)
End If
End Function


The next three functions use the locale constants to return the country, language, and display names.

' Returns the localized country/region name (e.g. España)
Public Function GetCountryNameEx(ByVal lcid As Long) As String
Dim localeName As String
localeName = ConvertLCIDToLocaleName(lcid)
GetCountryNameEx = GetLocaleStringEx(localeName, LOCALE_SLOCALIZEDCOUNTRYNAME)
End Function

' Returns the localized language name capitalized (e.g., "Español")
Public Function GetLanguageNameEx(ByVal lcid As Long) As String
Dim localeName As String

localeName = ConvertLCIDToLocaleName(lcid)
GetLanguageNameEx = GetLocaleStringEx(localeName, LOCALE_SLOCALIZEDLANGUAGENAME)

End Function

' Returns the localized language & locale names e.g. Español (España, International Sort), English (United Kingdom)
Public Function GetDisplayNameEx(ByVal lcid As Long) As String
Dim localeName As String

localeName = ConvertLCIDToLocaleName(lcid)
GetDisplayNameEx = GetLocaleStringEx(localeName, LOCALE_SLOCALIZEDDISPLAYNAME)

End Function




Office Locale Code

The above functions are used together with the Office locale enum value to obtain all locale info for Office apps (locale name/language name/country name/display name).

Using the language settings code requires the reference library Microsoft Office 16.0 Object Library to be added to your VBA project.

'######### Office Language functions #########

' Current Office locale
Public Function GetCurrentOfficeLocaleEnum()
'get current Office locale enum e.g. 2057 (for English UK)
GetCurrentOfficeLocaleEnum = Application.LanguageSettings.LanguageID(msoLanguageIDUI)
End Function

Public Function GetCurrentOfficeLocaleName()
'get current Office locale name e.g. en-GB (for English UK)
GetCurrentOfficeLocaleName = ConvertLCIDToLocaleName(GetCurrentOfficeLocaleEnum())
End Function

Public Function GetCurrentOfficeLanguage()
'get current Office language name e.g. English (for en-GB)
GetCurrentOfficeLanguage = GetLanguageNameEx(GetCurrentOfficeLocaleEnum())
End Function

Public Function GetCurrentOfficeCountry()
'get current Office country name e.g. United Kingdom (for en-GB)
GetCurrentOfficeCountry = GetCountryNameEx(GetCurrentOfficeLocaleEnum())
End Function

Public Function GetCurrentOfficeDisplayName()
'get current Office display name e.g. English (United Kingdom) (for en-GB)
GetCurrentOfficeDisplayName = GetDisplayNameEx(GetCurrentOfficeLocaleEnum())
End Function

' Office Install locale
Public Function GetOfficeInstallLocaleEnum()
'get Office install locale enum e.g. 1033 (for English US)
GetOfficeInstallLocaleEnum = Application.LanguageSettings.LanguageID(msoLanguageIDInstall)
End Function

Public Function GetOfficeInstallLocaleName()
'get Office install locale name e.g. en-US (for English US)
GetOfficeInstallLocaleName = ConvertLCIDToLocaleName(GetOfficeInstallLocaleEnum())
End Function

Public Function GetOfficeInstallLanguage()
'get Office install language name e.g. English (for en-US)
GetOfficeInstallLanguage = GetLanguageNameEx(GetOfficeInstallLocaleEnum())
End Function

Public Function GetOfficeInstallCountry()
'get Office install country name e.g. United States(for en-US)
GetOfficeInstallCountry = GetCountryNameEx(GetOfficeInstallLocaleEnum())
End Function

Public Function GetOfficeInstallDisplayName()
'get Office install display name e.g. English (United States) (for en-US)
GetOfficeInstallDisplayName = GetDisplayNameEx(GetOfficeInstallLocaleEnum())
End Function

'Previous Office locale
Public Function GetPreviousOfficeLocaleEnum()
'get previous Office locale enum e.g. 1031 (for German)
GetPreviousOfficeLocaleEnum = Application.LanguageSettings.LanguageID(msoLanguageIDUIPrevious)
End Function

Public Function GetPreviousOfficeLocaleName()
'get previous Office locale name e.g. de-DE (for German)
GetPreviousOfficeLocaleName = ConvertLCIDToLocaleName(GetPreviousOfficeLocaleEnum())
End Function

Public Function GetPreviousOfficeLanguage()
'get Office install language name e.g. German (for de-DE)
GetPreviousOfficeLanguage = GetLanguageNameEx(GetPreviousOfficeLocaleEnum())
End Function

Public Function GetPreviousOfficeCountry()
'get Office install country name e.g. Germany (for de-DE)
GetPreviousOfficeCountry = GetCountryNameEx(GetPreviousOfficeLocaleEnum())
End Function

Public Function GetPreviousOfficeDisplayName()
'get Office install display name e.g. German (Germany) (for de-DE)
GetPreviousOfficeDisplayName = GetDisplayNameEx(GetPreviousOfficeLocaleEnum())
End Function


Example output where the Office locale is currently English (United Kingdom) but was previously Spanish (Spain).

Example Output - Office


VBE Language/Locale Code

The language/locale used in the Visual Basic Editor (VBE) is often identical to the current Office language. However, the list of languages available is more limited.
For example, where the Office language is English (United Kingdom), the VBE Language is English (United States).

In addition, differences can occur after swapping Office languages and then reverting to the default language.
For more details, see my article: BUG: Office & VBE Menu Languages Different

Example output:

Example Output - VBE

' VBE Language Functions
' Returns the VBE Locale Enum (LCID as string) e.g. 1032 for Spanish (Spain, International Sort)
Public Function GetVBELocaleEnum() As String
Dim hModule As LongPtr
Dim buffer As String * 260
Dim length As Long
Dim dllPath As String
Dim parts() As String

hModule = GetModuleHandle("VBE7INTL.DLL")

If hModule <> 0 Then
length = GetModuleFileName(hModule, buffer, 260)
dllPath = Left(buffer, length)
parts = Split(dllPath, "\")

If UBound(parts) >= 1 Then
GetVBELocaleEnum = parts(UBound(parts) - 1)
Exit Function
End If
Else
GetVBELocaleEnum = "Unknown"
End If

End Function

Public Function GetVBELocaleName()
'get VBE locale name e.g. es-ES (for 1032)
GetVBELocaleName = ConvertLCIDToLocaleName(GetVBELocaleEnum())
End Function

Public Function GetVBELocaleDisplayName()
'get VBE locale display name e.g. Spanish (Spain) (for 1032)
GetVBELocaleDisplayName = GetDisplayNameEx(GetVBELocaleEnum())
End Function




Windows Language/Locale Code

Code similar to that used for the Office language is used with the GetUserDefaultUILanguage API to obtain the Windows language for the current user.

'###### Windows Language functions ###########

Public Function GetWinUserDefaultUILocaleEnum()
'This gives the Windows user locale enum from the API e.g. 2057
GetWinUserDefaultUILocaleEnum = GetUserDefaultUILanguage()
End Function

Public Function GetWinUserDefaultUILocaleName()
'get Windows user locale name e.g. en-GB (for 2057)
GetWinUserDefaultUILocaleName = ConvertLCIDToLocaleName(GetUserDefaultUILanguage())
End Function

Public Function GetWinUserDefaultUILanguage()
'get Windows user language name e.g. English (for en-GB)
GetWinUserDefaultUILanguage = GetLanguageNameEx(GetUserDefaultUILanguage())
End Function

Public Function GetWinUserDefaultUICountry()
'get Windows user country name e.g. United Kingdom (for en-GB)
GetWinUserDefaultUICountry = GetCountryNameEx(GetUserDefaultUILanguage())
End Function

Public Function GetWinUserDefaultUIDisplayName()
'get Windows user display name e.g. English (United Kingdom) (for en-GB)
GetWinUserDefaultUIDisplayName = GetDisplayNameEx(GetUserDefaultUILanguage())
End Function


Example output:

Example Output - Windows
The attached app also includes an example form that uses many of the functions shown above.

Language Code Form
The form buttons are used to display the information as new-style FluentUI messages. For example, the Get Full Access/Windows Info button returns a message such as:

Access/Windows Info Message


Acknowledgements

Many thanks to Xevi Batlle who used Google Gemini AI to obtain a significant part of this code. I have slightly modified the code for the purpose of this article.



Download

Click to download:     OfficeWindowsLangAPICode_v1.2    Approx 0.6 MB   (ACCDB - zipped)

As is the case for all files downloaded from the internet, first unblock the downloaded file, unzip it, then save to a trusted location.
For more details, see my article: Unblock downloaded files by removing the Mark of the Web



Feedback

Please use the Email button in the contact form below to let me know whether you found this article useful, or if you have any questions.

Please also consider making a donation towards the costs of maintaining this website. Thank you


Colin Riddington Mendip Data Systems Last Updated 22 Sept 2026




Return to Code Samples Page




Return to Top