27 #include <boost/multi_index/hashed_index.hpp>
34 #define LOG_CF LOG_STREAM(info, log_config)
35 #define ERR_CF LOG_STREAM(err, log_config)
41 const char TRANSLATABLE_PART = 0x01;
42 const char UNTRANSLATABLE_PART = 0x02;
43 const char TEXTDOMAIN_SEPARATOR = 0x03;
44 const char ID_TRANSLATABLE_PART = 0x04;
45 const char PLURAL_PART = 0x05;
51 boost::hash_combine(seed,
value_);
58 : string_(string.value_)
60 , end_(string_.
size())
62 , translatable_(false)
71 static std::string
mark = std::string(TRANSLATABLE_PART, 1) + UNTRANSLATABLE_PART + ID_TRANSLATABLE_PART + PLURAL_PART;
77 if(
begin_ == string_.size()) {
82 case TRANSLATABLE_PART: {
84 std::string::size_type textdomain_end = string_.find(TEXTDOMAIN_SEPARATOR,
begin_ + 1);
86 if(textdomain_end == std::string::npos || textdomain_end >= string_.size() - 1) {
87 ERR_CF <<
"Error: invalid string: " << string_;
92 end_ = string_.find_first_of(
mark, textdomain_end + 1);
93 if(end_ == std::string::npos) {
94 end_ = string_.size();
97 textdomain_ = std::string(string_,
begin_ + 1, textdomain_end -
begin_ - 1);
99 begin_ = textdomain_end + 1;
103 case ID_TRANSLATABLE_PART:
105 if(
begin_ + 3 >= string_.size()) {
106 ERR_CF <<
"Error: invalid string: " << string_;
111 end_ = string_.find_first_of(
mark,
begin_ + 3);
112 if(end_ == std::string::npos) {
113 end_ = string_.size();
116 id =
static_cast<unsigned char>(string_[
begin_ + 1]) +
static_cast<unsigned char>(string_[
begin_ + 2]) * 256;
118 ERR_CF <<
"Error: invalid string: " << string_;
129 case UNTRANSLATABLE_PART:
130 end_ = string_.find_first_of(
mark,
begin_ + 1);
131 if(end_ == std::string::npos) {
132 end_ = string_.size();
136 ERR_CF <<
"Error: invalid string: " << string_;
147 begin_ = string_.find_first_of(
mark, end_ + 5);
148 if(
begin_ == std::string::npos) {
152 if(string_[
begin_] == PLURAL_PART) {
153 ERR_CF <<
"Error: invalid string: " << string_;
162 end_ = string_.size();
170 if(end_ + 5 >= string_.size()) {
171 ERR_CF <<
"Error: invalid string: " << string_;
176 std::string::size_type real_end = string_.find_first_of(
mark, end_ + 6);
177 if(real_end < string_.size() && string_[real_end] == PLURAL_PART) {
178 ERR_CF <<
"Error: invalid string: " << string_;
190 std::copy_n(string_.data() + end_ + 1, 4, cvt.data);
213 std::string::size_type pl_end = string_.find_first_of(
mark, end_ + 5);
214 if(pl_end == std::string::npos) {
215 pl_end = string_.size();
218 return string_.begin() + pl_end;
235 : value_(string.value_)
236 , translated_value_(string.translated_value_)
237 , translation_timestamp_(string.translation_timestamp_)
238 , translatable_(string.translatable_)
239 , last_untranslatable_(string.last_untranslatable_)
245 , translated_value_()
246 , translation_timestamp_(0)
247 , translatable_(false)
248 , last_untranslatable_(false)
253 : value_(1, ID_TRANSLATABLE_PART)
254 , translated_value_()
255 , translation_timestamp_(0)
256 , translatable_(true)
257 , last_untranslatable_(false)
265 std::map<std::string, unsigned int>::const_iterator idi =
textdomain_to_id.find(textdomain);
276 value_ +=
static_cast<char>(
id & 0xff);
277 value_ +=
static_cast<char>(
id >> 8);
282 : value_(1, ID_TRANSLATABLE_PART)
283 , translated_value_()
284 , translation_timestamp_(0)
285 , translatable_(true)
286 , last_untranslatable_(false)
288 if(sing.empty() && pl.empty()) {
294 std::map<std::string, unsigned int>::const_iterator idi =
textdomain_to_id.find(textdomain);
305 value_ +=
static_cast<char>(
id & 0xff);
306 value_ +=
static_cast<char>(
id >> 8);
316 for(
char c : cvt.data) {
325 , translated_value_()
326 , translation_timestamp_(0)
327 , translatable_(false)
328 , last_untranslatable_(false)
336 if(!
string.
empty() && (
string[0] == TRANSLATABLE_PART ||
string[0] == UNTRANSLATABLE_PART)) {
344 for(
walker w(orig); !
w.eos();
w.next()) {
345 std::string substr(
w.begin(),
w.end());
347 if(
w.translatable()) {
360 for(
walker w(*
this); !
w.eos();
w.next()) {
361 res += std::string(
w.begin(),
w.end());
371 for(
walker w(*
this); !
w.eos();
w.next()) {
374 std::string substr(
w.begin(),
w.end());
375 if(
w.translatable()) {
378 chunk.
value_ = TRANSLATABLE_PART +
w.textdomain() + TEXTDOMAIN_SEPARATOR + substr;
446 if(
string.
value_.empty()) {
466 value_.append(
string.
value_.begin() + 1,
string.value_.end());
474 value_ += UNTRANSLATABLE_PART;
500 value_ += UNTRANSLATABLE_PART;
526 value_ += UNTRANSLATABLE_PART;
571 for(
walker w(*
this); !
w.eos();
w.next()) {
572 std::string part(
w.begin(),
w.end());
574 if(
w.translatable()) {
576 std::string plural(
w.plural_begin(),
w.plural_end());
622 : val_(new
base(o, textdomain))
627 : val_(new
base(
s, pl,
c, textdomain))
646 LOG_CF <<
"Binding textdomain " << name <<
" to path " <<
path;
664 stream <<
string.str();
const route_iterator begin_
std::string::const_iterator plural_end() const
walker(const t_string_base &string)
std::string::const_iterator plural_begin() const
t_string_base & operator=(const t_string_base &)
Default implementation, but defined out-of-line for efficiency reasons.
bool last_untranslatable_
static std::map< std::string, unsigned int > textdomain_to_id
std::string translated_value_
t_string_base & operator+=(const t_string_base &)
std::string to_serialized() const
bool operator==(const t_string_base &) const
std::string base_str() const
const std::string & value() const
bool operator<(const t_string_base &string) const
static std::vector< std::string > id_to_textdomain
~t_string_base()
Default implementation, but defined out-of-line for efficiency reasons.
unsigned translation_timestamp_
std::size_t hash_value() const
const std::string & str() const
static t_string_base from_serialized(const std::string &string)
t_string_base operator+(const t_string_base &) const
static void reset_translations()
static void add_textdomain(const std::string &name, const std::string &path)
void swap(t_string &other)
~t_string()
Default implementation, but defined out-of-line for efficiency reasons.
std::shared_ptr< const t_string_base > val_
t_string & operator=(const t_string &)
Default implementation, but defined out-of-line for efficiency reasons.
t_string()
Default implementation, but defined out-of-line for efficiency reasons.
std::string id
Text to match against addon_info.tags()
Standard logging facilities (interface).
void bind_textdomain(const char *domain, const char *directory, const char *)
std::string dsgettext(const char *domainname, const char *msgid)
std::string dsngettext(const char *domainname, const char *singular, const char *plural, int n)
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
static map_location::DIRECTION s
static unsigned language_counter
void swap(t_string &lhs, t_string &rhs)
Implement non-member swap function for std::swap (calls t_string::swap).
std::ostream & operator<<(std::ostream &stream, const t_string_base &string)
static lg::log_domain log_config("config")