00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "global.hpp"
00022
00023 #include <sstream>
00024 #include <vector>
00025 #include <map>
00026
00027 #include "tstring.hpp"
00028 #include "gettext.hpp"
00029 #include "log.hpp"
00030
00031 #define LOG_CF lg::info(lg::config)
00032 #define ERR_CF lg::err(lg::config)
00033
00034 namespace {
00035 const char TRANSLATABLE_PART = 0x01;
00036 const char UNTRANSLATABLE_PART = 0x02;
00037 const char TEXTDOMAIN_SEPARATOR = 0x03;
00038 const char ID_TRANSLATABLE_PART = 0x04;
00039 const char UNTRANSLATABLE_STRING = 0x05;
00040
00041 std::vector<std::string> id_to_textdomain;
00042 std::map<std::string, unsigned int> textdomain_to_id;
00043 }
00044
00045 t_string::walker::walker(const t_string& string) :
00046 string_(string.value_),
00047 begin_(0),
00048 end_(string_.size()),
00049 textdomain_(),
00050 translatable_(false)
00051 {
00052 if(string.translatable_) {
00053 update();
00054 }
00055 }
00056
00057 t_string::walker::walker(const std::string& string) :
00058 string_(string),
00059 begin_(0),
00060 end_(string_.size()),
00061 textdomain_(),
00062 translatable_(false)
00063 {
00064 update();
00065 }
00066
00067 void t_string::walker::update()
00068 {
00069 unsigned int id;
00070
00071 static std::string mark = std::string(TRANSLATABLE_PART, 1) + UNTRANSLATABLE_PART +
00072 ID_TRANSLATABLE_PART;
00073
00074 if(begin_ == string_.size())
00075 return;
00076
00077 switch(string_[begin_]) {
00078 case TRANSLATABLE_PART: {
00079 std::string::size_type textdomain_end =
00080 string_.find(TEXTDOMAIN_SEPARATOR, begin_ + 1);
00081
00082 if(textdomain_end == std::string::npos || textdomain_end >= string_.size() - 1) {
00083 ERR_CF << "Error: invalid string: " << string_ << "\n";
00084 begin_ = string_.size();
00085 return;
00086 }
00087
00088 end_ = string_.find_first_of(mark, textdomain_end + 1);
00089 if(end_ == std::string::npos)
00090 end_ = string_.size();
00091
00092 textdomain_ = std::string(string_, begin_+1, textdomain_end - begin_ - 1);
00093 translatable_ = true;
00094 begin_ = textdomain_end + 1;
00095
00096 break;
00097 }
00098 case ID_TRANSLATABLE_PART:
00099 if(begin_ + 3 >= string_.size()) {
00100 ERR_CF << "Error: invalid string: " << string_ << "\n";
00101 begin_ = string_.size();
00102 return;
00103 }
00104 end_ = string_.find_first_of(mark, begin_ + 3);
00105 if(end_ == std::string::npos)
00106 end_ = string_.size();
00107
00108 id = string_[begin_ + 1] + string_[begin_ + 2] * 256;
00109 if(id >= id_to_textdomain.size()) {
00110 ERR_CF << "Error: invalid string: " << string_ << "\n";
00111 begin_ = string_.size();
00112 return;
00113 }
00114 textdomain_ = id_to_textdomain[id];
00115 begin_ += 3;
00116 translatable_ = true;
00117
00118 break;
00119
00120 case UNTRANSLATABLE_PART:
00121 end_ = string_.find_first_of(mark, begin_ + 1);
00122 if(end_ == std::string::npos)
00123 end_ = string_.size();
00124
00125 if(end_ <= begin_ + 1) {
00126 ERR_CF << "Error: invalid string: " << string_ << "\n";
00127 begin_ = string_.size();
00128 return;
00129 }
00130
00131 translatable_ = false;
00132 textdomain_ = "";
00133 begin_ += 1;
00134 break;
00135
00136 default:
00137 end_ = string_.size();
00138 translatable_ = false;
00139 textdomain_ = "";
00140 break;
00141 }
00142 }
00143
00144 t_string::t_string() :
00145 value_(),
00146 translated_value_(),
00147 translatable_(false),
00148 last_untranslatable_(false)
00149 {
00150 }
00151
00152 t_string::t_string(const t_string& string) :
00153 value_(string.value_),
00154 translated_value_(string.translated_value_),
00155 translatable_(string.translatable_),
00156 last_untranslatable_(string.last_untranslatable_)
00157 {
00158 }
00159
00160 t_string::t_string(const std::string& string) :
00161 value_(string),
00162 translated_value_(),
00163 translatable_(false),
00164 last_untranslatable_(false)
00165 {
00166 }
00167
00168 t_string::t_string(const std::string& string, const std::string& textdomain) :
00169 value_(1, ID_TRANSLATABLE_PART),
00170 translated_value_(),
00171 translatable_(true),
00172 last_untranslatable_(false)
00173 {
00174 std::map<std::string, unsigned int>::const_iterator idi = textdomain_to_id.find(textdomain);
00175 unsigned int id;
00176
00177 if(idi == textdomain_to_id.end()) {
00178 id = id_to_textdomain.size();
00179 textdomain_to_id[textdomain] = id;
00180 id_to_textdomain.push_back(textdomain);
00181 } else {
00182 id = idi->second;
00183 }
00184
00185 value_ += char(id & 0xff);
00186 value_ += char(id >> 8);
00187 value_ += string;
00188 }
00189
00190 t_string::t_string(const char* string) :
00191 value_(string),
00192 translated_value_(),
00193 translatable_(false),
00194 last_untranslatable_(false)
00195 {
00196 }
00197
00198 t_string t_string::from_serialized(const std::string& string)
00199 {
00200 t_string orig(string);
00201
00202 if(!string.empty() && (string[0] == TRANSLATABLE_PART || string[0] == UNTRANSLATABLE_PART)) {
00203 orig.translatable_ = true;
00204 } else {
00205 orig.translatable_ = false;
00206 }
00207
00208 t_string res;
00209
00210 for(walker w(orig); !w.eos(); w.next()) {
00211 std::string substr(w.begin(), w.end());
00212
00213 if(w.translatable()) {
00214 res += t_string(substr, w.textdomain());
00215 } else {
00216 res += substr;
00217 }
00218 }
00219
00220 return res;
00221 }
00222
00223 const std::string t_string::base_str() const
00224 {
00225 std::string res;
00226 for(walker w(*this); !w.eos(); w.next()) {
00227 res += std::string(w.begin(), w.end());
00228 }
00229 return res;
00230 }
00231
00232 std::string t_string::to_serialized() const
00233 {
00234 t_string res;
00235
00236 for(walker w(*this); !w.eos(); w.next()) {
00237 t_string chunk;
00238
00239 std::string substr(w.begin(), w.end());
00240 if(w.translatable()) {
00241 chunk.translatable_ = true;
00242 chunk.last_untranslatable_ = false;
00243 chunk.value_ = TRANSLATABLE_PART + w.textdomain() +
00244 TEXTDOMAIN_SEPARATOR + substr;
00245 } else {
00246 chunk.translatable_ = false;
00247 chunk.value_ = substr;
00248 }
00249
00250 res += chunk;
00251 }
00252
00253 return res.value();
00254 }
00255
00256 t_string& t_string::operator=(const t_string& string)
00257 {
00258 value_ = string.value_;
00259 translatable_ = string.translatable_;
00260 last_untranslatable_ = string.last_untranslatable_;
00261 translated_value_ = string.translated_value_;
00262
00263 return *this;
00264 }
00265
00266 t_string& t_string::operator=(const std::string& string)
00267 {
00268 translatable_ = false;
00269 value_ = string;
00270 translated_value_ = "";
00271
00272 return *this;
00273 }
00274
00275 t_string& t_string::operator=(const char* string)
00276 {
00277 translatable_ = false;
00278 value_ = string;
00279 translated_value_ = "";
00280
00281 return *this;
00282 }
00283
00284 t_string t_string::operator+(const t_string& string) const
00285 {
00286 t_string res(*this);
00287 res += string;
00288 return res;
00289 }
00290
00291 t_string t_string::operator+(const std::string& string) const
00292 {
00293 t_string res(*this);
00294 res += string;
00295 return res;
00296 }
00297
00298 t_string t_string::operator+(const char* string) const
00299 {
00300 t_string res(*this);
00301 res += string;
00302 return res;
00303 }
00304
00305 t_string& t_string::operator+=(const t_string& string)
00306 {
00307 if (string.value_.empty())
00308 return *this;
00309 if (value_.empty()) {
00310 *this = string;
00311 return *this;
00312 }
00313
00314 if(translatable_ || string.translatable_) {
00315 if(!translatable_) {
00316 value_ = UNTRANSLATABLE_PART + value_;
00317 translatable_ = true;
00318 last_untranslatable_ = true;
00319 } else
00320 translated_value_ = "";
00321 if(string.translatable_) {
00322 if (last_untranslatable_ && string.value_[0] == UNTRANSLATABLE_PART)
00323 value_.append(string.value_.begin() + 1, string.value_.end());
00324 else
00325 value_ += string.value_;
00326 last_untranslatable_ = string.last_untranslatable_;
00327 } else {
00328 if (!last_untranslatable_) {
00329 value_ += UNTRANSLATABLE_PART;
00330 last_untranslatable_ = true;
00331 }
00332 value_ += string.value_;
00333 }
00334 } else {
00335 value_ += string.value_;
00336 }
00337
00338 return *this;
00339 }
00340
00341 t_string& t_string::operator+=(const std::string& string)
00342 {
00343 if (string.empty())
00344 return *this;
00345 if (value_.empty()) {
00346 *this = string;
00347 return *this;
00348 }
00349
00350 if(translatable_) {
00351 if (!last_untranslatable_) {
00352 value_ += UNTRANSLATABLE_PART;
00353 last_untranslatable_ = true;
00354 }
00355 value_ += string;
00356 translated_value_ = "";
00357 } else {
00358 value_ += string;
00359 }
00360
00361 return *this;
00362 }
00363
00364 t_string& t_string::operator+=(const char* string)
00365 {
00366 if (string[0] == 0)
00367 return *this;
00368 if (value_.empty()) {
00369 *this = string;
00370 return *this;
00371 }
00372
00373 if(translatable_) {
00374 if (!last_untranslatable_) {
00375 value_ += UNTRANSLATABLE_PART;
00376 last_untranslatable_ = true;
00377 }
00378 value_ += string;
00379 translated_value_ = "";
00380 } else {
00381 value_ += string;
00382 }
00383
00384 return *this;
00385 }
00386
00387
00388 const std::string& t_string::str() const
00389 {
00390 if(!translatable_)
00391 return value_;
00392
00393 if(translatable_ && !translated_value_.empty())
00394 return translated_value_;
00395
00396 for(walker w(*this); !w.eos(); w.next()) {
00397 std::string part(w.begin(), w.end());
00398
00399 if(w.translatable()) {
00400 translated_value_ += dsgettext(w.textdomain().c_str(), part.c_str());
00401 } else {
00402 translated_value_ += part;
00403 }
00404 }
00405
00406 return translated_value_;
00407 }
00408
00409
00410 void t_string::add_textdomain(const std::string& name, const std::string& path)
00411 {
00412 LOG_CF << "Binding textdomain " << name << " to path " << path << "\n";
00413
00414
00415 bindtextdomain(name.c_str(), path.c_str());
00416 bind_textdomain_codeset(name.c_str(), "UTF-8");
00417 }
00418
00419 std::ostream& operator<<(std::ostream& stream, const t_string& string)
00420 {
00421 stream << string.str();
00422 return stream;
00423 }
00424