ECGetText.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /*
  2. * Copyright 2005 - 2016 Zarafa and its licensors
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3,
  6. * as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. */
  17. #include <kopano/zcdefs.h>
  18. #include <kopano/lockhelper.hpp>
  19. #include <kopano/platform.h>
  20. #include <kopano/ECGetText.h>
  21. #include <kopano/charset/convert.h>
  22. #include <map>
  23. #include <mutex>
  24. #include <string>
  25. #include <cassert>
  26. namespace KC {
  27. namespace detail {
  28. /**
  29. * This class performs the actual conversion and caching of the translated messages.
  30. * Results are cached based on the pointer value, not the string content. This implies
  31. * two assumptions:
  32. * 1. Gettext always returns the same pointer for a particular translation.
  33. * 2. If there's no translation, the original pointer is returned. So we assume that the
  34. * compiler optimized string literals to have the same address if they're equal. If
  35. * this assumption is false, this will lead to more conversions, and more memory usage
  36. * by the cache.
  37. */
  38. class converter _kc_final {
  39. public:
  40. /**
  41. * Get the global converter instance.
  42. * @return The global converter instance.
  43. */
  44. static converter *getInstance() {
  45. scoped_lock locker(s_hInstanceLock);
  46. if (!s_lpInstance) {
  47. s_lpInstance = new converter;
  48. atexit(&destroy);
  49. }
  50. return s_lpInstance;
  51. }
  52. /**
  53. * Perform the actual cache lookup or conversion.
  54. *
  55. * @param[in] lpsz The string to convert.
  56. * @return The converted string.
  57. */
  58. const wchar_t *convert(const char *lpsz) {
  59. scoped_lock l_cache(m_hCacheLock);
  60. auto insResult = m_cache.insert(cache_type::value_type(lpsz, std::wstring()));
  61. if (insResult.second == true) // successful insert, so not found in cache
  62. insResult.first->second.assign(m_converter.convert_to<std::wstring>(lpsz));
  63. const wchar_t *lpszW = insResult.first->second.c_str();
  64. return lpszW;
  65. }
  66. private:
  67. /**
  68. * Destroys the instance in application exit.
  69. */
  70. static void destroy() {
  71. assert(s_lpInstance);
  72. delete s_lpInstance;
  73. s_lpInstance = NULL;
  74. }
  75. private:
  76. static converter *s_lpInstance;
  77. static std::mutex s_hInstanceLock;
  78. typedef std::map<const char *, std::wstring> cache_type;
  79. convert_context m_converter;
  80. cache_type m_cache;
  81. std::mutex m_hCacheLock;
  82. };
  83. std::mutex converter::s_hInstanceLock;
  84. converter* converter::s_lpInstance = NULL;
  85. } // namespace detail
  86. /**
  87. * Performs a 'regular' gettext and converts the result to a wide character string.
  88. *
  89. * @param[in] domainname The domain to use for the translation
  90. * @param[in] msgid The msgid of the message to be translated.
  91. *
  92. * @return The converted, translated string.
  93. */
  94. LPWSTR kopano_dcgettext_wide(const char *domainname, const char *msgid)
  95. {
  96. const char *lpsz = msgid;
  97. #ifndef NO_GETTEXT
  98. lpsz = dcgettext(domainname, msgid, LC_MESSAGES);
  99. #endif
  100. return const_cast<wchar_t *>(detail::converter::getInstance()->convert(lpsz));
  101. }
  102. } /* namespace */