36

Had tried following code in Linux, but always return 'C' under different LANG settings.

#include <iostream>
#include <locale.h>
#include <locale>
using namespace std;

int main()
{
    cout<<"locale 1: "<<setlocale(LC_ALL, NULL)<<endl;
    cout<<"locale 2: "<<setlocale(LC_CTYPE, NULL)<<endl;

    locale l;
    cout<<"locale 3: "<<l.name()<<endl;
}

$ ./a.out
locale 1: C
locale 2: C
locale 3: C
$
$ export LANG=zh_CN.UTF-8
$ ./a.out
locale 1: C
locale 2: C
locale 3: C

What should I do to get current locale setting in Linux(like Ubuntu)?

Another question is, is it the same way to get locale in Windows?

Deqing
  • 14,098
  • 15
  • 84
  • 131
  • 6
    In C and C++ the locale always starts out as the "C" locale. You have to specifically ask for the program's locale to be changed to the environment's locale. – bames53 Aug 29 '12 at 23:01

5 Answers5

35

From man 3 setlocale (New maxim: "When in doubt, read the entire manpage."):

If locale is "", each part of the locale that should be modified is set according to the environment variables.

So, we can read the environment variables by calling setlocale at the beginning of the program, as follows:

#include <iostream>
#include <locale.h>
using namespace std;

int main()
{
    setlocale(LC_ALL, "");
    cout << "LC_ALL: " << setlocale(LC_ALL, NULL) << endl;
    cout << "LC_CTYPE: " << setlocale(LC_CTYPE, NULL) << endl;
    return 0;
}

My system does not support the zh_CN locale, as the following output reveals:

$ ./a.out 
LC_ALL: en_US.utf8
LC_CTYPE: en_US.utf8
$ export LANG=zh_CN.UTF-8
$ ./a.out 
LC_ALL: C
LC_CTYPE: C

Windows: I have no idea about Windows locales. I suggest starting with an MSDN search, and then opening a separate Stack Overflow question if you still have questions.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • 1
    Thanks. Is there a C++ version of getting current locale? I assume it should be in `` but have no idea how to use it. – Deqing Aug 29 '12 at 04:57
  • 1
    @Deqing: I have no idea. Search for documentation. https://www.google.com/search?q=c%2B%2B+locale – Dietrich Epp Aug 29 '12 at 05:26
  • Note that Windows systems will often return `English_United States` instead of `en-US` and possibly with the code page appended, usually `English_United States.1252`. – Jesse Chisholm Jun 15 '18 at 01:04
  • For windows there is also a function strftime_l which takes a private local object without changing the global locale: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/strftime-wcsftime-strftime-l-wcsftime-l?view=vs-2019 – RED SOFT ADAIR Jul 17 '19 at 11:38
26

Just figured out how to get locale by C++, simply use an empty string "" to construct std::locale, which does the same thing as setlocale(LC_ALL, "").

locale l("");
cout<<"Locale by C++: "<<l.name()<<endl;

This link described differences in details between C locale and C++ locale.

Deqing
  • 14,098
  • 15
  • 84
  • 131
4

For Windows use the following code:

LCID lcid = GetThreadLocale();
wchar_t name[LOCALE_NAME_MAX_LENGTH];
if (LCIDToLocaleName(lcid, name, LOCALE_NAME_MAX_LENGTH, 0) == 0)
    error(GetLastError());
std::wcout << L"Locale name = " << name << std::endl;

This is going to print something like "en-US".

To purge sublanguage information use the following:

wchar_t parentLocateName[LOCALE_NAME_MAX_LENGTH];
if (GetLocaleInfoEx(name, LOCALE_SPARENT, parentLocateName, LOCALE_NAME_MAX_LENGTH) == 0)
    error(GetLastError());
std::wcout << L"parentLocateName = " << parentLocateName << std::endl;

This will give you just "en".

zzz
  • 41
  • 4
3

A good alternative to consider instead of std::locale is boost::locale which is capable of returning more reliable information - see http://www.boost.org/doc/libs/1_52_0/libs/locale/doc/html/locale_information.html

boost::locale::info has the following member functions:

std::string name() -- the full name of the locale, for example en_US.UTF-8
std::string language() -- the ISO-639 language code of the current locale, for example "en".
std::string country() -- the ISO-3199 country code of the current locale, for example "US".
std::string variant() -- the variant of current locale, for example "euro".
std::string encoding() -- the encoding used for char based strings, for example "UTF-8"
bool utf8() -- a fast way to check whether the encoding is UTF-8.
Riot
  • 15,723
  • 4
  • 60
  • 67
  • is boost cross platform? – kittu May 05 '20 at 14:12
  • My use case is just to provide correctly encoded strings (and boost is already part of the project), so this is a neat way to figure out the required target encoding. – resi Nov 30 '20 at 14:46
2

The default constructor of std::locale creates a copy of the global C++ locale.

So to get the name of the current locale:

std::cout << std::locale().name() << '\n';
Synck
  • 2,727
  • 22
  • 20
  • That returns the global locale whose name is usually "C" and hence not very useful. As others have said, you want `locale("")` not `locale()` See https://www.cplusplus.com/reference/locale/locale/name/ and https://en.cppreference.com/w/cpp/locale/locale/name – InsanityPants Sep 23 '21 at 16:43