---------------
void print_date(const Date& d) // drukuje w odpowiednim formacie
{
    switch(where_am_I) { // zdefiniowany przez uytkownika wskanik stylu
    case PL:  // np. 7 marca 1999
        cout << d.day() << " " << dk_month[d.month()] << " " << d.year();
        break;
    case ISO: // np. 1999-3-7
        cout << d.year() << " - " << d.month() << " - " << d.day();
        break;
    case US:  // np. 3/7/1999
        cout << d.month() << "/" << d.day() << "/" << d.year();
        break;
    //...
    }
}
---------------
void cpy(istream& is, ostream& os) // kopiuje strumie (Date,double)
{
    Date d;
    double volume;

    while (is >> d >> volume)
        os << d << ' '<< volume << '\n';
}
---------------
void f(istream& fin, ostream& fout, istream& fin2, ostream& fout2)
{
    fin.imbue(locale{"en_US.UTF-8"});  // amerykaski angielski
    fout.imbue(locale{"pl_PL.UTF-8"}); // polski
    cpy(fin,fout);                     // wczytuje amerykaski angielski, zapisuje polski
    //...

    fin2.imbue(locale{"pl_PL.UTF-8"});  // polski
    fout2.imbue(locale{"en_US.UTF-8"}); // amerykaski angielski
    cpy(fin2,fout2);                    // wczytuje polski, zapisuje amerykaski angielski
    //...
}
---------------
Apr 12, 1999 1000.3
Apr 13, 1999 345.45
Apr 14, 1999 9688.321
...
3 lipca 1950 10,3
3 lipca 1951 134,45
3 lipca 1952 67,9
...
---------------
12 kwietnia 1999 1000,3
13 kwietnia 1999 345,45
14 kwietnia 1999 9688,321
...
July 3, 1950 10.3
July 3, 1951 134.45
July 3, 1952 67.9
...

---------------
locale loc1;                         // kopia biecej lokalizacji globalnej
locale loc2 {""};                    // kopia lokalizacji preferowanej przez uytkownika

locale loc3 {"C"};                   // kopia lokalizacji C
locale loc4 {locale::classic()};     // kopia lokalizacji C

locale loc5 {"POSIX"};               // kopia lokalizacji o nazwie "POSIX"
locale loc6 {"Danish_Denmark.1252"}; // kopia lokalizacji o nazwie "Danish_Denmark.1252"
locale loc7 {"en_US.UTF-8"};         // kopia lokalizacji o nazwie "en_US.UTF-8"
---------------
locale loc("");
cout << loc.name() << '\n';
---------------
English_United States.1252
---------------
en_US.UTF-8
---------------
void user_set_locale(const string& question)
{
    cout << question; // np. "Jeli chcesz uy innej lokalizacji, wpisz jej nazw"
    string s;
    cin >> s;
    locale::global(locale{s}); // ustawia globaln lokalizacj na podan przez uytkownika
}
---------------
void set_loc(locale& loc, const char* name)
try
{
    loc = locale{name};
}
catch (runtime_error&) {
    cerr << "locale
    //...
}
---------------
void print_locale_names(const locale& my_loc)
{
    cout << "nazwa biecej globalnej lokalizacji: " << locale().name() << "\n";
    cout << "nazwa klasycznej lokalizacji C: " << locale::classic().name() << "\n";
    cout << "nazwa lokalizacji preferowanej przez uytkownika: " << locale("").name() << "\n";
    cout << "nazwa mojej lokalizacji: " << my_loc.name() << "\n";
}
---------------
void f(const locale& loc, const My_money_io* mio) // My_money_io zdefiniowana w 39.4.3.1
{
    locale loc1(locale{"POSIX"},loc,locale::monetary); // uywa faset walutowych z loc
    locale loc2 = locale(locale::classic(), mio);      // klasyczna plus mio
    //...
}
---------------
void g(const locale::facet *mio1, const money_put<char>* mio2)
{
    locale loc3 = locale(locale::classic(), mio1); // bd: nieznany typ fasety
    locale loc4 = locale(locale::classic(), mio2); // OK: typ fasety jest znany (moneyput<char>)
    //...
}
---------------
template<typename Facet> locale(const locale& x, Facet* f);
---------------
void user(const string s1, const string s2, const locale& my_locale)
{
    if (my_locale(s,s2)) { // czy s<s2 zgodnie z lokalizacj my_locale?
        //...
    }
}
---------------
void f(vector<string>& v, const locale& my_locale)
{
    sort(v.begin(),v.end());           // sortuje przy uyciu operatora < do porwnywania elementw
    //...
    sort(v.begin(),v.end(),my_locale); // sortuje zgodnie z zasadami lokalizacji my_locale
    //...
}
---------------
class locale::facet {
protected:
    explicit facet(size_t refs = 0);
    virtual ~facet();
    facet(const facet&) = delete;
    void operator=(const facet&) = delete;
};
---------------
class locale::id {
public:
    id();
    void operator=(const id&) = delete;
    id(const id&) = delete;
};
---------------
void f(const locale& my_locale)
{
    char c = use_facet<numpunct<char>>(my_locale).decimal_point(); // uycie standardowej fasety
    //...

    if (has_facet<Encrypt>(my_locale)) { // czy my_locale zawiera faset Encrypt?
        const Encrypt& f = use_facet<Encrypt>(my_locale);  // pobiera faset Encrypt
        const Crypto c = f.get_crypto();                   // uywa fasety Encrypt
        //...
    }
    //...
}
---------------
enum Season { spring, summer, fall, winter }; // bardzo prosty typ zdefiniowany przez uytkownika
---------------
class Season_io : public locale::facet {
public:
    Season_io(int i = 0) : locale::facet{i} { }
    ~Season_io() { } // umoliwia usuwanie obiektw Season_io (39.3)

    virtual const string& to_str(Season x) const = 0;            // acuchowa reprezentacja x
    virtual bool from_str(const string& s, Season& x) const = 0; // wstawia Season dla s do x

    static locale::id id; // obiekt identyfikujcy faset (39.2, 39.3, 39.3.1)
};

locale::id Season_io::id; // definicja obiektu identyfikujcego
---------------
ostream& operator<<(ostream& os, Season x)
{
    locale loc {os.getloc()};  // pobiera lokalizacj strumienia (38.4.4)

    if (has_facet<Season_io>(loc))
        return os << use_facet<Season_io>(loc).to_str(x); // reprezentacja acuchowa
    return os << static_cast<int>(x);                     // reprezentacja cakowitoliczbowa
}
---------------
istream& operator>>(istream& is, Season& x)
{
    const locale& loc {is.getloc()};                    // pobiera lokalizacj strumienia (38.4.4)

    if (has_facet<Season_io>(loc)) {
        const Season_io& f {use_facet<Season_io>(loc)}; // poinformowanie o fasecie Season_io lokalizacji

        string buf;
        if (!(is>>buf && f.from_str(buf,x)))            // wczytuje reprezentacj alfabetyczn
            is.setstate(ios_base::failbit);
        return is;
    }

    int i;
    is >> i;                                            // wczytanie reprezentacji liczbowej
    x = static_cast<Season>(i);
    return is;
}
---------------
int main()
    // prosty test
{
    Season x;
    // uywa domylnej lokalizacji (bez fasety Season_io) - wejcie i wyjcie s cakowitoliczbowe:
    cin >> x;
    cout << x << endl;

    locale loc(locale(),new US_season_io{});
    cout.imbue(loc); // uywa lokalizacji z faset Season_io
    cin.imbue(loc);  // uywa lokalizacji z faset Season_io

    cin >> x;
    cout << x << endl;
}
---------------
2
summer
---------------
2
summer
---------------
class US_season_io : public Season_io {
    static const string seasons[];
public:
    const string& to_str(Season) const;
    bool from_str(const string&, Season&) const;

    // uwaga: brak US_season_io::id
};

const string US_season_io::seasons[] = {
    "spring",
    "summer",
    "fall",
    "winter"
};
---------------
const string& US_season_io::to_str(Season x) const
{
    if (x<spring || winter<x) {
        static const string ss = "nie-ma-takiej-pory";
        return ss;
    }
    return seasons[x];
}

bool US_season_io::from_str(const string& s, Season& x) const
{
    const string* p = find(begin(seasons),end(seasons),s);
    if (p==end)
        return false;

    x = Season(p-begin(seasons));
    return true;
}

---------------
locale dk {"da_DK"}; // wczytuje jeden raz dusk lokalizacj (z wszystkimi fasetami),
                     // a potem uywa lokalizacji dk

void f(vector<string>& v, const locale& loc)
{
    const collate<char>& col {use_facet<collate<char>>(dk)};
    const ctype<char>& ctyp {use_facet<ctype<char>>(dk)};

    locale dk1 {loc,&col};  // stosuje duskie porwnywanie znakw
    locale dk2 {dk1,&ctyp}; // stosuje dusk klasyfikacj znakw i zasady porwnywania acuchw

    sort(v.begin(),v.end(),dk2);
    //...
}
---------------
locale dk_us(locale::classic(),dk,collate|ctype);  // duskie litery, amerykaskie liczby
---------------
template<typename C>
class collate : public locale::facet {
public:
    using char_type = C;
    using string_type = basic_string<C>;

    explicit collate(size_t = 0);

    int compare(const C* b, const C* e, const C* b2, const C* e2) const
        { return do_compare(b,e,b2,e2); }

    long hash(const C* b, const C* e) const
        { return do_hash(b,e); }
    string_type transform(const C* b, const C* e) const
        { return do_transform(b,e); }

    static locale::id id; // obiekt identyfikujcy fasety (39.2, 39.3, 39.3.1)

protected:
    ~collate(); // uwaga: destruktor chroniony

    virtual int do_compare(const C* b, const C* e, const C* b2, const C* e2) const;
    virtual string_type do_transform(const C* b, const C* e) const;
    virtual long do_hash(const C* b, const C* e) const;
};

---------------
cf.compare(cf.transform(s),cf.transform(s2)) == cf.compare(s,s2)
---------------
void f(const string& s1, const string& s2, const collate<char>& cmp)
{
    const char* cs1 {s1.data()}; // bo compare() dziaa na char[]
    const char* cs2 {s2.data()};

    switch (cmp.compare(cs1,cs1+s1.size(),cs2,cs2+s2.size()) {
    case 0:  // acuchy identyczne wg cmp
        //...
        break;
    case -1: // s1 < s2
        //...
        break;
    case 1:  // s1 > s2
        //...
        break;
    }
}
---------------
void f(const string& s1, const string& s2, const string& name)
{
    bool b {s1==s2}; // porwnywanie wartoci z zestawu znakw implementacji

    const char* s1b {s1.data()};            // pobranie pocztku danych
    const char* s1e {s1.data()+s1.size()};  // pobranie koca danych
    const char* s2b {s2.data()};
    const char* s2e {s2.data()+s2.size()};

    using Col = collate<char>;

    const Col& global {use_facet<Col>(locale{})};     // z biecej globalnej lokalizacji
    int i0 {global.compare(s1b,s1e,s2b,s2e)};

    const Col& my_coll {use_facet<Col>(locale{""})};  // z preferowanej lokalizacji
    int i1 {my_coll.compare(s1b,s1e,s2b,s2e)};

    const Col& n_coll {use_facet<Col>(locale{name})}; // z nazwanej lokalizacji
    int i2 {n_coll.compare(s1b,s1e,s2b,s2e)};
}
---------------
void f(const string& s1, const string& s2, const string& name)
{
    int i0 = locale{}(s1,s2);     // porwnanie przy uyciu biecej globalnej lokalizacji
    int i1 = locale{""}(s1,s2);   // porwnanie przy uyciu preferowanej lokalizacji
    int i2 = locale{name}(s1,s2); // porwnanie przy uyciu nazwanej lokalizacji
    //...
}
---------------
Dialekt, Dit, dich, dichten, Dichtung
---------------
Dialekt, Dit, Dichtung, dich, dichten
---------------
Dialekt, Dichtung, Dit, dich, dichten
---------------
template<typename C>
class collate_byname : public collate<C> { // uwaga: brak id i nowych funkcji
public:
    typedef basic_string<C> string_type;

    explicit collate_byname(const char*, size_t r = 0); // konstrukcja z nazwanej lokalizacji
    explicit collate_byname(const string&, size_t r = 0);
protected:
    ~collate_byname(); // uwaga: destruktor chroniony

    int do_compare(const C* b, const C* e, const C* b2, const C* e2) const override;
    string_type do_transform(const C* b, const C* e) const override;
    long do_hash(const C* b, const C* e) const override;
};

---------------
class My_punct : public numpunct<char> {
public:
    explicit My_punct(size_t r = 0) :numpunct<char>(r) { }
protected:
    char do_decimal_point() const override  { return ','; } // przecinek
    char do_thousands_sep() const override { return '_'; }  // znak podkrelenia
    string do_grouping() const override { return "\003"; }  // trzycyfrowe grupy
};

void f()
{
    cout << "styl A: " << 12345678
        << "***" << 1234567.8
        << "***" << fixed << 1234567.8 << '\n';
    cout << defaultfloat; // reset formatu liczb zmiennoprzecinkowych
    locale loc(locale(),new My_punct);
    cout.imbue(loc);
    cout << "styl B: " << 12345678
        << "***" << 1234567.8
        << "***" << fixed << 1234567.8 << '\n';
}
---------------
styl A: 12345678***1.23457e+06***1234567.800000
styl B: 12_345_678***1_234_567,800000***1_234_567,800000
---------------
template<typename C>
class numpunct_byname : public numpunct<C> {
    //...
};

---------------
template<typename C>
class String_numput : public num_put<C,typename basic_string<C>::iterator> {
public:
    String_numput() :num_put<C,typename basic_string<C>::iterator>{1} { }
};
---------------
void f(int i, string& s, int pos)    // formatuje i do s, zaczynajc od pos
{
    String_numput<char> f;
    f.put(s.begin()+pos,cout,' ',i); // formatuje i do s; stosuje zasady formatowania cout
}
---------------
void test(iostream& io)
{
    locale loc = io.getloc();

    wchar_t wc = use_facet<ctype<char>>(loc).widen(c);              // konwersja char na C
    string s = use_facet<numpunct<char>>(loc).decimal_point();      // domylnie: '.'
    string false_name = use_facet<numpunct<char>>(loc).falsename(); // domylnie: "false"
}
---------------
template<typename C, typename Tr>
basic_ostream<C,Tr>& basic_ostream<C,Tr>::operator<<(double d)
{
    sentry guard(*this); // patrz 38.4.1
    if (!guard) return *this;

    try{
        if (use_facet<num_put<C,Tr>>(getloc()).put(*this,*this,this->fill(),d).failed())
            setstate(badbit);
    }
    catch (...) {
        handle_ioexception(*this);
    }
    return *this;
}
---------------
template<typename C, typename Tr>
void handle_ioexception(basic_ostream<C,Tr>& s) // wywoywana z klauzuli catch
{
    if (s.exceptions()&ios_base::badbit) {
        try{
            s.setstate(ios_base::badbit); // moe zgosi basic_ios::failure
        }
        catch(...) {
            //... nic nie rb...
        }
        throw; // ponowne zgoszenie
    }
    s.setstate(ios_base::badbit);
}

---------------
template<typename C, typename Tr>
basic_istream<C,Tr>& basic_istream<C,Tr>::operator>>(double& d)
{
    sentry guard(*this); // patrz 38.4.1
    if (!guard) return *this;

    iostate state = 0;   // dobry
    istreambuf_iterator<C,Tr> eos;
    try{
        double dd;
        use_facet<num_get<C,Tr>>(getloc()).get(*this,eos,*this,state,dd);
        if (state==0 || state==eofbit) d = dd;  // ustawia warto, tylko jeli uda si get()
        setstate(state);
    }
    catch (...) {
        handle_ioexception(*this);              // zobacz 39.4.2.2
    }
    return *this;
}
---------------
void f()
{
    cout << "styl A: "
    int i1;
    double d1;
    cin >> i1 >> d1; // wczytuje przy uyciu standardowego formatu 12345678

    locale loc(locale::classic(),new My_punct);
    cin.imbue(loc);
    cout << "styl B: "
    int i2;
    double d2;
    cin >> i1 >> d2; // wczytuje przy uyciu formatu 12_345_678
}
---------------
struct Money {               // prosty typ do przechowywania kwot pieninych
    using Value = long long; // dla walut, ktre ucierpiay z powodu inflacji
    Value amount;
};

//...

void f(long int i)
{
    cout << "warto= " << i << " kwota= " << Money{i} << '\n';
}
---------------
warto= 1234567 kwota= $12345.67
warto= 1234567 kwota= 12345,67 DKK
warto= 1234567 kwota= CAD 12345,67
warto= -1234567 kwota= $-12345.67
warto= -1234567 kwota= -12345.67
warto= -1234567 kwota= (CHF12345,67)
---------------
class money_base {
public:
    enum part {      // czci wartoci
        none, space, symbol, sign, value
    };

    struct pattern { // specyfikacja ukadu
        char field[4];
    };
};

template<typename C, bool International = false>
class moneypunct : public locale::facet, public money_base {
public:
    using char_type = C;
    using string_type = basic_string<C>;
    //...
};

---------------
template<typename C, bool Intl = false>
class moneypunct_byname : public moneypunct<C, Intl> {
    //...
};
---------------
"USD"
"DKK"
"EUR"
---------------
+$ 123.45   // { sign, symbol, space, value }, positive_sign() zwraca "+"
$+123.45    // { symbol, sign, value, none }, positive_sign() zwraca "+"
$123.45     // { symbol, sign, value, none }, positive_sign() zwraca ""
$123.45-    // { symbol, value, sign, none }
-123.45 DKK // { sign, value, space, symbol }
($123.45)   // { sign, symbol, value, none }, negative_sign() zwraca "()"
(123.45DKK) // { sign, value, symbol, none }, negative_sign() zwraca "()"
---------------
-$123.45        // {sign, symbol, value, none}, negative_sign() zwraca "-"
*$123.45 wygup // {sign, symbol, value, none}, negative_sign() zwraca "* wygup"
---------------
pattern pat = {sign, value, none, none}; // bd: brak symbolu
---------------
class  My_money_io : public moneypunct<char,true> {
public:
    explicit My_money_io(size_tr=0):moneypunct<char,true>(r) { }

    char_type do_decimal_point() const { return '.'; }
    char_type do_thousands_sep() const { return ','; }
    string do_grouping() const { return "\003\003\003"; }

    string_type do_curr_symbol() const { return "USD "; }
    string_type do_positive_sign() const { return ""; }
    string_type do_negative_sign() const { return "()"; }

    int do_frac_digits() const { return 2; } // dwie cyfry za punktem dziesitnym

    pattern do_pos_format() const { return pat; }
    pattern do_neg_format() const { return pat; }
private:
    static const pattern pat;
};

const pattern My_money_io::pat { sign, symbol, value , none };

---------------
ostream& operator<<(ostream& s, Money m)
{
    ostream::sentry guard(s); // zobacz 38.4.1
    if (!guard) return s;

    try{
        const money_put<char>& f = use_facet<money_put<char>>(s.getloc());
        if (m==static_cast<long long>(m)) { // m moe mie reprezentacj long long
            if (f.put(s,true,s,s.fill(),m).failed())
                s.setstate(ios_base::badbit);
        }
        else {
            ostringstream v;
            v<<m; // konwersja na reprezentacj acuchow
            if (f.put(s,true,s,s.fill(),v.str()).failed())
                s.setstate(ios_base::badbit);
        }
    }
    catch (...) {
        handle_ioexception(s); // zobacz 39.4.2.2
    }
    return s;
}
---------------
int main()
{
    Money m;
    while (cin>>m)
        cout << m << "\n";
}
---------------
istream& operator>>(istream& s, Money& m)
{
    istream::sentry guard(s); // zobacz _io.sentry_
    if (guard) try {
        ios_base::iostate state = 0; // dobry
        istreambuf_iterator<char> eos;
        string str;

        use_facet<money_get<char>>(s.getloc()).get(s,eos,true,state,str);

        if (state==0 || state==ios_base::eofbit) { // ustawia warto, tylko gdy get() si uda
            long long i = stoll(str); // 36.3.5
            if (errno==ERANGE) {
                state |= ios_base::failbit;
            }
            else {
                m=i; // ustawia warto, tylko gdy uda si konwersja na long long
            }
            s.setstate(state);
        }
    }
    catch (...) {
        handle_ioexception(s); // zobacz 39.4.2.2
    }
    return s;
}
---------------
class Date {
public:
    explicit Date(int d ={}, Month m ={}, int year ={});
    //...
};
---------------
ostream& operator<<(ostream& os, Date d)
{
    ostringstream ss;
    tm t;
    t.tm_mday = d.day;
    t.tm_mon = static_cast<int>(d.month-1);
    t.tm_year= d.year-1900;
    char fmt[] = "{%Y-%m-%d}"; // 43.6
    use_facet<time_put<char>>(os.getloc()).put(os,os,' ',&t,begin(fmt),end(fmt)); 
    (// wstawia z t do os
    return os;
}
---------------
class time_base {
public:
    enum dateorder {
        no_order, // znaczy mdr
        dmy,      // znaczy "%d%m%r"
        mdy,      // znaczy "%m%d%r"
        ymd,      // znaczy "%r%m%d"
        ydm       // znaczy "%r%d%m"
    };
};

---------------
istream& operator>>(istream& is, Date& d)
{
    if (istream::sentry guard{is}) {
        ios_base::iostate err = ios_base::goodbit;
        struct tm t;
        use_facet<time_get<char>>(is.getloc()).get_date(is,0,is,err,&t); // wczytuje do t
        if (!err) {
            Month m = static_cast<Month>(t.tm_mon+1);
            d = Date(t.tm_mday,m,t.tm_year+1900);
        }
        is.setstate(err);
    }
    return is;
}
---------------
void test()
{
    Date d1(3,10,1980);
    cout << d1 << '\n'; // wysya dat na wyjcie
    auto order = use_facet<time_get<char>>(cin.getloc()).date_order(); // odczytuje 
                                                                       // uporzdkowanie daty
    if (order == time_base::mdy)
                cout << "miesic dzie rok\n";
    else
                cout << "nie zgade\n";
    stringstream ss ("10/3/1980");
    ss>>d1; // pobieranie daty
    cout << d1 << '\n'; // wysyanie daty na wyjcie
}
---------------
class ctype_base {
public:
    enum mask { // rzeczywiste wartoci zale od implementacji
        space = 1,         // biae znaki (w lokalizacji "C": ' ', '\n', '\t'...)
        print = 1<<1,      // znaki drukowalne
        cntrl = 1<<2,      // znaki sterujce
        upper = 1<<3,      // wielkie litery
        lower = 1<<4,      // mae litery
        alpha = 1<<5,      // znaki alfabetu
        digit = 1<<6,      // cyfry dziesitne
        punct = 1<<7,      // znaki interpunkcyjne
        xdigit = 1<<8,     // cyfry szesnastkowe
        blank = 1 << 9;    // tabulator pionowy i poziomy
        alnum=alpha|digit, // znaki alfanumeryczne
        graph=alnum|punct
    };
};
template<typename C>
class ctype : public locale::facet, public ctype_base {
public:
    using char_type = C;
    //...
};
---------------
table['P'] == upper|alpha
table['a'] == lower|alpha|xdigit
table['1'] == digit|xdigit
table[' '] == space|blank

---------------
int count_spaces(const string& s, const locale& loc)
{
    const ctype<char>& ct = use_facet<ctype<char>>(loc);
    int i = 0;
    for(auto p = s.begin(); p!=s.end(); ++p)
        if (ct.is(ctype_base::space,*p)) // biae znaki wg definicji ct
            ++i;
    return i;
}
---------------
ct.is(ctype_base::space|ctype_base::punct,c); // czy c jest znakiem biaym lub interpunkcyjnym?
---------------
template<typename C>
const C* ctype<C>::do_scan_is(mask m, const C* b, const C* e) const
{
    while (b!=e && !is(m,*b))
        ++b;
    return b;
}
---------------
template<typename C>
const C* ctype<C>::to_upper(C* b, const C* e)
{
    for (; b!=e; ++b)
        *b = toupper(*b);
    return e;
}
---------------
wcout << use_facet<ctype<wchar_t>>(wcout.getloc()).widen('e');
---------------
char EBCDIC_e = use_facet<ctype<char>>(ebcdic).widen('e');
---------------
c == narrow(widen(c),0) // brak gwarancji
---------------
widen(narrow(ch,def)) == ch || widen(narrow(ch,def)) == widen(def) // brak gwarancji
---------------
widen(narrow(ch_lit,0)) == ch_lit
---------------
widen(narrow('x',0)) == 'x'
---------------
template<typename C>
class ctype_byname : public ctype<C> {
    //...
};
---------------
class codecvt_base {
public:
    enum result { // indykatory wyniku
        ok, partial, error, noconv
    };
};

template<typename In, typename Ex, typename SS>
class codecvt : public locale::facet, public codecvt_base {
public:
    using intern_type = In;
    using extern_type = Ex;
    using state_type = SS;
    //...
};

---------------
class JISstate { /*..*/};

p = new codecvt<wchar_t,char,mbstate_t>;  // standardowa konwersja char na wchar_t
q = new codecvt<wchar_t,char,JISstate>;   // JIS na wchar_t
---------------
class JIScvt : public codecvt<wchar_t,char,mbstate_t> {
    //...
};

---------------
class Cvt_to_upper : public codecvt<char,char,mbstate_t> { // konwertuje na wielkie litery
public:
    explicit Cvt_to_upper(size_t r = 0) : codecvt(r) { }

protected:
    // wczytuje zewntrzn reprezentacj, zapisuje wewntrzn reprezentacj:
    result do_in(State& s,
                   const char* from, const char* from_end, const char*& from_next,
                   char* to, char* to_end, char*& to_next
                )  const override;

    // wczytuje wewntrzn reprezentacj, zapisuje zewntrzn reprezentacj:
    result do_out(State& s,
                   const char* from, const char* from_end, const char*& from_next,
                   char* to, char* to_end, char*& to_next
                 ) const override;

    result do_unshift(State&, E* to, E* to_end, E*& to_next) const override { return ok; }

    int do_encoding() const noexcept override { return 1; }
    bool do_always_noconv() const noexcept override { return false; }

    int do_length(const State&, const E* from, const E* from_end, size_t max) const 
    (override;
    int do_max_length() const noexcept override;  // maksymalna moliwa dugo
};

codecvt<char,char,mbstate_t>::result
Cvt_to_upper::do_out(State& s,
                   const char* from, const char* from_end, const char*& from_next,
                   char* to, char* to_end, char*& to_next) const
{
    return codecvt<char,char,mbstate_t>::do_out(s,from,from_end,from_next,to,to_end,to_next);
}

codecvt<char,char,mbstate_t>::result
Cvt_to_upper::do_in(State& s,
                       const char* from, const char* from_end, const char*& from_next,
                       char* to, char* to_end, char*& to_next) const
{
    //...
}

int main() // prosty test
{
    locale ulocale(locale(), new Cvt_to_upper);

    cin.imbue(ulocale);

    for (char ch; cin>>ch; )
        cout << ch;
}
---------------
template<typename I, typename E, typename State>
class codecvt_byname : public codecvt<I,E,State> {
    //...
};
---------------
class messages_base {
public:
    using catalog = /* zdefiniowany przez implementacj typ cakowitoliczbowy */; // typ identyfikatora katalogu
};
template<typename C>
class messages : public locale::facet, public messages_base {
public:
    using char_type = C;
    using string_type = basic_string<C>;
    //...
};

---------------
struct Set {
    vector<string> msgs;
};

struct Cat {
    vector<Set> sets;
};

class My_messages : public messages<char> {
    vector<Cat>& catalogs;
public:
explicit My_messages(size_t = 0) :catalogs{*new vector<Cat>} { }

catalog do_open(const string& s, const locale& loc) const;     // otwiera katalog s
string do_get(catalog cat, int s, int m, const string&) const; // pobiera wiadomo (s,m) z cat

void do_close(catalog cat) const
{
    if (catalogs.size()<=cat)
        catalogs.erase(catalogs.begin()+cat);
}

    ~My_messages() { delete &catalogs; }
};
---------------
string My_messages::do_get(catalog cat, int set, int id, const string& def) const
{
    if (catalogs.size()<=cat)
        return def;
    Cat& c = catalogs[cat];
    if (c.sets.size()<=set)
        return def;
    Set& s = c.sets[set];
    if (s.msgs.size()<=id)
        return def;
    return s.msgs[id];
}
---------------
messages<char>::catalog My_messages::do_open(const string& n, const locale& loc) const
{
    string nn = n + locale().name();
    ifstream f(nn.c_str());
    if (!f) return -1;

    catalogs.push_back(Cat{});             // tworzy katalog
    Cat& c = catalogs.back();

    for(string s; f>>s && s=="<<<"; ) {    // odczytuje zbir
        c.sets.push_back(Set{});
        Set& ss = c.sets.back();
        while (getline(f,s) && s != ">>>") // odczytuje wiadomo
            ss.msgs.push_back(s);
    }
    return catalogs.size()-1;
}
---------------
int main()
    // prosty test
{
    if (!has_facet<My_messages>(locale())) {
        cerr << "nie znaleziono wiadomoci w" << locale().name() << '\n';
        exit(1);
    }

    const messages<char>& m = use_facet<My_messages>(locale());
    extern string message_directory; // gdzie trzymam wiadomoci

    auto cat = m.open(message_directory,locale());
    if (cat<0) {
        cerr << "nie znaleziono katalogu\n";
        exit(1);
    }
    cout << m.get(cat,0,0,"Pudo!") << endl;
    cout << m.get(cat,1,2,"Pudo!") << endl;
    cout << m.get(cat,1,3,"Pudo!") << endl;
    cout << m.get(cat,3,0,"Pudo!") << endl;
}
---------------
<<<
witaj
egnaj
>>>
<<<
tak
nie
moe
>>>
---------------
witaj
moe
Pudo!
Pudo!
---------------
class Season_io : public locale::facet {
    const messages<char>& m;    // magazyn wiadomoci
    messages_base::catalog cat; // katalog wiadomoci
public:
    class Missing_messages { };

    Season_io(size_ti=0)
        : locale::facet(i),
        m(use_facet<Season_messages>(locale())),
        cat(m.open(message_directory,locale()))
    {
        if (cat<0)
            throw Missing_messages();
    }

    ~Season_io() { }      // aby umoliwi niszczenie obiektw klasy Season_io (39.3)

    const string& to_str(Season x) const;            // acuchowa reprezentacja x

    bool from_str(const string& s, Season& x) const; // wstawia Season odpowiadajcy s do x
    
    static locale::id id; // obiekt identyfikacyjny fasety (39.2, 39.3, 39.3.1)
};

locale::id Season_io::id; // definicja obiektu identyfikacyjnego

string Season_io::to_str(Season x) const
{
    return m->get(cat,0,x,"nie ma takiej pory roku");
}

bool Season_io::from_str(const string& s, Season& x) const
{
    for (int i = Season::spring; i<=Season::winter; i++)
        if (m->get(cat,0,i,"nie ma takiej pory roku") == s) {
            x = Season(i);
            return true;
        }
    return false;
}
---------------
template<typename C>
class messages_byname : public messages<C> {
    //...
};

---------------
template<typename C>

inline bool isspace(C c, const locale& loc)
{
    return use_facet<ctype<C>>(loc).is(space,c);
}
---------------
inline int isspace(int i)
{
    return isspace(i,locale()); // prawie
}

---------------
wstring_conver t<codecvt_utf8<wchar_t>> myconv;
string s = myconv.to_bytes(L"Cze\n");
cout << s;
---------------
template<typename Codecvt,
         class Wc = wchar_t,
         class Wa = std::allocator<Wc>,   // alokator szerokich znakw
         class Ba = std::allocator<char>  // alokator bajtw
       >
class wstring_conver t{
public:
    using byte_string = basic_string<char, char_traits<char>, Ba>;
    using wide_string = basic_string<Wc, char_traits<Wc>, Wa>;
    using state_type = typename Codecvt::state_type;
    using int_type = typename wide_string::traits_type::int_type;
    //...
};

---------------
void test()
{
    wstring_convert<codecvt_utf8_utf16<wchar_t>> converter;

    string s8 = u8"To jest acuch UTF-8";
    wstring s16 = converter.from_bytes(s8);
    string s88 = converter.to_bytes(s16);

    if (s8!=s88)
        cerr << "Szalestwo!\n";
}
---------------
template<typename Codecvt,
         class C = wchar_t,
         class Tr = std::char_traits<C>
       >
class wbuffer_convert
    : public std::basic_streambuf<C,Tr> {
public:
    using state_type = typename Codecvt::state_type;
    //...
};