CppCMS
booster/locale/message.h
00001 //
00002 //  Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
00003 //
00004 //  Distributed under the Boost Software License, Version 1.0. (See
00005 //  accompanying file LICENSE_1_0.txt or copy at
00006 //  http://www.boost.org/LICENSE_1_0.txt)
00007 //
00008 #ifndef BOOSTER_LOCALE_MESSAGE_H_INCLUDED
00009 #define BOOSTER_LOCALE_MESSAGE_H_INCLUDED
00010 
00011 #include <booster/config.h>
00012 #ifdef BOOSTER_MSVC
00013 #  pragma warning(push)
00014 #  pragma warning(disable : 4275 4251 4231 4660)
00015 #endif
00016 #include <locale>
00017 #include <string>
00018 #include <vector>
00019 #include <set>
00020 #include <memory>
00021 #include <booster/locale/formatting.h>
00022 
00023 
00024 namespace booster {
00025     namespace locale {
00033 
00035 
00036         template<typename CharType>
00037         struct base_message_format: public std::locale::facet
00038         {
00039         };
00040        
00042        
00046         template<typename CharType>
00047         class message_format : public base_message_format<CharType>
00048         {
00049         public:
00050 
00054             typedef CharType char_type;
00058             typedef std::basic_string<CharType> string_type;
00059 
00063             message_format(size_t refs = 0) : 
00064                 base_message_format<CharType>(refs)
00065             {
00066             }
00067 
00078             virtual char_type const *get(int domain_id,char_type const *context,char_type const *id) const = 0;
00092             virtual char_type const *get(int domain_id,char_type const *context,char_type const *single_id,int n) const = 0;
00093 
00097             virtual int domain(std::string const &domain) const = 0;
00098 
00107             virtual char_type const *convert(char_type const *msg,string_type &buffer) const = 0;
00108 
00109 #if defined (__SUNPRO_CC) && defined (_RWSTD_VER)
00110             std::locale::id& __get_id (void) const { return id; }
00111 #endif
00112         protected:
00113             virtual ~message_format()
00114             {
00115             }
00116 
00117         };
00118         
00120 
00121         namespace details {
00122             inline bool is_us_ascii_char(char c)
00123             {
00124                 // works for null terminated strings regardless char "signness"
00125                 return 0<c && c<0x7F; 
00126             }
00127             inline bool is_us_ascii_string(char const *msg)
00128             {
00129                 while(*msg) {
00130                     if(!is_us_ascii_char(*msg++))
00131                         return false;
00132                 }
00133                 return true;
00134             }
00135 
00136             template<typename CharType>
00137             struct string_cast_traits {
00138                 static CharType const *cast(CharType const *msg,std::basic_string<CharType> &/*unused*/)
00139                 {
00140                     return msg;
00141                 }
00142             };
00143 
00144             template<>
00145             struct string_cast_traits<char> {
00146                 static char const *cast(char const *msg,std::string &buffer)
00147                 {
00148                     if(is_us_ascii_string(msg))
00149                         return msg;
00150                     buffer.reserve(strlen(msg));
00151                     char c;
00152                     while((c=*msg++)!=0) {
00153                         if(is_us_ascii_char(c))
00154                             buffer+=c;
00155                     }
00156                     return buffer.c_str();
00157                 }
00158             };
00159         } // details
00160 
00162 
00170         template<typename CharType>
00171         class basic_message {
00172         public:
00173 
00174             typedef CharType char_type; 
00175             typedef std::basic_string<char_type> string_type;   
00176             typedef message_format<char_type> facet_type;   
00177 
00181             basic_message() :
00182                 n_(0),
00183                 c_id_(0),
00184                 c_context_(0),
00185                 c_plural_(0)
00186             {
00187             }
00188 
00193             explicit basic_message(char_type const *id) :
00194                 n_(0),
00195                 c_id_(id),
00196                 c_context_(0),
00197                 c_plural_(0)
00198             {
00199             }
00200 
00207             explicit basic_message(char_type const *single,char_type const *plural,int n) :
00208                 n_(n),
00209                 c_id_(single),
00210                 c_context_(0),
00211                 c_plural_(plural)
00212             {
00213             }
00214 
00220             explicit basic_message(char_type const *context,char_type const *id) :
00221                 n_(0),
00222                 c_id_(id),
00223                 c_context_(context),
00224                 c_plural_(0)
00225             {
00226             }
00227 
00234             explicit basic_message(char_type const *context,char_type const *single,char_type const *plural,int n) :
00235                 n_(n),
00236                 c_id_(single),
00237                 c_context_(context),
00238                 c_plural_(plural)
00239             {
00240             }
00241 
00242 
00246             explicit basic_message(string_type const &id) :
00247                 n_(0),
00248                 c_id_(0),
00249                 c_context_(0),
00250                 c_plural_(0),
00251                 id_(id)
00252             {
00253             }
00254 
00260             explicit basic_message(string_type const &single,string_type const &plural,int number) :
00261                 n_(number),
00262                 c_id_(0),
00263                 c_context_(0),
00264                 c_plural_(0),
00265                 id_(single),
00266                 plural_(plural)
00267             {
00268             }
00269 
00273             explicit basic_message(string_type const &context,string_type const &id) :
00274                 n_(0),
00275                 c_id_(0),
00276                 c_context_(0),
00277                 c_plural_(0),
00278                 id_(id),
00279                 context_(context)
00280             {
00281             }
00282 
00288             explicit basic_message(string_type const &context,string_type const &single,string_type const &plural,int number) :
00289                 n_(number),
00290                 c_id_(0),
00291                 c_context_(0),
00292                 c_plural_(0),
00293                 id_(single),
00294                 context_(context),
00295                 plural_(plural)
00296             {
00297             }
00298 
00302             basic_message(basic_message const &other) :
00303                 n_(other.n_),
00304                 c_id_(other.c_id_),
00305                 c_context_(other.c_context_),
00306                 c_plural_(other.c_plural_),
00307                 id_(other.id_),
00308                 context_(other.context_),
00309                 plural_(other.plural_)
00310             {
00311             }
00312 
00316             basic_message const &operator=(basic_message const &other)
00317             {
00318                 if(this==&other) {
00319                     return *this;
00320                 }
00321                 basic_message tmp(other);
00322                 swap(tmp);
00323                 return *this;
00324             }
00325 
00329             void swap(basic_message &other)
00330             {
00331                 std::swap(n_,other.n_);
00332                 std::swap(c_id_,other.c_id_);
00333                 std::swap(c_context_,other.c_context_);
00334                 std::swap(c_plural_,other.c_plural_);
00335 
00336                 id_.swap(other.id_);
00337                 context_.swap(other.context_);
00338                 plural_.swap(other.plural_);
00339             }
00340 
00344 
00345             operator string_type () const
00346             {
00347                 return str();
00348             }
00349 
00353             string_type str() const
00354             {
00355                 std::locale loc;
00356                 return str(loc,0);
00357             }
00358             
00362             string_type str(std::locale const &locale) const
00363             {
00364                 return str(locale,0);
00365             }
00366            
00370             string_type str(std::locale const &locale,std::string const &domain_id) const
00371             {
00372                 int id=0;
00373                 if(std::has_facet<facet_type>(locale))
00374                     id=std::use_facet<facet_type>(locale).domain(domain_id);
00375                 return str(locale,id);
00376             }
00377 
00381             string_type str(std::string const &domain_id) const
00382             {
00383                 int id=0;
00384                 std::locale loc;
00385                 if(std::has_facet<facet_type>(loc))
00386                     id=std::use_facet<facet_type>(loc).domain(domain_id);
00387                 return str(loc,id);
00388             }
00389 
00390             
00394             string_type str(std::locale const &loc,int id) const
00395             {
00396                 string_type buffer;                
00397                 char_type const *ptr = write(loc,id,buffer);
00398                 if(ptr == buffer.c_str())
00399                     return buffer;
00400                 else
00401                     buffer = ptr;
00402                 return buffer;
00403             }
00404 
00405 
00410             void write(std::basic_ostream<char_type> &out) const
00411             {
00412                 std::locale const &loc = out.getloc();
00413                 int id = ios_info::get(out).domain_id();
00414                 string_type buffer;
00415                 out << write(loc,id,buffer);
00416             }
00417 
00418         private:
00419             char_type const *plural() const
00420             {
00421                 if(c_plural_)
00422                     return c_plural_;
00423                 if(plural_.empty())
00424                     return 0;
00425                 return plural_.c_str();
00426             }
00427             char_type const *context() const
00428             {
00429                 if(c_context_)
00430                     return c_context_;
00431                 if(context_.empty())
00432                     return 0;
00433                 return context_.c_str();
00434             }
00435 
00436             char_type const *id() const
00437             {
00438                 return c_id_ ? c_id_ : id_.c_str();
00439             }
00440             
00441             char_type const *write(std::locale const &loc,int domain_id,string_type &buffer) const
00442             {
00443                 char_type const *translated = 0;
00444                 static const char_type empty_string[1] = {0};
00445 
00446                 char_type const *id = this->id();
00447                 char_type const *context = this->context();
00448                 char_type const *plural = this->plural();
00449                 
00450                 if(*id == 0)
00451                     return empty_string;
00452                 
00453                 facet_type const *facet = 0;
00454                 if(std::has_facet<facet_type>(loc))
00455                     facet = &std::use_facet<facet_type>(loc);
00456 
00457                 if(facet) { 
00458                     if(!plural) {
00459                         translated = facet->get(domain_id,context,id);
00460                     }
00461                     else {
00462                         translated = facet->get(domain_id,context,id,n_);
00463                     }
00464                 }
00465 
00466                 if(!translated) {
00467                     char_type const *msg = plural ? ( n_ == 1 ? id : plural) : id;
00468 
00469                     if(facet) {
00470                         translated = facet->convert(msg,buffer);
00471                     }
00472                     else {
00473                         translated = details::string_cast_traits<char_type>::cast(msg,buffer);
00474                     }
00475                 }
00476                 return translated;
00477             }
00478 
00480 
00481             int n_;
00482             char_type const *c_id_;
00483             char_type const *c_context_;
00484             char_type const *c_plural_;
00485             string_type id_;
00486             string_type context_;
00487             string_type plural_;
00488         };
00489 
00490 
00494         typedef basic_message<char> message;
00498         typedef basic_message<wchar_t> wmessage;
00499         #ifdef BOOSTER_HAS_CHAR16_T
00500 
00501 
00502 
00503         typedef basic_message<char16_t> u16message;
00504         #endif
00505         #ifdef BOOSTER_HAS_CHAR32_T
00506 
00507 
00508 
00509         typedef basic_message<char32_t> u32message;
00510         #endif
00511 
00515         template<typename CharType>
00516         std::basic_ostream<CharType> &operator<<(std::basic_ostream<CharType> &out,basic_message<CharType> const &msg)
00517         {
00518             msg.write(out);
00519             return out;
00520         }
00521 
00525 
00529         template<typename CharType>
00530         inline basic_message<CharType> translate(CharType const *msg)
00531         {
00532             return basic_message<CharType>(msg);
00533         }
00537         template<typename CharType>
00538         inline basic_message<CharType> translate(   CharType const *context,
00539                                                     CharType const *msg)
00540         {
00541             return basic_message<CharType>(context,msg);
00542         }
00546         template<typename CharType>
00547         inline basic_message<CharType> translate(   CharType const *single,
00548                                                     CharType const *plural,
00549                                                     int n)
00550         {
00551             return basic_message<CharType>(single,plural,n);
00552         }
00556         template<typename CharType>
00557         inline basic_message<CharType> translate(   CharType const *context,
00558                                                     CharType const *single,
00559                                                     CharType const *plural,
00560                                                     int n)
00561         {
00562             return basic_message<CharType>(context,single,plural,n);
00563         }
00564         
00568         template<typename CharType>
00569         inline basic_message<CharType> translate(std::basic_string<CharType> const &msg)
00570         {
00571             return basic_message<CharType>(msg);
00572         }
00573         
00577         template<typename CharType>
00578         inline basic_message<CharType> translate(   std::basic_string<CharType> const &context,
00579                                                     std::basic_string<CharType> const &msg)
00580         {
00581             return basic_message<CharType>(context,msg);
00582         }
00586         template<typename CharType>
00587         inline basic_message<CharType> translate(   std::basic_string<CharType> const &context,
00588                                                     std::basic_string<CharType> const &single,
00589                                                     std::basic_string<CharType> const &plural,
00590                                                     int n)
00591         {
00592             return basic_message<CharType>(context,single,plural,n);
00593         }
00594 
00598 
00599         template<typename CharType>
00600         inline basic_message<CharType> translate(   std::basic_string<CharType> const &single,
00601                                                     std::basic_string<CharType> const &plural,
00602                                                     int n)
00603         {
00604             return basic_message<CharType>(single,plural,n);
00605         }
00606 
00608 
00612 
00616         template<typename CharType>
00617         std::basic_string<CharType> gettext(CharType const *id,
00618                                             std::locale const &loc=std::locale())
00619         {
00620             return basic_message<CharType>(id).str(loc);
00621         }
00625         template<typename CharType>
00626         std::basic_string<CharType> ngettext(   CharType const *s,
00627                                                 CharType const *p,
00628                                                 int n,
00629                                                 std::locale const &loc=std::locale())
00630         {
00631             return basic_message<CharType>(s,p,n).str(loc);
00632         }
00636         template<typename CharType>
00637         std::basic_string<CharType>  dgettext(  char const *domain,
00638                                                 CharType const *id,
00639                                                 std::locale const &loc=std::locale())
00640         {
00641             return basic_message<CharType>(id).str(loc,domain);
00642         }
00643 
00647         template<typename CharType>
00648         std::basic_string<CharType>  dngettext( char const *domain,
00649                                                 CharType const *s,
00650                                                 CharType const *p,
00651                                                 int n,
00652                                                 std::locale const &loc=std::locale())
00653         {
00654             return basic_message<CharType>(s,p,n).str(loc,domain);
00655         }
00659         template<typename CharType>
00660         std::basic_string<CharType>  pgettext(  CharType const *context,
00661                                                 CharType const *id,
00662                                                 std::locale const &loc=std::locale())
00663         {
00664             return basic_message<CharType>(context,id).str(loc);
00665         }
00669         template<typename CharType>
00670         std::basic_string<CharType>  npgettext( CharType const *context,
00671                                                 CharType const *s,
00672                                                 CharType const *p,
00673                                                 int n,
00674                                                 std::locale const &loc=std::locale())
00675         {
00676             return basic_message<CharType>(context,s,p,n).str(loc);
00677         }
00681         template<typename CharType>
00682         std::basic_string<CharType>  dpgettext( char const *domain,
00683                                                 CharType const *context,
00684                                                 CharType const *id,
00685                                                 std::locale const &loc=std::locale())
00686         {
00687             return basic_message<CharType>(context,id).str(loc,domain);
00688         }
00692         template<typename CharType>
00693         std::basic_string<CharType>  dnpgettext(char const *domain,
00694                                                 CharType const *context,
00695                                                 CharType const *s,
00696                                                 CharType const *p,
00697                                                 int n,
00698                                                 std::locale const &loc=std::locale())
00699         {
00700             return basic_message<CharType>(context,s,p,n).str(loc,domain);
00701         }
00702 
00706         
00707         template<>
00708         struct BOOSTER_API base_message_format<char> : public std::locale::facet 
00709         {
00710             base_message_format(size_t refs = 0) : std::locale::facet(refs)
00711             {
00712             }
00713             static std::locale::id id;
00714         };
00715         
00716         template<>
00717         struct BOOSTER_API base_message_format<wchar_t> : public std::locale::facet 
00718         {
00719             base_message_format(size_t refs = 0) : std::locale::facet(refs)
00720             {
00721             }
00722             static std::locale::id id;
00723         };
00724         
00725         #ifdef BOOSTER_HAS_CHAR16_T
00726 
00727         template<>
00728         struct BOOSTER_API base_message_format<char16_t> : public std::locale::facet 
00729         {
00730             base_message_format(size_t refs = 0) : std::locale::facet(refs)
00731             {
00732             }
00733             static std::locale::id id;
00734         };
00735 
00736         #endif
00737 
00738         #ifdef BOOSTER_HAS_CHAR32_T
00739 
00740         template<>
00741         struct BOOSTER_API base_message_format<char32_t> : public std::locale::facet 
00742         {
00743             base_message_format(size_t refs = 0) : std::locale::facet(refs)
00744             {
00745             }
00746             static std::locale::id id;
00747         };
00748         
00749         #endif
00750 
00752 
00756 
00757         namespace as {
00759             namespace details {
00760                 struct set_domain {
00761                     std::string domain_id;
00762                 };
00763                 template<typename CharType>
00764                 std::basic_ostream<CharType> &operator<<(std::basic_ostream<CharType> &out, set_domain const &dom)
00765                 {
00766                     int id = std::use_facet<message_format<CharType> >(out.getloc()).domain(dom.domain_id);
00767                     ios_info::get(out).domain_id(id);
00768                     return out;
00769                 }
00770             } // details
00772 
00777             
00783             inline 
00784             #ifdef BOOSTER_LOCALE_DOXYGEN
00785             unspecified_type
00786             #else
00787             details::set_domain 
00788             #endif
00789             domain(std::string const &id)
00790             {
00791                 details::set_domain tmp = { id };
00792                 return tmp;
00793             }
00795         } // as
00796     } // locale 
00797 } // boost
00798 
00799 #ifdef BOOSTER_MSVC
00800 #pragma warning(pop)
00801 #endif
00802 
00803 
00804 #endif
00805 
00806 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
00807