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 <boost/locale/util/string.hpp>
12 #include <locale>
13 #include <memory>
14 #include <set>
15 #include <string>
16 
17 #ifdef BOOST_MSVC
18 # pragma warning(push)
19 # pragma warning(disable : 4275 4251 4231 4660)
20 #endif
21 
22 // glibc < 2.3.4 declares those as macros if compiled with optimization turned on
23 #ifdef gettext
24 # undef gettext
25 # undef ngettext
26 # undef dgettext
27 # undef dngettext
28 #endif
29 
30 namespace boost { namespace locale {
38 
40 
41  template<typename CharType>
42  struct base_message_format;
43 
45 
47  template<typename CharType>
48  class BOOST_SYMBOL_VISIBLE message_format : public base_message_format<CharType> {
49  public:
51  typedef CharType char_type;
53  typedef std::basic_string<CharType> string_type;
54 
56  message_format(size_t refs = 0) : base_message_format<CharType>(refs) {}
57 
65  virtual const char_type* get(int domain_id, const char_type* context, const char_type* id) const = 0;
66 
77  virtual const char_type*
78  get(int domain_id, const char_type* context, const char_type* single_id, int n) const = 0;
79 
81  virtual int domain(const std::string& domain) const = 0;
82 
89  virtual const char_type* convert(const char_type* msg, string_type& buffer) const = 0;
90 
91  protected:
92  virtual ~message_format() = default;
93  };
94 
96 
97  namespace detail {
98  inline bool is_us_ascii_char(char c)
99  {
100  // works for null terminated strings regardless char "signedness"
101  return 0 < c && c < 0x7F;
102  }
103  inline bool is_us_ascii_string(const char* msg)
104  {
105  while(*msg) {
106  if(!is_us_ascii_char(*msg++))
107  return false;
108  }
109  return true;
110  }
111 
112  template<typename CharType>
113  struct string_cast_traits {
114  static const CharType* cast(const CharType* msg, std::basic_string<CharType>& /*unused*/) { return msg; }
115  };
116 
117  template<>
118  struct string_cast_traits<char> {
119  static const char* cast(const char* msg, std::string& buffer)
120  {
121  if(is_us_ascii_string(msg))
122  return msg;
123  buffer.reserve(strlen(msg));
124  char c;
125  while((c = *msg++) != 0) {
126  if(is_us_ascii_char(c))
127  buffer += c;
128  }
129  return buffer.c_str();
130  }
131  };
132  } // namespace detail
133 
135 
141  template<typename CharType>
143  public:
144  typedef CharType char_type;
145  typedef std::basic_string<char_type> string_type;
147 
149  basic_message() : n_(0), c_id_(0), c_context_(0), c_plural_(0) {}
150 
153  explicit basic_message(const char_type* id) : n_(0), c_id_(id), c_context_(0), c_plural_(0) {}
154 
159  explicit basic_message(const char_type* single, const char_type* plural, int n) :
160  n_(n), c_id_(single), c_context_(0), c_plural_(plural)
161  {}
162 
166  explicit basic_message(const char_type* context, const char_type* id) :
167  n_(0), c_id_(id), c_context_(context), c_plural_(0)
168  {}
169 
174  explicit basic_message(const char_type* context, const char_type* single, const char_type* plural, int n) :
175  n_(n), c_id_(single), c_context_(context), c_plural_(plural)
176  {}
177 
179  explicit basic_message(const string_type& id) : n_(0), c_id_(0), c_context_(0), c_plural_(0), id_(id) {}
180 
184  explicit basic_message(const string_type& single, const string_type& plural, int number) :
185  n_(number), c_id_(0), c_context_(0), c_plural_(0), id_(single), plural_(plural)
186  {}
187 
189  explicit basic_message(const string_type& context, const string_type& id) :
190  n_(0), c_id_(0), c_context_(0), c_plural_(0), id_(id), context_(context)
191  {}
192 
196  explicit basic_message(const string_type& context,
197  const string_type& single,
198  const string_type& plural,
199  int number) :
200  n_(number),
201  c_id_(0), c_context_(0), c_plural_(0), id_(single), context_(context), plural_(plural)
202  {}
203 
205  basic_message(const basic_message& other) = default;
206  basic_message(basic_message&& other) = default;
207 
209  basic_message& operator=(const basic_message& other) = default;
210  basic_message& operator=(basic_message&& other) = default;
211 
213  void swap(basic_message& other)
214  {
215  std::swap(n_, other.n_);
216  std::swap(c_id_, other.c_id_);
217  std::swap(c_context_, other.c_context_);
218  std::swap(c_plural_, other.c_plural_);
219 
220  id_.swap(other.id_);
221  context_.swap(other.context_);
222  plural_.swap(other.plural_);
223  }
224 
226  operator string_type() const { return str(); }
227 
229  string_type str() const
230  {
231  std::locale loc;
232  return str(loc, 0);
233  }
234 
236  string_type str(const std::locale& locale) const { return str(locale, 0); }
237 
239  string_type str(const std::locale& locale, const std::string& domain_id) const
240  {
241  int id = 0;
242  if(std::has_facet<facet_type>(locale))
243  id = std::use_facet<facet_type>(locale).domain(domain_id);
244  return str(locale, id);
245  }
246 
248  string_type str(const std::string& domain_id) const
249  {
250  int id = 0;
251  std::locale loc;
252  if(std::has_facet<facet_type>(loc))
253  id = std::use_facet<facet_type>(loc).domain(domain_id);
254  return str(loc, id);
255  }
256 
258  string_type str(const std::locale& loc, int id) const
259  {
260  string_type buffer;
261  const char_type* ptr = write(loc, id, buffer);
262  if(ptr == buffer.c_str())
263  return buffer;
264  else
265  buffer = ptr;
266  return buffer;
267  }
268 
271  void write(std::basic_ostream<char_type>& out) const
272  {
273  const std::locale& loc = out.getloc();
274  int id = ios_info::get(out).domain_id();
275  string_type buffer;
276  out << write(loc, id, buffer);
277  }
278 
279  private:
280  const char_type* plural() const
281  {
282  if(c_plural_)
283  return c_plural_;
284  if(plural_.empty())
285  return 0;
286  return plural_.c_str();
287  }
288  const char_type* context() const
289  {
290  if(c_context_)
291  return c_context_;
292  if(context_.empty())
293  return 0;
294  return context_.c_str();
295  }
296 
297  const char_type* id() const { return c_id_ ? c_id_ : id_.c_str(); }
298 
299  const char_type* write(const std::locale& loc, int domain_id, string_type& buffer) const
300  {
301  const char_type* translated = 0;
302  static const char_type empty_string[1] = {0};
303 
304  const char_type* id = this->id();
305  const char_type* context = this->context();
306  const char_type* plural = this->plural();
307 
308  if(*id == 0)
309  return empty_string;
310 
311  const facet_type* facet = 0;
312  if(std::has_facet<facet_type>(loc))
313  facet = &std::use_facet<facet_type>(loc);
314 
315  if(facet) {
316  if(!plural) {
317  translated = facet->get(domain_id, context, id);
318  } else {
319  translated = facet->get(domain_id, context, id, n_);
320  }
321  }
322 
323  if(!translated) {
324  const char_type* msg = plural ? (n_ == 1 ? id : plural) : id;
325 
326  if(facet) {
327  translated = facet->convert(msg, buffer);
328  } else {
329  translated = detail::string_cast_traits<char_type>::cast(msg, buffer);
330  }
331  }
332  return translated;
333  }
334 
336 
337  int n_;
338  const char_type* c_id_;
339  const char_type* c_context_;
340  const char_type* c_plural_;
341  string_type id_;
342  string_type context_;
343  string_type plural_;
344  };
345 
350 #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
353 #endif
354 #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
357 #endif
358 
360  template<typename CharType>
361  std::basic_ostream<CharType>& operator<<(std::basic_ostream<CharType>& out, const basic_message<CharType>& msg)
362  {
363  msg.write(out);
364  return out;
365  }
366 
369 
371  template<typename CharType>
372  inline basic_message<CharType> translate(const CharType* msg)
373  {
374  return basic_message<CharType>(msg);
375  }
376 
378  template<typename CharType>
379  inline basic_message<CharType> translate(const CharType* context, const CharType* msg)
380  {
381  return basic_message<CharType>(context, msg);
382  }
383 
385  template<typename CharType>
386  inline basic_message<CharType> translate(const CharType* single, const CharType* plural, int n)
387  {
388  return basic_message<CharType>(single, plural, n);
389  }
390 
392  template<typename CharType>
393  inline basic_message<CharType>
394  translate(const CharType* context, const CharType* single, const CharType* plural, int n)
395  {
396  return basic_message<CharType>(context, single, plural, n);
397  }
398 
400  template<typename CharType>
401  inline basic_message<CharType> translate(const std::basic_string<CharType>& msg)
402  {
403  return basic_message<CharType>(msg);
404  }
405 
407  template<typename CharType>
408  inline basic_message<CharType> translate(const std::basic_string<CharType>& context,
409  const std::basic_string<CharType>& msg)
410  {
411  return basic_message<CharType>(context, msg);
412  }
413 
415  template<typename CharType>
416  inline basic_message<CharType> translate(const std::basic_string<CharType>& context,
417  const std::basic_string<CharType>& single,
418  const std::basic_string<CharType>& plural,
419  int n)
420  {
421  return basic_message<CharType>(context, single, plural, n);
422  }
423 
425  template<typename CharType>
426  inline basic_message<CharType>
427  translate(const std::basic_string<CharType>& single, const std::basic_string<CharType>& plural, int n)
428  {
429  return basic_message<CharType>(single, plural, n);
430  }
431 
433 
435 
437  template<typename CharType>
438  std::basic_string<CharType> gettext(const CharType* id, const std::locale& loc = std::locale())
439  {
440  return basic_message<CharType>(id).str(loc);
441  }
443  template<typename CharType>
444  std::basic_string<CharType>
445  ngettext(const CharType* s, const CharType* p, int n, const std::locale& loc = std::locale())
446  {
447  return basic_message<CharType>(s, p, n).str(loc);
448  }
449 
451  template<typename CharType>
452  std::basic_string<CharType> dgettext(const char* domain, const CharType* id, const std::locale& loc = std::locale())
453  {
454  return basic_message<CharType>(id).str(loc, domain);
455  }
456 
458  template<typename CharType>
459  std::basic_string<CharType>
460  dngettext(const char* domain, const CharType* s, const CharType* p, int n, const std::locale& loc = std::locale())
461  {
462  return basic_message<CharType>(s, p, n).str(loc, domain);
463  }
464 
466  template<typename CharType>
467  std::basic_string<CharType>
468  pgettext(const CharType* context, const CharType* id, const std::locale& loc = std::locale())
469  {
470  return basic_message<CharType>(context, id).str(loc);
471  }
472 
474  template<typename CharType>
475  std::basic_string<CharType> npgettext(const CharType* context,
476  const CharType* s,
477  const CharType* p,
478  int n,
479  const std::locale& loc = std::locale())
480  {
481  return basic_message<CharType>(context, s, p, n).str(loc);
482  }
483 
485  template<typename CharType>
486  std::basic_string<CharType>
487  dpgettext(const char* domain, const CharType* context, const CharType* id, const std::locale& loc = std::locale())
488  {
489  return basic_message<CharType>(context, id).str(loc, domain);
490  }
491 
493  template<typename CharType>
494  std::basic_string<CharType> dnpgettext(const char* domain,
495  const CharType* context,
496  const CharType* s,
497  const CharType* p,
498  int n,
499  const std::locale& loc = std::locale())
500  {
501  return basic_message<CharType>(context, s, p, n).str(loc, domain);
502  }
503 
505 
506  template<>
507  struct BOOST_LOCALE_DECL base_message_format<char> : public std::locale::facet {
508  base_message_format(size_t refs = 0) : std::locale::facet(refs) {}
509  ~base_message_format();
510  static std::locale::id id;
511  };
512 
513  template<>
514  struct BOOST_LOCALE_DECL base_message_format<wchar_t> : public std::locale::facet {
515  base_message_format(size_t refs = 0) : std::locale::facet(refs) {}
516  ~base_message_format();
517  static std::locale::id id;
518  };
519 
520 #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
521 
522  template<>
523  struct BOOST_LOCALE_DECL base_message_format<char16_t> : public std::locale::facet {
524  base_message_format(size_t refs = 0) : std::locale::facet(refs) {}
525  ~base_message_format();
526  static std::locale::id id;
527  };
528 
529 #endif
530 
531 #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
532 
533  template<>
534  struct BOOST_LOCALE_DECL base_message_format<char32_t> : public std::locale::facet {
535  base_message_format(size_t refs = 0) : std::locale::facet(refs) {}
536  ~base_message_format();
537  static std::locale::id id;
538  };
539 
540 #endif
541 
544 
545  namespace as {
547  namespace detail {
548  struct set_domain {
549  std::string domain_id;
550  };
551  template<typename CharType>
552  std::basic_ostream<CharType>& operator<<(std::basic_ostream<CharType>& out, const set_domain& dom)
553  {
554  int id = std::use_facet<message_format<CharType>>(out.getloc()).domain(dom.domain_id);
555  ios_info::get(out).domain_id(id);
556  return out;
557  }
558  } // namespace detail
560 
564 
569  inline
570 #ifdef BOOST_LOCALE_DOXYGEN
571  unspecified_type
572 #else
573  detail::set_domain
574 #endif
575  domain(const std::string& id)
576  {
577  detail::set_domain tmp = {id};
578  return tmp;
579  }
581  } // namespace as
582 }} // namespace boost::locale
583 
584 #ifdef BOOST_MSVC
585 # pragma warning(pop)
586 #endif
587 
588 #endif
basic_message< CharType > translate(const CharType *msg)
Translate a message, msg is not copied.
Definition: message.hpp:372
message_format(size_t refs=0)
Default constructor.
Definition: message.hpp:56
string_type str(const std::locale &locale, const std::string &domain_id) const
Translate message to a string using locale locale and message domain domain_id.
Definition: message.hpp:239
std::basic_string< CharType > npgettext(const CharType *context, const CharType *s, const CharType *p, int n, const std::locale &loc=std::locale())
Translate plural form according to locale loc in context context.
Definition: message.hpp:475
std::basic_string< CharType > ngettext(const CharType *s, const CharType *p, int n, const std::locale &loc=std::locale())
Translate plural form according to locale loc.
Definition: message.hpp:445
string_type str(const std::locale &loc, int id) const
Translate message to a string using locale loc and message domain index id.
Definition: message.hpp:258
basic_message(const char_type *context, const char_type *single, const char_type *plural, int n)
Definition: message.hpp:174
CharType char_type
The character this message object is used with.
Definition: message.hpp:144
basic_message & operator=(const basic_message &other)=default
Assign other message object to this one.
basic_message(const string_type &context, const string_type &single, const string_type &plural, int number)
Definition: message.hpp:196
std::basic_string< char_type > string_type
The string type this object can be used with.
Definition: message.hpp:145
void swap(basic_message &other)
Swap two message objects.
Definition: message.hpp:213
basic_message< wchar_t > wmessage
Convenience typedef for wchar_t.
Definition: message.hpp:349
std::basic_string< CharType > pgettext(const CharType *context, const CharType *id, const std::locale &loc=std::locale())
Translate message id according to locale loc in context context.
Definition: message.hpp:468
This class represents a message that can be converted to a specific locale message.
Definition: message.hpp:142
basic_message< char32_t > u32message
Convenience typedef for char32_t.
Definition: message.hpp:356
string_type str() const
Translate message to a string in the default global locale, using default domain.
Definition: message.hpp:229
This facet provides message formatting abilities.
Definition: message.hpp:48
std::basic_string< CharType > dpgettext(const char *domain, const CharType *context, const CharType *id, const std::locale &loc=std::locale())
Translate message id according to locale loc in domain domain in context context.
Definition: message.hpp:487
Generate conversion facets.
std::ios_base & number(std::ios_base &ios)
Definition: formatting.hpp:211
CharType char_type
Character type.
Definition: message.hpp:51
basic_message< char > message
Convenience typedef for char.
Definition: message.hpp:347
basic_message(const char_type *single, const char_type *plural, int n)
Definition: message.hpp:159
unspecified_type domain(const std::string &id)
Definition: message.hpp:575
static ios_info & get(std::ios_base &ios)
Get ios_info instance for specific stream object.
basic_message()
Create default empty message.
Definition: message.hpp:149
void write(std::basic_ostream< char_type > &out) const
Definition: message.hpp:271
std::basic_ostream< CharType > & operator<<(std::basic_ostream< CharType > &out, const date_time &t)
Definition: date_time.hpp:719
void domain_id(int)
Set special message domain identification.
basic_message< char16_t > u16message
Convenience typedef for char16_t.
Definition: message.hpp:352
std::basic_string< CharType > string_type
String type.
Definition: message.hpp:53
std::basic_string< CharType > dngettext(const char *domain, const CharType *s, const CharType *p, int n, const std::locale &loc=std::locale())
Translate plural form according to locale loc in domain domain.
Definition: message.hpp:460
basic_message(const string_type &single, const string_type &plural, int number)
Definition: message.hpp:184
message_format< char_type > facet_type
The type of the facet the messages are fetched with.
Definition: message.hpp:146
std::basic_string< CharType > dgettext(const char *domain, const CharType *id, const std::locale &loc=std::locale())
Translate message id according to locale loc in domain domain.
Definition: message.hpp:452
basic_message(const char_type *context, const char_type *id)
Definition: message.hpp:166
string_type str(const std::string &domain_id) const
Translate message to a string using the default locale and message domain domain_id.
Definition: message.hpp:248
basic_message(const string_type &context, const string_type &id)
Create a simple message from a string with context.
Definition: message.hpp:189
std::basic_string< CharType > dnpgettext(const char *domain, const CharType *context, const CharType *s, const CharType *p, int n, const std::locale &loc=std::locale())
Translate plural form according to locale loc in domain domain in context context.
Definition: message.hpp:494
Domain code - for message formatting.
Definition: formatting.hpp:77
string_type str(const std::locale &locale) const
Translate message to a string in the locale locale, using default domain.
Definition: message.hpp:236
basic_message(const char_type *id)
Definition: message.hpp:153
basic_message(const string_type &id)
Create a simple message from a string.
Definition: message.hpp:179
std::basic_string< CharType > gettext(const CharType *id, const std::locale &loc=std::locale())
Translate message id according to locale loc.
Definition: message.hpp:438