Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

Introduction to C++ Standard Library localization support

Getting familiar with standard C++ Locales

The C++ standard library offers a simple and powerful way to provide locale-specific information. It is done via the std::locale class, the container that holds all the required information about a specific culture, such as number formatting patterns, date and time formatting, currency, case conversion etc.

All this information is provided by facets, special classes derived from the std::locale::facet base class. Such facets are packed into the std::locale class and allow you to provide arbitrary information about the locale. The std::locale class keeps reference counters on installed facets and can be efficiently copied.

Each facet that was installed into the std::locale object can be fetched using the std::use_facet function. For example, the std::ctype<Char> facet provides rules for case conversion, so you can convert a character to upper-case like this:

std::ctype<char> const &ctype_facet = std::use_facet<std::ctype<char> >(some_locale);
char upper_a = ctype_facet.toupper('a');

A locale object can be imbued into an iostream so it would format information according to the locale:

cout.imbue(std::locale("en_US.UTF-8"));
cout << 1345.45 << endl;
cout.imbue(std::locale("ru_RU.UTF-8"));
cout << 1345.45 << endl;

Would display:

    1,345.45 1.345,45

You can also create your own facets and install them into existing locale objects. For example:

    class measure : public std::locale::facet {
    public:
        typedef enum { inches, ... } measure_type;
        measure(measure_type m,size_t refs=0) 
        double from_metric(double value) const;
        std::string name() const;
        ...
    };

And now you can simply provide this information to a locale:

    std::locale::global(std::locale(std::locale("en_US.UTF-8"),new measure(measure::inches)));
    /// Create default locale built from en_US locale and add paper size facet.

Now you can print a distance according to the correct locale:

    void print_distance(std::ostream &out,double value)
    {
        measure const &m = std::use_facet<measure>(out.getloc());
        // Fetch locale information from stream
        out << m.from_metric(value) << " " << m.name();
    }

This technique was adopted by the Boost.Locale library in order to provide powerful and correct localization. Instead of using the very limited C++ standard library facets, it uses ICU under the hood to create its own much more powerful ones.

Common Critical Problems with the Standard Library

There are numerous issues in the standard library that prevent the use of its full power, and there are several additional issues: