ChipMaster's trial hacks on C++CMS starting with v1.2.1. Not sure I'll follow on with the v2 since it looks to be breaking and mostly frivolous.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

808 lines
27 KiB

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