Angelika Langer - Training & Consulting
HOME | COURSES | TALKS | ARTICLES | GENERICS | LAMBDAS | IOSTREAMS | ABOUT | NEWSLETTER | CONTACT | Twitter | Lanyrd | Linkedin
 
HOME 

  OVERVIEW

  BY TOPIC
    JAVA
    C++

  BY COLUMN
    EFFECTIVE JAVA
    EFFECTIVE STDLIB

  BY MAGAZINE
    JAVA MAGAZIN
    JAVA SPEKTRUM
    JAVA WORLD
    JAVA SOLUTIONS
    JAVA PRO
    C++ REPORT
    CUJ
    OTHER
 

GENERICS 
LAMBDAS 
IOSTREAMS 
ABOUT 
NEWSLETTER 
CONTACT 
Internationalization Using Standard C++

Internationalization Using Standard C++
Internationalization Using Standard C++

C/C++ User Journal, September 1997
Klaus Kreft & Angelika Langer


 
 

Introduction

Computer users all over the world prefer to interact with their systems using their own language and cultural conventions. Cultural differences affect for instance the display of monetary values, of date and time. Just think of the way numeric values are formatted in different cultures: 1,000,000.00 in the US is 1.000.000,00 in Germany and 10,00,000.00 in Nepal. If you aim for high international acceptance of your products you must build into your software the flexibility to adapt to varying requirements that stem from cultural differences. Building into software the potential for worldwide use is called internationalization . It is one of the challenges of software development in these days.

Traditionally, internationalization was achieved by means of C. Standards like POSIX and X/Open define locales and wide character input and output for standard C. Windows 95 and Windows NT have a C interface, too, the Win32 NLSAPI. None of the Win32 NLSAPI interfaces matches any of the standard C interfaces though, and locales are thread-specific in Windows whereas they are provided per process in Unix. These are important differences. The concept and level of support, however, is equivalent. There is a common notion of locales, and the services provided cover almost the same range of i18n problems. Naturally, C++ cannot stand back. The ISO/ANSI C++ standard defines an extensible framework that facilitates internationalization of C++ programs in a portable manner. Its main elements are locales and facets . This article gives an overview of the locale framework and the standard facets defined by ISO/ANSI C++.


Overview
A Recap - C Locales
The C++ Locales
C Locales vs. C++ Locales
Relationship between C Locale and C++ Locales
Using C++ Locales and Facets
Locales and IOStreams
Summary

Code Examples
Multiple locales in C and C++
Class locale as defined in the C++ standard
Accessing a Locale's Facet
A locale-sensitive date inserter


A Recap - C Locales
As a software developer and reader of C++ Users Journal, you may already have some background in the C programming language, and the internationalization services provided by the ANSI C library. For this reason, let us start with a short recap of the internationalization services provided by the C library, and then build on existing knowledge to describe the C++ locales in terms of the C locale.

Internationalization requires that developers consciously design and implement their software and avoid hard-coding information or rules that can be localized. For example, careful developers never assume specific conventions for formatting numeric or monetary values, or for displaying date and time, not even for comparing or sorting strings. For internationalization, all culture and language dependencies need to be represented in a kind of language table. Such a table is called a locale . A locale in the C library contains support for the several problem domains. The information in a C locale is composed of categories . Each of the categories represents a set of related information:
 

Category
Content 
LC_NUMERIC Rules and symbols for numbers 
LC_TIME Values for date and time information 
LC_MONETARY Rules and symbols for monetary information 
LC_CTYPE Character classification and case conversion 
LC_COLLATE Collation sequence
LC_MESSAGE Formats and values of messages 
Inside a program, the C locale is represented by one or more global data structures . The C library provides a functions that use information from those global data structures to adapt their behavior to local conventions. Examples of these functions and the information they cover are listed below:
 
C locale function Information covered
setlocale(), ... Locale initialization and language information 
isalpha() , isupper() , isdigit() , ... Character classification
strftime() , ... Date and time functions
strfmon() Monetary functions
printf() , scanf() , ... Number parsing and formatting
strcoll() , wcscoll() , ... String collation
mblen() , mbtowc() , wctomb() , ... Multibyte functions
cat_open() , catgets() , cat_close() Message retrieval
The C++ Locales
In C++, internationalization semantics are broken out into separate classes, so-called facets . Each facet offers a set of internationalization services. For instance, the formatting of monetary values is encapsulated in the money_put<> facet. (Don't get distracted by the template parenthesis; they are added because all facets are class templates.) Facets may also represent a set of information about certain culture and language dependencies. The rules and symbols for monetary information are an example; they are contained in a facet called moneypunct<> .

In C++, there is also a class called locale . Different from a C locale, which is a global data structure representing various culture and language dependencies, the C++ class locale is an abstraction that manages facets. Basically, you can think of a C++ locale as a container of facets. This concept is illustrated graphically below:

The Standard Facets
The C++ standard defines a number of standard facets . They provide services and information similar to those contained in the C library. As we have seen, the C locale is composed of six categories of information. Similarly, there are six groups of standard facets. Here is a brief overview:
  • Numeric. The facets num_get<charT,InputIterator> and num_put<charT, OutputIterator> handle numeric formatting and parsing. The facets provide get() and put() member functions for values of type long , double , etc.

  • The facet numpunct<charT> specifies numeric formats and punctuation. It provides functions like decimal_point(),thousands_sep(), etc.
  • Monetary. The facets money_get<charT,bool,InputIterator> and money_put<charT, bool, OutputIterator> handle formatting and parsing of monetary values. They provide get() and put() member functions that parse or produce a sequence of digits, representing a count of the smallest unit of the currency. For example, the sequence $1,056.23 in a common US locale would yield 105623 units, or the character sequence "105623”.

  • The facet moneypunct <charT, bool International> handles monetary formats and punctuation like the facet numpunct<charT> handles numeric formats and punctuation. It comes with functions like curr_symbol(), etc.
  • Time. The facets time_get<charT,InputIterator> and time_put<charT, OutputIterator> handle date and time formatting and parsing. They provide functions like put(), get_time(), get_date(), get_weekday(), etc.
  • Ctype. The facet ctype<charT> encapsulates the Standard C++ Library ctype features for character classification, like tolower(), toupper(), is(ctype_base::space,...) etc.
  • Collate. The facet collate<charT> provides features for string collation, including a compare() function used for string comparison.
  • Code Conversion. The facet codecvt<internT,externT,stateT> is used when converting from one encoding scheme to another, such as from the multibyte encoding JIS to the wide-character encoding Unicode. The main member functions are in() and out().
  • Messages. The facet messages<charT> implements message retrieval. It provides facilities to access message catalogues via open() and close(catalog), and to retrieve messages via get(..., int msgid,...).
As you might have noticed, the names of the standard facets obey certain naming rules. The get facets, like num_get and time_get , offer services for parsing. The put facets provide formatting services The punct facets, like numpunct and moneypunct , represent rules and symbols.
C Locale vs. C++ Locales
Apparently, the C locale and the C++ locale along with the standard facets offer similar services. However, the semantics of the C++ locale are different from the semantics of the C locale:
  • The Standard C locale is a global resource: there is only one locale for the entire application. This makes it hard to build an application that has to handle several locales at a time.
  • The Standard C++ locale is a class. Numerous instances of class locale can be c reated at will, so you can have as many locale objects as you need.
To explore this difference in further detail, let us see how locales can be used. It may well happen that you have to work with multiple locales. For example, if you have to implement an application for Switzerland, you might want to output messages in Italian, French, and German. As the C locale is a global data structure, you will have to switch locales several times.

Let's discuss an application that works with multiple locales. Say, the application runs at a US company that ships products worldwide. Our application's responsibility is printing of invoices to be sent to customers all over the world. Of course, the invoices need to be printed in the customer's native language. Say, the application reads input (the product price list) in US English, and writes output (the invoice) in the customer's native language, say German. Since there is only one global locale in C that affects both input and output, the global locale must change between input and output operations.

Here is the C code that corresponds to the previous example:

float price;
while ( … )  // processing the German invoice
{  setlocale(LC_ALL, "En_US”);
   fscanf(priceFile,”%f”,&price);
   // convert $ to DM accosrding to the current exchange rate
   setlocale(LC_ALL,”De_DE”);
   fprintf(invoiceFile,”%f”,price);
}
Using C++ locale objects dramatically simplifies the task of using multiple locales. The iostreams in the Standard C++ Library are internationalized so that streams can be imbued with separate locale objects. For example, the input stream can be imbued with an English locale object, and the output stream can be imbued with a German locale object. In this way, switching locales becomes unnecessary.

Here is the C++ code corresponding to the previous example:

priceFile.imbue(locale("En_US”));
invoiceFile.imbue(locale("De_DE”));
float price;
while ( … )  // processing the German invoice
{  priceFile >> price;
   // convert $ to DM according to the current exchange rate
   invoiceFile << price;
}
With these toy examples given above switching locales might look like a minor inconvenience. However, consider the need for multiple locales in an application with multiple threads of execution. Because all threads share one global locale in C, access to the global locale must be serialized by means of mutual exclusion. A lot of locking would occur and mostly slow down the program.

Ideally, you would want to have locales be completely independent of each other. Each component shall have a locale of its own, that is unrelated to other locales in your program. This is what you have in C++. You can create infinitely many, independent, light-weight locale objects that you can attach to streams, and exchange between components, or pass around as function arguments for instance.

Relationship between the C Locale and the C++ Locale.

The C locale and the C++ locales are mostly unrelated. There is only one occasion when they effect each other: making a C++ locale global.

The matter is that there is a global locale in C++, as there is in C. You can make a given locale object global by calling locale::global() . The notion of a global C++ locale was added for all those users who do not want to bother with internationalization and rely on internationalized components to pick a sensible default locale. The global C++ locale is often used as the default locale. IOStreams, for instance, uses it; if you do not explicitly imbue your streams with any particular locale object, a snapshot of the global locale is used.

Making a C++ locale object global via locale::global() affects the global C locale in that it results in a call to setlocale() . When this happens, locale-sensitive C functions called from within a C++ program will use the global C++ locale. Conversely, there is no way to affect the C++ locale from within a C program though.


Using C++ Locales and Facets

After this brief overview of C++ locales and facets let us now explore how they are used. Remember, a locale in C++ is a container of facets, and a facet is a set of internationalization services and information. The general pattern of usage is:
  • Create a locale. First, you create a locale object and stuff all the facets you need into the locale.
  • Make available a locale. You can pass around such a locale object to those components that might need it; for instance, you can attach it to a stream and the stream's shift operator will use it.
  • Retrieve a facet. When you need a service from the locale, then you ask the locale to give you a handle to the respective facet that contains the service you need.
  • Invoke a service. Via this handle you eventually invoke the facet's service.
This sounds more complicated than it actually is, as we will see later. However, it points out that the locale does not know anything about the facets' capabilities. The locale only maintains the facets. It registers them and makes them accessible on demand. The locale, however, does not provide you with the internationalization services itself. It only gives you access to facets that provide services. It is your task to memorize which facets you need for which particular service. The advantage of separating maintenance from functionality is that a locale can maintain any kind of facet, not only the predefined standard facets from the C++ library, but also novel facets that are added to the library for special purposes.
Creating Locales
Class locale has numerous constructors; see Box 2 for a comprehensive list. Basically they fall into three categories:
  1. By name. You can create a locale object from a C locale's external representation. Class locale has a constructor locale::locale(const char* std_name) that takes the name of a C locale. This locale name is like the one you would use for a call to the C library function setlocale() . We have already used this constructor in the example above when we created a US English locale by invoking locale("En_US");. A locale created this way contains all the standard facets and therefore makes available all services and information equivalent to the C locale you specified.
  2. The classic locale. The standard C++ library contains a predefined locale object, locale :: classic() , which represents the US English ASCII environment. The is the counterpart to the locale named "C" in the C library.
  3. By composition. You can construct a new locale object as a copy of an existing locale object, that has one or several fac et objects replaced. Below are a couple of constructors of class locale that allow creation of locales by composition.
class locale {
public:
  locale(const locale& other, const char* std_name, category);
  template <class Facet> locale(const locale& other, Facet* f);
  template <class Facet> locale(const locale& other
                               ,const locale& one);
  locale(const locale& other, const locale& one, category);
};
The following example uses the first constructor and shows how you can construct a locale object as a copy of the classic locale object with the classic numeric facets replaced by the numeric facet objects taken from a German locale object.
locale loc ( locale::classic(), locale("De_DE”), LC_NUMERIC );
The classic locale is created via locale::classic(), the German locale is crated via locale("De_DE").LC_NUMERIC is a locale category. As mentioned earlier, the facets fall into categories, and the LC_NUMERIC is the category that designates all numeric facets in a locale.

Note that some of the constructors are member templates, which is a language feature that is relatively new to the language and not supported by all compilers.

Immutability of Locales . It's important to understand that locales are immutable objects: once a locale object is created, it cannot be modified, i.e. no facets can be replaced after construction. This makes locales reliable and easy to use and you can safely pass them around between components.

Copying locales. Copying a locale object is a cheap operation. You should have no hesitation about passing locale objects around by value. You may copy locale objects for composing new locale objects; you may pass copies of locale objects as arguments to functions, etc.

Locales are implemented using reference counting and the handle-body-idiom: When a locale object is copied, only its handle is duplicated, a fast and inexpensive action.

The following figure gives an overview of the locale architecture. A locale is a handle to a body that maintains a sequence of pointers to facets. The facets are reference-counted, too.



Accessing a Locale's Facets
A ccess to the facet objects of a locale object is via two template functions, use_facet and has_facet :

template <class Facet> const Facet&     use_facet(const locale&);
template <class Facet> bool             has_facet(const locale&);
The function use_facet is the one that gives access to a facet by providing a constant reference to a facet. The function has_facet is for checking whether a certain facet is present in a given locale. The requested facet is specified via its type. Note, that both functions are template functions. The template parameter they take is the type of the facet they try to access in a locale. In other words, these function are capable of deciding which facet object is meant from just the information about the facet's type. It works because a locale contains at most one exemplar of a certain facet type. This kind of compile-time dispatch is a novel technique in C++. A discussion of it and the design of the locale framework's architecture is beyond the scope of this article. A detailed description can be found in C++ Report, September 1997, "The Locale Framework" by Klaus Kreft & Angelika Langer.

The code below demonstrates how these functions are used to get access to a facet and invoke an internationalization service. It is an example of the conversion service tolower() from the ctype facet; all upper case letters of a string read from the standard input stream are converted to lower case letters and are written to the standard output stream.


string in;
cin >> in;
use_facet< ctype<char> >(locale::locale()).tolower(in.c_str(),in.c_str()+in.length());
cout << in;
The function template use_facet< ctype<char> >() returns a constant reference to the locale's facet object. Then the facet object's member function tolower() is called. It has the functionality of the C function tolower() ; it converts all upper case letters into lower case letters. A couple of further comments on this example:

Explicit Template Argument Specification. The syntax of the call use_facet < ctype<char> > (locale::locale()) might look surprising to you. It is an example of explicit template argument specification, a language feature that is relatively new to C++. Template arguments of a function instantiated from a function template can either be explicitly specified in a call or be deduced from the function arguments. The explicit template argument specification is needed in the call to use_facet above, because the compiler can only deduce a template argument if it is the type of one of the function arguments.

Storing references to facets. Note, that we do not store the reference to the facet, but just use the temporary reference returned by use_facet for immediately calling the desired member function of that facet. This is a safe way of using facets retrieved from a locale. If you kept the reference, you needed to keep track of the object's lifetime and validity. The facet reference does stay valid throughout the lifetime of the locale object it was retrieved from. Moreover, the facet referred to does not even change in any way; it is immutable. However, when the locale goes out of scope, the references obtained from it might become invalid. For this reason it is advisable to combine retrieval and invocation as shown in the example above, unless you have a need for doing differently.

Need for has_facet . Note also, that we did not call has_facet< ctype<char> >() in order to check whether the locale has a ctype facet. In most situations, you do not have to check for the presence of a standard facet object like ctype<char> . This is because locale objects are created by composition; you start with the classic locale or a locale object constructed "by name" from a C locale's external representation. Because you can only add or replace facet objects in a locale object, you cannot compose a locale that misses one of the standard facets. A call to has_facet() is useful, however, when you expect that a certain non-standard facet object should be present in a locale object.


Locales and IOStreams

The standard iostreams are an example of an internationalized component that uses locales and facets. This feature of iostreams enables you to implement locale-sensitive standard i/o operations for your user-defined types. Each stream has a locale object attached. Attaching a locale to a stream is done via the stream's imbue() operation. If you do not explicitly imbue a locale the stream uses a snapshot of the current global locale as a default.

Here is an example that demonstrates how one can use a stream's locale for printing a date. Let us assume we have a date object of type tm , which is the time structure defined in the standard C library, and we want to print it. Let's assume our program is supposed to run in a German-speaking canton of Switzerland. Hence, we attach a Swiss locale to the standard output stream. When we print the date we expect an output like: 1. September 1989 or 01.09.89


struct tm aDate;                                              
aDate.tm_year = 1989;
aDate.tm_mon = 9;
aDate.tm_mday = 1;                                            

cout.imbue(locale::locale("De_CH”));                          
cout << aDate;
As there is no operator<<() defined in the Standard C++ Library for the time structure tm from the C library, we have to provide this inserter ourselves. The following code suggests a way this can be done. To keep it simple, the handling of exceptions thrown during the formatting is omitted.

template<class Ostream >
Ostream& operator<< (Ostream& os, const struct tm& date)   
{
  typedef typename Ostream::char_type          char_t;
  typedef typename Ostream::traits_type        traits_t;
  typedef ostreambuf_iterator<char_t,traits_t> outIter_t;        

  locale loc = os.getloc();                                  
 
  const time_put<char_t,outIter_t>& fac = 
     use_facet < time_put<char_t, outIter_t > > (loc);
   
  outIter_t nextpos = fac.put(os,os,os.fill(),&date,'x');

  if (nextpos.failed())                                      
        os.setstate(ios_base::badbit);   
                        
  return os;
}

There's a lot going on here. Let's discuss the interface of the shift operator first. The code above shows a typical stream inserter. As function arguments it takes a reference to an output stream and a constant reference to the object to be printed. It returns a reference to the same stream. The inserter is a template function because the standard iostreams are templates; they take a character type and an associated traits type describing the character type as template arguments. Naturally, we have the same template parameters for our date inserter.

Now, we need to get hold of the stream's locale object, because we want to use its time formatting facet for output of our date object. As you can see in the code above, the stream's locale object is obtained via the stream's member function getloc() . We retrieve the time formatting facet from the locale via use_facet ; that's an old hat meanwhile. We then call the facet's member function put().

The put() function does all the magic, i.e. it produces a character sequence that represents the equivalent of the date object, formatted according to culture-dependent rules and information. It then inserts the formatted output into the stream via an output iterator. Before we delve into the details of the put() function let us take a look at its return value.

The put() function returns an output iterator that points to the position immediately after the last inserted character. The output iterator used here is an output stream buffer iterator. These are special purpose iterators contained in the standard C++ library that bypass the stream's formatting layer and write directly to the output stream's underlying stream buffer. Output stream buffer iterators have a member function failed() for error indication. So we can check for errors happening during the time formatting. If there was an error, we set the stream's state accordingly which is done via the stream's setstate() function.

Let's return to the facet's formatting service put() and see what arguments it takes. Here is the function's interface:

iter_type put (iter_type (a)
,ios_base& (b)
,char_type (c)
,const tm* (d)
, char) (e)
The types iter_type and char_type stand for the types that were provided as template arguments when the facet class was instantiated. In this case, they are ostreambuf_iterator<charT,traits> and charT , where charT and traits are the respective streams template arguments.

Here is the actual call:



nextpos = fac.put(os,os,os.fill(),&date,'x');

Now let's see what the arguments mean:
  1. The first parameter is supposed to be an output iterator. We provide an iterator to the stream's underlying stream buffer. The reference os to the output stream is converted to an output iterator, because output stream buffer iterators have a constructor taking an output stream, that is, basic_ostream<charT,traits>& .
  2. The second parameter is of type ios_base&, which is one of the stream base classes. The class ios_base contains data for format control (see the section on iostreams for details). The facet object uses this formatting information. We provide the output stream's ios_base part here, using the automatic cast from a reference to an output stream, to a reference to its base class.
  3. The third parameter is the fill character. It is used when the output has to be adjusted and blank characters have to be filled in. We provide the stream's fill character, which one can get by calling the stream's fill() function.
  4. The fourth parameter is a pointer to a time structure tm from the C library.
  5. The fifth parameter is a format character as in the C function strftime() ; the x stands for the locale's appropriate date representation.
As you can see from the example of a date inserter function, it is relatively easy to implement powerful, locale-sensitive i/o operations using standard iostreams and locale. It takes just a couple of lines of C++ code.


Summary
This article gave a brief overview of locales and facets - the components in the standard C++ library for support of internationalization of C++ programs. The functionality of the standard facets contained in the standard C++ library covers traditional C functionality. However, C++ allows multiple locales and overcomes the limitation of one, single global locale that was imposed by C. Naturally, this brief introduction to internationalization support in standard C++ is far from being comprehensive. For instance, we concealed that locales and facets are designed as an open and extensible frame. A description of the framework's architecture and of techniques for extending the framework would fill another article.


Acknowledgements
This article is based on material we put together for a book on "Standard C++ IOStreams and Locales" to be published by Addison-Wesley-Longman in 1998. Part of the article was inspired by work Angelika Langer did for Rogue Wave Software, Inc. in 1996. We also want to thank Nathan Myers, who initially proposed locales and facets to the standards committee. He patiently answered countless questions during the past months.


Code Examples

The subsequent code examples are compiled with MVC V4.0 and the locale component that comes with it. This locale component does only partly comply to the standard. Workarounds are marked as such. 
Example 1: Multiple locales in C and C++
MVC does not support namespaces, hence we had to comment out the otherwise necessary using statement. The locale names used are those supported on Windows 95 and Windows NT. Also, we read input from standard input rather than a price list file, as was suggested in the example.
#include <stdio.h>
#include <locale.h>
#include <iostream>
#include <locale>

/*
using namespace ::std;
*/

void c_style_example()
{
        float price;
        int i = 1;

        while ( i-- )  // processing the German invoice
        {        setlocale(LC_ALL, "American_America.1252");
                printf("Type in the amount(as float): ");
                scanf("%f",&price);
                // convert $ to DM according to the current exchange rate
                setlocale(LC_ALL,"German_Germany.1252");
                printf("Der Betrag ist: %f \n",price);
        }
        setlocale(LC_ALL, "American_America.1252");
}

void cplusplus_style_example()
{

        cin.imbue(locale("American_America.1252"));
        cout.imbue(locale("German_Germany.1252"));

        int i= 1;
        float price;

        while ( i-- )  // processing the German invoice
        {      cout << "Type in the amount(as float): ";
                cin >> price;
                // convert $ to DM according to the current exchange rate
                cout << "Der Betrag ist: " << price << endl;
        }
}

int main()
{
        cout << "Test Begin !!!" << endl;

        cout << "***** c_style_example *****" << endl;
        c_style_example();
        cout << endl;

        cout << "***** cplusplus_style_example *****" << endl;
        cplusplus_style_example();
        cout << endl;

        cout << "Test End !!!" << endl;
        cout << endl;
}

Example 2: Class locale as defined in the C++ standard

  
namespace std {
    class locale {
    public:
    // types:
      class facet;
      class id;
      typedef int category;
      static const category   // values assigned here are for exposition only
        none     = 0,
        collate  = 0x010, ctype    = 0x020,
        monetary = 0x040, numeric  = 0x080,
        time     = 0x100, messages = 0x200,
        all = collate | ctype | monetary | numeric | time  | messages;
    // construct/copy/destroy:
      locale() throw()
      locale(const locale& other) throw()
      explicit locale(const char* std_name);
      locale(const locale& other, const char* std_name, category);
      template <class Facet> locale(const locale& other, Facet* f);
      template <class Facet> locale(const locale& other,
                                    const locale& one);
      locale(const locale& other, const locale& one, category);
     ~locale() throw();  // non-virtual
      const locale& operator=(const locale& other) throw();
    // locale operations:
      basic_string<char>                  name() const;
      bool operator==(const locale& other) const;
      bool operator!=(const locale& other) const;
      template <class charT, class Traits, class Allocator>
        bool operator()(const basic_string<charT,Traits,Allocator>& s1,
                        const basic_string<charT,Traits,Allocator>& s2) const;
    // global locale objects:
      static       locale  global(const locale&);
      static const locale& classic();
    };
  }

Example 3: Accessing a Locale's Facet
MVC does not support namespaces, hence we had to comment out the otherwise necessary using statement.

MVC does not support explicit template argument specification. For this reason the standard interface of function templates like use_facet and has_facet cannot be implemented. The library that comes with MVC 4.0 offers a workaround, which is shown below.


#include <iostr
eam>
#include <locale>
#include <sstream>

/*
using namespace ::std;
*/

void tolower_example()
{
        string in;
        cout << "Input string needed(with uppercase characters): ";
        cin >> in;

/* original code:
        if (has_facet< ctype<char> >(locale::locale()))
        {  use_facet< ctype<char> >(locale::locale())
                .tolower(in.c_str(),in.c_str()+in.length());
                cout << in;
        }
*/

// workaround for MVC 4.0
        if (_HAS(locale::locale(), ctype<char>))
        {
                _USE(locale::locale(), ctype<char>).tolower(in.begin(),in.end());
                cout << in;
        }
}

Example 4: A locale-sensitive date inserter
MVC does not support namespaces, hence we had to comment out the otherwise necessary using statement.

MVC does not support explicit template argument specification. For this reason the standard interface of function templates like use_facet and has_facet cannot be implemented. The library that comes with MVC 4.0 offers a workaround, which is shown below.

MVC does not support default template arguments. For reasons we simplified the example and implemented the inserter only for tiny character streams of type ostream , instead of providing an inserter template, which would be natural.

MVC does not support the standard interface of the time_put facet's put() function; we had to omit one of the arguments.


#include <iostream>
#include <locale>
#include <sstream>

/*
using namespace ::std;
*/


/* original code:

template<class Ostream>
Ostream& operator<< (Ostream& os, const struct tm& date)   
{
  typedef typename Ostream::char_type          char_t;
  typedef typename Ostream::traits_type        traits_t; 
  typedef ostreambuf_iterator<char_t,traits_t> outIter_t;        

  locale loc = os.getloc();                                  
 
  const time_put<char_t,outIter_t>& fac = 
     use_facet < time_put<char_t, outIter_t > > (loc);    
  outIter_t nextpos = fac.put(os,os,os.fill(),&date,'x');
  if (nextpos.failed())                                      
        os.setstate(ios_base::badbit);                           
  return os;
}
*/


// simplified version for MVC 4.0

ostream& operator<< (ostream& os, const struct tm& date)
{
        typedef ostream::char_type charType;
        typedef ostream::traits_type traitsType;
        typedef ostreambuf_iterator<charType,traitsType> outIter_t;
        typedef time_put<charType, outIter_t> time_put_facet_t;
                 

        locale loc = os.getloc();                                    
 
        const time_put<charType,outIter_t>& fac =
 
       /* original code
       use_facet < time_put<charType, bufIter_t > > (loc); 
       */
       // workaround for MVC 4.0
           _USE(loc,time_put_facet_t);
                 
        outIter_t nextpos = fac.put(os,os /* ,os.fill() */ ,&date,'x');
        if (nextpos.failed())                                         
                os.setstate(ios_base::badbit);                            
    return os;
}



void date_inserter_example()
{
        struct tm aDate;                                              
        aDate.tm_year = 1989;
        aDate.tm_mon = 9;
        aDate.tm_mday = 1;                                            

        cout.imbue(locale::locale("german-swiss"));

        cout << "Das Datum: " << aDate << endl;      
}
 

 
 
 
 

If you are interested to hear more about this and related topics you might want to check out the following seminar:
Seminar
 
Effective STL Programming - The Standard Template Library in Depth
4-day seminar (open enrollment and on-site)
IOStreams and Locales - Standard C++ IOStreams and Locales in Depth
5-day seminar (open enrollment and on-site)
 

 

  © Copyright 1995-2005 by Angelika Langer.  All Rights Reserved.    URL: < http://www.AngelikaLanger.com/Articles/Cuj/Internationalization/I18N.html  last update: 16 Aug 2005