27 #include <boost/multi_index/hashed_index.hpp>
33 #define LOG_CF LOG_STREAM(info, log_config)
34 #define ERR_CF LOG_STREAM(err, log_config)
40 const char TRANSLATABLE_PART = 0x01;
41 const char UNTRANSLATABLE_PART = 0x02;
42 const char TEXTDOMAIN_SEPARATOR = 0x03;
43 const char ID_TRANSLATABLE_PART = 0x04;
44 const char PLURAL_PART = 0x05;
50 boost::hash_combine(seed,
value_);
57 : string_(string.value_)
59 , end_(string_.
size())
61 , translatable_(false)
70 static std::string
mark = std::string(TRANSLATABLE_PART, 1) + UNTRANSLATABLE_PART + ID_TRANSLATABLE_PART + PLURAL_PART;
76 if(
begin_ == string_.size()) {
81 case TRANSLATABLE_PART: {
83 std::string::size_type textdomain_end = string_.find(TEXTDOMAIN_SEPARATOR,
begin_ + 1);
85 if(textdomain_end == std::string::npos || textdomain_end >= string_.size() - 1) {
86 ERR_CF <<
"Error: invalid string: " << string_;
91 end_ = string_.find_first_of(
mark, textdomain_end + 1);
92 if(end_ == std::string::npos) {
93 end_ = string_.size();
96 textdomain_ = std::string(string_,
begin_ + 1, textdomain_end -
begin_ - 1);
98 begin_ = textdomain_end + 1;
102 case ID_TRANSLATABLE_PART:
104 if(
begin_ + 3 >= string_.size()) {
105 ERR_CF <<
"Error: invalid string: " << string_;
110 end_ = string_.find_first_of(
mark,
begin_ + 3);
111 if(end_ == std::string::npos) {
112 end_ = string_.size();
115 id =
static_cast<unsigned char>(string_[
begin_ + 1]) +
static_cast<unsigned char>(string_[
begin_ + 2]) * 256;
117 ERR_CF <<
"Error: invalid string: " << string_;
128 case UNTRANSLATABLE_PART:
129 end_ = string_.find_first_of(
mark,
begin_ + 1);
130 if(end_ == std::string::npos) {
131 end_ = string_.size();
135 ERR_CF <<
"Error: invalid string: " << string_;
146 begin_ = string_.find_first_of(
mark, end_ + 5);
147 if(
begin_ == std::string::npos) {
151 if(string_[
begin_] == PLURAL_PART) {
152 ERR_CF <<
"Error: invalid string: " << string_;
161 end_ = string_.size();
169 if(end_ + 5 >= string_.size()) {
170 ERR_CF <<
"Error: invalid string: " << string_;
175 std::string::size_type real_end = string_.find_first_of(
mark, end_ + 6);
176 if(real_end < string_.size() && string_[real_end] == PLURAL_PART) {
177 ERR_CF <<
"Error: invalid string: " << string_;
189 std::copy_n(string_.data() + end_ + 1, 4, cvt.data);
212 std::string::size_type pl_end = string_.find_first_of(
mark, end_ + 5);
213 if(pl_end == std::string::npos) {
214 pl_end = string_.size();
217 return string_.begin() + pl_end;
234 : value_(string.value_)
235 , translated_value_(string.translated_value_)
236 , translation_timestamp_(string.translation_timestamp_)
237 , translatable_(string.translatable_)
238 , last_untranslatable_(string.last_untranslatable_)
244 , translated_value_()
245 , translation_timestamp_(0)
246 , translatable_(false)
247 , last_untranslatable_(false)
252 : value_(1, ID_TRANSLATABLE_PART)
253 , translated_value_()
254 , translation_timestamp_(0)
255 , translatable_(true)
256 , last_untranslatable_(false)
264 std::map<std::string, unsigned int>::const_iterator idi =
textdomain_to_id.find(textdomain);
275 value_ +=
static_cast<char>(
id & 0xff);
276 value_ +=
static_cast<char>(
id >> 8);
281 : value_(1, ID_TRANSLATABLE_PART)
282 , translated_value_()
283 , translation_timestamp_(0)
284 , translatable_(true)
285 , last_untranslatable_(false)
287 if(sing.empty() && pl.empty()) {
293 std::map<std::string, unsigned int>::const_iterator idi =
textdomain_to_id.find(textdomain);
304 value_ +=
static_cast<char>(
id & 0xff);
305 value_ +=
static_cast<char>(
id >> 8);
315 for(
char c : cvt.data) {
324 , translated_value_()
325 , translation_timestamp_(0)
326 , translatable_(false)
327 , last_untranslatable_(false)
335 if(!
string.
empty() && (
string[0] == TRANSLATABLE_PART ||
string[0] == UNTRANSLATABLE_PART)) {
343 for(
walker w(orig); !
w.eos();
w.next()) {
344 std::string substr(
w.begin(),
w.end());
346 if(
w.translatable()) {
359 for(
walker w(*
this); !
w.eos();
w.next()) {
360 res += std::string(
w.begin(),
w.end());
370 for(
walker w(*
this); !
w.eos();
w.next()) {
373 std::string substr(
w.begin(),
w.end());
374 if(
w.translatable()) {
377 chunk.
value_ = TRANSLATABLE_PART +
w.textdomain() + TEXTDOMAIN_SEPARATOR + substr;
445 if(
string.
value_.empty()) {
465 value_.append(
string.
value_.begin() + 1,
string.value_.end());
473 value_ += UNTRANSLATABLE_PART;
499 value_ += UNTRANSLATABLE_PART;
525 value_ += UNTRANSLATABLE_PART;
570 for(
walker w(*
this); !
w.eos();
w.next()) {
571 std::string part(
w.begin(),
w.end());
573 if(
w.translatable()) {
575 std::string plural(
w.plural_begin(),
w.plural_end());
621 : val_(new
base(o, textdomain))
626 : val_(new
base(
s, pl,
c, textdomain))
645 LOG_CF <<
"Binding textdomain " << name <<
" to path " <<
path;
663 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
Helper class for translatable strings.
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")