CppCMS
|
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