00001
00002
00003
00004
00005
00006
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
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> &)
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 }
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 }
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 }
00796 }
00797 }
00798
00799 #ifdef BOOSTER_MSVC
00800 #pragma warning(pop)
00801 #endif
00802
00803
00804 #endif
00805
00806
00807