dictionary.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. // tinygettext - A gettext replacement that works directly on .po files
  2. // Copyright (c) 2006 Ingo Ruhnke <grumbel@gmail.com>
  3. //
  4. // This software is provided 'as-is', without any express or implied
  5. // warranty. In no event will the authors be held liable for any damages
  6. // arising from the use of this software.
  7. //
  8. // Permission is granted to anyone to use this software for any purpose,
  9. // including commercial applications, and to alter it and redistribute it
  10. // freely, subject to the following restrictions:
  11. //
  12. // 1. The origin of this software must not be misrepresented; you must not
  13. // claim that you wrote the original software. If you use this software
  14. // in a product, an acknowledgement in the product documentation would be
  15. // appreciated but is not required.
  16. // 2. Altered source versions must be plainly marked as such, and must not be
  17. // misrepresented as being the original software.
  18. // 3. This notice may not be removed or altered from any source distribution.
  19. #include <assert.h>
  20. #include "tinygettext/log_stream.hpp"
  21. #include "tinygettext/dictionary.hpp"
  22. namespace tinygettext {
  23. namespace {
  24. std::ostream& operator<<(std::ostream& o, const std::vector<std::string>& v)
  25. {
  26. for (std::vector<std::string>::const_iterator it = v.begin(); it != v.end(); ++it)
  27. {
  28. if (it != v.begin())
  29. o << ", ";
  30. o << "'" << *it << "'";
  31. }
  32. return o;
  33. }
  34. } // namespace
  35. Dictionary::Dictionary(const std::string& charset_) :
  36. entries(),
  37. ctxt_entries(),
  38. charset(charset_),
  39. plural_forms(),
  40. m_has_fallback(false),
  41. m_fallback()
  42. {
  43. }
  44. Dictionary::~Dictionary()
  45. {
  46. }
  47. std::string
  48. Dictionary::get_charset() const
  49. {
  50. return charset;
  51. }
  52. void
  53. Dictionary::set_plural_forms(const PluralForms& plural_forms_)
  54. {
  55. plural_forms = plural_forms_;
  56. }
  57. PluralForms
  58. Dictionary::get_plural_forms() const
  59. {
  60. return plural_forms;
  61. }
  62. std::string
  63. Dictionary::translate_plural(const std::string& msgid, const std::string& msgid_plural, int num) const
  64. {
  65. return translate_plural(entries, msgid, msgid_plural, num);
  66. }
  67. std::string
  68. Dictionary::translate_plural(const Entries& dict, const std::string& msgid, const std::string& msgid_plural, int count) const
  69. {
  70. Entries::const_iterator it = dict.find(msgid);
  71. if (it != dict.end())
  72. {
  73. unsigned int n = plural_forms.get_plural(count);
  74. const std::vector<std::string>& msgstrs = it->second;
  75. if (n >= msgstrs.size())
  76. {
  77. log_error << "Plural translation not available (and not set to empty): '" << msgid << "'" << std::endl;
  78. log_error << "Missing plural form: " << n << std::endl;
  79. return msgid;
  80. }
  81. if (!msgstrs[n].empty())
  82. return msgstrs[n];
  83. else
  84. if (count == 1) // default to english rules
  85. return msgid;
  86. else
  87. return msgid_plural;
  88. }
  89. else
  90. {
  91. log_info << "Couldn't translate: " << msgid << std::endl;
  92. log_info << "Candidates: " << std::endl;
  93. for (it = dict.begin(); it != dict.end(); ++it)
  94. log_info << "'" << it->first << "'" << std::endl;
  95. if (count == 1) // default to english rules
  96. return msgid;
  97. else
  98. return msgid_plural;
  99. }
  100. }
  101. std::string
  102. Dictionary::translate(const std::string& msgid) const
  103. {
  104. return translate(entries, msgid);
  105. }
  106. std::string
  107. Dictionary::translate(const Entries& dict, const std::string& msgid) const
  108. {
  109. Entries::const_iterator i = dict.find(msgid);
  110. if (i != dict.end() && !i->second.empty())
  111. {
  112. return i->second[0];
  113. }
  114. else
  115. {
  116. log_info << "Couldn't translate: " << msgid << std::endl;
  117. if (m_has_fallback) return m_fallback->translate(msgid);
  118. else return msgid;
  119. }
  120. }
  121. std::string
  122. Dictionary::translate_ctxt(const std::string& msgctxt, const std::string& msgid) const
  123. {
  124. CtxtEntries::const_iterator i = ctxt_entries.find(msgctxt);
  125. if (i != ctxt_entries.end())
  126. {
  127. return translate(i->second, msgid);
  128. }
  129. else
  130. {
  131. log_info << "Couldn't translate: " << msgid << std::endl;
  132. return msgid;
  133. }
  134. }
  135. std::string
  136. Dictionary::translate_ctxt_plural(const std::string& msgctxt,
  137. const std::string& msgid, const std::string& msgidplural, int num) const
  138. {
  139. CtxtEntries::const_iterator i = ctxt_entries.find(msgctxt);
  140. if (i != ctxt_entries.end())
  141. {
  142. return translate_plural(i->second, msgid, msgidplural, num);
  143. }
  144. else
  145. {
  146. log_info << "Couldn't translate: " << msgid << std::endl;
  147. if (num != 1) // default to english
  148. return msgidplural;
  149. else
  150. return msgid;
  151. }
  152. }
  153. void
  154. Dictionary::add_translation(const std::string& msgid, const std::string& msgid_plural,
  155. const std::vector<std::string>& msgstrs)
  156. {
  157. std::vector<std::string>& vec = entries[msgid];
  158. if (vec.empty())
  159. {
  160. vec = msgstrs;
  161. }
  162. else if (vec != msgstrs)
  163. {
  164. log_warning << "collision in add_translation: '"
  165. << msgid << "', '" << msgid_plural
  166. << "' -> [" << vec << "] vs [" << msgstrs << "]" << std::endl;
  167. vec = msgstrs;
  168. }
  169. }
  170. void
  171. Dictionary::add_translation(const std::string& msgid, const std::string& msgstr)
  172. {
  173. std::vector<std::string>& vec = entries[msgid];
  174. if (vec.empty())
  175. {
  176. vec.push_back(msgstr);
  177. }
  178. else if (vec[0] != msgstr)
  179. {
  180. log_warning << "collision in add_translation: '"
  181. << msgid << "' -> '" << msgstr << "' vs '" << vec[0] << "'" << std::endl;
  182. vec[0] = msgstr;
  183. }
  184. }
  185. void
  186. Dictionary::add_translation(const std::string& msgctxt,
  187. const std::string& msgid, const std::string& msgid_plural,
  188. const std::vector<std::string>& msgstrs)
  189. {
  190. std::vector<std::string>& vec = ctxt_entries[msgctxt][msgid];
  191. if (vec.empty())
  192. {
  193. vec = msgstrs;
  194. }
  195. else if (vec != msgstrs)
  196. {
  197. log_warning << "collision in add_translation: '"
  198. << msgctxt << "', '" << msgid << "', '" << msgid_plural
  199. << "' -> [" << vec << "] vs [" << msgstrs << "]" << std::endl;
  200. vec = msgstrs;
  201. }
  202. }
  203. void
  204. Dictionary::add_translation(const std::string& msgctxt, const std::string& msgid, const std::string& msgstr)
  205. {
  206. std::vector<std::string>& vec = ctxt_entries[msgctxt][msgid];
  207. if (vec.empty())
  208. {
  209. vec.push_back(msgstr);
  210. }
  211. else if (vec[0] != msgstr)
  212. {
  213. log_warning << "collision in add_translation: '"
  214. << msgctxt << "', '" << msgid
  215. << "' -> '" << vec[0] << "' vs '" << msgstr << "'" << std::endl;
  216. vec[0] = msgstr;
  217. }
  218. }
  219. } // namespace tinygettext
  220. /* EOF */