C++ Three letter language name to LCID

Viewed 408

How can I convert ISO639-3 three-letter language names (e.g. "PLK", "DEU", "ENU") to language codes (ie. 0x0415 for PLK, 0x0407 for DEU, 0x0409 for ENU) or to culture name (ie. "pl-PL" for PLK, "de" for DEU, "en-US" for ENU)?

I need to make the reverse conversion from the one in the following line of code:

GetLocaleInfoA(0x0415, LOCALE_SABBREVLANGNAME, buffer.data(), buffer.size());
    // now buffer will have "PLK"

I would like to be able to write something like:

LCID langCode = SomeMagicalFunctionThatISearchFor("PLK");
//and landCode should be now 0x0415 (1045 in decimal)

My code targets Microsoft Windows, so use of WinAPI is possible.

2 Answers
static LCID lcid = -1;
::EnumSystemLocalesEx([](LPWSTR a1, DWORD a2, LPARAM a3) -> BOOL {
        const int cch = 512;
        wchar_t wcBuffer[cch] = { 0 };
        int iResult = ::GetLocaleInfoEx(a1, LOCALE_SABBREVLANGNAME, wcBuffer, cch);
        if(iResult > 0 && 0 == ::_wcsicmp(L"PLK", wcBuffer))
        {
            lcid = ::LocaleNameToLCID(a1, 0);
            return FALSE;
        }
        return TRUE;
}, LOCALE_ALL, NULL, nullptr);

You could build your own since it doesn't seem to exist. If you need to make many lookups, an unordered_map should do the trick to keep the information stored for quick access.

#include <iostream>
#include <unordered_map>
#include <string_view>
#include <Windows.h>

class LocaleAbbr {
public:
    LocaleAbbr() {
        // enumerate all locales and call "proxy" for each one      
        ::EnumSystemLocalesEx(proxy, LOCALE_ALL, reinterpret_cast<LPARAM>(this), nullptr);
    }
    LCID operator[](std::wstring_view abbr) const {
        // operator to query for LCID from abbreviation
        return name_lcid_map.at(abbr.data());
    }
private:
    BOOL callback(LPWSTR Arg1, DWORD Arg2) {
        // extract abbreviation and LCID
        wchar_t Buffer[512];
        int rv = ::GetLocaleInfoEx(Arg1, LOCALE_SABBREVLANGNAME, Buffer, 512);
        if (rv > 0) // put result in a name->LCID map:
            name_lcid_map.emplace(Buffer, ::LocaleNameToLCID(Arg1, 0));
        return TRUE;
    }
    static BOOL proxy(LPWSTR Arg1, DWORD Arg2, LPARAM Arg3) {
        // cast Arg3 to "this" (set in the constructor) and call "callback"
        return reinterpret_cast<LocaleAbbr*>(Arg3)->callback(Arg1, Arg2);
    }

    std::unordered_map<std::wstring, LCID> name_lcid_map;
};

int main() {
    LocaleAbbr abbr;

    std::wcout << abbr[L"PLK"];
}
Related