25 Localization library [localization]

25.4 Standard locale categories [locale.categories]

25.4.8 Program-defined facets [facets.examples]

A C++ program may define facets to be added to a locale and used identically as the built-in facets.
To create a new facet interface, C++ programs simply derive from locale​::​facet a class containing a static member: static locale​::​id id.
[Note
:
The locale member function templates verify its type and storage class.
end note
]
[Example
:
Traditional global localization is still easy:
#include <iostream>
#include <locale>
int main(int argc, char** argv) {
  using namespace std;
  locale::global(locale(""));           // set the global locale
                                        // imbue it on all the std streams
  cin.imbue(locale());
  cout.imbue(locale());
  cerr.imbue(locale());
  wcin.imbue(locale());
  wcout.imbue(locale());
  wcerr.imbue(locale());

  return MyObject(argc, argv).doit();
}
end example
]
[Example
:
Greater flexibility is possible:
#include <iostream>
#include <locale>
int main() {
  using namespace std;
  cin.imbue(locale(""));        // the user's preferred locale
  cout.imbue(locale::classic());
  double f;
  while (cin >> f) cout << f << endl;
  return (cin.fail() != 0);
}
In a European locale, with input 3.456,78, output is 3456.78.
end example
]
This can be important even for simple programs, which may need to write a data file in a fixed format, regardless of a user's preference.
[Example
:
Here is an example of the use of locales in a library interface.
// file: Date.h
#include <iosfwd>
#include <string>
#include <locale>

class Date {
public:
  Date(unsigned day, unsigned month, unsigned year);
  std::string asString(const std::locale& = std::locale());
};

std::istream& operator>>(std::istream& s, Date& d);
std::ostream& operator<<(std::ostream& s, Date d);
locales.tex5146This example illustrates two architectural uses of class locale.
locales.tex5150The first is as a default argument in Date​::​asString(), where the default is the global (presumably user-preferred) locale.
locales.tex5156The second is in the operators << and >>, where a locale “hitchhikes” on another object, in this case a stream, to the point where it is needed.
// file: Date.C
#include "Date"                 // includes <ctime>
#include <sstream>
std::string Date::asString(const std::locale& l) {
  using namespace std;
  ostringstream s; s.imbue(l);
  s << *this; return s.str();
}

std::istream& operator>>(std::istream& s, Date& d) {
  using namespace std;
  istream::sentry cerberos(s);
  if (cerberos) {
    ios_base::iostate err = goodbit;
    struct tm t;
    use_facet<time_get<char>>(s.getloc()).get_date(s, 0, s, err, &t);
    if (!err) d = Date(t.tm_day, t.tm_mon + 1, t.tm_year + 1900);
    s.setstate(err);
  }
  return s;
}
end example
]
A locale object may be extended with a new facet simply by constructing it with an instance of a class derived from locale​::​facet.
The only member a C++ program must define is the static member id, which identifies your class interface as a new facet.
[Example
:
Classifying Japanese characters:
// file: <jctype>
#include <locale>
namespace My {
  using namespace std;
  class JCtype : public locale::facet {
  public:
    static locale::id id;       // required for use as a new locale facet
    bool is_kanji (wchar_t c) const;
    JCtype() { }
  protected:
    ~JCtype() { }
  };
}

// file: filt.C
#include <iostream>
#include <locale>
#include "jctype"               // above
std::locale::id My::JCtype::id; // the static JCtype member declared above.

int main() {
  using namespace std;
  using wctype = ctype<wchar_t>;
  locale loc(locale(""),        // the user's preferred locale ...
         new My::JCtype);       // and a new feature ...
  wchar_t c = use_facet<wctype>(loc).widen('!');
  if (!use_facet<My::JCtype>(loc).is_kanji(c))
    cout << "no it isn't!" << endl;
}
locales.tex5232The new facet is used exactly like the built-in facets.
end example
]
[Example
:
Replacing an existing facet is even easier.
The code does not define a member id because it is reusing the numpunct<charT> facet interface:
// file: my_­bool.C
#include <iostream>
#include <locale>
#include <string>
namespace My {
  using namespace std;
  using cnumpunct = numpunct_byname<char>;
  class BoolNames : public cnumpunct {
  protected:
    string do_truename()  const { return "Oui Oui!"; }
    string do_falsename() const { return "Mais Non!"; }
    ~BoolNames() { }
  public:
    BoolNames(const char* name) : cnumpunct(name) { }
  };
}

int main(int argc, char** argv) {
  using namespace std;
  // make the user's preferred locale, except for...
  locale loc(locale(""), new My::BoolNames(""));
  cout.imbue(loc);
  cout << boolalpha << "Any arguments today? " << (argc > 1) << endl;
}
end example
]