tstring.cpp

Go to the documentation of this file.
00001 /* $Id: tstring.cpp 26799 2008-05-23 18:16:41Z mordante $ */
00002 /*
00003    Copyright (C) 2004 by Philippe Plantier <ayin@anathas.org>
00004    Copyright (C) 2005 - 2008 by Guillaume Melquiond <guillaume.melquiond@gmail.com>
00005    Part of the Battle for Wesnoth Project http://www.wesnoth.org
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License version 2
00009    or at your option any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 /**
00017  *  @file tstring.cpp
00018  *  Routines for translatable strings.
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     // Register and (re-)bind this textdomain
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 

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs