Boost.Locale
message.hpp
1 //
2 // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
3 //
4 // Distributed under the Boost Software License, Version 1.0.
5 // https://www.boost.org/LICENSE_1_0.txt
6 
7 #ifndef BOOST_LOCALE_MESSAGE_HPP_INCLUDED
8 #define BOOST_LOCALE_MESSAGE_HPP_INCLUDED
9 
10 #include <boost/locale/formatting.hpp>
11 #include <locale>
12 #include <memory>
13 #include <set>
14 #include <string>
15 
16 #ifdef BOOST_MSVC
17 # pragma warning(push)
18 # pragma warning(disable : 4275 4251 4231 4660)
19 #endif
20 
21 // glibc < 2.3.4 declares those as macros if compiled with optimization turned on
22 #ifdef gettext
23 # undef gettext
24 # undef ngettext
25 # undef dgettext
26 # undef dngettext
27 #endif
28 
29 namespace boost {
30  namespace locale {
38 
40 
41  template<typename CharType>
42  struct base_message_format;
43 
45 
49  template<typename CharType>
50  class BOOST_SYMBOL_VISIBLE message_format : public base_message_format<CharType>
51  {
52  public:
53 
57  typedef CharType char_type;
61  typedef std::basic_string<CharType> string_type;
62 
66  message_format(size_t refs = 0): base_message_format<CharType>(refs) {}
67 
78  virtual char_type const *get(int domain_id,char_type const *context,char_type const *id) const = 0;
92  virtual char_type const *get(int domain_id,char_type const *context,char_type const *single_id,int n) const = 0;
93 
97  virtual int domain(std::string const &domain) const = 0;
98 
107  virtual char_type const *convert(char_type const *msg,string_type &buffer) const = 0;
108 
109 #if defined (__SUNPRO_CC) && defined (_RWSTD_VER)
110  std::locale::id& __get_id (void) const { return id; }
111 #endif
112  protected:
113  virtual ~message_format() {}
114  };
115 
117 
118  namespace details {
119  inline bool is_us_ascii_char(char c)
120  {
121  // works for null terminated strings regardless char "signness"
122  return 0<c && c<0x7F;
123  }
124  inline bool is_us_ascii_string(char const *msg)
125  {
126  while(*msg) {
127  if(!is_us_ascii_char(*msg++))
128  return false;
129  }
130  return true;
131  }
132 
133  template<typename CharType>
134  struct string_cast_traits {
135  static CharType const *cast(CharType const *msg,std::basic_string<CharType> &/*unused*/)
136  {
137  return msg;
138  }
139  };
140 
141  template<>
142  struct string_cast_traits<char> {
143  static char const *cast(char const *msg,std::string &buffer)
144  {
145  if(is_us_ascii_string(msg))
146  return msg;
147  buffer.reserve(strlen(msg));
148  char c;
149  while((c=*msg++)!=0) {
150  if(is_us_ascii_char(c))
151  buffer+=c;
152  }
153  return buffer.c_str();
154  }
155  };
156  } // details
157 
159 
167  template<typename CharType>
169  public:
170 
171  typedef CharType char_type;
172  typedef std::basic_string<char_type> string_type;
174 
178  basic_message(): n_(0), c_id_(0), c_context_(0), c_plural_(0) {}
179 
184  explicit basic_message(char_type const *id): n_(0), c_id_(id), c_context_(0), c_plural_(0) {}
185 
192  explicit basic_message(char_type const *single,char_type const *plural,int n):
193  n_(n),
194  c_id_(single),
195  c_context_(0),
196  c_plural_(plural)
197  {}
198 
204  explicit basic_message(char_type const *context,char_type const *id):
205  n_(0),
206  c_id_(id),
207  c_context_(context),
208  c_plural_(0)
209  {}
210 
217  explicit basic_message(char_type const *context,char_type const *single,char_type const *plural,int n):
218  n_(n),
219  c_id_(single),
220  c_context_(context),
221  c_plural_(plural)
222  {}
223 
224 
228  explicit basic_message(string_type const &id):
229  n_(0),
230  c_id_(0),
231  c_context_(0),
232  c_plural_(0),
233  id_(id)
234  {}
235 
241  explicit basic_message(string_type const &single,string_type const &plural,int number):
242  n_(number),
243  c_id_(0),
244  c_context_(0),
245  c_plural_(0),
246  id_(single),
247  plural_(plural)
248  {}
249 
253  explicit basic_message(string_type const &context,string_type const &id):
254  n_(0),
255  c_id_(0),
256  c_context_(0),
257  c_plural_(0),
258  id_(id),
259  context_(context)
260  {}
261 
267  explicit basic_message(string_type const &context,string_type const &single,string_type const &plural,int number):
268  n_(number),
269  c_id_(0),
270  c_context_(0),
271  c_plural_(0),
272  id_(single),
273  context_(context),
274  plural_(plural)
275  {}
276 
281  n_(other.n_),
282  c_id_(other.c_id_),
283  c_context_(other.c_context_),
284  c_plural_(other.c_plural_),
285  id_(other.id_),
286  context_(other.context_),
287  plural_(other.plural_)
288  {}
289 
294  {
295  swap(other);
296  return *this;
297  }
298 
302  void swap(basic_message &other)
303  {
304  std::swap(n_,other.n_);
305  std::swap(c_id_,other.c_id_);
306  std::swap(c_context_,other.c_context_);
307  std::swap(c_plural_,other.c_plural_);
308 
309  id_.swap(other.id_);
310  context_.swap(other.context_);
311  plural_.swap(other.plural_);
312  }
313 
317 
318  operator string_type () const
319  {
320  return str();
321  }
322 
326  string_type str() const
327  {
328  std::locale loc;
329  return str(loc,0);
330  }
331 
335  string_type str(std::locale const &locale) const
336  {
337  return str(locale,0);
338  }
339 
343  string_type str(std::locale const &locale,std::string const &domain_id) const
344  {
345  int id=0;
346  if(std::has_facet<facet_type>(locale))
347  id=std::use_facet<facet_type>(locale).domain(domain_id);
348  return str(locale,id);
349  }
350 
354  string_type str(std::string const &domain_id) const
355  {
356  int id=0;
357  std::locale loc;
358  if(std::has_facet<facet_type>(loc))
359  id=std::use_facet<facet_type>(loc).domain(domain_id);
360  return str(loc,id);
361  }
362 
363 
367  string_type str(std::locale const &loc,int id) const
368  {
369  string_type buffer;
370  char_type const *ptr = write(loc,id,buffer);
371  if(ptr == buffer.c_str())
372  return buffer;
373  else
374  buffer = ptr;
375  return buffer;
376  }
377 
378 
383  void write(std::basic_ostream<char_type> &out) const
384  {
385  std::locale const &loc = out.getloc();
386  int id = ios_info::get(out).domain_id();
387  string_type buffer;
388  out << write(loc,id,buffer);
389  }
390 
391  private:
392  char_type const *plural() const
393  {
394  if(c_plural_)
395  return c_plural_;
396  if(plural_.empty())
397  return 0;
398  return plural_.c_str();
399  }
400  char_type const *context() const
401  {
402  if(c_context_)
403  return c_context_;
404  if(context_.empty())
405  return 0;
406  return context_.c_str();
407  }
408 
409  char_type const *id() const
410  {
411  return c_id_ ? c_id_ : id_.c_str();
412  }
413 
414  char_type const *write(std::locale const &loc,int domain_id,string_type &buffer) const
415  {
416  char_type const *translated = 0;
417  static const char_type empty_string[1] = {0};
418 
419  char_type const *id = this->id();
420  char_type const *context = this->context();
421  char_type const *plural = this->plural();
422 
423  if(*id == 0)
424  return empty_string;
425 
426  facet_type const *facet = 0;
427  if(std::has_facet<facet_type>(loc))
428  facet = &std::use_facet<facet_type>(loc);
429 
430  if(facet) {
431  if(!plural) {
432  translated = facet->get(domain_id,context,id);
433  }
434  else {
435  translated = facet->get(domain_id,context,id,n_);
436  }
437  }
438 
439  if(!translated) {
440  char_type const *msg = plural ? ( n_ == 1 ? id : plural): id;
441 
442  if(facet) {
443  translated = facet->convert(msg,buffer);
444  }
445  else {
446  translated = details::string_cast_traits<char_type>::cast(msg,buffer);
447  }
448  }
449  return translated;
450  }
451 
453 
454  int n_;
455  char_type const *c_id_;
456  char_type const *c_context_;
457  char_type const *c_plural_;
458  string_type id_;
459  string_type context_;
460  string_type plural_;
461  };
462 
463 
472  #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
477  #endif
478  #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
483  #endif
484 
488  template<typename CharType>
489  std::basic_ostream<CharType>& operator<<(std::basic_ostream<CharType> &out,basic_message<CharType> const &msg)
490  {
491  msg.write(out);
492  return out;
493  }
494 
498 
502  template<typename CharType>
503  inline basic_message<CharType> translate(CharType const *msg)
504  {
505  return basic_message<CharType>(msg);
506  }
510  template<typename CharType>
511  inline basic_message<CharType> translate( CharType const *context,
512  CharType const *msg)
513  {
514  return basic_message<CharType>(context,msg);
515  }
519  template<typename CharType>
520  inline basic_message<CharType> translate( CharType const *single,
521  CharType const *plural,
522  int n)
523  {
524  return basic_message<CharType>(single,plural,n);
525  }
529  template<typename CharType>
530  inline basic_message<CharType> translate( CharType const *context,
531  CharType const *single,
532  CharType const *plural,
533  int n)
534  {
535  return basic_message<CharType>(context,single,plural,n);
536  }
537 
541  template<typename CharType>
542  inline basic_message<CharType> translate(std::basic_string<CharType> const &msg)
543  {
544  return basic_message<CharType>(msg);
545  }
546 
550  template<typename CharType>
551  inline basic_message<CharType> translate( std::basic_string<CharType> const &context,
552  std::basic_string<CharType> const &msg)
553  {
554  return basic_message<CharType>(context,msg);
555  }
559  template<typename CharType>
560  inline basic_message<CharType> translate( std::basic_string<CharType> const &context,
561  std::basic_string<CharType> const &single,
562  std::basic_string<CharType> const &plural,
563  int n)
564  {
565  return basic_message<CharType>(context,single,plural,n);
566  }
567 
571 
572  template<typename CharType>
573  inline basic_message<CharType> translate( std::basic_string<CharType> const &single,
574  std::basic_string<CharType> const &plural,
575  int n)
576  {
577  return basic_message<CharType>(single,plural,n);
578  }
579 
581 
585 
589  template<typename CharType>
590  std::basic_string<CharType> gettext(CharType const *id,
591  std::locale const &loc=std::locale())
592  {
593  return basic_message<CharType>(id).str(loc);
594  }
598  template<typename CharType>
599  std::basic_string<CharType> ngettext( CharType const *s,
600  CharType const *p,
601  int n,
602  std::locale const &loc=std::locale())
603  {
604  return basic_message<CharType>(s,p,n).str(loc);
605  }
609  template<typename CharType>
610  std::basic_string<CharType> dgettext( char const *domain,
611  CharType const *id,
612  std::locale const &loc=std::locale())
613  {
614  return basic_message<CharType>(id).str(loc,domain);
615  }
616 
620  template<typename CharType>
621  std::basic_string<CharType> dngettext( char const *domain,
622  CharType const *s,
623  CharType const *p,
624  int n,
625  std::locale const &loc=std::locale())
626  {
627  return basic_message<CharType>(s,p,n).str(loc,domain);
628  }
632  template<typename CharType>
633  std::basic_string<CharType> pgettext( CharType const *context,
634  CharType const *id,
635  std::locale const &loc=std::locale())
636  {
637  return basic_message<CharType>(context,id).str(loc);
638  }
642  template<typename CharType>
643  std::basic_string<CharType> npgettext( CharType const *context,
644  CharType const *s,
645  CharType const *p,
646  int n,
647  std::locale const &loc=std::locale())
648  {
649  return basic_message<CharType>(context,s,p,n).str(loc);
650  }
654  template<typename CharType>
655  std::basic_string<CharType> dpgettext( char const *domain,
656  CharType const *context,
657  CharType const *id,
658  std::locale const &loc=std::locale())
659  {
660  return basic_message<CharType>(context,id).str(loc,domain);
661  }
665  template<typename CharType>
666  std::basic_string<CharType> dnpgettext(char const *domain,
667  CharType const *context,
668  CharType const *s,
669  CharType const *p,
670  int n,
671  std::locale const &loc=std::locale())
672  {
673  return basic_message<CharType>(context,s,p,n).str(loc,domain);
674  }
675 
679 
680  template<>
681  struct BOOST_LOCALE_DECL base_message_format<char> : public std::locale::facet
682  {
683  base_message_format(size_t refs = 0): std::locale::facet(refs) {}
684  static std::locale::id id;
685  };
686 
687  template<>
688  struct BOOST_LOCALE_DECL base_message_format<wchar_t> : public std::locale::facet
689  {
690  base_message_format(size_t refs = 0): std::locale::facet(refs) {}
691  static std::locale::id id;
692  };
693 
694  #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
695 
696  template<>
697  struct BOOST_LOCALE_DECL base_message_format<char16_t> : public std::locale::facet
698  {
699  base_message_format(size_t refs = 0): std::locale::facet(refs) {}
700  static std::locale::id id;
701  };
702 
703  #endif
704 
705  #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
706 
707  template<>
708  struct BOOST_LOCALE_DECL base_message_format<char32_t> : public std::locale::facet
709  {
710  base_message_format(size_t refs = 0): std::locale::facet(refs) {}
711  static std::locale::id id;
712  };
713 
714  #endif
715 
717 
721 
722  namespace as {
724  namespace details {
725  struct set_domain {
726  std::string domain_id;
727  };
728  template<typename CharType>
729  std::basic_ostream<CharType>& operator<<(std::basic_ostream<CharType> &out, set_domain const &dom)
730  {
731  int id = std::use_facet<message_format<CharType> >(out.getloc()).domain(dom.domain_id);
732  ios_info::get(out).domain_id(id);
733  return out;
734  }
735  } // details
737 
742 
748  inline
749  #ifdef BOOST_LOCALE_DOXYGEN
750  unspecified_type
751  #else
752  details::set_domain
753  #endif
754  domain(std::string const &id)
755  {
756  details::set_domain tmp = { id };
757  return tmp;
758  }
760  } // as
761  } // locale
762 } // boost
763 
764 #ifdef BOOST_MSVC
765 #pragma warning(pop)
766 #endif
767 
768 
769 #endif
770 
771 
std::basic_string< CharType > ngettext(CharType const *s, CharType const *p, int n, std::locale const &loc=std::locale())
Definition: message.hpp:599
message_format(size_t refs=0)
Definition: message.hpp:66
basic_message(char_type const *context, char_type const *id)
Definition: message.hpp:204
string_type str(std::string const &domain_id) const
Definition: message.hpp:354
basic_message(string_type const &id)
Definition: message.hpp:228
CharType char_type
The character this message object is used with.
Definition: message.hpp:171
basic_message(string_type const &context, string_type const &id)
Definition: message.hpp:253
std::basic_string< char_type > string_type
The string type this object can be used with.
Definition: message.hpp:172
void swap(basic_message &other)
Definition: message.hpp:302
basic_message(char_type const *id)
Definition: message.hpp:184
basic_message< wchar_t > wmessage
Definition: message.hpp:471
This class represents a message that can be converted to a specific locale message.
Definition: message.hpp:168
std::basic_string< CharType > npgettext(CharType const *context, CharType const *s, CharType const *p, int n, std::locale const &loc=std::locale())
Definition: message.hpp:643
basic_message< char32_t > u32message
Definition: message.hpp:482
string_type str() const
Definition: message.hpp:326
This facet provides message formatting abilities.
Definition: message.hpp:50
string_type str(std::locale const &loc, int id) const
Definition: message.hpp:367
std::basic_string< CharType > dnpgettext(char const *domain, CharType const *context, CharType const *s, CharType const *p, int n, std::locale const &loc=std::locale())
Definition: message.hpp:666
std::ios_base & number(std::ios_base &ios)
Definition: formatting.hpp:292
CharType char_type
Definition: message.hpp:57
basic_message< char > message
Definition: message.hpp:467
basic_message(string_type const &single, string_type const &plural, int number)
Definition: message.hpp:241
static ios_info & get(std::ios_base &ios)
basic_message()
Definition: message.hpp:178
std::basic_string< CharType > dgettext(char const *domain, CharType const *id, std::locale const &loc=std::locale())
Definition: message.hpp:610
basic_message< CharType > translate(CharType const *msg)
Translate a message, msg is not copied.
Definition: message.hpp:503
unspecified_type domain(std::string const &id)
Definition: message.hpp:754
std::basic_string< CharType > pgettext(CharType const *context, CharType const *id, std::locale const &loc=std::locale())
Definition: message.hpp:633
basic_message(string_type const &context, string_type const &single, string_type const &plural, int number)
Definition: message.hpp:267
std::basic_string< CharType > dpgettext(char const *domain, CharType const *context, CharType const *id, std::locale const &loc=std::locale())
Definition: message.hpp:655
string_type str(std::locale const &locale, std::string const &domain_id) const
Definition: message.hpp:343
void write(std::basic_ostream< char_type > &out) const
Definition: message.hpp:383
basic_message< char16_t > u16message
Definition: message.hpp:476
std::basic_string< CharType > gettext(CharType const *id, std::locale const &loc=std::locale())
Definition: message.hpp:590
basic_message(char_type const *single, char_type const *plural, int n)
Definition: message.hpp:192
basic_message & operator=(basic_message other)
Definition: message.hpp:293
std::basic_ostream< CharType > & operator<<(std::basic_ostream< CharType > &out, date_time const &t)
Definition: date_time.hpp:869
basic_message(char_type const *context, char_type const *single, char_type const *plural, int n)
Definition: message.hpp:217
std::basic_string< CharType > string_type
Definition: message.hpp:61
string_type str(std::locale const &locale) const
Definition: message.hpp:335
message_format< char_type > facet_type
The type of the facet the messages are fetched with.
Definition: message.hpp:173
std::basic_string< CharType > dngettext(char const *domain, CharType const *s, CharType const *p, int n, std::locale const &loc=std::locale())
Definition: message.hpp:621
Domain code - for message formatting.
Definition: formatting.hpp:86
basic_message(basic_message const &other)
Definition: message.hpp:280