File indexing completed on 2025-01-30 09:44:58
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_LOCALE_MESSAGE_HPP_INCLUDED
0009 #define BOOST_LOCALE_MESSAGE_HPP_INCLUDED
0010
0011 #include <boost/locale/detail/facet_id.hpp>
0012 #include <boost/locale/detail/is_supported_char.hpp>
0013 #include <boost/locale/formatting.hpp>
0014 #include <boost/locale/util/string.hpp>
0015 #include <locale>
0016 #include <memory>
0017 #include <set>
0018 #include <string>
0019 #include <type_traits>
0020
0021 #ifdef BOOST_MSVC
0022 # pragma warning(push)
0023 # pragma warning(disable : 4275 4251 4231 4660)
0024 #endif
0025
0026
0027 #ifdef gettext
0028 # undef gettext
0029 # undef ngettext
0030 # undef dgettext
0031 # undef dngettext
0032 #endif
0033
0034 namespace boost { namespace locale {
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044 using count_type = long long;
0045
0046
0047 template<typename CharType>
0048 class BOOST_SYMBOL_VISIBLE message_format : public std::locale::facet,
0049 public detail::facet_id<message_format<CharType>> {
0050 BOOST_LOCALE_ASSERT_IS_SUPPORTED(CharType);
0051
0052 public:
0053
0054 typedef CharType char_type;
0055
0056 typedef std::basic_string<CharType> string_type;
0057
0058
0059 message_format(size_t refs = 0) : std::locale::facet(refs) {}
0060
0061
0062
0063
0064
0065
0066
0067
0068 virtual const char_type* get(int domain_id, const char_type* context, const char_type* id) const = 0;
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080 virtual const char_type*
0081 get(int domain_id, const char_type* context, const char_type* single_id, count_type n) const = 0;
0082
0083
0084 virtual int domain(const std::string& domain) const = 0;
0085
0086
0087
0088
0089
0090
0091
0092 virtual const char_type* convert(const char_type* msg, string_type& buffer) const = 0;
0093 };
0094
0095
0096
0097 namespace detail {
0098 inline bool is_us_ascii_char(char c)
0099 {
0100
0101 return 0 < c && c < 0x7F;
0102 }
0103 inline bool is_us_ascii_string(const char* msg)
0104 {
0105 while(*msg) {
0106 if(!is_us_ascii_char(*msg++))
0107 return false;
0108 }
0109 return true;
0110 }
0111
0112 template<typename CharType>
0113 struct string_cast_traits {
0114 static const CharType* cast(const CharType* msg, std::basic_string<CharType>& ) { return msg; }
0115 };
0116
0117 template<>
0118 struct string_cast_traits<char> {
0119 static const char* cast(const char* msg, std::string& buffer)
0120 {
0121 if(is_us_ascii_string(msg))
0122 return msg;
0123 buffer.reserve(strlen(msg));
0124 char c;
0125 while((c = *msg++) != 0) {
0126 if(is_us_ascii_char(c))
0127 buffer += c;
0128 }
0129 return buffer.c_str();
0130 }
0131 };
0132 }
0133
0134
0135
0136
0137
0138
0139
0140
0141 template<typename CharType>
0142 class basic_message {
0143 public:
0144 typedef CharType char_type;
0145 typedef std::basic_string<char_type> string_type;
0146 typedef message_format<char_type> facet_type;
0147
0148
0149 basic_message() : n_(0), c_id_(nullptr), c_context_(nullptr), c_plural_(nullptr) {}
0150
0151
0152
0153 explicit basic_message(const char_type* id) : n_(0), c_id_(id), c_context_(nullptr), c_plural_(nullptr) {}
0154
0155
0156
0157
0158
0159 explicit basic_message(const char_type* single, const char_type* plural, count_type n) :
0160 n_(n), c_id_(single), c_context_(nullptr), c_plural_(plural)
0161 {}
0162
0163
0164
0165
0166 explicit basic_message(const char_type* context, const char_type* id) :
0167 n_(0), c_id_(id), c_context_(context), c_plural_(nullptr)
0168 {}
0169
0170
0171
0172
0173
0174 explicit basic_message(const char_type* context,
0175 const char_type* single,
0176 const char_type* plural,
0177 count_type n) :
0178 n_(n),
0179 c_id_(single), c_context_(context), c_plural_(plural)
0180 {}
0181
0182
0183 explicit basic_message(const string_type& id) :
0184 n_(0), c_id_(nullptr), c_context_(nullptr), c_plural_(nullptr), id_(id)
0185 {}
0186
0187
0188
0189
0190 explicit basic_message(const string_type& single, const string_type& plural, count_type number) :
0191 n_(number), c_id_(nullptr), c_context_(nullptr), c_plural_(nullptr), id_(single), plural_(plural)
0192 {}
0193
0194
0195 explicit basic_message(const string_type& context, const string_type& id) :
0196 n_(0), c_id_(nullptr), c_context_(nullptr), c_plural_(nullptr), id_(id), context_(context)
0197 {}
0198
0199
0200
0201
0202 explicit basic_message(const string_type& context,
0203 const string_type& single,
0204 const string_type& plural,
0205 count_type number) :
0206 n_(number),
0207 c_id_(nullptr), c_context_(nullptr), c_plural_(nullptr), id_(single), context_(context), plural_(plural)
0208 {}
0209
0210
0211 basic_message(const basic_message&) = default;
0212 basic_message(basic_message&&) noexcept = default;
0213
0214
0215 basic_message& operator=(const basic_message&) = default;
0216 basic_message&
0217 operator=(basic_message&&) noexcept(std::is_nothrow_move_assignable<string_type>::value) = default;
0218
0219
0220 void
0221 swap(basic_message& other) noexcept(noexcept(std::declval<string_type&>().swap(std::declval<string_type&>())))
0222 {
0223 using std::swap;
0224 swap(n_, other.n_);
0225 swap(c_id_, other.c_id_);
0226 swap(c_context_, other.c_context_);
0227 swap(c_plural_, other.c_plural_);
0228 swap(id_, other.id_);
0229 swap(context_, other.context_);
0230 swap(plural_, other.plural_);
0231 }
0232 friend void swap(basic_message& x, basic_message& y) noexcept(noexcept(x.swap(y))) { x.swap(y); }
0233
0234
0235 operator string_type() const { return str(); }
0236
0237
0238 string_type str() const { return str(std::locale()); }
0239
0240
0241 string_type str(const std::locale& locale) const { return str(locale, 0); }
0242
0243
0244 string_type str(const std::locale& locale, const std::string& domain_id) const
0245 {
0246 int id = 0;
0247 if(std::has_facet<facet_type>(locale))
0248 id = std::use_facet<facet_type>(locale).domain(domain_id);
0249 return str(locale, id);
0250 }
0251
0252
0253 string_type str(const std::string& domain_id) const { return str(std::locale(), domain_id); }
0254
0255
0256 string_type str(const std::locale& loc, int id) const
0257 {
0258 string_type buffer;
0259 const char_type* ptr = write(loc, id, buffer);
0260 if(ptr != buffer.c_str())
0261 buffer = ptr;
0262 return buffer;
0263 }
0264
0265
0266
0267 void write(std::basic_ostream<char_type>& out) const
0268 {
0269 const std::locale& loc = out.getloc();
0270 int id = ios_info::get(out).domain_id();
0271 string_type buffer;
0272 out << write(loc, id, buffer);
0273 }
0274
0275 private:
0276 const char_type* plural() const
0277 {
0278 if(c_plural_)
0279 return c_plural_;
0280 if(plural_.empty())
0281 return nullptr;
0282 return plural_.c_str();
0283 }
0284 const char_type* context() const
0285 {
0286 if(c_context_)
0287 return c_context_;
0288 if(context_.empty())
0289 return nullptr;
0290 return context_.c_str();
0291 }
0292
0293 const char_type* id() const { return c_id_ ? c_id_ : id_.c_str(); }
0294
0295 const char_type* write(const std::locale& loc, int domain_id, string_type& buffer) const
0296 {
0297 static const char_type empty_string[1] = {0};
0298
0299 const char_type* id = this->id();
0300 const char_type* context = this->context();
0301 const char_type* plural = this->plural();
0302
0303 if(*id == 0)
0304 return empty_string;
0305
0306 const facet_type* facet = nullptr;
0307 if(std::has_facet<facet_type>(loc))
0308 facet = &std::use_facet<facet_type>(loc);
0309
0310 const char_type* translated = nullptr;
0311 if(facet) {
0312 if(!plural)
0313 translated = facet->get(domain_id, context, id);
0314 else
0315 translated = facet->get(domain_id, context, id, n_);
0316 }
0317
0318 if(!translated) {
0319 const char_type* msg = plural ? (n_ == 1 ? id : plural) : id;
0320
0321 if(facet)
0322 translated = facet->convert(msg, buffer);
0323 else
0324 translated = detail::string_cast_traits<char_type>::cast(msg, buffer);
0325 }
0326 return translated;
0327 }
0328
0329
0330
0331 count_type n_;
0332 const char_type* c_id_;
0333 const char_type* c_context_;
0334 const char_type* c_plural_;
0335 string_type id_;
0336 string_type context_;
0337 string_type plural_;
0338 };
0339
0340
0341 typedef basic_message<char> message;
0342
0343 typedef basic_message<wchar_t> wmessage;
0344 #ifndef BOOST_LOCALE_NO_CXX20_STRING8
0345
0346 typedef basic_message<char8_t> u8message;
0347 #endif
0348 #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
0349
0350 typedef basic_message<char16_t> u16message;
0351 #endif
0352 #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
0353
0354 typedef basic_message<char32_t> u32message;
0355 #endif
0356
0357
0358 template<typename CharType>
0359 std::basic_ostream<CharType>& operator<<(std::basic_ostream<CharType>& out, const basic_message<CharType>& msg)
0360 {
0361 msg.write(out);
0362 return out;
0363 }
0364
0365
0366
0367
0368
0369 template<typename CharType>
0370 inline basic_message<CharType> translate(const CharType* msg)
0371 {
0372 return basic_message<CharType>(msg);
0373 }
0374
0375
0376 template<typename CharType>
0377 inline basic_message<CharType> translate(const CharType* context, const CharType* msg)
0378 {
0379 return basic_message<CharType>(context, msg);
0380 }
0381
0382
0383 template<typename CharType>
0384 inline basic_message<CharType> translate(const CharType* single, const CharType* plural, count_type n)
0385 {
0386 return basic_message<CharType>(single, plural, n);
0387 }
0388
0389
0390 template<typename CharType>
0391 inline basic_message<CharType>
0392 translate(const CharType* context, const CharType* single, const CharType* plural, count_type n)
0393 {
0394 return basic_message<CharType>(context, single, plural, n);
0395 }
0396
0397
0398 template<typename CharType>
0399 inline basic_message<CharType> translate(const std::basic_string<CharType>& msg)
0400 {
0401 return basic_message<CharType>(msg);
0402 }
0403
0404
0405 template<typename CharType>
0406 inline basic_message<CharType> translate(const std::basic_string<CharType>& context,
0407 const std::basic_string<CharType>& msg)
0408 {
0409 return basic_message<CharType>(context, msg);
0410 }
0411
0412
0413 template<typename CharType>
0414 inline basic_message<CharType> translate(const std::basic_string<CharType>& context,
0415 const std::basic_string<CharType>& single,
0416 const std::basic_string<CharType>& plural,
0417 count_type n)
0418 {
0419 return basic_message<CharType>(context, single, plural, n);
0420 }
0421
0422
0423 template<typename CharType>
0424 inline basic_message<CharType>
0425 translate(const std::basic_string<CharType>& single, const std::basic_string<CharType>& plural, count_type n)
0426 {
0427 return basic_message<CharType>(single, plural, n);
0428 }
0429
0430
0431
0432
0433
0434
0435 template<typename CharType>
0436 std::basic_string<CharType> gettext(const CharType* id, const std::locale& loc = std::locale())
0437 {
0438 return basic_message<CharType>(id).str(loc);
0439 }
0440
0441 template<typename CharType>
0442 std::basic_string<CharType>
0443 ngettext(const CharType* s, const CharType* p, count_type n, const std::locale& loc = std::locale())
0444 {
0445 return basic_message<CharType>(s, p, n).str(loc);
0446 }
0447
0448
0449 template<typename CharType>
0450 std::basic_string<CharType> dgettext(const char* domain, const CharType* id, const std::locale& loc = std::locale())
0451 {
0452 return basic_message<CharType>(id).str(loc, domain);
0453 }
0454
0455
0456 template<typename CharType>
0457 std::basic_string<CharType> dngettext(const char* domain,
0458 const CharType* s,
0459 const CharType* p,
0460 count_type n,
0461 const std::locale& loc = std::locale())
0462 {
0463 return basic_message<CharType>(s, p, n).str(loc, domain);
0464 }
0465
0466
0467 template<typename CharType>
0468 std::basic_string<CharType>
0469 pgettext(const CharType* context, const CharType* id, const std::locale& loc = std::locale())
0470 {
0471 return basic_message<CharType>(context, id).str(loc);
0472 }
0473
0474
0475 template<typename CharType>
0476 std::basic_string<CharType> npgettext(const CharType* context,
0477 const CharType* s,
0478 const CharType* p,
0479 count_type n,
0480 const std::locale& loc = std::locale())
0481 {
0482 return basic_message<CharType>(context, s, p, n).str(loc);
0483 }
0484
0485
0486 template<typename CharType>
0487 std::basic_string<CharType>
0488 dpgettext(const char* domain, const CharType* context, const CharType* id, const std::locale& loc = std::locale())
0489 {
0490 return basic_message<CharType>(context, id).str(loc, domain);
0491 }
0492
0493
0494 template<typename CharType>
0495 std::basic_string<CharType> dnpgettext(const char* domain,
0496 const CharType* context,
0497 const CharType* s,
0498 const CharType* p,
0499 count_type n,
0500 const std::locale& loc = std::locale())
0501 {
0502 return basic_message<CharType>(context, s, p, n).str(loc, domain);
0503 }
0504
0505
0506
0507 namespace as {
0508
0509 namespace detail {
0510 struct set_domain {
0511 std::string domain_id;
0512 };
0513 template<typename CharType>
0514 std::basic_ostream<CharType>& operator<<(std::basic_ostream<CharType>& out, const set_domain& dom)
0515 {
0516 int id = std::use_facet<message_format<CharType>>(out.getloc()).domain(dom.domain_id);
0517 ios_info::get(out).domain_id(id);
0518 return out;
0519 }
0520 }
0521
0522
0523
0524
0525
0526
0527
0528
0529
0530
0531 inline
0532 #ifdef BOOST_LOCALE_DOXYGEN
0533 unspecified_type
0534 #else
0535 detail::set_domain
0536 #endif
0537 domain(const std::string& id)
0538 {
0539 detail::set_domain tmp = {id};
0540 return tmp;
0541 }
0542
0543 }
0544 }}
0545
0546 #ifdef BOOST_MSVC
0547 # pragma warning(pop)
0548 #endif
0549
0550 #endif