]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/locale/include/boost/locale/message.hpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / locale / include / boost / locale / message.hpp
1 //
2 // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See
5 // accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 //
8 #ifndef BOOST_LOCALE_MESSAGE_HPP_INCLUDED
9 #define BOOST_LOCALE_MESSAGE_HPP_INCLUDED
10
11 #include <boost/locale/config.hpp>
12 #ifdef BOOST_MSVC
13 # pragma warning(push)
14 # pragma warning(disable : 4275 4251 4231 4660)
15 #endif
16 #include <locale>
17 #include <string>
18 #include <vector>
19 #include <set>
20 #include <memory>
21 #include <boost/locale/formatting.hpp>
22
23
24 namespace boost {
25 namespace locale {
26 ///
27 /// \defgroup message Message Formatting (translation)
28 ///
29 ///This module provides message translation functionality, i.e. allow your application to speak native language
30 ///
31 /// @{
32 ///
33
34 /// \cond INTERNAL
35
36 template<typename CharType>
37 struct base_message_format: public std::locale::facet
38 {
39 };
40
41 /// \endcond
42
43 ///
44 /// \brief This facet provides message formatting abilities
45 ///
46 template<typename CharType>
47 class message_format : public base_message_format<CharType>
48 {
49 public:
50
51 ///
52 /// Character type
53 ///
54 typedef CharType char_type;
55 ///
56 /// String type
57 ///
58 typedef std::basic_string<CharType> string_type;
59
60 ///
61 /// Default constructor
62 ///
63 message_format(size_t refs = 0) :
64 base_message_format<CharType>(refs)
65 {
66 }
67
68 ///
69 /// This function returns a pointer to the string for a message defined by a \a context
70 /// and identification string \a id. Both create a single key for message lookup in
71 /// a domain defined by \a domain_id.
72 ///
73 /// If \a context is NULL it is not considered to be a part of the key
74 ///
75 /// If a translated string is found, it is returned, otherwise NULL is returned
76 ///
77 ///
78 virtual char_type const *get(int domain_id,char_type const *context,char_type const *id) const = 0;
79 ///
80 /// This function returns a pointer to the string for a plural message defined by a \a context
81 /// and identification string \a single_id.
82 ///
83 /// If \a context is NULL it is not considered to be a part of the key
84 ///
85 /// Both create a single key for message lookup in
86 /// a domain defined \a domain_id. \a n is used to pick the correct translation string for a specific
87 /// number.
88 ///
89 /// If a translated string is found, it is returned, otherwise NULL is returned
90 ///
91 ///
92 virtual char_type const *get(int domain_id,char_type const *context,char_type const *single_id,int n) const = 0;
93
94 ///
95 /// Convert a string that defines \a domain to the integer id used by \a get functions
96 ///
97 virtual int domain(std::string const &domain) const = 0;
98
99 ///
100 /// Convert the string \a msg to target locale's encoding. If \a msg is already
101 /// in target encoding it would be returned otherwise the converted
102 /// string is stored in temporary \a buffer and buffer.c_str() is returned.
103 ///
104 /// Note: for char_type that is char16_t, char32_t and wchar_t it is no-op, returns
105 /// msg
106 ///
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 }
116
117 };
118
119 /// \cond INTERNAL
120
121 namespace details {
122 inline bool is_us_ascii_char(char c)
123 {
124 // works for null terminated strings regardless char "signness"
125 return 0<c && c<0x7F;
126 }
127 inline bool is_us_ascii_string(char const *msg)
128 {
129 while(*msg) {
130 if(!is_us_ascii_char(*msg++))
131 return false;
132 }
133 return true;
134 }
135
136 template<typename CharType>
137 struct string_cast_traits {
138 static CharType const *cast(CharType const *msg,std::basic_string<CharType> &/*unused*/)
139 {
140 return msg;
141 }
142 };
143
144 template<>
145 struct string_cast_traits<char> {
146 static char const *cast(char const *msg,std::string &buffer)
147 {
148 if(is_us_ascii_string(msg))
149 return msg;
150 buffer.reserve(strlen(msg));
151 char c;
152 while((c=*msg++)!=0) {
153 if(is_us_ascii_char(c))
154 buffer+=c;
155 }
156 return buffer.c_str();
157 }
158 };
159 } // details
160
161 /// \endcond
162
163 ///
164 /// \brief This class represents a message that can be converted to a specific locale message
165 ///
166 /// It holds the original ASCII string that is queried in the dictionary when converting to the output string.
167 /// The created string may be UTF-8, UTF-16, UTF-32 or other 8-bit encoded string according to the target
168 /// character type and locale encoding.
169 ///
170 template<typename CharType>
171 class basic_message {
172 public:
173
174 typedef CharType char_type; ///< The character this message object is used with
175 typedef std::basic_string<char_type> string_type; ///< The string type this object can be used with
176 typedef message_format<char_type> facet_type; ///< The type of the facet the messages are fetched with
177
178 ///
179 /// Create default empty message
180 ///
181 basic_message() :
182 n_(0),
183 c_id_(0),
184 c_context_(0),
185 c_plural_(0)
186 {
187 }
188
189 ///
190 /// Create a simple message from 0 terminated string. The string should exist
191 /// until the message is destroyed. Generally useful with static constant strings
192 ///
193 explicit basic_message(char_type const *id) :
194 n_(0),
195 c_id_(id),
196 c_context_(0),
197 c_plural_(0)
198 {
199 }
200
201 ///
202 /// Create a simple plural form message from 0 terminated strings. The strings should exist
203 /// until the message is destroyed. Generally useful with static constant strings.
204 ///
205 /// \a n is the number, \a single and \a plural are singular and plural forms of the message
206 ///
207 explicit basic_message(char_type const *single,char_type const *plural,int n) :
208 n_(n),
209 c_id_(single),
210 c_context_(0),
211 c_plural_(plural)
212 {
213 }
214
215 ///
216 /// Create a simple message from 0 terminated strings, with context
217 /// information. The string should exist
218 /// until the message is destroyed. Generally useful with static constant strings
219 ///
220 explicit basic_message(char_type const *context,char_type const *id) :
221 n_(0),
222 c_id_(id),
223 c_context_(context),
224 c_plural_(0)
225 {
226 }
227
228 ///
229 /// Create a simple plural form message from 0 terminated strings, with context. The strings should exist
230 /// until the message is destroyed. Generally useful with static constant strings.
231 ///
232 /// \a n is the number, \a single and \a plural are singular and plural forms of the message
233 ///
234 explicit basic_message(char_type const *context,char_type const *single,char_type const *plural,int n) :
235 n_(n),
236 c_id_(single),
237 c_context_(context),
238 c_plural_(plural)
239 {
240 }
241
242
243 ///
244 /// Create a simple message from a string.
245 ///
246 explicit basic_message(string_type const &id) :
247 n_(0),
248 c_id_(0),
249 c_context_(0),
250 c_plural_(0),
251 id_(id)
252 {
253 }
254
255 ///
256 /// Create a simple plural form message from strings.
257 ///
258 /// \a n is the number, \a single and \a plural are single and plural forms of the message
259 ///
260 explicit basic_message(string_type const &single,string_type const &plural,int number) :
261 n_(number),
262 c_id_(0),
263 c_context_(0),
264 c_plural_(0),
265 id_(single),
266 plural_(plural)
267 {
268 }
269
270 ///
271 /// Create a simple message from a string with context.
272 ///
273 explicit basic_message(string_type const &context,string_type const &id) :
274 n_(0),
275 c_id_(0),
276 c_context_(0),
277 c_plural_(0),
278 id_(id),
279 context_(context)
280 {
281 }
282
283 ///
284 /// Create a simple plural form message from strings.
285 ///
286 /// \a n is the number, \a single and \a plural are single and plural forms of the message
287 ///
288 explicit basic_message(string_type const &context,string_type const &single,string_type const &plural,int number) :
289 n_(number),
290 c_id_(0),
291 c_context_(0),
292 c_plural_(0),
293 id_(single),
294 context_(context),
295 plural_(plural)
296 {
297 }
298
299 ///
300 /// Copy an object
301 ///
302 basic_message(basic_message const &other) :
303 n_(other.n_),
304 c_id_(other.c_id_),
305 c_context_(other.c_context_),
306 c_plural_(other.c_plural_),
307 id_(other.id_),
308 context_(other.context_),
309 plural_(other.plural_)
310 {
311 }
312
313 ///
314 /// Assign other message object to this one
315 ///
316 basic_message const &operator=(basic_message const &other)
317 {
318 if(this==&other) {
319 return *this;
320 }
321 basic_message tmp(other);
322 swap(tmp);
323 return *this;
324 }
325
326 ///
327 /// Swap two message objects
328 ///
329 void swap(basic_message &other)
330 {
331 std::swap(n_,other.n_);
332 std::swap(c_id_,other.c_id_);
333 std::swap(c_context_,other.c_context_);
334 std::swap(c_plural_,other.c_plural_);
335
336 id_.swap(other.id_);
337 context_.swap(other.context_);
338 plural_.swap(other.plural_);
339 }
340
341 ///
342 /// Message class can be explicitly converted to string class
343 ///
344
345 operator string_type () const
346 {
347 return str();
348 }
349
350 ///
351 /// Translate message to a string in the default global locale, using default domain
352 ///
353 string_type str() const
354 {
355 std::locale loc;
356 return str(loc,0);
357 }
358
359 ///
360 /// Translate message to a string in the locale \a locale, using default domain
361 ///
362 string_type str(std::locale const &locale) const
363 {
364 return str(locale,0);
365 }
366
367 ///
368 /// Translate message to a string using locale \a locale and message domain \a domain_id
369 ///
370 string_type str(std::locale const &locale,std::string const &domain_id) const
371 {
372 int id=0;
373 if(std::has_facet<facet_type>(locale))
374 id=std::use_facet<facet_type>(locale).domain(domain_id);
375 return str(locale,id);
376 }
377
378 ///
379 /// Translate message to a string using the default locale and message domain \a domain_id
380 ///
381 string_type str(std::string const &domain_id) const
382 {
383 int id=0;
384 std::locale loc;
385 if(std::has_facet<facet_type>(loc))
386 id=std::use_facet<facet_type>(loc).domain(domain_id);
387 return str(loc,id);
388 }
389
390
391 ///
392 /// Translate message to a string using locale \a loc and message domain index \a id
393 ///
394 string_type str(std::locale const &loc,int id) const
395 {
396 string_type buffer;
397 char_type const *ptr = write(loc,id,buffer);
398 if(ptr == buffer.c_str())
399 return buffer;
400 else
401 buffer = ptr;
402 return buffer;
403 }
404
405
406 ///
407 /// Translate message and write to stream \a out, using imbued locale and domain set to the
408 /// stream
409 ///
410 void write(std::basic_ostream<char_type> &out) const
411 {
412 std::locale const &loc = out.getloc();
413 int id = ios_info::get(out).domain_id();
414 string_type buffer;
415 out << write(loc,id,buffer);
416 }
417
418 private:
419 char_type const *plural() const
420 {
421 if(c_plural_)
422 return c_plural_;
423 if(plural_.empty())
424 return 0;
425 return plural_.c_str();
426 }
427 char_type const *context() const
428 {
429 if(c_context_)
430 return c_context_;
431 if(context_.empty())
432 return 0;
433 return context_.c_str();
434 }
435
436 char_type const *id() const
437 {
438 return c_id_ ? c_id_ : id_.c_str();
439 }
440
441 char_type const *write(std::locale const &loc,int domain_id,string_type &buffer) const
442 {
443 char_type const *translated = 0;
444 static const char_type empty_string[1] = {0};
445
446 char_type const *id = this->id();
447 char_type const *context = this->context();
448 char_type const *plural = this->plural();
449
450 if(*id == 0)
451 return empty_string;
452
453 facet_type const *facet = 0;
454 if(std::has_facet<facet_type>(loc))
455 facet = &std::use_facet<facet_type>(loc);
456
457 if(facet) {
458 if(!plural) {
459 translated = facet->get(domain_id,context,id);
460 }
461 else {
462 translated = facet->get(domain_id,context,id,n_);
463 }
464 }
465
466 if(!translated) {
467 char_type const *msg = plural ? ( n_ == 1 ? id : plural) : id;
468
469 if(facet) {
470 translated = facet->convert(msg,buffer);
471 }
472 else {
473 translated = details::string_cast_traits<char_type>::cast(msg,buffer);
474 }
475 }
476 return translated;
477 }
478
479 /// members
480
481 int n_;
482 char_type const *c_id_;
483 char_type const *c_context_;
484 char_type const *c_plural_;
485 string_type id_;
486 string_type context_;
487 string_type plural_;
488 };
489
490
491 ///
492 /// Convenience typedef for char
493 ///
494 typedef basic_message<char> message;
495 ///
496 /// Convenience typedef for wchar_t
497 ///
498 typedef basic_message<wchar_t> wmessage;
499 #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
500 ///
501 /// Convenience typedef for char16_t
502 ///
503 typedef basic_message<char16_t> u16message;
504 #endif
505 #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
506 ///
507 /// Convenience typedef for char32_t
508 ///
509 typedef basic_message<char32_t> u32message;
510 #endif
511
512 ///
513 /// Translate message \a msg and write it to stream
514 ///
515 template<typename CharType>
516 std::basic_ostream<CharType> &operator<<(std::basic_ostream<CharType> &out,basic_message<CharType> const &msg)
517 {
518 msg.write(out);
519 return out;
520 }
521
522 ///
523 /// \anchor boost_locale_translate_family \name Indirect message translation function family
524 /// @{
525
526 ///
527 /// \brief Translate a message, \a msg is not copied
528 ///
529 template<typename CharType>
530 inline basic_message<CharType> translate(CharType const *msg)
531 {
532 return basic_message<CharType>(msg);
533 }
534 ///
535 /// \brief Translate a message in context, \a msg and \a context are not copied
536 ///
537 template<typename CharType>
538 inline basic_message<CharType> translate( CharType const *context,
539 CharType const *msg)
540 {
541 return basic_message<CharType>(context,msg);
542 }
543 ///
544 /// \brief Translate a plural message form, \a single and \a plural are not copied
545 ///
546 template<typename CharType>
547 inline basic_message<CharType> translate( CharType const *single,
548 CharType const *plural,
549 int n)
550 {
551 return basic_message<CharType>(single,plural,n);
552 }
553 ///
554 /// \brief Translate a plural message from in constext, \a context, \a single and \a plural are not copied
555 ///
556 template<typename CharType>
557 inline basic_message<CharType> translate( CharType const *context,
558 CharType const *single,
559 CharType const *plural,
560 int n)
561 {
562 return basic_message<CharType>(context,single,plural,n);
563 }
564
565 ///
566 /// \brief Translate a message, \a msg is copied
567 ///
568 template<typename CharType>
569 inline basic_message<CharType> translate(std::basic_string<CharType> const &msg)
570 {
571 return basic_message<CharType>(msg);
572 }
573
574 ///
575 /// \brief Translate a message in context,\a context and \a msg is copied
576 ///
577 template<typename CharType>
578 inline basic_message<CharType> translate( std::basic_string<CharType> const &context,
579 std::basic_string<CharType> const &msg)
580 {
581 return basic_message<CharType>(context,msg);
582 }
583 ///
584 /// \brief Translate a plural message form in constext, \a context, \a single and \a plural are copied
585 ///
586 template<typename CharType>
587 inline basic_message<CharType> translate( std::basic_string<CharType> const &context,
588 std::basic_string<CharType> const &single,
589 std::basic_string<CharType> const &plural,
590 int n)
591 {
592 return basic_message<CharType>(context,single,plural,n);
593 }
594
595 ///
596 /// \brief Translate a plural message form, \a single and \a plural are copied
597 ///
598
599 template<typename CharType>
600 inline basic_message<CharType> translate( std::basic_string<CharType> const &single,
601 std::basic_string<CharType> const &plural,
602 int n)
603 {
604 return basic_message<CharType>(single,plural,n);
605 }
606
607 /// @}
608
609 ///
610 /// \anchor boost_locale_gettext_family \name Direct message translation functions family
611 ///
612
613 ///
614 /// Translate message \a id according to locale \a loc
615 ///
616 template<typename CharType>
617 std::basic_string<CharType> gettext(CharType const *id,
618 std::locale const &loc=std::locale())
619 {
620 return basic_message<CharType>(id).str(loc);
621 }
622 ///
623 /// Translate plural form according to locale \a loc
624 ///
625 template<typename CharType>
626 std::basic_string<CharType> ngettext( CharType const *s,
627 CharType const *p,
628 int n,
629 std::locale const &loc=std::locale())
630 {
631 return basic_message<CharType>(s,p,n).str(loc);
632 }
633 ///
634 /// Translate message \a id according to locale \a loc in domain \a domain
635 ///
636 template<typename CharType>
637 std::basic_string<CharType> dgettext( char const *domain,
638 CharType const *id,
639 std::locale const &loc=std::locale())
640 {
641 return basic_message<CharType>(id).str(loc,domain);
642 }
643
644 ///
645 /// Translate plural form according to locale \a loc in domain \a domain
646 ///
647 template<typename CharType>
648 std::basic_string<CharType> dngettext( char const *domain,
649 CharType const *s,
650 CharType const *p,
651 int n,
652 std::locale const &loc=std::locale())
653 {
654 return basic_message<CharType>(s,p,n).str(loc,domain);
655 }
656 ///
657 /// Translate message \a id according to locale \a loc in context \a context
658 ///
659 template<typename CharType>
660 std::basic_string<CharType> pgettext( CharType const *context,
661 CharType const *id,
662 std::locale const &loc=std::locale())
663 {
664 return basic_message<CharType>(context,id).str(loc);
665 }
666 ///
667 /// Translate plural form according to locale \a loc in context \a context
668 ///
669 template<typename CharType>
670 std::basic_string<CharType> npgettext( CharType const *context,
671 CharType const *s,
672 CharType const *p,
673 int n,
674 std::locale const &loc=std::locale())
675 {
676 return basic_message<CharType>(context,s,p,n).str(loc);
677 }
678 ///
679 /// Translate message \a id according to locale \a loc in domain \a domain in context \a context
680 ///
681 template<typename CharType>
682 std::basic_string<CharType> dpgettext( char const *domain,
683 CharType const *context,
684 CharType const *id,
685 std::locale const &loc=std::locale())
686 {
687 return basic_message<CharType>(context,id).str(loc,domain);
688 }
689 ///
690 /// Translate plural form according to locale \a loc in domain \a domain in context \a context
691 ///
692 template<typename CharType>
693 std::basic_string<CharType> dnpgettext(char const *domain,
694 CharType const *context,
695 CharType const *s,
696 CharType const *p,
697 int n,
698 std::locale const &loc=std::locale())
699 {
700 return basic_message<CharType>(context,s,p,n).str(loc,domain);
701 }
702
703 ///
704 /// \cond INTERNAL
705 ///
706
707 template<>
708 struct BOOST_LOCALE_DECL base_message_format<char> : public std::locale::facet
709 {
710 base_message_format(size_t refs = 0) : std::locale::facet(refs)
711 {
712 }
713 static std::locale::id id;
714 };
715
716 template<>
717 struct BOOST_LOCALE_DECL base_message_format<wchar_t> : public std::locale::facet
718 {
719 base_message_format(size_t refs = 0) : std::locale::facet(refs)
720 {
721 }
722 static std::locale::id id;
723 };
724
725 #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
726
727 template<>
728 struct BOOST_LOCALE_DECL base_message_format<char16_t> : public std::locale::facet
729 {
730 base_message_format(size_t refs = 0) : std::locale::facet(refs)
731 {
732 }
733 static std::locale::id id;
734 };
735
736 #endif
737
738 #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
739
740 template<>
741 struct BOOST_LOCALE_DECL base_message_format<char32_t> : public std::locale::facet
742 {
743 base_message_format(size_t refs = 0) : std::locale::facet(refs)
744 {
745 }
746 static std::locale::id id;
747 };
748
749 #endif
750
751 /// \endcond
752
753 ///
754 /// @}
755 ///
756
757 namespace as {
758 /// \cond INTERNAL
759 namespace details {
760 struct set_domain {
761 std::string domain_id;
762 };
763 template<typename CharType>
764 std::basic_ostream<CharType> &operator<<(std::basic_ostream<CharType> &out, set_domain const &dom)
765 {
766 int id = std::use_facet<message_format<CharType> >(out.getloc()).domain(dom.domain_id);
767 ios_info::get(out).domain_id(id);
768 return out;
769 }
770 } // details
771 /// \endcond
772
773 ///
774 /// \addtogroup manipulators
775 ///
776 /// @{
777
778 ///
779 /// Manipulator for switching message domain in ostream,
780 ///
781 /// \note The returned object throws std::bad_cast if the I/O stream does not have \ref message_format facet installed
782 ///
783 inline
784 #ifdef BOOST_LOCALE_DOXYGEN
785 unspecified_type
786 #else
787 details::set_domain
788 #endif
789 domain(std::string const &id)
790 {
791 details::set_domain tmp = { id };
792 return tmp;
793 }
794 /// @}
795 } // as
796 } // locale
797 } // boost
798
799 #ifdef BOOST_MSVC
800 #pragma warning(pop)
801 #endif
802
803
804 #endif
805
806 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
807